-
Notifications
You must be signed in to change notification settings - Fork 6.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move sample from appengine-guestbook-namespaces-python
- Loading branch information
Jerjou Cheng
committed
Sep 23, 2015
1 parent
000ff37
commit 3a562d3
Showing
8 changed files
with
253 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Guestbook with Namespaces | ||
|
||
This application implements the Python [Guestbook sample][7] but uses | ||
datastore namespaces to keep values in separate places. | ||
|
||
Guestbook is an example application showing basic usage of Google App | ||
Engine. Users can read & write text messages and optionaly log-in with | ||
their Google account. Messages are stored in App Engine (NoSQL) | ||
High Replication Datastore (HRD) and retrieved using a strongly consistent | ||
(ancestor) query. | ||
|
||
## Products | ||
- [App Engine][1] | ||
|
||
## Language | ||
- [Python][2] | ||
|
||
## APIs | ||
- [NDB Datastore API][3] | ||
- [Users API][4] | ||
|
||
## Dependencies | ||
- [webapp2][5] | ||
- [jinja2][6] | ||
|
||
[1]: https://developers.google.com/appengine | ||
[2]: https://python.org | ||
[3]: https://developers.google.com/appengine/docs/python/ndb/ | ||
[4]: https://developers.google.com/appengine/docs/python/users/ | ||
[5]: http://webapp-improved.appspot.com/ | ||
[6]: http://jinja.pocoo.org/docs/ | ||
[7]: https://github.com/GoogleCloudPlatform/appengine-guestbook-python/tree/part6-staticfiles |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
application: guestbook-namespaces | ||
version: 1 | ||
runtime: python27 | ||
api_version: 1 | ||
threadsafe: true | ||
|
||
handlers: | ||
- url: /stylesheets | ||
static_dir: stylesheets | ||
|
||
- url: /.* | ||
script: guestbook.application | ||
|
||
libraries: | ||
- name: webapp2 | ||
version: latest | ||
- name: jinja2 | ||
version: latest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# Copyright 2010 Google Inc. All Rights Reserved. | ||
|
||
""" | ||
Manages the namespace for the application. | ||
This file presents ways an ISV (Independent Software Vendor) might use | ||
namespaces to distribute the guestbook application to different corporate | ||
clients. The original guestbook.py is left unchanged. Our namespace choosing | ||
hook is run when datastore or memcache attempt to resolve the namespace. | ||
When defined in appengine_config.py the lib_config mechanism substitutes this | ||
function for the default definition which returns None. This hopefully shows | ||
how easy it can be to make an existing app namespace aware. | ||
Setting _NAMESPACE_PICKER has the following effects: | ||
If _USE_SERVER_NAME, we read the server name | ||
foo.guestbook-isv.appspot.com and set the namespace. | ||
If _USE_GOOGLE_APPS_DOMAIN, we allow the namespace manager to infer the | ||
namespace from the request. | ||
If _USE_COOKIE, then the ISV might have a gateway page that sets a cookie | ||
called 'namespace' for example, and we read this cookie and set the namespace | ||
to its value. Note this is not a secure use of cookies. | ||
Other possibilities not implemented here include using a mapping from user to | ||
namespace and possibly setting a namespace cookie from this mapping. If the | ||
mapping is stored in datastore, we would probably not wish to look it up on | ||
every query. | ||
""" | ||
|
||
__author__ = '[email protected] (Nicholas Verne)' | ||
|
||
|
||
import Cookie | ||
import os | ||
|
||
from google.appengine.api import namespace_manager | ||
|
||
|
||
_USE_SERVER_NAME = 0 | ||
_USE_GOOGLE_APPS_DOMAIN = 1 | ||
_USE_COOKIE = 2 | ||
|
||
_NAMESPACE_PICKER = _USE_SERVER_NAME | ||
|
||
|
||
def namespace_manager_default_namespace_for_request(): | ||
"""Determine which namespace is to be used for a request. | ||
The value of _NAMESPACE_PICKER has the following effects: | ||
If _USE_SERVER_NAME, we read server name | ||
foo.guestbook-isv.appspot.com and set the namespace. | ||
If _USE_GOOGLE_APPS_DOMAIN, we allow the namespace manager to infer | ||
the namespace from the request. | ||
If _USE_COOKIE, then the ISV might have a gateway page that sets a | ||
cookie called 'namespace', and we set the namespace to the cookie's value | ||
""" | ||
name = None | ||
|
||
if _NAMESPACE_PICKER == _USE_SERVER_NAME: | ||
name = os.environ['SERVER_NAME'] | ||
elif _NAMESPACE_PICKER == _USE_GOOGLE_APPS_DOMAIN: | ||
name = namespace_manager.google_apps_namespace() | ||
elif _NAMESPACE_PICKER == _USE_COOKIE: | ||
cookies = os.getenv('HTTP_COOKIE', None) | ||
if cookies: | ||
name = Cookie.BaseCookie(cookies).get('namespace') | ||
|
||
return name |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import os | ||
import urllib | ||
|
||
from google.appengine.api import users | ||
from google.appengine.ext import ndb | ||
|
||
import jinja2 | ||
|
||
import webapp2 | ||
|
||
JINJA_ENVIRONMENT = jinja2.Environment( | ||
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)), | ||
extensions=['jinja2.ext.autoescape']) | ||
|
||
DEFAULT_GUESTBOOK_NAME = 'default_guestbook' | ||
|
||
|
||
# We set a parent key on the 'Greetings' to ensure that they are all in the | ||
# same entity group. Queries across the single entity group will be consistent. | ||
# However, the write rate should be limited to ~1/second. | ||
|
||
def guestbook_key(guestbook_name=DEFAULT_GUESTBOOK_NAME): | ||
"""Constructs a Datastore key for a Guestbook entity with guestbook_name""" | ||
return ndb.Key('Guestbook', guestbook_name) | ||
|
||
|
||
class Greeting(ndb.Model): | ||
"""Models an individual Guestbook entry with author, content, and date.""" | ||
author = ndb.UserProperty() | ||
content = ndb.StringProperty(indexed=False) | ||
date = ndb.DateTimeProperty(auto_now_add=True) | ||
|
||
|
||
class MainPage(webapp2.RequestHandler): | ||
|
||
def get(self): | ||
guestbook_name = self.request.get('guestbook_name', | ||
DEFAULT_GUESTBOOK_NAME) | ||
greetings_query = Greeting.query( | ||
ancestor=guestbook_key(guestbook_name)).order(-Greeting.date) | ||
greetings = greetings_query.fetch(10) | ||
|
||
if users.get_current_user(): | ||
url = users.create_logout_url(self.request.uri) | ||
url_linktext = 'Logout' | ||
else: | ||
url = users.create_login_url(self.request.uri) | ||
url_linktext = 'Login' | ||
|
||
template_values = { | ||
'greetings': greetings, | ||
'guestbook_name': urllib.quote_plus(guestbook_name), | ||
'url': url, | ||
'url_linktext': url_linktext, | ||
} | ||
|
||
template = JINJA_ENVIRONMENT.get_template('index.html') | ||
self.response.write(template.render(template_values)) | ||
|
||
|
||
class Guestbook(webapp2.RequestHandler): | ||
|
||
def post(self): | ||
# We set the same parent key on the 'Greeting' to ensure each Greeting | ||
# is in the same entity group. Queries across the single entity group | ||
# will be consistent. However, the write rate to a single entity group | ||
# should be limited to ~1/second. | ||
guestbook_name = self.request.get('guestbook_name', | ||
DEFAULT_GUESTBOOK_NAME) | ||
greeting = Greeting(parent=guestbook_key(guestbook_name)) | ||
|
||
if users.get_current_user(): | ||
greeting.author = users.get_current_user() | ||
|
||
greeting.content = self.request.get('content') | ||
greeting.put() | ||
|
||
query_params = {'guestbook_name': guestbook_name} | ||
self.redirect('/?' + urllib.urlencode(query_params)) | ||
|
||
|
||
application = webapp2.WSGIApplication([ | ||
('/', MainPage), | ||
('/sign', Guestbook), | ||
], debug=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<!DOCTYPE html> | ||
{% autoescape true %} | ||
<html> | ||
|
||
<head> | ||
<link type="text/css" rel="stylesheet" href="/stylesheets/main.css" /> | ||
</head> | ||
|
||
<body> | ||
{% for greeting in greetings %} | ||
{% if greeting.author %} | ||
<b>{{ greeting.author.nickname() }}</b> wrote: | ||
{% else %} | ||
An anonymous person wrote: | ||
{% endif %} | ||
<blockquote>{{ greeting.content }}</blockquote> | ||
{% endfor %} | ||
|
||
<form action="/sign?guestbook_name={{ guestbook_name }}" method="post"> | ||
<div><textarea name="content" rows="3" cols="60"></textarea></div> | ||
<div><input type="submit" value="Sign Guestbook"></div> | ||
</form> | ||
|
||
<hr> | ||
|
||
<form>Guestbook name: | ||
<input value="{{ guestbook_name }}" name="guestbook_name"> | ||
<input type="submit" value="switch"> | ||
</form> | ||
|
||
<a href="{{ url|safe }}">{{ url_linktext }}</a> | ||
|
||
</body> | ||
</html> | ||
{% endautoescape %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
indexes: | ||
- kind: Greeting | ||
ancestor: yes | ||
properties: | ||
- name: date | ||
direction: desc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
body { | ||
font-family: Verdana, Helvetica, sans-serif; | ||
background-color: #DDDDDD; | ||
} |