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 19Contains several RequestHandler subclasses used to handle post operations. 20This 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 27import cgi 28from datetime import datetime 29from django.utils import simplejson 30from google.appengine.api import users 31from google.appengine.ext import db 32from google.appengine.ext import webapp 33from model import datastore 34import wsgiref.handlers 35 36 37class 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 57class 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 98class 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 132def toJSON(object): 133 """Dumps the data represented by the object to JSON for wire transfer.""" 134 return simplejson.dumps(object) 135 136class 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 162def 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 172if __name__ == "__main__": 173 main()