def GetAccess( self, pebbleToken, createIfRequired ): if self.CheckPlatformAccess( pebbleToken ): return # Check to see if we already have facebook access accessToken = storage.FindPlatformAccessCode( pebbleToken, defines.PLATFORM ) if accessToken: response = \ { 'status' : "success", } self.response.status = requests.codes.ok self.response.data = jsonToString( response ) return # No access code yet, perhaps we've already got an existing auth request on the go? authRequest = self.DBGetExistingDeviceAuthCode( pebbleToken ) if authRequest is None and createIfRequired: # No existing auth request found for this watch logging.debug( "Creating new auth request" ) # Request new code from facebook authRequestResponse = net.GetNewDeviceLoginCode()[ 1 ] # Store new request authRequest = self.DBCreateNewDeviceAuthCode( pebbleToken, authRequestResponse ) elif authRequest: # Check status self.CheckLoginCodeStatus( pebbleToken, authRequest ) return if authRequest: logging.debug( "Turning auth request into json response" ) returnData = \ { "status" : "require_auth", "url" : authRequest.user_uri, "code" : authRequest.user_code, "interval" : authRequest.update_interval } self.response.status = requests.codes.ok self.response.data = jsonToString( returnData ) else: logging.debug( "No auth request - creating json error response" ) returnData = \ { "status" : "no_auth", "error" : "No authorisation code found" } self.response.status = requests.codes.bad_request self.response.data = jsonToString( returnData )
def CalcHash( data ): if data is None: return 0 if isinstance( data, unicode ): logging.debug( "Data is unicode, converting: " + data ) data = jsonToString( data ) logging.debug( "Data is json: " + data ) return zlib.adler32( data )
def CheckLoginCodeStatus( self, pebbleToken, authRequest ): #todo: Check time since last poll? logging.debug( "Checking log in status with facebook" ) loginCodeStatus = net.GetDeviceLoginCodeStatus( authRequest.auth_code ) if loginCodeStatus[ 0 ] == requests.codes.ok: # Create parent object, this does not need to be written to the # database as it's only purpose is to contain the pebble token watch = storage.CreateWatch( pebbleToken ) accessToken = loginCodeStatus[ 1 ][ 'access_token' ] access = storage.CreateAccess( watch, defines.PLATFORM, accessToken ) # store it in the database access.put() # We need to store the facebook user id for when we're told about event changes # And also the user's name so that we can display it on the watch as evidence of a successful sign in getDataStatus = net.GetCurrentUserData( accessToken ) if( getDataStatus[ 0 ] == requests.codes.ok ): self.response.status = requests.codes.ok response = \ { 'status' : "success", 'name' : getDataStatus[ 1 ][ 'name' ] } newSub = storage.CreateFacebookSubscription( getDataStatus[ 1 ][ 'id' ], pebbleToken ) newSub.put() # No longer required authRequest.delete() else: self.response.status = requests.codes.bad_request response = \ { 'status' : "failure", 'message' : "Could not get user details", } else: self.response.status = requests.codes.bad_request response = \ { 'status' : "error", 'message' : status[ 1 ][ 'error' ][ 'message' ], 'user_code' : authRequest.user_code } self.response.data = jsonToString( response )
def Process(pebbleToken, events, fbuid): # Create parent object, this does not need to be written to the # database as it's only purpose is to contain the pebble token watch = storage.CreateWatch(pebbleToken) for event in events: logging.debug("Event '" + event["name"] + "', ID: " + event["id"]) # We need to associate the key with facebook events # ts-fbev-XXXXXXXXXXXXXXXX-YYYYYYYYYYYYYYYYY key = "ts-fbev-" + str(fbuid) + "-" + str(event["id"]) startTime = defines.ISO8601ToDateTime(event["start_time"]) if "description" in event: description = event["description"] else: description = "No description" pin = storage.CreateWatchPin(watch, key, event["name"], description, startTime) pin.put() # Convert time to UTC startTimeUtc = startTime.astimezone(defines.UTC) # Construct HTTP put request pebbleDateFormat = "%Y-%m-%dT%H:%M:%SZ" eventTimeInPebbleFormat = startTimeUtc.strftime(pebbleDateFormat) body = { "id": key, "time": eventTimeInPebbleFormat, "layout": { "type": "genericPin", "title": event["name"], "tinyIcon": "system://images/NOTIFICATION_FACEBOOK", "body": description, }, } headers = {"X-User-Token": pebbleToken, "Content-Type": "application/json"} url = "https://timeline-api.getpebble.com/v1/user/pins/" + key bodyStr = jsonToString(body) response = requests.put(url=url, headers=headers, data=bodyStr) logging.debug("Pin URL: " + str(response.url)) logging.debug("Pin Data: " + bodyStr) logging.debug("Pin Headers: " + str(headers)) logging.debug("Pin response status: " + str(response.status_code)) logging.debug("Pin response data: " + response.text)
def SubscribeBirthdays( self, pebbleToken, action ): logging.debug( "SubscribeBirthdays()" ) # update sub data fbSubData = storage.FindFacebookSubscriptionByWatchToken( pebbleToken ) fbSubData.birthdays = action fbSubData.put() response = \ { 'status' : "success", } self.response.status = requests.codes.ok self.response.data = jsonToString( response )
def CheckPlatformAccess( self, pebbleToken ): # Check to see if we already have facebook access access = storage.FindPlatformAccessCode( pebbleToken, defines.PLATFORM ) if access: response = \ { 'status' : "success", } self.response.status = requests.codes.ok self.response.data = jsonToString( response ) return True return False
def common( self, params, method ): if method != "delete": self.response.set_status( codes.file_not_found ) return if 'X-User-Token' not in self.request.headers: self.response.set_status( codes.unauthorized ) return common.storage.DeleteAllPinsForUser( self.request.headers[ 'X-User-Token' ] ) response = jsonToString( { 'status' : "success" } ) self.response.set_status( codes.ok ) self.response.write( response ) self.response.headers[ "Content-Type" ] = "application/json"
def SubscribeEvents( self, pebbleToken, action ): logging.debug( "SubscribeEvents()" ) # update sub data fbSubData = storage.FindFacebookSubscriptionByWatchToken( pebbleToken ) fbSubData.events = action fbSubData.put() if action: # Grab all the events for the user events.Fetch( pebbleToken, fbSubData.key().name() ) response = \ { 'status' : "success", } self.response.status = requests.codes.ok self.response.data = jsonToString( response )
def common( self, params, method ): logging.debug( "Base Handler" ) #Fetch config from derived class config = self.GetConfig() logging.debug( "Params: " + str( params ) ) if "handler" in params: branch = None handlerConfig = config[ params[ "handler" ] ] if method in handlerConfig: methodConfig = handlerConfig[ method ] if "branch" in params and params[ "branch" ] in methodConfig: branch = methodConfig[ params[ "branch" ] ] elif "default" in methodConfig: branch = methodConfig[ "default" ] branch = self.ProcessBranch( branch ) if branch is None: return # Import library lib = importlib.import_module( handlerConfig[ "lib" ] ) # Create handler handler = lib.Handler( self.app, self.request ) # Call branch getattr( handler, branch )( params ) if isinstance( handler.response.data, basestring ): data = handler.response.data else: data = jsonToString( handler.response.data ) self.response.set_status( handler.response.status ) self.response.write( data ) else: logging.warning( "Invalid handler or method" ) self.response.set_status( codes.not_found )
def Send( self ): now = datetime.now( common.datetime.UTC ) timeUntilPin = self.time - now # Can't have pins more than a year in the future if timeUntilPin.days > 364: logging.warning( "Ignoring pin with id " + str( self.id ) + " as it's more than a year in the future" ) return ( codes.bad_request, { "message" : "INVALID_DATE_FUTURE" } ) # Can't have pins more than 2 days in the past if timeUntilPin.days < -2: logging.warning( "Ignoring pin with id " + str( self.id ) + " as it's more than 2 days in the past" ) return ( codes.bad_request, { "message" : "INVALID_DATE_PAST" } ) if self.DataMatchesExistingPin(): logging.info( "Skipping pin with id " + str( self.id ) + " as there have been no changes since the previous time this pin was sent to the server" ) return ( codes.ok, { "message" : "NO_CHANGE" } ) #Convert the python datetime object into an iso8601-ish format for the pebble api pebbleDateFormat = "%Y-%m-%dT%H:%M:%SZ" timeInPebbleFormat = self.time.strftime( pebbleDateFormat ) lastUpdated = now.strftime( pebbleDateFormat ) if self.source is not None: self.headings.append( "Source" ) self.paragraphs.append( self.source ) self.headings.append( "Application" ) self.paragraphs.append( AssemblePinSignature() ) data = \ { 'id' : self.id, 'time' : timeInPebbleFormat, 'layout' : \ { 'type' : "genericPin", 'title' : self.title, 'tinyIcon' : self.icon, 'lastUpdated' : lastUpdated, 'headings' : self.headings, 'paragraphs' : self.paragraphs } } if self.description is not None: data[ "layout" ][ "body" ] = self.description if self.subtitle is not None: data[ "layout" ][ "subtitle" ] = self.subtitle if self.location is not None: data[ "layout" ][ "locationName" ] = self.location data[ "layout" ][ "type" ] = "calendarPin" if self.duration is not None: data[ "duration" ] = self.duration data[ "layout" ][ "type" ] = "calendarPin" if len( self.actions ) > 0: data[ "actions" ] = self.actions # Construct the request config config = \ { 'request' : { 'url' : "https://timeline-api.getpebble.com/v1/user/pins/" + self.id, 'method' : "PUT", 'headers' : { 'X-User-Token' : self.pebbleToken, 'Content-Type' : "application/json" }, 'data' : jsonToString( data ) }, 'response' : { 'success' : { 'status' : codes.ok, 'map' : {} }, 'failure' : { 'map' : { 'message' : "errorCode" } } } } response = net.MakeRequest( config ) if response[ 0 ] != codes.ok: if response[ 1 ][ "message" ] == "INVALID_JSON": logFunc = logging.error else: logFunc = logging.warning logFunc( "Create Pin Failed Response: " + str( response[ 1 ] ) ) logFunc( "Create Pin Failed Request : " + str( config ) ) return ( response[ 0 ], response[ 1 ] )
def post( self ): self.response.set_status( codes.not_found ) self.response.write( jsonToString( { 'status' : "Invalid URL" } ) ) self.response.headers[ "Content-Type" ] = "application/json"