def attachments_delete(self, request): """Retrieve metainfo for a single attachments for a timeline card""" current_user = endpoints.get_current_user() if current_user is None: raise endpoints.UnauthorizedException("Authentication required.") card = ndb.Key("TimelineItem", request.itemId).get() if card is None or card.user != current_user: raise endpoints.NotFoundException("Attachment not found.") if card.attachments is not None: for att in card.attachments: if att.id == request.attachmentId: # Delete attachment from blobstore blobkey = blobstore.BlobKey(request.attachmentId) blobstore.delete(blobkey) # Remove attachment from timeline card card.attachments.remove(att) card.put() return AttachmentResponse(id=att.id) raise endpoints.NotFoundException("Attachment not found.")
def ValidateUserIsAuthorized(): """Raises endpoints.UnauthorizedException if the caller is not signed in or is not allowed to publish content. """ user = endpoints.get_current_user() if user is None or user.email() not in CONTENT_DEVELOPERS: raise endpoints.UnauthorizedException()
def get_task_lists_for_user(self, request): """ Returns all the TaskLists for the logged in user. """ current_user = endpoints.get_current_user() if current_user is None: raise endpoints.UnauthorizedException('Invalid token.') current_users_task_user = TaskUser.get_task_user_by_email(current_user.email().lower()) users_task_lists = [] for a_task_list_key in current_users_task_user.task_list_keys: a_task_list = a_task_list_key.get() all_tasks_in_list = [] for a_task_key in a_task_list.task_keys: a_task = a_task_key.get() assigned_to_task_user_msg = None if a_task.assigned_to_email: assigned_to_task_user = TaskUser.get_task_user_by_email(a_task.assigned_to_email) assigned_to_task_user_msg = TaskUserResponseMessage(lowercase_email=assigned_to_task_user.lowercase_email, preferred_name=assigned_to_task_user.preferred_name, google_plus_id=assigned_to_task_user.google_plus_id) all_tasks_in_list.append(TaskResponseMessage(identifier=a_task.key.id(), text=a_task.text, details=a_task.details, complete=a_task.complete, assigned_to=assigned_to_task_user_msg)) all_task_users_in_list = [] for a_task_user_email in a_task_list.task_user_emails: a_task_user = TaskUser.get_task_user_by_email(a_task_user_email) all_task_users_in_list.append(TaskUserResponseMessage(lowercase_email=a_task_user.lowercase_email, preferred_name=a_task_user.preferred_name, google_plus_id=a_task_user.google_plus_id)) users_task_lists.append(TaskListResponseMessage(identifier=a_task_list.key.id(), title=a_task_list.title, tasks=all_tasks_in_list, task_users=all_task_users_in_list)) logging.info("Returning a list of TaskList, count = " + str(len(users_task_lists))) return TaskListListResponse(items=users_task_lists)
def timeline_get(self, card): """Get card with ID for the current user""" if not card.from_datastore or card.user != endpoints.get_current_user(): raise endpoints.NotFoundException("Card not found.") return card
def timeline_list(self, query): """List timeline cards for the current user.""" query = query.order(-TimelineItem.updated) query = query.filter(TimelineItem.user == endpoints.get_current_user()) query = query.filter(TimelineItem.isDeleted == False) return query
def locations_insert(self, location): """Insert a new location for the current user. Not part of the actual mirror API but used by the emulator. """ if location.id is not None: raise endpoints.BadRequestException("ID is not allowed in request body.") location.put() # Notify location subscriptions data = {} data["collection"] = "locations" data["itemId"] = "latest" operation = Operation.UPDATE data["operation"] = operation.name header = {"Content-type": "application/json"} query = Subscription.query().filter(Subscription.user == endpoints.get_current_user()) query = query.filter(Subscription.collection == "locations") query = query.filter(Subscription.operation == operation) for subscription in query.fetch(): data["userToken"] = subscription.userToken data["verifyToken"] = subscription.verifyToken req = urllib2.Request(subscription.callbackUrl, json.dumps(data), header) try: urllib2.urlopen(req) except: logging.error(sys.exc_info()[0]) return location
def _get_user_id_from_id_token(jwt): """Attempts to get Google+ User ID from ID Token. First calls endpoints.get_current_user() to assure there is a valid user. If it has already been called, there will be environment variables set so this will be a low-cost call (no network overhead). After this, we know the JWT is valid and can simply parse a value from it. Args: jwt: String, containing the JSON web token which acts as the ID Token. Returns: String containing the Google+ user ID or None if it can't be determined from the JWT. """ if endpoints.get_current_user() is None: return segments = jwt.split('.') if len(segments) != 3: return json_body = users_id_token._urlsafe_b64decode(segments[1]) try: parsed = json.loads(json_body) return parsed.get('sub') except: pass
def contacts_get(self, contact): """Get contact with ID for the current user""" if not contact.from_datastore or contact.user != endpoints.get_current_user(): raise endpoints.NotFoundException("Contact not found.") return contact
def get_google_plus_user_id(): """Method to get the Google+ User ID from the environment. Attempts to get the user ID if the token in the environment is either an ID token or a bearer token. If there is no token in the environment or there the current token is invalid (no current endpoints user), will not attempt either. Returns: The Google+ User ID of the user whose token is in the environment if it can be retrieved, else None. """ # Assumes endpoints.get_current_user has already returned a # non-null value, hence the needed environment variables # should already be set and this won't make the RPC/urlfetch # a second time. if endpoints.get_current_user() is None: return token = users_id_token._get_token(None) if token is None: return user_id = _get_user_id_from_id_token(token) if user_id is None: user_id = _get_user_id_from_bearer_token(token) return user_id
def _get_user_id_from_bearer_token(token): """Attempts to get Google+ User ID from Bearer Token. First calls endpoints.get_current_user() to assure there is a valid user. If it has already been called, there will be environment variables set so this will be a low-cost call (no network overhead). Since we have already called endpoints.get_current_user, if the token is a valid Bearer token, a call to the TOKENINFO url must have been made hence a URLFetch response object corresponding to the token should be in _SAVED_TOKEN_DICT. Args: token: String, containing a Bearer Token. Returns: String containing the Google+ user ID or None if it can't be determined from the token. """ if endpoints.get_current_user() is None: return urlfetch_result = _SAVED_TOKEN_DICT.get(token) if urlfetch_result is None: return if urlfetch_result.status_code == 200: try: user_info = json.loads(urlfetch_result.content) return user_info.get('user_id') except: pass
def RequirePicturesqueUser(cls): """Makes sure the user from the environment has a Picturesque account. Checks first that there is a valid endpoints user, then checks if the current token can allow access to the user's Google+ ID and finally checks that a corresponding PicturesqueUser for that Google+ ID exists. Returns: The PicturesqueUser entity corresponding to the token user from the environment. Raises: endpoints.UnauthorizedException: If there is no endpoints current user. This results in a 401 response. endpoints.ForbiddenException: If either the token can't access the Google+ ID or no Picturesque account exists for the user. This results in a 403 response. """ current_user = endpoints.get_current_user() if current_user is None: raise endpoints.UnauthorizedException(cls.INVALID_TOKEN) googleplus_user_id = auth_util.get_google_plus_user_id() if googleplus_user_id is None: raise endpoints.ForbiddenException(cls.NO_GPLUS_ID) existing_picturesque_user = cls.get_by_id(googleplus_user_id) if existing_picturesque_user is None: raise endpoints.ForbiddenException(cls.NO_ACCOUNT) return existing_picturesque_user
def contacts_update(self, contact): """Update Contact with ID for the current user""" if not contact.from_datastore or contact.user != endpoints.get_current_user(): raise endpoints.NotFoundException("Card not found.") contact.put() return contact
def shareEntities_list(self, query): """List all Share entities registered for the current user. This isn't part of the actual Mirror API but necessary for the emulator part to be able to display relevant Share options. """ return query.filter(ShareEntity.user == endpoints.get_current_user())
def start(self, request): ValidateUserIsAuthorized() change = publish.start_change( request.project_prefixes, request.upload_paths, endpoints.get_current_user()) response = StartResponse(change_id=change.get_change_id()) return response
def ScoresGet(self, score): if not score.from_datastore: raise endpoints.NotFoundException('Score not found.') if score.player != endpoints.get_current_user(): raise endpoints.ForbiddenException( 'You do not have access to this score.') return score
def contacts_delete(self, contact): """Remove an existing Contact for the current user.""" if not contact.from_datastore or contact.user != endpoints.get_current_user(): raise endpoints.NotFoundException("Contact not found.") contact.key.delete() return contact
def subscription_delete(self, subscription): """Remove an existing subscription for the current user.""" if not subscription.from_datastore or subscription.user != endpoints.get_current_user(): raise endpoints.NotFoundException("Card not found.") subscription.key.delete() return subscription
def subscription_delete(self, subscription): """Remove an existing subscription for the current user.""" if not subscription.from_datastore or subscription.user != endpoints.get_current_user(): raise endpoints.NotFoundException("Card not found.") subscription.key.delete() # TODO: Check if a success HTTP code can be returned with an empty body return subscription
def contacts_delete(self, contact): """Remove an existing Contact for the current user.""" if not contact.from_datastore or contact.user != endpoints.get_current_user(): raise endpoints.NotFoundException("Contact not found.") contact.key.delete() # TODO: Check if a success HTTP code can be returned with an empty body return contact
def shareEntities_delete(self, shareEntity): """Remove an existing ShareEntity for the current user.""" if not shareEntity.from_datastore or shareEntity.user != endpoints.get_current_user(): raise endpoints.NotFoundException("shareEntity not found.") shareEntity.key.delete() # TODO: Check if a success HTTP code can be returned with an empty body return shareEntity
def locations_get(self, location): """Retrieve a single location for the current user. ID can be a specific location ID or "latest" to retrieve the latest known position of the user. """ if not location.from_datastore or location.user != endpoints.get_current_user(): raise endpoints.NotFoundException("Location not found.") return location
def MyModelInsert(self, my_model): # Since user_required is True, we know endpoints.get_current_user will # return a valid user. my_model.owner = endpoints.get_current_user() # Also note, since we don't override the default ProtoRPC message schema, # API users can send an owner object in the request, but we overwrite the # model property with the current user before the entity is inserted into # the datastore and this put operation will only occur if a valid token # identifying the user was sent in the Authorization header. my_model.put() return my_model
def timeline_list(self, query): """List timeline cards for the current user. Args: query: An ndb Query object for Cards. Returns: An update ndb Query object for the current user. """ query = query.order(-Card.when) return query.filter(Card.user == endpoints.get_current_user())
def timeline_update(self, card): """Update card with ID for the current user""" if not card.from_datastore or card.user != endpoints.get_current_user(): raise endpoints.NotFoundException("Card not found.") card.put() channel.send_message(card.user.email(), json.dumps({"id": card.id})) return card
def task_list_insert(self, a_task_list): """ Insert a TaskList. """ #TODO: Check if current user is in this TaskList a_task_list.creator = endpoints.get_current_user() current_user_email = endpoints.get_current_user().email().lower() if not current_user_email in a_task_list.task_user_emails: a_task_list.task_user_emails.append(current_user_email) # Consider: Check the email list for duplicates and remove them. if a_task_list.from_datastore: #logging.info("This is an update not a new TaskList") if not a_task_list.task_user_emails is None: TaskList.flush_task_users(a_task_list.id, a_task_list.task_user_emails) else: a_task_list.put() # Generate a key because it'll be needed for next steps. if not a_task_list.task_user_emails is None: for an_email in a_task_list.task_user_emails: #logging.info("Adding " + an_email.lower() + " to the TaskList") TaskUser.add_task_list(a_task_list.key, an_email) a_task_list.put() return a_task_list
def timeline_get(self, card): """Get card with ID for the current user Args: card: An instance of Card parsed from the API request. Returns: An instance of Card requested. """ if not card.from_datastore or card.user != endpoints.get_current_user(): raise endpoints.NotFoundException('Card not found.') return card
def task_insert(self, a_task): """ Insert a Task. """ #TODO: Check if current user is in this TaskList a_task.creator = endpoints.get_current_user() parent_task_list = TaskList.get_by_id(a_task.task_list_id) a_task.anestor = parent_task_list if a_task.assigned_to_email and not a_task.assigned_to_email.lower() in parent_task_list.task_user_emails: logging.info("Attempt to assign user that is not in the TaskList. " + a_task.assigned_to_email.lower() + " not found.") a_task.assigned_to_email = None a_task.put() if not a_task.key in parent_task_list.task_keys: parent_task_list.task_keys.append(a_task.key) parent_task_list.put() return a_task
def get_endpoints_current_user(raise_unauthorized=True): """Returns a current user and (optionally) causes an HTTP 401 if no user. Args: raise_unauthorized: Boolean; defaults to True. If True, this method raises an exception which causes an HTTP 401 Unauthorized to be returned with the request. Returns: The signed in user if there is one, else None if there is no signed in user and raise_unauthorized is False. """ current_user = endpoints.get_current_user() if raise_unauthorized and current_user is None: raise endpoints.UnauthorizedException('Invalid token.') return current_user
def task_user_insert(self, a_task_user): """ Insert a TaskUser. """ request_email = a_task_user.lowercase_email.lower() current_user_email = endpoints.get_current_user().email().lower() if current_user_email != request_email: logging.info('Current user email = ' + current_user_email + ' TaskUser email = ' + request_email) #Allow odd creations for testing. Turn off later as you should only edit yourself. raise endpoints.ForbiddenException("Only can only edit/create your own TaskUser.") the_task_user = TaskUser.get_task_user_by_email(request_email) if not a_task_user.preferred_name is None: the_task_user.preferred_name = a_task_user.preferred_name if not a_task_user.google_plus_id is None: the_task_user.google_plus_id = a_task_user.google_plus_id the_task_user.put() return the_task_user
def _set_value(self, entity, value): """Internal helper to set value on model entity. If the value to be set is null, will try to retrieve the current user and will return a 401 if a user can't be found and raise_unauthorized is True. Args: entity: An instance of some NDB model. value: The value of this property to be set on the instance. """ if value is None: value = endpoints.get_current_user() if self._raise_unauthorized and value is None: raise endpoints.UnauthorizedException('Invalid token.') super(EndpointsUserProperty, self)._set_value(entity, value)
def action_insert(self, action): """Perform an action on a timeline card for the current user. This isn't part of the actual Mirror API but necessary for the emulator to send actions to the subscribed services. Returns just a simple success message """ current_user = endpoints.get_current_user() if current_user is None: raise endpoints.UnauthorizedException("Authentication required.") card = ndb.Key("TimelineItem", action.itemId).get() if card is None or card.user != current_user: raise endpoints.NotFoundException("Card not found.") data = None operation = None if action.action == MenuAction.SHARE: operation = Operation.UPDATE data = {} data["collection"] = "timeline" data["itemId"] = action.itemId data["operation"] = operation.name data["userActions"] = [{"type": MenuAction.SHARE.name}] if action.action == MenuAction.REPLY or action.action == MenuAction.REPLY_ALL: operation = Operation.INSERT data = {} data["collection"] = "timeline" data["itemId"] = action.itemId data["operation"] = operation.name data["userActions"] = [{"type": MenuAction.REPLY.name}] if action.action == MenuAction.DELETE: operation = Operation.DELETE data = {} data["collection"] = "timeline" data["itemId"] = action.itemId data["operation"] = operation.name data["userActions"] = [{"type": MenuAction.DELETE.name}] if action.action == MenuAction.CUSTOM: operation = Operation.UPDATE data = {} data["collection"] = "timeline" data["itemId"] = action.itemId data["operation"] = operation.name data["userActions"] = [{ "type": MenuAction.CUSTOM.name, "payload": action.value }] if data is not None and operation is not None: header = {"Content-type": "application/json"} query = Subscription.query().filter( Subscription.user == current_user) query = query.filter(Subscription.collection == "timeline") query = query.filter(Subscription.operation == operation) for subscription in query.fetch(): data["userToken"] = subscription.userToken data["verifyToken"] = subscription.verifyToken req = urllib2.Request(subscription.callbackUrl, json.dumps(data), header) try: urllib2.urlopen(req) except: logging.error(sys.exc_info()[0]) # Report back to Glass emulator channel.send_message(current_user.email(), json.dumps({"id": action.itemId})) return ActionResponse(success=True)
def timeline_list(self, query): """List timeline cards for the current user.""" query = query.order(-TimelineItem.updated) query = query.filter(TimelineItem.user == endpoints.get_current_user()) return query
def login_required(): current_user = endpoints.get_current_user() if current_user is None: raise endpoints.UnauthorizedException('Invalid token.') return current_user
def timeline_delete(self, card): """Remove an existing card for the current user. This will set all properties except the ID to None and set isDeleted to true """ if not card.from_datastore or card.user != endpoints.get_current_user(): raise endpoints.NotFoundException("Contact not found.") if card.isDeleted: raise endpoints.NotFoundException("Card has been deleted") # Delete attachments keys = [] if card.attachments is not None: for att in card.attachments: keys.append(blobstore.BlobKey(att.id)) blobstore.delete_async(keys) card.attachments = [] card.bundleId = None card.canonicalUrl = None card.created = None card.creator = None card.displayTime = None card.html = None card.htmlPages = [] card.inReplyTo = None card.isBundleCover = None card.isPinned = None card.menuItems = [] card.notification = None card.recipients = [] card.sourceItemId = None card.speakableText = None card.text = None card.title = None card.updated = None card.isDeleted = True card.put() # Notify Glass emulator channel.send_message(card.user.email(), json.dumps({"id": card.id})) # Notify timeline DELETE subscriptions data = {} data["collection"] = "timeline" data["itemId"] = card.id operation = Operation.DELETE data["operation"] = operation.name header = {"Content-type": "application/json"} query = Subscription.query().filter(Subscription.user == endpoints.get_current_user()) query = query.filter(Subscription.collection == "timeline") query = query.filter(Subscription.operation == operation) for subscription in query.fetch(): data["userToken"] = subscription.userToken data["verifyToken"] = subscription.verifyToken req = urllib2.Request(subscription.callbackUrl, json.dumps(data), header) try: urllib2.urlopen(req) except: logging.error(sys.exc_info()[0]) return card
def contacts_list(self, query): """List all Contacts registered for the current user.""" return query.filter(Contact.user == endpoints.get_current_user())
def subscriptions_list(self, query): """List all Subscriptions registered for the current user.""" return query.filter(Contact.user == endpoints.get_current_user())
def locations_list(self, query): """List locations for the current user.""" query = query.order(-Location.timestamp) return query.filter(TimelineItem.user == endpoints.get_current_user())