def post(self): if self.ensure_is_logged_in() and self.ensure_has_display_name(): self.check_CSRF() user_id = self.user_id friend_id_invite = self.request.get('invite') friend_id_remove = self.request.get('remove') friend_name_search = self.request.get('search').strip()[:( EnkiModelDisplayName.DISPLAY_NAME_LENGTH_MAX + 4)] # 4 allows for some leading and trailing characters already_friends = '' has_friends = EnkiModelFriends.exist_by_user_id(user_id) error_message = '' result = '' if friend_id_invite: # send invitation to user to become friend outcome = EnkiModelFriends.send_friend_request( user_id, int(friend_id_invite)) if outcome == EnkiModelFriends.INFO_FRIENDS: self.add_infomessage( MSG.SUCCESS(), MSG.FRIEND_ADDED( EnkiModelDisplayName.get_display_name( int(friend_id_invite)))) elif outcome == enki.libutil.ENKILIB_OK: self.add_infomessage( MSG.SUCCESS(), MSG.FRIEND_INVITATION_SENT( EnkiModelDisplayName.get_display_name( int(friend_id_invite)))) elif friend_id_remove: # unfriend EnkiModelFriends.remove_friend(user_id, int(friend_id_remove)) has_friends = EnkiModelFriends.exist_by_user_id(user_id) self.add_infomessage( MSG.SUCCESS(), MSG.FRIEND_REMOVED( EnkiModelDisplayName.get_display_name( int(friend_id_remove)))) elif friend_name_search: # search for user to invite users_ids_to_ignore = [user_id] if has_friends: users_ids_to_ignore += EnkiModelFriends.get_friends_user_id( user_id) result = EnkiModelDisplayName.find_users_by_display_name( friend_name_search, users_ids_to_ignore) if result.error == EnkiModelDisplayName.ERROR_DISPLAY_NAME_INVALID: error_message = MSG.DISPLAY_NAME_INVALID() elif result.error == EnkiModelDisplayName.ERROR_DISPLAY_NAME_NOT_EXIST: error_message = MSG.DISPLAY_NAME_NOT_EXIST() else: error_message = MSG.DISPLAY_NAME_NEEDED() if has_friends: already_friends = EnkiModelFriends.get_friends_user_id_display_name_url( user_id) self.render_tmpl('friends.html', data=already_friends, error=error_message, result=result, friend_name=friend_name_search)
def get_thread_data(cls, thread_selected, post_requested=POST_DEFAULT, post_count=POSTS_PER_PAGE): # get posts by thread forums_url = enki.libutil.get_local_url('forums') thread = EnkiModelThread.get_by_id(int(thread_selected)) thread_url = enki.libutil.get_local_url( 'thread', {'thread': str(thread_selected)}) forum = EnkiModelForum.get_by_id(thread.forum) forum_url = enki.libutil.get_local_url('forum', {'forum': str(forum.key.id())}) if post_requested == cls.POST_LAST: post_requested = thread.num_posts list = cls.fetch_by_thread(int(thread_selected), offset=(int(post_requested) - 1), limit=int(post_count)) if list: for i, item in enumerate(list): item.author_data = EnkiModelDisplayName.get_user_id_display_name_url( EnkiModelDisplayName.get_by_user_id_current(item.author)) item.post_page = enki.libutil.get_local_url( 'post', {'post': str(item.key.id())}) item.sticky = True if (item.sticky_order > 0) else False list[i] = item thread_data = threadData(forums_url, forum, forum_url, thread, thread_url, list, enki.libutil.markdown_escaped_extras, thread_selected) return thread_data
def get_author_posts(cls, author_selected): # get posts by author to display on their profile. If the author hasn't set a display name, return nothing author_display_name = EnkiModelDisplayName.get_by_user_id_current( int(author_selected)) if author_display_name: forums_url = enki.libutil.get_local_url('forums') author_data = EnkiModelDisplayName.get_user_id_display_name_url( author_display_name) list = cls.fetch_by_author(int(author_selected)) if list: for i, item in enumerate(list): thread = EnkiModelThread.get_by_id(item.thread) forum = EnkiModelForum.get_by_id(thread.forum) item.thread_title = thread.title item.thread_url = enki.libutil.get_local_url( 'thread', {'thread': str(item.thread)}) item.forum_title = forum.title item.forum_group = forum.group item.forum_url = enki.libutil.get_local_url( 'forum', {'forum': str(forum.key.id())}) item.post_page = enki.libutil.get_local_url( 'post', {'post': str(item.key.id())}) item.sticky = True if (item.sticky_order > 0) else False list[i] = item author_posts_data = authorpostsData( forums_url, author_data, list, enki.libutil.markdown_escaped_extras) return author_posts_data
def delete_account(self, delete_posts=False, token=''): token_to_save = 'accountdelete' if not token: # there is no token if the user has no email address: they are deleted immediately. They must be logged in. user_to_delete = self.enki_user else: # a user has followed a accountdelete token link. The user account associated with the token will be deleted tokenEntity = EnkiModelTokenVerify.get_by_token(token) user_to_delete = EnkiModelUser.get_by_id(tokenEntity.user_id) # delete all user related tokens except any verify token related to account deletion that's not yet been used if tokenEntity.type == token_to_save: token_to_save = 'accountandpostsdelete' verify_tokens_to_delete = EnkiModelTokenVerify.fetch_keys_by_user_id_except_type( user_to_delete.key.id(), token_to_save) if verify_tokens_to_delete: ndb.delete_multi(verify_tokens_to_delete) email_rollback_tokens_to_delete = EnkiModelTokenEmailRollback.fetch_keys_by_user_id( user_to_delete.key.id()) if email_rollback_tokens_to_delete: ndb.delete_multi(email_rollback_tokens_to_delete) # Delete the user account and log them out. if not HandlerBase.account_is_active(user_to_delete.key.id()): # delete user if the account is inactive display_names = EnkiModelDisplayName.fetch_keys_by_user_id( user_to_delete.key.id()) if display_names: ndb.delete_multi(display_names) user_to_delete.key.delete() else: # anonymise the user if user_to_delete.email: # delete email subscriptions EnkiModelEmailSubscriptions.remove_by_email( user_to_delete.email) user_to_delete.email = None if user_to_delete.password: user_to_delete.password = None if user_to_delete.auth_ids_provider: user_to_delete.auth_ids_provider = [] user_to_delete.put() # keep all historical display_names. Add a new current display_name '[deleted]' (unless it's already been deleted) display_name = EnkiModelDisplayName.get_by_user_id_current( user_to_delete.key.id()) if display_name: if display_name.prefix != EnkiModelDisplayName.DELETED_PREFIX or display_name.suffix != EnkiModelDisplayName.DELETED_SUFFIX: EnkiModelDisplayName.set_display_name( user_to_delete.key.id(), EnkiModelDisplayName.DELETED_PREFIX, EnkiModelDisplayName.DELETED_SUFFIX) # delete user's sent and received messages EnkiModelMessage.delete_user_messages(user_to_delete.key.id()) # delete user's posts if required if delete_posts: EnkiModelPost.delete_user_posts(user_to_delete.key.id()) # log the deleted user out if self.enki_user == user_to_delete.key.id(): self.log_out() EnkiModelTokenAuth.revoke_user_authentications(user_to_delete.key.id())
def get_friends_user_id_display_name_url(cls, user_id): friend_list = [] list = cls.get_friends_user_id(user_id) if list: for friend_id in list: friend = EnkiModelDisplayName.get_user_id_display_name_url( EnkiModelDisplayName.get_by_user_id_current(friend_id)) friend_list.append(friend) return friend_list
def set_display_name( user_id, prefix, suffix ): # get the current name old_display_name = get_EnkiUserDisplayName_by_user_id_current( user_id ) # save the new name display_name = EnkiModelDisplayName( parent = ndb.Key( EnkiModelUser, user_id ), user_id = user_id, prefix = prefix, suffix = suffix ) display_name.put() if old_display_name: # if the user already had a display name, and a new same was set, set the old name to not current old_display_name.current = False old_display_name.put()
def set_display_name(user_id, prefix, suffix): # get the current name old_display_name = get_EnkiUserDisplayName_by_user_id_current(user_id) # save the new name display_name = EnkiModelDisplayName(parent=ndb.Key(EnkiModelUser, user_id), user_id=user_id, prefix=prefix, suffix=suffix) display_name.put() if old_display_name: # if the user already had a display name, and a new same was set, set the old name to not current old_display_name.current = False old_display_name.put()
def get_messages(cls, user_id): list = cls.fetch_by_recipient(user_id) message_list = [] if list: for i, item in enumerate(list): entity = EnkiModelDisplayName.get_by_user_id_current( item.sender) sender = EnkiModelDisplayName.get_user_id_display_name_url( entity) type = item.type message_id = item.key.id() message = messageData(message_id, type, sender) message_list.append(message) return message_list
def add_thread_and_post(cls, user_id, forum, thread_title, thread_sticky_order, post_body, post_sticky_order): result = enki.libutil.ENKILIB_OK if user_id and forum and thread_title and post_body: if len(thread_title ) <= EnkiModelThread.THREAD_TITLE_LENGTH_MAX and len( post_body) <= cls.POST_LENGTH_MAX: if EnkiModelDisplayName.get_by_user_id_current(user_id): thread = EnkiModelThread( author=user_id, forum=int(forum), title=thread_title, num_posts=1, sticky_order=int(thread_sticky_order)) thread.put() post = cls(author=user_id, body=post_body, thread=thread.key.id(), sticky_order=int(post_sticky_order)) post.put() forum_selected = ndb.Key(EnkiModelForum, int(forum)).get() forum_selected.num_posts += 1 forum_selected.num_threads += 1 forum_selected.put() else: result = cls.ERROR_POST_CREATION else: result = cls.ERROR_POST_LENGTH else: result = cls.ERROR_POST_CREATION return result
def post(self): if self.ensure_is_logged_in() and self.ensure_has_display_name(): self.check_CSRF() user_id = self.user_id message_accept = self.request.get('accept') message_decline = self.request.get('decline') if message_accept: sender_id = EnkiModelMessage.get_by_id( int(message_accept)).sender if sender_id: EnkiModelFriends.add_friend(user_id, sender_id) self.add_infomessage( MSG.SUCCESS(), MSG.FRIEND_ADDED( EnkiModelDisplayName.get_display_name(sender_id))) elif message_decline: sender_id = EnkiModelMessage.get_by_id( int(message_decline)).sender if sender_id: EnkiModelMessage.remove_messages_crossed( user_id, sender_id) self.render_tmpl('messages.html', data=EnkiModelMessage.get_messages(self.user_id))
def post( self ): jsonobject = json.loads( self.request.body ) success = False error = 'Invalid request' answer = {} if jsonobject: user_id = int( jsonobject.get( 'user_id', '')) auth_token = jsonobject.get( 'auth_token', '') app_secret = jsonobject.get( 'app_secret', '') if user_id and auth_token and app_secret: if EnkiModelApp.check_secret( user_id, auth_token, app_secret ): if EnkiModelRestAPITokenVerify.exist_by_user_id_token( user_id, auth_token ): user_displayname = EnkiModelDisplayName.get_display_name( user_id ) if user_displayname: answer.update({ 'user_displayname' : user_displayname }) success = True error = '' else: error = 'Not found' else: error = 'Unauthorised user' else: error = 'Unauthorised app' answer.update({ 'success' : success, 'error' : error }) self.response.headers[ 'Content-Type' ] = 'application/json' self.response.write( json.dumps( answer, separators=(',',':') ))
def exist_EnkiUserDisplayName_by_user_id_prefix( user_id, prefix ): count = EnkiModelDisplayName.query( EnkiModelDisplayName.prefix == prefix, ancestor = ndb.Key( EnkiModelUser, user_id )).count( 1 ) if count: return True else: return False
def post( self ): jsonobject = json.loads( self.request.body ) success = False error = 'Invalid request' answer = {} if jsonobject: code = jsonobject.get( 'code', '') displayname = jsonobject.get( 'displayname', '') app_id = jsonobject.get( 'app_id', '') app_secret = jsonobject.get( 'app_secret', '') if code and displayname and app_id and app_secret: if EnkiModelApp.exist_by_app_id_app_secret( app_id, app_secret ): # check against registered apps user_id = EnkiModelDisplayName.get_user_id_from_display_name( displayname ) if user_id: entity = EnkiModelRestAPIConnectToken.get_by_user_id_token_valid_age( user_id, code ) if entity: auth_token = enki.libutil.generate_auth_token() entity.key.delete() # single use token verification_token = EnkiModelRestAPITokenVerify( token = auth_token, user_id = user_id, app_id = app_id, app_secret = app_secret, type = 'apiconnect' ) verification_token.put() # persistent authentication token, a user may have several answer.update({ 'user_id' : str( user_id ), 'auth_token' : auth_token }) success = True error = '' else: error = 'Unauthorised user' else: error = 'Unauthorised app' answer.update({ 'success' : success, 'error' : error }) self.response.headers[ 'Content-Type' ] = 'application/json' self.response.write( json.dumps( answer, separators=(',',':') ))
def get_EnkiUserDisplayName_by_user_id_current( user_id ): entity = EnkiModelDisplayName.query( EnkiModelDisplayName.current == True, ancestor = ndb.Key( EnkiModelUser, user_id )).get() if entity: return entity else: return None
def exist_EnkiUserDisplayName_by_prefix_suffix( prefix, suffix ): count = EnkiModelDisplayName.query( ndb.AND( EnkiModelDisplayName.prefix == prefix, EnkiModelDisplayName.suffix == suffix )).count( 1 ) if count: return True else: return False
def get_EnkiUserDisplayName_by_user_id_prefix( user_id, prefix ): entity = EnkiModelDisplayName.query( EnkiModelDisplayName.prefix == prefix, ancestor = ndb.Key( EnkiModelUser, user_id )).get() if entity: return entity else: return None
def get_EnkiUserDisplayName_by_prefix_suffix_current_minus_user_id( prefix, suffix, user_id ): entity = EnkiModelDisplayName.query( ndb.AND( EnkiModelDisplayName.prefix == prefix, EnkiModelDisplayName.suffix == suffix, EnkiModelDisplayName.current == True, EnkiModelDisplayName.user_id != user_id )).get() if entity: return entity else: return None
def get_post_data(cls, post_selected): # get a post forums_url = enki.libutil.get_local_url('forums') post = cls.get_by_id(int(post_selected)) sticky = True if (post.sticky_order > 0) else False post_page = enki.libutil.get_local_url('post', {'post': str(post.key.id())}) thread = EnkiModelThread.get_by_id(post.thread) thread_url = enki.libutil.get_local_url( 'thread', {'thread': str(thread.key.id())}) forum = EnkiModelForum.get_by_id(thread.forum) forum_url = enki.libutil.get_local_url('forum', {'forum': str(forum.key.id())}) author_data = EnkiModelDisplayName.get_user_id_display_name_url( EnkiModelDisplayName.get_by_user_id_current(post.author)) post_data = postData(forums_url, forum, forum_url, thread, thread_url, post, sticky, post_page, author_data, enki.libutil.markdown_escaped_extras) return post_data
def get_forum_data(cls, forum_selected): forums_url = enki.libutil.get_local_url('forums') forum = EnkiModelForum.get_by_id(int(forum_selected)) num_posts = 0 threads = cls.fetch_by_forum(int(forum_selected)) if threads: for i, thread in enumerate(threads): num_posts += thread.num_posts url = enki.libutil.get_local_url( 'thread', {'thread': str(thread.key.id())}) thread.url = url thread.author_data = EnkiModelDisplayName.get_user_id_display_name_url( EnkiModelDisplayName.get_by_user_id_current(thread.author)) thread.sticky = True if (thread.sticky_order > 0) else False threads[i] = thread forum_data = forumData(forums_url, forum, num_posts, threads, enki.libutil.markdown_escaped_extras, forum_selected) return forum_data
def ensure_has_display_name(self, url=None): # user must set their display_name to continue user_display_name = EnkiModelDisplayName.get_by_user_id_current( self.user_id) if not user_display_name: if not url: url = self.request.url # get referal path to return the user to it after they've set their display name self.session['sessiondisplaynamerefpath'] = url self.add_infomessage(MSG.INFORMATION(), MSG.DISPLAYNAME_NEEDED()) self.redirect(enki.libutil.get_local_url('displayname')) return False return True
def render_tmpl(self, template_file, CSRFneeded=True, **kwargs): # render an html template with data using jinja2 try: navbar_items = enki.ExtensionLibrary.get_navbar_items() navbar_extensions = enki.ExtensionLibrary.get_navbar_extensions( self) page_extensions = enki.ExtensionLibrary.get_page_extensions(self) user_is_logged_in = self.is_logged_in() display_name = EnkiModelDisplayName.get_display_name( self.user_id) if user_is_logged_in else '' CSRFtoken = '' if CSRFneeded or user_is_logged_in: # when user is logged in we always need CSRF for stay logged in navbar CSRFtoken = self.create_CSRF(self.request.path) self.response.write( self.jinja2.render_template( template_file, request_url=self.request.url, CSRFtoken=CSRFtoken, is_logged_in=self.is_logged_in(), navbar_items=navbar_items, page_extensions=page_extensions, navbar_extensions=navbar_extensions, display_name=display_name, locale=i18n.get_i18n().locale, debug=self.session.pop('debugmessage', None) if enki.libutil.is_debug else None, infomessage=self.session.pop('infomessage', None), deleted_post=EnkiModelPost.POST_DELETED, deleted_post_display=MSG.POST_DELETED_DISPLAY(), deleted_dn=EnkiModelDisplayName.DELETED_PREFIX + EnkiModelDisplayName.DELETED_SUFFIX, deleted_dn_display=MSG.DISPLAY_NAME_DELETED_DISPLAY(), stay_logged_in=self._stay_logged_in, **kwargs)) except TemplateNotFound: self.abort(404)
def exist_EnkiUserDisplayName_by_user_id( user_id ): count = EnkiModelDisplayName.query( ancestor = ndb.Key( EnkiModelUser, user_id )).count( 1 ) return count > 0
def fetch_EnkiUserDisplayName_by_user_id_not_current(user_id): list = EnkiModelDisplayName.query(EnkiModelDisplayName.current == False, ancestor=ndb.Key(EnkiModelUser, user_id)).fetch() return list
def exist_EnkiUserDisplayName_by_prefix_lower_suffix( prefix_lower, suffix ): count = EnkiModelDisplayName.query( ndb.AND( EnkiModelDisplayName.prefix_lower == prefix_lower, EnkiModelDisplayName.suffix == suffix )).count( 1 ) return count > 0
def exist_EnkiUserDisplayName_by_prefix_lower_suffix(prefix_lower, suffix): count = EnkiModelDisplayName.query( ndb.AND(EnkiModelDisplayName.prefix_lower == prefix_lower, EnkiModelDisplayName.suffix == suffix)).count(1) return count > 0
def fetch_EnkiUserDisplayName_by_user_id(user_id): list = EnkiModelDisplayName.query( ancestor=ndb.Key(EnkiModelUser, user_id)).fetch(keys_only=True) return list
def get_EnkiUserDisplayName_by_user_id_prefix_lower(user_id, prefix_lower): entity = EnkiModelDisplayName.query( EnkiModelDisplayName.prefix_lower == prefix_lower, ancestor=ndb.Key(EnkiModelUser, user_id)).get() return entity
def get_EnkiUserDisplayName_by_prefix_lower_suffix(prefix_lower, suffix): entity = EnkiModelDisplayName.query( EnkiModelDisplayName.prefix_lower == prefix_lower, EnkiModelDisplayName.suffix == suffix).get() return entity
def exist_EnkiUserDisplayName_by_user_id(user_id): count = EnkiModelDisplayName.query( ancestor=ndb.Key(EnkiModelUser, user_id)).count(1) return count > 0
def exist_EnkiUserDisplayName_by_user_id_prefix_lower(user_id, prefix_lower): count = EnkiModelDisplayName.query( EnkiModelDisplayName.prefix_lower == prefix_lower, ancestor=ndb.Key(EnkiModelUser, user_id)).count(1) return count > 0
def get_EnkiUserDisplayName_by_user_id_current(user_id): entity = EnkiModelDisplayName.query(EnkiModelDisplayName.current == True, ancestor=ndb.Key( EnkiModelUser, user_id)).get() return entity
def fetch_EnkiUserDisplayName_by_prefix_lower_current(prefix_lower): list = EnkiModelDisplayName.query( ndb.AND(EnkiModelDisplayName.prefix_lower == prefix_lower, EnkiModelDisplayName.current == True)).fetch() return list
def get_EnkiUserDisplayName_by_prefix_lower_suffix( prefix_lower, suffix ): entity = EnkiModelDisplayName.query( EnkiModelDisplayName.prefix_lower == prefix_lower, EnkiModelDisplayName.suffix == suffix ).get() return entity
def exist_EnkiUserDisplayName_by_user_id_prefix_lower( user_id, prefix_lower ): count = EnkiModelDisplayName.query( EnkiModelDisplayName.prefix_lower == prefix_lower, ancestor = ndb.Key( EnkiModelUser, user_id )).count( 1 ) return count > 0
def fetch_EnkiUserDisplayName_by_user_id_not_current( user_id ): list = EnkiModelDisplayName.query( EnkiModelDisplayName.current == False, ancestor = ndb.Key( EnkiModelUser, user_id ) ).fetch() return list
def fetch_EnkiUserDisplayName_by_user_id( user_id ): list = EnkiModelDisplayName.query( ancestor = ndb.Key( EnkiModelUser, user_id ) ).fetch( keys_only = True ) return list
def fetch_EnkiUserDisplayName_by_prefix_current_minus_user_minus_best_guess( prefix, user_id, best_guess_user_id ): list = EnkiModelDisplayName.query( ndb.AND( EnkiModelDisplayName.prefix == prefix, EnkiModelDisplayName.current == True, EnkiModelDisplayName.user_id != user_id, EnkiModelDisplayName.user_id != best_guess_user_id )).fetch() return list
def fetch_EnkiUserDisplayName_by_prefix_lower_current( prefix_lower ): list = EnkiModelDisplayName.query( ndb.AND( EnkiModelDisplayName.prefix_lower == prefix_lower, EnkiModelDisplayName.current == True )).fetch() return list
def get_EnkiUserDisplayName_by_user_id_prefix_lower( user_id, prefix_lower ): entity = EnkiModelDisplayName.query( EnkiModelDisplayName.prefix_lower == prefix_lower, ancestor = ndb.Key( EnkiModelUser, user_id )).get() return entity