1 #!/usr/bin/env python 2 # 3 # Copyright 2007 Google Inc. 4 # 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 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 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. 16 # 17 18 import appengine_config 19 20 import cgi 21 import datetime 22 import time 23 import wsgiref.handlers 24 25 from google.appengine.ext import db 26 from google.appengine.api import users 27 from google.appengine.ext import webapp 28 29 from protorpc import message_types 30 from protorpc import messages 31 from protorpc import remote 32 from protorpc.webapp import service_handlers 33 34 35 class Greeting(db.Model): 36 author = db.UserProperty() 37 content = db.StringProperty(multiline=True) 38 date = db.DateTimeProperty(auto_now_add=True) 39 40 41 class MainPage(webapp.RequestHandler): 42 def get(self): 43 self.response.out.write('<html><body>') 44 45 greetings = db.GqlQuery("SELECT * " 46 "FROM Greeting " 47 "ORDER BY date DESC LIMIT 10") 48 49 for greeting in greetings: 50 if greeting.author: 51 self.response.out.write('<b>%s</b> wrote:' % greeting.author.nickname()) 52 else: 53 self.response.out.write('An anonymous person wrote:') 54 self.response.out.write('<blockquote>%s</blockquote>' % 55 cgi.escape(greeting.content)) 56 57 58 self.response.out.write(""" 59 <form action="/sign" method="post"> 60 <div><textarea name="content" rows="3" cols="60"></textarea></div> 61 <div><input type="submit" value="Sign Guestbook"></div> 62 </form> 63 </body> 64 </html>""") 65 66 67 class Guestbook(webapp.RequestHandler): 68 def post(self): 69 greeting = Greeting() 70 71 if users.get_current_user(): 72 greeting.author = users.get_current_user() 73 74 greeting.content = self.request.get('content') 75 greeting.put() 76 self.redirect('/') 77 78 79 class Note(messages.Message): 80 81 text = messages.StringField(1, required=True) 82 when = messages.IntegerField(2) 83 84 85 class GetNotesRequest(messages.Message): 86 87 limit = messages.IntegerField(1, default=10) 88 on_or_before = messages.IntegerField(2) 89 90 class Order(messages.Enum): 91 WHEN = 1 92 TEXT = 2 93 order = messages.EnumField(Order, 3, default=Order.WHEN) 94 95 96 class Notes(messages.Message): 97 notes = messages.MessageField(Note, 1, repeated=True) 98 99 100 class PostService(remote.Service): 101 102 # Add the remote decorator to indicate the service methods 103 @remote.method(Note) 104 def post_note(self, request): 105 106 # If the Note instance has a timestamp, use that timestamp 107 if request.when is not None: 108 when = datetime.datetime.utcfromtimestamp(request.when) 109 110 # Else use the current time 111 else: 112 when = datetime.datetime.now() 113 note = Greeting(content=request.text, date=when) 114 note.put() 115 return message_types.VoidMessage() 116 117 @remote.method(GetNotesRequest, Notes) 118 def get_notes(self, request): 119 query = Greeting.all().order('-date') 120 121 if request.on_or_before: 122 when = datetime.datetime.utcfromtimestamp( 123 request.on_or_before) 124 query.filter('date <=', when) 125 126 notes = [] 127 for note_model in query.fetch(request.limit): 128 if note_model.date: 129 when = int(time.mktime(note_model.date.utctimetuple())) 130 else: 131 when = None 132 note = Note(text=note_model.content, when=when) 133 notes.append(note) 134 135 if request.order == GetNotesRequest.Order.TEXT: 136 notes.sort(key=lambda note: note.text) 137 138 return Notes(notes=notes) 139 140 141 service_mapping = service_handlers.service_mapping( 142 [('/postservice', PostService)]) 143 144 application = webapp.WSGIApplication([ 145 ('/', MainPage), 146 ('/sign', Guestbook), 147 ] + service_mapping, 148 debug=True) 149 150 151 def main(): 152 wsgiref.handlers.CGIHandler().run(application) 153 154 155 if __name__ == '__main__': 156 main() 157