1 #!/usr/bin/python2.5 2 3 # Copyright (C) 2010 The Android Open Source Project 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); you may not 6 # use this file except in compliance with the License. You may obtain a copy of 7 # 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, WITHOUT 13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 # License for the specific language governing permissions and limitations under 15 # the License. 16 17 """Handlers for Sample SyncAdapter services. 18 19 Contains several RequestHandler subclasses used to handle post operations. 20 This script is designed to be run directly as a WSGI application. 21 22 Authenticate: Handles user requests for authentication. 23 FetchFriends: Handles user requests for friend list. 24 FriendData: Stores information about user's friends. 25 """ 26 27 import cgi 28 from datetime import datetime 29 from django.utils import simplejson 30 from google.appengine.api import users 31 from google.appengine.ext import db 32 from google.appengine.ext import webapp 33 from model import datastore 34 import wsgiref.handlers 35 36 37 class Authenticate(webapp.RequestHandler): 38 """Handles requests for login and authentication. 39 40 UpdateHandler only accepts post events. It expects each 41 request to include username and password fields. It returns authtoken 42 after successful authentication and "invalid credentials" error otherwise. 43 """ 44 45 def post(self): 46 self.username = self.request.get('username') 47 self.password = self.request.get('password') 48 password = datastore.UserCredentials.get(self.username) 49 if password == self.password: 50 self.response.set_status(200, 'OK') 51 # return the password as AuthToken 52 self.response.out.write(password) 53 else: 54 self.response.set_status(401, 'Invalid Credentials') 55 56 57 class FetchFriends(webapp.RequestHandler): 58 """Handles requests for fetching user's friendlist. 59 60 UpdateHandler only accepts post events. It expects each 61 request to include username and authtoken. If the authtoken is valid 62 it returns user's friend info in JSON format.It uses helper 63 class FriendData to fetch user's friendlist. 64 """ 65 66 def post(self): 67 self.username = self.request.get('username') 68 self.password = self.request.get('password') 69 self.timestamp = None 70 timestamp = self.request.get('timestamp') 71 if timestamp: 72 self.timestamp = datetime.strptime(timestamp, '%Y/%m/%d %H:%M') 73 password = datastore.UserCredentials.get(self.username) 74 if password == self.password: 75 self.friend_list = [] 76 friends = datastore.UserFriends.get_friends(self.username) 77 if friends: 78 for friend in friends: 79 friend_handle = getattr(friend, 'friend_handle') 80 81 if self.timestamp is None or getattr(friend, 'updated') > self.timestamp: 82 if (getattr(friend, 'deleted')) == True: 83 friend = {} 84 friend['u'] = friend_handle 85 friend['d'] = 'true' 86 friend['i'] = str(datastore.User.get_user_id(friend_handle)) 87 self.friend_list.append(friend) 88 else: 89 FriendsData(self.friend_list, friend_handle) 90 else: 91 if datastore.User.get_user_last_updated(friend_handle) > self.timestamp: 92 FriendsData(self.friend_list, friend_handle) 93 self.response.set_status(200) 94 self.response.out.write(toJSON(self.friend_list)) 95 else: 96 self.response.set_status(401, 'Invalid Credentials') 97 98 class FetchStatus(webapp.RequestHandler): 99 """Handles requests fetching friend statuses. 100 101 UpdateHandler only accepts post events. It expects each 102 request to include username and authtoken. If the authtoken is valid 103 it returns status info in JSON format. 104 """ 105 106 def post(self): 107 self.username = self.request.get('username') 108 self.password = self.request.get('password') 109 password = datastore.UserCredentials.get(self.username) 110 if password == self.password: 111 self.status_list = [] 112 friends = datastore.UserFriends.get_friends(self.username) 113 if friends: 114 for friend in friends: 115 friend_handle = getattr(friend, 'friend_handle') 116 status_text = datastore.User.get_user_status(friend_handle) 117 user_id = datastore.User.get_user_id(friend_handle) 118 status = {} 119 status['i'] = str(user_id) 120 status['s'] = status_text 121 self.status_list.append(status) 122 self.response.set_status(200) 123 self.response.out.write(toJSON(self.status_list)) 124 else: 125 self.response.set_status(401, 'Invalid Credentials') 126 127 def toJSON(self): 128 """Dumps the data represented by the object to JSON for wire transfer.""" 129 return simplejson.dumps(self.friend_list) 130 131 132 def toJSON(object): 133 """Dumps the data represented by the object to JSON for wire transfer.""" 134 return simplejson.dumps(object) 135 136 class FriendsData(object): 137 """Holds data for user's friends. 138 139 This class knows how to serialize itself to JSON. 140 """ 141 __FIELD_MAP = { 142 'handle': 'u', 143 'firstname': 'f', 144 'lastname': 'l', 145 'status': 's', 146 'phone_home': 'h', 147 'phone_office': 'o', 148 'phone_mobile': 'm', 149 'email': 'e', 150 } 151 152 def __init__(self, friend_list, username): 153 obj = datastore.User.get_user_info(username) 154 friend = {} 155 for obj_name, json_name in self.__FIELD_MAP.items(): 156 if hasattr(obj, obj_name): 157 friend[json_name] = str(getattr(obj, obj_name)) 158 friend['i'] = str(obj.key().id()) 159 friend_list.append(friend) 160 161 162 def main(): 163 application = webapp.WSGIApplication( 164 [('/auth', Authenticate), 165 ('/login', Authenticate), 166 ('/fetch_friend_updates', FetchFriends), 167 ('/fetch_status', FetchStatus), 168 ], 169 debug=True) 170 wsgiref.handlers.CGIHandler().run(application) 171 172 if __name__ == "__main__": 173 main()