3 # Copyright 2008 Google Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
18 """Suggestion Box - An example paging application.
20 A simple Suggestion Box application that demonstrates
21 paging by creating a unique value for each suggestion. The
22 uniqueness is created by sharding counters across
23 all the users of the system.
30 import wsgiref
.handlers
32 from google
.appengine
.ext
import webapp
33 from google
.appengine
.ext
.webapp
import template
34 from google
.appengine
.ext
import db
35 from google
.appengine
.api
import users
36 from google
.appengine
.ext
.webapp
.util
import login_required
37 from google
.appengine
.ext
.webapp
.util
import run_wsgi_app
43 class Contributor (db
.Model
):
45 Contributors are stored with a key of the users email
46 address. The 'count' is used as a per user
47 counter that is incremented each time a user
48 adds a Suggestion and is used to generate a unique
49 property value 'Suggestion.when' that allows paging
50 over suggestions in creation order.
52 count
= db
.IntegerProperty(default
=0)
55 class Suggestion(db
.Model
):
57 A suggestion in the suggestion box, which we want to display
58 in the order they were created.
60 suggestion
= db
.StringProperty()
61 created
= db
.DateTimeProperty(auto_now_add
=True)
62 when
= db
.StringProperty()
65 def _unique_user(user
):
67 Creates a unique string by using an increasing
68 counter sharded per user. The resulting string
69 is hashed to keep the users email address private.
72 The currently logged in user.
75 A hashed unique value based on the user
76 and the associated incremented Contributor.count.
81 contributor
= Contributor
.get_by_key_name(email
)
82 if contributor
== None:
83 contributor
= Contributor(key_name
=email
)
84 contributor
.count
+= 1
86 return contributor
.count
88 count
= db
.run_in_transaction(txn
)
90 return hashlib
.md5(email
+ '|' + str(count
)).hexdigest()
93 def whenfromcreated(created
):
95 Create a unique 'when' property value based on the
96 time the entity was created.
99 created: datetime the entity was created.
102 A unique value that will be ordered by
103 entity creation time.
105 return created
.isoformat()[0:19] + '|' + _unique_user(users
.get_current_user())
108 class SuggestionHandler(webapp
.RequestHandler
):
110 Handles the creation of a single Suggestion, and the display
111 of suggestions broken into PAGESIZE pages.
116 bookmark
= self
.request
.get('bookmark')
119 query
= Suggestion
.gql('WHERE when <= :bookmark ORDER BY when DESC',
121 suggestions
= query
.fetch(PAGESIZE
+1)
123 suggestions
= Suggestion
.gql('ORDER BY when DESC').fetch(PAGESIZE
+1)
124 if len(suggestions
) == PAGESIZE
+1:
125 next
= suggestions
[-1].when
126 suggestions
= suggestions
[:PAGESIZE
]
128 template_values
= {'next': next
, 'suggestions': suggestions
}
129 template_file
= os
.path
.join(os
.path
.dirname(__file__
), 'suggestion.html')
130 self
.response
.out
.write(template
.render(template_file
, template_values
))
133 now
= datetime
.datetime
.now()
134 when
= whenfromcreated(now
)
136 suggestion
= self
.request
.get('suggestion'),
141 self
.redirect('/unique/')
144 class SuggestionPopulate(webapp
.RequestHandler
):
146 now
= datetime
.datetime
.now()
149 suggestion
= 'Suggestion %d' % i
,
151 when
= whenfromcreated(now
))
154 self
.redirect('/unique/')
158 application
= webapp
.WSGIApplication([
159 ('/unique/pop/', SuggestionPopulate
),
160 ('/unique/', SuggestionHandler
)
162 wsgiref
.handlers
.CGIHandler().run(application
)
165 if __name__
== '__main__':