class LeagueMemberDocument(Document): '''社团成员. :Parameters: - `league`: 社团 - `member`: 社团成员 - `join_time`: 将该成员添加到该社团中的时间 ''' league = ReferenceField(UserDocument, required=True) member = ReferenceField(UserDocument, required=True) time = DateTimeField(required=True) meta = {'collection': 'user_league_member'} @gen.coroutine def get_member(league_id, skip=0, limit=9): '''得到某个社团的成员''' cursor = LeagueMemberDocument.find({ 'league': DBRef(UserDocument.meta['collection'], ObjectId(league_id)) }).sort([('time', pymongo.DESCENDING)]).skip(skip).limit(limit) member_list = yield LeagueMemberDocument.to_list(cursor) for member in member_list: member['member'] = yield LeagueMemberDocument.translate_dbref( member['member']) raise gen.Return(member_list) @gen.coroutine def get_member_num(league_id): '''得到某社团成员数量''' cursor = LeagueMemberDocument.find({ 'league': DBRef(UserDocument.meta['collection'], ObjectId(league_id)) }) result = yield cursor.count() raise gen.Return(result) @gen.coroutine def get_member_page_size(league_id): member_num = yield LeagueMemberDocument.find({ 'league': DBRef(UserDocument.meta['collection'], ObjectId(league_id)) }).count() result = member_num / HOME_SETTINGS['league_member_num_per_page'] if member_num % HOME_SETTINGS['league_member_num_per_page']: result += 1 raise gen.Return(result)
class UserActivityDocument(Document): '''用户的活动 :Variables: - `user`: 用户 - `activity_type`: 活动类型 - `time`: 时间 - `relevant`: 相关者 - `data`: 有关的数据 ''' VISIT = 'visit' COMMENT = 'comment' REPLY = 'reply' LIKE = 'like' DOWNLOAD_SHARE = 'download_share' FETCH_LOGIN_REWARD = 'fetch_login_reward' STATUS_NEW = 'status_new' TOPIC_NEW = 'topic_new' SHARE_NEW = 'share_new' FRIEND_REQUEST_NEW = 'friend_request_new' LEAVE_MESSAGE_NEW = 'leave_message_new' user = ReferenceField(UserDocument, required=True) activity_type = StringField(required=True) time = DateTimeField(required=True) relevant = ReferenceField(UserDocument) data = ReferenceField() meta = {'collection': 'user_activity'} @gen.coroutine def login_reward_fetched(user_id, day=None): '''判断某一天是否领取了登陆奖励''' if day is None: day = datetime.now() today = datetime(year=day.year, month=day.month, day=day.day) tomorrow = today + timedelta(days=1) activity = yield UserActivityDocument.find_one({ 'user': DBRef(UserDocument.meta['collection'], ObjectId(user_id)), 'activity_type': UserActivityDocument.FETCH_LOGIN_REWARD, 'time': { '$gte': today, '$lt': tomorrow } }) raise gen.Return(True if activity else False)
class StatusPhotoDocument(Document): '''状态图片 :Variables: - `status`: 相关的状态 - `name`: 照片名称 - `body`: 相片内容 - `thumbnail`: 相片略缩图 - `content_type`: 照片格式 - `upload_time`: 上传时间 ''' status = ReferenceField(StatusDocument, required=True) name = StringField(required=True, max_length=50) body = BinaryField(required=True) thumbnail = BinaryField(required=True) content_type = StringField(required=True) upload_time = DateTimeField(required=True) meta = {'collection': 'home_status_photo'} @gen.coroutine def generate_url(photo_id, thumbnail=False): '''生成照片的url''' url = '/status/photo/%s' % photo_id if thumbnail: url += '/thumbnail' raise gen.Return(url)
class OfficialProfileCoverDocument(Document): '''官方提供的个人封面. :Variables: - `image`: 注意: 里边是ImageDocument, 因为出现了循环引用, 因此没写 ''' image = ReferenceField(required=True) meta = {'collection': 'user_official_profile_cover'} @gen.coroutine def get_profile_cover_list(skip=0, limit=None): from app.base.document import ImageDocument cursor = OfficialProfileCoverDocument.find().skip(skip) if limit is not None: cursor = cursor.limit(limit) profile_cover_list = yield OfficialProfileCoverDocument.to_list(cursor) for item in profile_cover_list: url = yield ImageDocument.generate_image_url(item['image'].id) thumbnail = yield ImageDocument.generate_image_url( item['image'].id, thumbnail=True) item['photo'] = {'url': url, 'thumbnail': thumbnail} raise gen.Return(profile_cover_list)
class NodeAvatarDocument(Document): '''节点头像, 注意image里边包含有64x64略缩图. :Variables: - `node`: 节点 - `image`: 图片 - `uploader`: 上传者 - `upload_time`: 上传时间 ''' node = ReferenceField(NodeDocument, required=True) image = ReferenceField(ImageDocument, required=True) uploader = ReferenceField(UserDocument, required=True) upload_time = DateTimeField(required=True) meta = {'collection': 'community_node_avatar'} @gen.coroutine def get_node_avatar_url(node_id): '''得到node头像的url''' node = yield NodeAvatarDocument.find_one({ 'node': DBRef(NodeDocument.meta['collection'], ObjectId(node_id)) }) url = None if node: url = yield ImageDocument.generate_image_url(node['image'].id, thumbnail=True) raise gen.Return(url) @gen.coroutine def remove_one(query): node_avatar = yield NodeAvatarDocument.find_one(query) if node_avatar: yield ImageDocument.remove( {'_id': ObjectId(node_avatar['image'].id)}) yield NodeAvatarDocument.remove(query) raise gen.Return()
class WealthRecordDocument(Document): '''用户财富记录 :Variables: - `user`: 相关的用户 - `in_out_type`: 支出还是收入 - `activity`: 相关的活动 - `quantity`: 支出或者收入数量 - `time`: 时间 ''' IN = 'in' OUT = 'out' user = ReferenceField(UserDocument, required=True) in_out_type = StringField(required=True, candidate=[IN, OUT]) activity = ReferenceField(UserActivityDocument, required=True) quantity = IntegerField(required=True) time = DateTimeField(required=True) meta = {'collection': 'user_wealth_record'}
class TemporaryFileDocument(Document): '''临时文件 :Variables: - `body`: 文件内容,不超过16M - `chunk_index`: 片索引 - `filename`: 文件名称 - `uploader`: 上传者 - `upload_time`: 上传时间 - `upload_token`: 上传id ''' body = BinaryField(required=True) chunk_index = IntegerField(required=True) filename = StringField(required=True, max_length=500) uploader = ReferenceField(UserDocument, required=True) upload_time = DateTimeField(required=True) upload_token = StringField(required=True, max_length=100) meta = {'collection': 'tmporary_file'}
class AvatarDocument(Document): '''头像 :Variables: - `owner`: 所有者 - `name`: 图片名称 - `content`: 完整头像内容 - `content_type`: 图片类型 - `upload_time`: 上传时间 - `thumbnail50x50`: 略缩图50x50 - `thumbnail180x180`: 略缩图180x180 - `crop_area`: 头像裁剪区域 ''' owner = ReferenceField(UserDocument, required=True) name = StringField(required=True) content = BinaryField(required=True) content_type = StringField(required=True) upload_time = DateTimeField(required=True) thumbnail50x50 = BinaryField(required=True) thumbnail180x180 = BinaryField(required=True) crop_area = EmbeddedDocumentField(ImageCropAreaDocument) meta = {'collection': 'user_avatar'}
class TopicDocument(Document): ''' :Variables: - `author`: 话题者 - `publish_time`: 话题时间 - `last_update_time`: 最后更新时间, 添加此项是为了更好的排名, 当有新的评论时更新此项 - `title`: 标题 - `anonymous`: 是否匿名 - `nodes`: 所属节点 - `read_times`: 阅读次数 - `like_times`: 点赞次数 - `comment_times`: 评论次数 - `top`: 是否被置顶 - `perfect`: 是否被加精 - `content`: 话题的内容 - `images`: 话题内容里边的图片url, 每当话题内容改变时, 应该改变images ''' author = ReferenceField(UserDocument, required=True) publish_time = DateTimeField(required=True) last_update_time = DateTimeField(required=True) title = StringField(required=True, max_length=100) anonymous = BooleanField(required=True, default=False) nodes = ListField(ReferenceField(NodeDocument), required=True) read_times = IntegerField(required=True, default=0) like_times = IntegerField(required=True, default=0) comment_times = IntegerField(required=True, default=0) top = BooleanField(required=True, default=False) perfect = BooleanField(required=True, default=False) content = StringField(max_length=10**5) images = ListField(StringField()) meta = {'collection': 'community_topic'} @gen.coroutine def _extend_images(topic): regex = re.compile('^/image/([a-f0-9]{24})/?$') images = [] for image in topic['images']: url = thumbnail = image if regex.match(image): thumbnail = os.path.join(image, 'thumbnail') images.append({'url': url, 'thumbnail': thumbnail}) return images @gen.coroutine def get_topic(topic_id, user_id): ''' :Parameters: - `topic_id`: 话题id - `user_id`: 判断该user是否赞了该话题 ''' topic = yield TopicDocument.find_one({'_id': ObjectId(topic_id)}) if topic: topic['author'] = yield UserDocument.translate_dbref( topic['author']) liked = yield TopicLikeDocument.is_liked(topic_id, user_id) last_comment = yield TopicCommentDocument.get_last_comment( topic['_id']) topic.update({'liked': liked, 'last_comment': last_comment}) if 'images' in topic and topic['images']: topic['images'] = yield TopicDocument._extend_images(topic) for i, node in enumerate(topic['nodes']): topic['nodes'][i] = yield NodeDocument.translate_dbref(node) raise gen.Return(topic) @gen.coroutine def get_top_topic_list(user_id=None, skip=0, limit=None): '''得到置顶的帖子''' query = {'top': True} cursor = TopicDocument.find(query).sort([ ('publish_time', pymongo.DESCENDING) ]).skip(skip) if limit is not None: cursor = cursor.limit(limit) topic_list = yield TopicDocument.to_list(cursor) for topic in topic_list: topic['author'] = yield UserDocument.translate_dbref( topic['author']) topic[ 'last_comment'] = yield TopicCommentDocument.get_last_comment( topic['_id']) if 'images' in topic and topic['images']: topic['images'] = yield TopicDocument._extend_images(topic) if user_id is not None: topic['liked'] = yield TopicLikeDocument.is_liked( topic['_id'], user_id) for i, node in enumerate(topic['nodes']): topic['nodes'][i] = yield NodeDocument.translate_dbref(node) raise gen.Return(topic_list) @gen.coroutine def get_topic_list(node_id=None, user_id=None, sort=None, skip=0, limit=None): ''' :Parameters: - `node_id`: 如果node_id不为None, 那么得到该节点下的话题 - `sort`: 排序方式, 只可能为time或者popularity - `skip`: 默认0 - `limit`: 默认None NOTE: NEED CACHE !! ''' def score(topic): ''' 公式为: score = like_times + comment_times/2 + read_times/5 即: 1 * like_times = 2 * comment_times = 5 * read_times ''' return (topic['like_times'] + topic['comment_times'] / 2.0 + topic['read_times'] / 5.0) top_topic_list = yield TopicDocument.get_top_topic_list(user_id) if node_id is not None: query = { 'nodes': DBRef(NodeDocument.meta['collection'], ObjectId(node_id)) } else: query = { '_id': { '$nin': [ObjectId(t['_id']) for t in top_topic_list] } } cursor = TopicDocument.find(query) if sort == 'time' or sort is None: cursor = cursor.sort([('last_update_time', pymongo.DESCENDING) ]).skip(skip) if limit is not None: cursor = cursor.limit(limit) topic_list = yield TopicDocument.to_list(cursor) else: topic_list = yield TopicDocument.to_list(cursor) topic_list.sort(cmp=lambda x, y: -1 if score(x) < score(y) else 1, reverse=True) if limit is not None: topic_list = topic_list[skip:skip + limit] else: topic_list = topic_list[skip:] for topic in topic_list: topic['author'] = yield UserDocument.translate_dbref( topic['author']) topic[ 'last_comment'] = yield TopicCommentDocument.get_last_comment( topic['_id']) if 'images' in topic and topic['images']: topic['images'] = yield TopicDocument._extend_images(topic) if user_id is not None: topic['liked'] = yield TopicLikeDocument.is_liked( topic['_id'], user_id) for i, node in enumerate(topic['nodes']): topic['nodes'][i] = yield NodeDocument.translate_dbref(node) if not node_id and skip == 0 and top_topic_list: topic_list = top_topic_list + topic_list raise gen.Return(topic_list) @gen.coroutine def get_topic_number(node_id=None): '''统计某节点下共有多少话题''' if node_id: count = yield TopicDocument.find({ 'nodes': DBRef(NodeDocument.meta['collection'], ObjectId(node_id)) }).count() else: count = yield TopicDocument.count() raise gen.Return(count) @gen.coroutine def get_topic_number_by_someone(user_id, visitor_id=None): '''得到某人发布的状态总的个数''' query = { 'author': DBRef(UserDocument.meta['collection'], ObjectId(user_id)) } # if visitor_id is not None: # if ObjectId(user_id) != ObjectId(visitor_id): # query.update({'anonymous': False}) query.update({'anonymous': False}) topic_number = yield TopicDocument.find(query).count() raise gen.Return(topic_number) @gen.coroutine def get_hot_topic_list(period=None, skip=0, limit=None): '''在一段时间内的热门话题, 跟赞/评论/阅读的次数有关. :Parameters: - `period`: 从现在往前算起, 多长时间之内的新闻 - `skip`: 默认0 - `limit`: 最终得到的热门话题的个数 NOTE: NEED CACHE! ''' def score(topic): ''' 公式为: score = like_times + comment_times/2 + read_times/5 即: 1 * like_times = 2 * comment_times = 5 * read_times ''' return (topic['like_times'] + topic['comment_times'] / 2.0 + topic['read_times'] / 5.0) query = {} if period is not None: query.update( {'last_update_time': { '$gt': datetime.now() - period }}) cursor = TopicDocument.find(query) topic_list = yield TopicDocument.to_list(cursor) topic_list.sort(cmp=lambda x, y: -1 if score(x) < score(y) else 1, reverse=True) if limit is not None: topic_list = topic_list[skip:skip + limit] else: topic_list = topic_list[skip:] raise gen.Return(topic_list) @gen.coroutine def get_recommend_topic_list(topic_id, size=10): '''根据某一话题推荐话题''' topic_list = [] topic = yield TopicDocument.find_one({'_id': ObjectId(topic_id)}) if topic: query = { '$and': [{ '_id': { '$ne': ObjectId(topic_id) } }, { '$or': [{ 'nodes': node } for node in topic['nodes']] }] } count = yield TopicDocument.find(query).count() if count > size: skip = random.randint(0, count - size) cursor = TopicDocument.find(query).skip(skip).limit(size) else: cursor = TopicDocument.find(query) topic_list = yield TopicDocument.to_list(cursor) if not topic_list or len(topic_list) < size: query = {'$and': [{'_id': {'$ne': ObjectId(topic_id)}}]} count = yield TopicDocument.find(query).count() if count > size: skip = random.randint(0, count - size) cursor = TopicDocument.find(query).skip(skip).limit(size) else: cursor = TopicDocument.find(query) topic_list = yield TopicDocument.to_list(cursor) for topic in topic_list: topic['author'] = yield UserDocument.translate_dbref( topic['author']) raise gen.Return(topic_list) @gen.coroutine def get_topic_list_by_someone(author_id, skip=0, limit=None): '''得到某人的话题''' cursor = TopicDocument.find({ 'author': DBRef(UserDocument.meta['collection'], ObjectId(author_id)) }).sort([('publish_time', pymongo.DESCENDING)]).skip(skip) if limit is not None: cursor = cursor.limit(limit) topic_list = yield TopicDocument.to_list(cursor) for topic in topic_list: topic['author'] = yield UserDocument.translate_dbref( topic['author']) topic[ 'last_comment'] = yield TopicCommentDocument.get_last_comment( topic['_id']) for i, node in enumerate(topic['nodes']): topic['nodes'][i] = yield NodeDocument.translate_dbref(node) raise gen.Return(topic_list) @gen.coroutine def insert_one(document): topic_id = yield TopicDocument.insert(document) for node in document['nodes']: topic_number = yield TopicDocument.get_topic_number(node.id) yield NodeDocument.update({'_id': ObjectId(node.id)}, {'$set': { 'topic_number': topic_number }}) new_document = { 'author': document['author'], 'publish_time': document['publish_time'], 'nodes': document['nodes'], 'anonymous': document['anonymous'], 'data_type': 'topic', 'data': DBRef(TopicDocument.meta['collection'], ObjectId(topic_id)) } yield TopicStatisticsDocument.insert(new_document) raise gen.Return(topic_id) @gen.coroutine def delete_one(topic_id): topic = DBRef(TopicDocument.meta['collection'], ObjectId(topic_id)) yield TopicDocument.remove({'_id': ObjectId(topic_id)}) yield TopicStatisticsDocument.remove({'data': topic}) yield TopicLikeDocument.delete(topic_id) yield TopicCommentDocument.delete(topic_id) yield MessageDocument.remove({'data': topic}) raise gen.Return()
class NodeDocument(Document): ''' :Variables: - `name`: 节点名称 - `topic_number`: 节点下有多少话题, 添加该属性是为了高效的根据话题多少对节点进行排名 - `father`: 父节点 - `category`: 节点类型, 比如内建 - `sort`: 对于某些特殊节点的排序方式 - `description`: 节点描述 ''' BUILTIN = 'builtin' name = StringField(required=True, max_length=20, unique=True) topic_number = IntegerField(required=True, default=0) father = ReferenceField('NodeDocument') category = StringField(max_length=30) sort = IntegerField() description = StringField(max_length=300) last_modified_by = ReferenceField(UserDocument) last_modified_time = DateTimeField() meta = {'collection': 'community_node'} @gen.coroutine def get_node(node_id): node = yield NodeDocument.find_one({'_id': ObjectId(node_id)}) if node: node = yield NodeDocument.translate_dbref_in_document(node) url = yield NodeAvatarDocument.get_node_avatar_url(node['_id']) if url: node['avatar'] = url raise gen.Return(node) @gen.coroutine def get_node_list_by_category(category, skip=0, limit=None): cursor = NodeDocument.find({ 'category': category }).sort([('sort', pymongo.ASCENDING), ('topic_number', pymongo.DESCENDING)]).skip(skip) if isinstance(limit, int) and limit > 0: cursor = cursor.limit(limit) node_list = yield NodeDocument.to_list(cursor) raise gen.Return(node_list) @gen.coroutine def get_hot_node_list(size=None): cursor = NodeDocument.find({ 'category': { '$exists': False } }).sort([('topic_number', pymongo.DESCENDING)]) if size is not None: cursor = cursor.limit(size) node_list = yield NodeDocument.to_list(cursor) raise gen.Return(node_list) @gen.coroutine def get_top_header_node_list(): '''得到社区模块上边部分的节点''' node_list = yield NodeDocument.get_node_list_by_category( NodeDocument.BUILTIN) raise gen.Return(node_list)
class FriendDocument(Document): '''朋友 :Variables: - `owner`: 谁的朋友? - `friend`: 朋友 - `be_time`: 成为朋友的时间 - `shielded`: 该朋友是否被屏蔽, 被屏蔽后, 用户将收不到其朋友的动态 - `blocked`: 该朋友是否被拉黑, 被拉黑后, 朋友将收不到该用户的动态 ''' owner = ReferenceField(UserDocument, required=True) friend = ReferenceField(UserDocument, required=True) be_time = DateTimeField(required=True) shielded = BooleanField(required=True, default=False) blocked = BooleanField(required=True, default=False) meta = {'collection': 'user_friend'} @gen.coroutine def _gen_friend_list(friends, role): assert role in ["owner", "friend"] friend_list = [] for friend in friends: friend[role] = yield UserDocument.translate_dbref(friend[role]) friend[role].update({ 'shielded': friend['shielded'], 'blocked': friend['blocked'] }) friend_list.append(friend[role]) raise gen.Return(friend_list) @gen.coroutine def get_friend_list(user_id, skip=0, limit=None): '''得到某一个人的朋友列表 :Parameters: - `user_id`: 相关用户 ''' owner = DBRef(UserDocument.meta['collection'], ObjectId(user_id)) cursor = FriendDocument.find({ 'owner': owner }).sort([('be_time', pymongo.DESCENDING)]).skip(skip) if limit is not None: cursor = cursor.limit(limit) friends = yield FriendDocument.to_list(cursor) friend_list = yield FriendDocument._gen_friend_list(friends, "friend") raise gen.Return(friend_list) @gen.coroutine def get_shielded_friends(user_id, skip=0, limit=None): '''得到我将对方屏蔽的好友''' owner = DBRef(UserDocument.meta['collection'], ObjectId(user_id)) cursor = FriendDocument.find({ 'owner': owner, 'shielded': True }).skip(skip) if limit is not None: cursor = cursor.limit(limit) friends = yield FriendDocument.to_list(cursor) friend_list = yield FriendDocument._gen_friend_list(friends, "friend") raise gen.Return(friend_list) @gen.coroutine def get_blocked_friends(user_id, skip=0, limit=None): '''得到对方将我拉黑的朋友''' friend = DBRef(UserDocument.meta['collection'], ObjectId(user_id)) cursor = FriendDocument.find({ 'friend': friend, 'blocked': True }).skip(skip) if limit is not None: cursor = cursor.limit(limit) friends = yield FriendDocument.to_list(cursor) friend_list = yield FriendDocument._gen_friend_list(friends, "owner") raise gen.Return(friend_list) @gen.coroutine def get_reached_friends(user_id, skip=0, limit=None): '''我既没将对方屏蔽, 对方也没将我拉黑的朋友''' friend_list = yield FriendDocument.get_friend_list(user_id) shielded_friends = yield FriendDocument.get_shielded_friends(user_id) blocked_friends = yield FriendDocument.get_blocked_friends(user_id) shielded_friends_id = set( [friend['_id'] for friend in shielded_friends]) blocked_friends_id = set([friend['_id'] for friend in blocked_friends]) friends = [] for friend in friend_list: if (friend['_id'] not in shielded_friends_id and friend['_id'] not in blocked_friends_id): friends.append(friend) raise gen.Return(friends) def get_reached_friends_sync(user_id, skip=0, limit=None): user = DBRef(UserDocument.meta['collection'], ObjectId(user_id)) cursor = FriendDocument.get_collection(True).find({ 'owner': user, 'shielded': False, 'blocked': False }) friend_list = set(item['friend'] for item in cursor) cursor = FriendDocument.get_collection(True).find({ 'friend': user, 'shielded': False, 'blocked': False }) for item in cursor: friend_list.add(item['owner']) return list(friend_list) @gen.coroutine def get_same_friends(user_a, user_b): '''得到user_a和user_b的共同好友. :Parameters: - `user_a`: 用户a(id) - `user_b`: 用户b(id) ''' @gen.coroutine def get_friends(user_id): owner = DBRef(UserDocument.meta['collection'], ObjectId(user_id)) cursor = FriendDocument.find({'owner': owner}) friends = yield FriendDocument.to_list(cursor) friends = {friend['friend'] for friend in friends} raise gen.Return(friends) friends_a = yield get_friends(user_a) friends_b = yield get_friends(user_b) same_friends = [(yield UserDocument.translate_dbref(friend)) for friend in friends_a.intersection(friends_b)] raise gen.Return(same_friends) @gen.coroutine def get_same_friend_ids(user_a, user_b): same_friends = yield FriendDocument.get_same_friends(user_a, user_b) raise gen.Return([friend["_id"] for friend in same_friends]) @gen.coroutine def is_friend(user_a, user_b): '''判断user_a和user_b是否是好友. :Parameters: - `user_a`: 用户a(id) - `user_b`: 用户b(id) ''' a = DBRef(UserDocument.meta['collection'], ObjectId(user_a)) b = DBRef(UserDocument.meta['collection'], ObjectId(user_b)) friend = yield FriendDocument.find_one( {'$or': [{ 'owner': a, 'friend': b }, { 'owner': b, 'friend': a }]}) raise gen.Return(True if friend else False) def is_friend_sync(user_a, user_b): '''判断user_a和user_b的是否是好友. :Parameters: - `user_a`: 用户a(id) - `user_b`: 用户b(id) ''' a = DBRef(UserDocument.meta['collection'], ObjectId(user_a)) b = DBRef(UserDocument.meta['collection'], ObjectId(user_b)) friend = FriendDocument.get_collection(True).find_one( {'$or': [{ 'owner': a, 'friend': b }, { 'owner': b, 'friend': a }]}) return True if friend else False @gen.coroutine def add_friend(user_a, user_b): '''添加一对朋友''' now = datetime.now() user_a_dbref = DBRef(UserDocument.meta['collection'], ObjectId(user_a)) user_b_dbref = DBRef(UserDocument.meta['collection'], ObjectId(user_b)) yield FriendDocument.insert({ 'owner': user_a_dbref, 'friend': user_b_dbref, 'be_time': now }) yield FriendDocument.insert({ 'owner': user_b_dbref, 'friend': user_a_dbref, 'be_time': now }) raise gen.Return() @gen.coroutine def delete_friend(user_a, user_b): '''删除一对朋友''' user_a_dbref = DBRef(UserDocument.meta['collection'], ObjectId(user_a)) user_b_dbref = DBRef(UserDocument.meta['collection'], ObjectId(user_b)) yield FriendDocument.remove({ '$or': [{ 'owner': user_a_dbref, 'friend': user_b_dbref }, { 'owner': user_b_dbref, 'friend': user_a_dbref }] }) raise gen.Return()
class UserSettingDocument(Document): '''用户的设置 :Variables: - `user`: 用户 - `profile_cover`: 个人封面 - `require_verify_when_add_friend`: 加我为朋友时是否需要验证 - `allow_stranger_visiting_profile`: 是否允许陌生人查看个人主页 - `allow_stranger_chat_with_me`: 是否允许陌生人和我聊天 - `enable_leaving_message`: 是否允许留言 - `email_notify_when_offline`: 当离线有新的消息时发邮件通知 - `theme`: 主题 ''' user = ReferenceField(UserDocument, required=True) profile_cover = ReferenceField(required=True) require_verify_when_add_friend = BooleanField(required=True, default=True) allow_stranger_visiting_profile = BooleanField(required=True, default=False) allow_stranger_chat_with_me = BooleanField(required=True, default=False) enable_leaving_message = BooleanField(required=True, default=True) email_notify_when_offline = BooleanField(required=True, default=True) theme = StringField(required=True, default='default') meta = {'collection': 'user_setting'} def get_user_setting_sync(user_id): return UserSettingDocument.get_collection(True).find_one({ 'user': DBRef(UserDocument.meta['collection'], ObjectId(user_id)) }) @gen.coroutine def get_user_setting(user_id): user_setting = yield UserSettingDocument.find_one({ 'user': DBRef(UserDocument.meta['collection'], ObjectId(user_id)) }) raise gen.Return(user_setting) @gen.coroutine def get_profile_cover(user_id): '''得到用户profile_cover图片地址''' from app.base.document import ImageDocument user_setting = yield UserSettingDocument.get_user_setting(user_id) if not (user_setting and 'profile_cover' in user_setting and user_setting['profile_cover']): raise gen.Return("") cover = user_setting['profile_cover'] if cover.collection == OfficialProfileCoverDocument.meta['collection']: cover = yield OfficialProfileCoverDocument.translate_dbref(cover) url = yield ImageDocument.generate_image_url(cover['image'].id) else: url = yield ImageDocument.generate_image_url(cover.id, thumbnail=True) raise gen.Return(url) @gen.coroutine def set_profile_cover(user_id, cover): '''设置用户的个人封面''' from app.base.document import ImageDocument assert isinstance(cover, DBRef) uploader = DBRef(UserDocument.meta['collection'], ObjectId(user_id)) user_setting = yield UserSettingDocument.get_user_setting(user_id) if (user_setting and 'profile_cover' in user_setting and user_setting['profile_cover'] and user_setting['profile_cover'].collection == ImageDocument.meta['collection']): yield ImageDocument.remove( {'_id': ObjectId(user_setting['profile_cover'].id)}) yield UserSettingDocument.update({'user': uploader}, {'$set': { 'profile_cover': cover }}) raise gen.Return()
class TopicCommentDocument(Document): ''' :Variables: - `topic`: 被评论的话题 - `author`: 评论者 - `comment_time`: 评论时间 - `content`: 评论内容 - `anonymous`: 是否匿名 - `replyeder`: 被回复的人 ''' topic = ReferenceField(TopicDocument, required=True) author = ReferenceField(UserDocument, required=True) comment_time = DateTimeField(required=True) content = StringField(required=True, max_length=10**5) anonymous = BooleanField(required=True, default=False) replyeder = ReferenceField(UserDocument) meta = {'collection': 'community_topic_comment'} @gen.coroutine def get_comment_list(topic_id, skip=0, limit=None): cursor = TopicCommentDocument.find({ 'topic': DBRef(TopicDocument.meta['collection'], ObjectId(topic_id)) }).sort([('comment_time', pymongo.ASCENDING)]).skip(skip) if limit is not None: cursor = cursor.limit(limit) comment_list = yield TopicCommentDocument.to_list(cursor) for i, comment in enumerate(comment_list): comment['floor'] = skip + 1 + i comment['author'] = yield UserDocument.translate_dbref( comment['author']) if 'replyeder' in comment: comment['replyeder'] = yield UserDocument.translate_dbref( comment['replyeder']) raise gen.Return(comment_list) @gen.coroutine def get_comment_times(topic_id): comment_times = yield TopicCommentDocument.find({ 'topic': DBRef(TopicDocument.meta['collection'], ObjectId(topic_id)) }).count() raise gen.Return(comment_times) @gen.coroutine def insert_one(document): comment_id = yield TopicCommentDocument.insert(document) topic_id = document['topic'].id comment_times = yield TopicCommentDocument.get_comment_times(topic_id) yield TopicDocument.update({'_id': ObjectId(topic_id)}, { '$set': { 'comment_times': comment_times, 'last_update_time': datetime.now() } }) topic = yield TopicDocument.find_one({'_id': ObjectId(topic_id)}) if topic: new_document = { 'author': document['author'], 'publish_time': document['comment_time'], 'nodes': topic['nodes'], 'anonymous': document['anonymous'], 'data_type': 'topic_comment', 'data': DBRef(TopicCommentDocument.meta['collection'], ObjectId(comment_id)) } yield TopicStatisticsDocument.insert(new_document) raise gen.Return(comment_id) @gen.coroutine def get_last_comment(topic_id): '''得到某一话题的最后一个回复''' cursor = TopicCommentDocument.find({ 'topic': DBRef(TopicDocument.meta['collection'], ObjectId(topic_id)) }).sort([('comment_time', pymongo.DESCENDING)]).limit(1) comment_list = yield TopicCommentDocument.to_list(cursor) last_comment = None if comment_list: last_comment = comment_list[0] last_comment['author'] = yield UserDocument.translate_dbref( last_comment['author']) raise gen.Return(last_comment) @gen.coroutine def delete_one(comment_id): comment = yield TopicCommentDocument.find_one( {'_id': ObjectId(comment_id)}) if comment: yield TopicCommentDocument.remove({'_id': ObjectId(comment_id)}) comment_times = yield TopicCommentDocument.get_comment_times( comment['topic'].id) yield TopicDocument.update( {'_id': ObjectId(comment['topic'].id)}, {'$set': { 'comment_times': comment_times }}) yield MessageDocument.remove({ 'data': DBRef(TopicCommentDocument.meta['collection'], ObjectId(comment_id)) }) raise gen.Return() @gen.coroutine def delete(topic_id): '''将与某一个话题有关的评论都删除''' comment_list = yield TopicCommentDocument.get_comment_list(topic_id) for comment in comment_list: yield TopicCommentDocument.delete_one(comment['_id']) raise gen.Return()
class ShareDownloadDocument(Document): '''下载 :Variables: - `share`: 分享 - `downloader`: 下载者 - `download_time`: 下载时间 ''' share = ReferenceField(ShareDocument, required=True) downloader = ReferenceField(UserDocument, required=True) download_time = DateTimeField(required=True) meta = {'collection': 'share_download'} @gen.coroutine def get_download_times(share_id): download_times = yield ShareDownloadDocument.find({ 'share': DBRef(ShareDocument.meta['collection'], ObjectId(share_id)) }).count() raise gen.Return(download_times) @gen.coroutine def get_hot_download_list(period=timedelta(days=7), size=6): '''得到最近下载的比较多的资源的列表''' cursor = ShareDownloadDocument.aggregate([{ '$match': { 'download_time': { '$gt': datetime.now() - period } } }, { '$group': { '_id': '$share', 'download_times': { '$sum': 1 } } }, { '$sort': { 'download_times': -1 } }, { '$limit': size }]) r = [] while (yield cursor.fetch_next): r.append(cursor.next_object()) r = yield ShareDownloadDocument.translate_dbref_in_document_list(r) hot_download_list = [item['_id'] for item in r] translate = ShareDocument.translate_dbref_in_document_list hot_download_list = yield translate(hot_download_list) if not hot_download_list: hot_download_list = yield ShareDocument.get_share_list( sort='popularity', limit=6) raise gen.Return(hot_download_list)
class ShareLikeDocument(Document): ''' :Variables: - `share`: 分享 - `liker`: 点赞者 - `like_time`: 点赞时间 ''' share = ReferenceField(ShareDocument, required=True) liker = ReferenceField(UserDocument, required=True) like_time = DateTimeField(required=True) meta = {'collection': 'share_like'} @gen.coroutine def get_like_list(share_id, skip=0, limit=None): cursor = ShareLikeDocument.find({ 'share': DBRef(ShareDocument.meta['collection'], ObjectId(share_id)) }).sort([('like_time', pymongo.DESCENDING)]).skip(skip) if limit is not None: cursor = cursor.limit(limit) like_list = yield ShareLikeDocument.to_list(cursor) for like in like_list: like['liker'] = yield UserDocument.translate_dbref(like['liker']) raise gen.Return(like_list) @gen.coroutine def get_like_times(share_id): like_times = yield ShareLikeDocument.find({ 'share': DBRef(ShareDocument.meta['collection'], ObjectId(share_id)) }).count() raise gen.Return(like_times) @gen.coroutine def insert_one(document): like_id = yield ShareLikeDocument.insert(document) like_times = yield ShareLikeDocument.get_like_times( document['share'].id) yield ShareDocument.update({'_id': ObjectId(document['share'].id)}, {'$set': { 'like_times': like_times }}) raise gen.Return(like_id) @gen.coroutine def remove_one(query): like = yield ShareLikeDocument.find_one(query) if like: yield ShareLikeDocument.remove(query) like_times = yield ShareLikeDocument.get_like_times( like['share'].id) yield ShareDocument.update({'_id': ObjectId(like['share'].id)}, {'$set': { 'like_times': like_times }}) yield MessageDocument.remove({ 'data': DBRef(ShareLikeDocument.meta['collection'], ObjectId(like['_id'])) }) raise gen.Return() @gen.coroutine def is_liked(share_id, user_id): share_like = yield ShareLikeDocument.find_one({ 'share': DBRef(ShareDocument.meta['collection'], ObjectId(share_id)), 'liker': DBRef(UserDocument.meta['collection'], ObjectId(user_id)) }) raise gen.Return(True if share_like else False)
class StatusCommentDocument(Document): '''状态的评论. :Variables: - `status`: 相关的状态 - `commenter`: 评论者 - `comment_time`: 评论时间 - `content`: 评论内容 - `replyeder`: 被回复者, 如果有此属性, 说明该评论是回复某人的 ''' status = ReferenceField(StatusDocument, required=True) author = ReferenceField(UserDocument, required=True) comment_time = DateTimeField(required=True) content = StringField(required=True, max_length=200) replyeder = ReferenceField(UserDocument) meta = {'collection': 'home_status_comment'} @gen.coroutine def get_comment(comment_id): '''得到某一条评论, 是comment_list的一个item''' comment = yield StatusCommentDocument.find_one( {'_id': ObjectId(comment_id)}) if comment: comment = yield StatusCommentDocument.translate_dbref_in_document( comment) raise gen.Return(comment) @gen.coroutine def get_comment_list(status_id, user_id, skip=0, limit=None): '''得到某一状态的评论, 只能看到共同好友和自己的评论. :Parameters: - `status_id`: 相关的状态 - `user_id`: 查看评论者 - `skip`: 默认0 - `limit`: 默认None ''' comment_list = [] status = yield StatusDocument.find_one({'_id': ObjectId(status_id)}) if status: status = yield StatusDocument.translate_dbref_in_document(status) if status['author']['_id'] == ObjectId(user_id): cursor = StatusCommentDocument.find({ 'status': DBRef(StatusDocument.meta['collection'], ObjectId(status['_id'])) }) else: can_see = yield StatusDocument.can_see(status, user_id) if not can_see: raise gen.Return(comment_list) friend_ids = yield FriendDocument.get_same_friend_ids( status['author']['_id'], user_id) friend_ids += [ DBRef(UserDocument.meta['collection'], ObjectId(user_id)), DBRef(UserDocument.meta['collection'], ObjectId(status['author']['_id'])) ] cursor = StatusCommentDocument.find({ 'status': DBRef(StatusDocument.meta['collection'], ObjectId(status['_id'])), 'author': { '$in': friend_ids }, '$or': [{ 'replyeder': { '$exists': False } }, { 'replyeder': { '$exists': True, '$in': friend_ids } }] }) cursor = cursor.sort([('comment_time', pymongo.ASCENDING) ]).skip(skip) if limit is not None: cursor = cursor.limit(limit) translate = StatusCommentDocument.translate_dbref_in_document_list comment_list = yield StatusCommentDocument.to_list(cursor) comment_list = yield translate(comment_list) raise gen.Return(comment_list) @gen.coroutine def get_comment_times(status_id): '''得到某一个评论的评论次数, 所有人的评论''' comment_times = yield StatusCommentDocument.find({ 'status': DBRef(StatusDocument.meta['collection'], ObjectId(status_id)) }).count() raise gen.Return(comment_times) @gen.coroutine def get_comment_times_can_seen(status_id, user_id): '''得到某一个人能够看到的评论次数''' status = yield StatusDocument.get_status(status_id) if not status: raise gen.Return(0) if ObjectId(status['author']['_id']) == ObjectId(user_id): cnt = yield StatusCommentDocument.get_comment_times(status_id) raise gen.Return(cnt) can_see = yield StatusDocument.can_see(status, user_id) if not can_see: raise gen.Return(0) friend_ids = yield FriendDocument.get_same_friend_ids( status['author']['_id'], user_id) friend_ids += [ DBRef(UserDocument.meta['collection'], ObjectId(user_id)), DBRef(UserDocument.meta['collection'], ObjectId(status['author']['_id'])) ] cnt = yield StatusCommentDocument.find({ 'status': DBRef(StatusDocument.meta['collection'], ObjectId(status['_id'])), 'author': { '$in': friend_ids }, '$or': [{ 'replyeder': { '$exists': False } }, { 'replyeder': { '$exists': True, '$in': friend_ids } }] }).count() raise gen.Return(cnt) @gen.coroutine def insert_one(document): comment_id = yield StatusCommentDocument.insert(document) comment_times = yield StatusCommentDocument.get_comment_times( document['status'].id) yield StatusDocument.update({'_id': ObjectId(document['status'].id)}, {'$set': { 'comment_times': comment_times }}) raise gen.Return(comment_id)
class StatusLikeDocument(Document): '''赞 :Variables: - `status`: 相关状态 - `liker`: 点赞者 - `like_time`: 点赞时间 ''' status = ReferenceField(StatusDocument, required=True) liker = ReferenceField(UserDocument, required=True) like_time = DateTimeField(required=True) meta = {'collection': 'home_status_like'} @gen.coroutine def _get_status_liker_cursor(status, user_id): friend_ids = yield FriendDocument.get_same_friends( status['author']['_id'], user_id) friend_ids += [ DBRef(UserDocument.meta['collection'], ObjectId(user_id)), DBRef(UserDocument.meta['collection'], ObjectId(status['author']['_id'])) ] cursor = StatusLikeDocument.find({ 'status': DBRef(StatusDocument.meta['collection'], ObjectId(status['_id'])), 'liker': { '$in': friend_ids } }) raise gen.Return(cursor) @gen.coroutine def get_like_list(status_id, user_id, skip=0, limit=None): '''得到赞列表, 只能包括我和该状态发布者共同好友 :Parameters: - `status_id`: 状态id - `user_id`: 查看该状态的人 - `skip`: 0 - `limit`: None ''' like_list = [] status = yield StatusDocument.find_one({'_id': ObjectId(status_id)}) if status: status = yield StatusDocument.translate_dbref_in_document(status) if status['author']['_id'] == ObjectId(user_id): cursor = StatusLikeDocument.find({ 'status': DBRef(StatusDocument.meta['collection'], ObjectId(status['_id'])) }) else: can_see = yield StatusDocument.can_see(status, user_id) if not can_see: raise gen.Return(like_list) cursor = yield StatusLikeDocument._get_status_liker_cursor( status, user_id) cursor = cursor.sort([('like_time', pymongo.ASCENDING)]).skip(skip) if limit is not None: cursor = cursor.limit(limit) translate = StatusLikeDocument.translate_dbref_in_document_list like_list = yield StatusLikeDocument.to_list(cursor) like_list = yield translate(like_list) raise gen.Return(like_list) @gen.coroutine def is_liked(status_id, user_id): status = DBRef(StatusDocument.meta['collection'], ObjectId(status_id)) liker = DBRef(UserDocument.meta['collection'], ObjectId(user_id)) like = yield StatusLikeDocument.find_one({ 'status': status, 'liker': liker }) raise gen.Return(True if like else False) @gen.coroutine def get_like_times(status_id): '''得到点赞次数, 所有人的''' like_times = yield StatusLikeDocument.find({ 'status': DBRef(StatusDocument.meta['collection'], ObjectId(status_id)) }).count() raise gen.Return(like_times) @gen.coroutine def get_like_times_can_seen(status_id, user_id): '''得到某一个人能够看到的赞的次数''' status = yield StatusDocument.get_status(status_id) if not status: raise gen.Return(0) if ObjectId(status['author']['_id']) == ObjectId(user_id): cnt = yield StatusLikeDocument.get_like_times(status_id) raise gen.Return(cnt) can_see = yield StatusDocument.can_see(status, user_id) if not can_see: raise gen.Return(0) cursor = yield StatusLikeDocument._get_status_liker_cursor( status, user_id) cnt = yield cursor.count() raise gen.Return(cnt) @gen.coroutine def insert_one(document): like_id = yield StatusLikeDocument.insert(document) like_times = yield StatusLikeDocument.get_like_times( document['status'].id) yield StatusDocument.update({'_id': ObjectId(document['status'].id)}, {'$set': { 'like_times': like_times }}) raise gen.Return(like_id) @gen.coroutine def remove_one(query): like = yield StatusLikeDocument.find_one(query) if like: yield StatusLikeDocument.remove(query) like_times = yield StatusLikeDocument.get_like_times( like['status'].id) yield StatusDocument.update({'_id': ObjectId(like['status'].id)}, {'$set': { 'like_times': like_times }}) raise gen.Return()
class StatusDocument(Document): ''' :Variables: - `author`: 发布者 - `publish_time`: 发布时间 - `content`: 内容 - `like_times`: 点赞次数 - `comment_times`: 评论次数 ''' author = ReferenceField(UserDocument, required=True) publish_time = DateTimeField(required=True) content = StringField(required=True, max_length=1000) like_times = IntegerField(required=True, default=0) comment_times = IntegerField(required=True, default=0) meta = {'collection': 'home_status'} REGEX_AT = re.compile('@([^@\d\(\)]+)\(([0-9a-f]{24})\)') @gen.coroutine def translate_at(content): '''将status content中的@转换成链接''' result = StatusDocument.REGEX_AT.findall(content) for item in result: origin = '@%s(%s)' % (item[0], item[1]) link = '<a href="/profile/%s" data-userid="%s">@%s</a>' % ( item[1], item[1], item[0]) content = content.replace(origin, link) raise gen.Return(content) @gen.coroutine def get_status(status_id, user_id=None): '''得到一个status, 是status_list的item''' status = yield StatusDocument.find_one({'_id': ObjectId(status_id)}) if status: status = yield StatusDocument.translate_dbref_in_document(status) photo = yield StatusPhotoDocument.find_one({ 'status': DBRef(StatusDocument.meta['collection'], ObjectId(status['_id'])) }) if photo: url = yield StatusPhotoDocument.generate_url(photo['_id']) thumbnail = yield StatusPhotoDocument.generate_url( photo['_id'], thumbnail=True) status['photo'] = {'url': url, 'thumbnail': thumbnail} if user_id is not None: status['liked'] = yield StatusLikeDocument.is_liked( status['_id'], user_id) status['like_list'] = yield StatusLikeDocument.get_like_list( status['_id'], user_id) raise gen.Return(status) @gen.coroutine def _extend_status_list(status_list, user_id): for status in status_list: like_times_f = StatusLikeDocument.get_like_times_can_seen status['like_times'] = yield like_times_f(status['_id'], user_id) comment_times_f = StatusCommentDocument.get_comment_times_can_seen status['comment_times'] = yield comment_times_f( status['_id'], user_id) photo = yield StatusPhotoDocument.find_one({ 'status': DBRef(StatusDocument.meta['collection'], ObjectId(status['_id'])) }) if photo: url = yield StatusPhotoDocument.generate_url(photo['_id']) thumbnail = yield StatusPhotoDocument.generate_url( photo['_id'], thumbnail=True) status['photo'] = {'url': url, 'thumbnail': thumbnail} status['liked'] = yield StatusLikeDocument.is_liked( status['_id'], user_id) status['like_list'] = yield StatusLikeDocument.get_like_list( status['_id'], user_id) raise gen.Return(status_list) @gen.coroutine def get_status_list(user_id, visitor_id, skip=0, limit=None): '''按时间从近致远的顺序获取user_id发布的状态 :Parameters: - `user_id`: 用户id - `visitor_id`: 当前访问者id - `skip`: 默认0 - `limit`: 默认None ''' cursor = StatusDocument.find({ 'author': DBRef(UserDocument.meta['collection'], ObjectId(user_id)) }).sort([('publish_time', pymongo.DESCENDING)]).skip(skip) if limit is not None: cursor = cursor.limit(limit) status_list = yield StatusDocument.to_list(cursor) status_list = yield StatusDocument.translate_dbref_in_document_list( status_list) status_list = yield StatusDocument._extend_status_list( status_list, visitor_id) raise gen.Return(status_list) @gen.coroutine def get_friends_status_list(user_id, skip=0, limit=None): '''得到user_id的朋友的状态, 包括自己. :Parameters: - `user_id`: 用户id - `skip`: 默认0 - `limit`: 默认None ''' friend_list = yield FriendDocument.get_friend_list(user_id) shielded_friend_list = yield FriendDocument.get_shielded_friends( user_id) blocked_friend_list = yield FriendDocument.get_blocked_friends(user_id) all_friend_dbref_list = [ DBRef(UserDocument.meta['collection'], ObjectId(friend['_id'])) for friend in friend_list ] shielded_friend_dbref_list = [ DBRef(UserDocument.meta['collection'], ObjectId(friend['_id'])) for friend in shielded_friend_list ] blocked_friend_dbref_list = [ DBRef(UserDocument.meta['collection'], ObjectId(friend['_id'])) for friend in blocked_friend_list ] friend_dbref_list = [ DBRef(UserDocument.meta['collection'], ObjectId(user_id)) ] for friend in all_friend_dbref_list: if (friend not in shielded_friend_dbref_list and friend not in blocked_friend_dbref_list): friend_dbref_list.append(friend) cursor = StatusDocument.find({ 'author': { '$in': friend_dbref_list } }).sort([('publish_time', pymongo.DESCENDING)]).skip(skip) if limit is not None: cursor = cursor.limit(limit) status_list = yield StatusDocument.to_list(cursor) status_list = yield StatusDocument.translate_dbref_in_document_list( status_list) status_list = yield StatusDocument._extend_status_list( status_list, user_id) raise gen.Return(status_list) @gen.coroutine def get_status_number(user_id): '''得到某一个人的已发表的微博的数量''' status_number = yield StatusDocument.find({ 'author': DBRef(UserDocument.meta['collection'], ObjectId(user_id)) }).count() raise gen.Return(status_number) @gen.coroutine def can_see(status, user_id): '''判断某人能否看到某状态. :Parameters: - `status`: 状态, 是id或者document - `user_id`: 相关用户 ''' can = False if isinstance(status, (str, ObjectId)): status = yield StatusDocument.find_one({'_id': ObjectId(status)}) if status: if isinstance(status['author'], DBRef): author = status['author'].id elif isinstance(status['author'], dict): author = status['author']['_id'] else: raise gen.Return(can) is_friend = yield FriendDocument.is_friend(user_id, author) user_setting = yield UserSettingDocument.get_user_setting(author) if (str(author) == str(user_id) or is_friend or user_setting['allow_stranger_visiting_profile']): can = True raise gen.Return(can)
class TopicStatisticsDocument(Document): ''' 话题统计, 添加该集合的目的是为了更好的统计活跃用户 :Variables: - `author`: 用户 - `publish_time`: 发表时间, 可以根据发表时间来确定一段时间内的活跃用户,而不是所有时间段 的活跃用户 - `nodes`: 话题或者话题评论所属的节点 - `anonymous`: 是否匿名, 如果匿名的话, 则不算 - `data_type`: 所保存的数据类型 - `data`: 数据 ''' author = ReferenceField(UserDocument, required=True) publish_time = DateTimeField(required=True) nodes = ListField(ReferenceField(NodeDocument), required=True) anonymous = BooleanField(required=True) data_type = StringField(required=True, candidate=['topic', 'topic_comment']) data = ReferenceField(required=True) meta = {'collection': 'community_topic_statistics'} @gen.coroutine def get_active_author_list(node_id=None, period=None, skip=0, limit=None): '''得到某一节点下的活跃用户排名 :Parameters: - `node_id`: 如果不为None, 则表示某一节点下的活跃用户 - `period`: 如果不为None, 则为timedelta类型, 表示从现在往前算多长时间内的活跃用户 - `skip`: 默认0 - `limit`: 默认None ''' query = { 'anonymous': False, } if node_id is not None: query.update({ 'nodes': DBRef(NodeDocument.meta['collection'], ObjectId(node_id)) }) if period is not None: begin = datetime.now() - period query.update({'publish_time': {'$gt': begin}}) aggregate_pipeline = [{ '$match': query }, { '$group': { '_id': { 'author': '$author' }, 'times': { '$sum': 1 } } }, { '$sort': { 'times': -1 } }, { '$skip': skip }, { '$limit': limit }] cursor = TopicStatisticsDocument.aggregate(aggregate_pipeline) author_list = [] while (yield cursor.fetch_next): item = cursor.next_object() author_list.append({ 'author': item['_id']['author'], 'times': item['times'] }) author_list = yield UserDocument.translate_dbref_in_document_list( author_list) raise gen.Return(author_list)
class ChatMessageDocument(Document): '''两个人之间的私聊, 把两个人之间的聊天历史保存起来. :Variables: - `body`: 消息内容 - `betwwen`: 谁跟谁之间的私聊, 添加此属性是为了方便查询两人之间的私聊信息. - `sender`: 发送者 - `send_time`: 发送时间 - `recipient`: 接收者 - `received`: 是否被接收, 如果对方离线(未和Ejabberd服务器建立连接), 那么将会存储为离线消息 - `read`: 是否被阅读, 接收后不一定被阅读 ''' body = StringField(required=True, max_length=1000) between = ListField(ReferenceField(UserDocument), required=True) sender = ReferenceField(UserDocument, required=True) send_time = DateTimeField(required=True) recipient = ReferenceField(UserDocument, required=True) received = BooleanField(required=True, default=False) read = BooleanField(required=True, default=False) meta = { 'collection': 'chat_message' } @gen.coroutine def get_chat_message_list(user_id, skip=0, limit=None): '''得到与某人有关的私聊信息''' user_dbref = DBRef(UserDocument.meta['collection'], ObjectId(user_id)) query = { '$or': [{'sender': user_dbref}, {'recipient': user_dbref}] } cursor = ChatMessageDocument.find(query).sort( [('send_time', pymongo.DESCENDING)] ).skip(skip) if limit is not None: cursor = cursor.limit(limit) chat_message_list = yield ChatMessageDocument.to_list(cursor) chat_message_list = yield ChatMessageDocument.translate_dbref_in_document_list( chat_message_list) raise gen.Return(chat_message_list) @gen.coroutine def get_history_messages(id_a, id_b, since): '''得到两人之间的历史消息''' limit = setting.history_messages_number_per_time user_a = DBRef(UserDocument.meta['collection'], ObjectId(id_a)) user_b = DBRef(UserDocument.meta['collection'], ObjectId(id_b)) cursor = ChatMessageDocument.find({ 'between': user_a, 'between': user_b, 'send_time': {'$lt': since} }) cursor = ChatMessageDocument.find( {'$or': [{'between': [user_a, user_b]}, {'between': [user_b, user_a]}], 'send_time': {'$lt': since}} ).sort([('send_time', pymongo.DESCENDING)]).limit(limit) result = yield ChatMessageDocument.to_list(cursor) raise gen.Return(result[::-1]) def set_read(recipient_id): '''将某人所有的未读信息设置为已读''' ChatMessageDocument.get_collection(True).update( {'recipient': DBRef(UserDocument.meta['collection'], ObjectId(recipient_id))}, {'$set': {'read': True}}, multi=True ) def has_unread_chat_message(recipient_id): '''判断是否有未读的信息''' message = ChatMessageDocument.get_collection(pymongo=True).find_one({ 'recipient': DBRef(UserDocument.meta['collection'], ObjectId(recipient_id)), 'read': False }) return True if message else False def get_message_number(recipient_id, read=None): '''得到消息数量''' query = { 'recipient': DBRef(UserDocument.meta['collection'], ObjectId(recipient_id)) } if read is not None: assert isinstance(read, bool) query.update({'read': read}) count = ChatMessageDocument.get_collection(True).find(query).count() return count def get_unread_messages(user_id): '''得到某人未读信息''' recipient = DBRef(UserDocument.meta['collection'], ObjectId(user_id)) result = ChatMessageDocument.get_collection(True).aggregate([ {'$match': {'recipient': recipient, 'received': True, 'read': False}}, {'$sort': {'send_time': 1}}, {'$group': {'_id': '$sender', 'messages': {'$push': {'send_time': '$send_time', 'body': '$body', 'sender': '$sender'}}}} ]) return result['result']
class ImageDocument(Document): '''图片 :Variables: - `name`: 图片名称 - `body`: 图片内容 - `content_type`: 图片类型, 存储的内容是PNG, JPEG等 - `thumbnail`: 略缩图 - `uploader`: 上传者, 有可能是抓取的图片, 所以上传者不一定存在. - `upload_time`: 上传时间 - `description`: 图片描述 - `tag`: 标签 ''' name = StringField(required=True, max_length=200) body = BinaryField(required=True) content_type = StringField(required=True) thumbnail = BinaryField(required=True) uploader = ReferenceField(UserDocument) upload_time = DateTimeField() description = StringField(max_length=500) tags = ListField(StringField(max_length=50)) meta = {'collection': 'image'} @gen.coroutine def generate_image_url(image_id, thumbnail=False): url = '/image/%s' % image_id if thumbnail: url += '/thumbnail' raise gen.Return(url) @gen.coroutine def insert_one(uploaded_file, thumbnail_width=200, target_width=None, crop_area=None, uploader=None, upload_time=None, description=None, tags=None): ''' 插入一个图片 :Parameters: - `uploaded_file`: 上传的文件 - `thumbnail_width`: 略缩图宽度, 默认200px - `target_width`: Jcrop插件剪裁时, 图像所具有的宽度 - `crop_area`: 要剪裁的区域, 其格式为(x, y, w, h), x/y/w/h是Jcrop插件传过来的数据, x代表左上角x坐标, y代表左上角y坐标, w代表宽度, h代表高度 - `uploader`: 上传者, 不是ObjectId, 是DBRef - `upload_time`: 上传时间 - `description`: 描述 - `tags`: 标签, 列表类型 ''' try: image = Image.open(StringIO(uploaded_file['body'])) except: raise HTTPError(404) content_type = uploaded_file['content_type'].split('/')[1].upper() document = { 'name': uploaded_file['filename'], 'content_type': content_type, } if uploader: assert isinstance(uploader, DBRef) document["uploader"] = uploader if upload_time: document["upload_time"] = upload_time if description: document["description"] = description if tags: document["tags"] = tags if target_width is not None and crop_area is not None: scale = image.size[0] * 1.0 / target_width x, y, w, h = map(lambda x: int(x * scale), crop_area) box = (x, y, x + w, y + h) image = image.crop(box) _width = 1024 if image.size[0] > _width: height = _width * 1.0 * image.size[1] / image.size[0] image = image.resize(map(int, (_width, height)), Image.ANTIALIAS) output = StringIO() image.save(output, content_type, quality=100) document["body"] = Binary(output.getvalue()) output.close() thumbnail_height = thumbnail_width * 1.0 * image.size[1] / image.size[0] output = StringIO() image.resize(map(int, (thumbnail_width, thumbnail_height)), Image.ANTIALIAS).save(output, content_type, quality=100) document["thumbnail"] = Binary(output.getvalue()) output.close() image_id = yield ImageDocument.insert(document) raise gen.Return(image_id)
class TopicLikeDocument(Document): ''' :Variables: - `topic`: 话题 - `liker`: 点赞者 - `like_time`: 点赞时间 ''' topic = ReferenceField(TopicDocument, required=True) liker = ReferenceField(UserDocument, required=True) like_time = DateTimeField(required=True) meta = {'collection': 'community_topic_like'} @gen.coroutine def get_like_list(topic_id, skip=0, limit=None): cursor = TopicLikeDocument.find({ 'topic': DBRef(TopicDocument.meta['collection'], ObjectId(topic_id)) }).sort([('like_time', pymongo.DESCENDING)]).skip(skip) if limit is not None: cursor = cursor.limit(limit) like_list = yield TopicLikeDocument.to_list(cursor) for like in like_list: like['liker'] = yield UserDocument.translate_dbref(like['liker']) raise gen.Return(like_list) @gen.coroutine def get_like_times(topic_id): like_times = yield TopicLikeDocument.find({ 'topic': DBRef(TopicDocument.meta['collection'], ObjectId(topic_id)) }).count() raise gen.Return(like_times) @gen.coroutine def insert_one(document): like_id = yield TopicLikeDocument.insert(document) like_times = yield TopicLikeDocument.get_like_times( document['topic'].id) yield TopicDocument.update({'_id': ObjectId(document['topic'].id)}, {'$set': { 'like_times': like_times }}) raise gen.Return(like_id) @gen.coroutine def remove_one(query): like = yield TopicLikeDocument.find_one(query) if like: yield TopicLikeDocument.remove(query) like_times = yield TopicLikeDocument.get_like_times( like['topic'].id) yield TopicDocument.update({'_id': ObjectId(like['topic'].id)}, {'$set': { 'like_times': like_times }}) yield MessageDocument.remove({ 'data': DBRef(TopicLikeDocument.meta['collection'], ObjectId(like['_id'])) }) raise gen.Return() @gen.coroutine def delete(topic_id): '''将与某一topic有关的topic都删除掉''' like_list = yield TopicLikeDocument.get_like_list(topic_id) for like in like_list: yield TopicLikeDocument.remove_one({'_id': ObjectId(like['_id'])}) raise gen.Return() @gen.coroutine def is_liked(topic_id, user_id): topic_like = yield TopicLikeDocument.find_one({ 'topic': DBRef(TopicDocument.meta['collection'], ObjectId(topic_id)), 'liker': DBRef(UserDocument.meta['collection'], ObjectId(user_id)) }) raise gen.Return(True if topic_like else False)
class ShareCommentDocument(Document): ''' :Variables: - `share`: 被评论的分享 - `author`: 评论者 - `comment_time`: 评论时间 - `content`: 评论内容 - `anonymous`: 是否匿名 - `replyeder`: 被回复的人 ''' share = ReferenceField(ShareDocument, required=True) author = ReferenceField(UserDocument, required=True) comment_time = DateTimeField(required=True) content = StringField(required=True, max_length=10**5) anonymous = BooleanField(required=True, default=False) replyeder = ReferenceField(UserDocument) meta = {'collection': 'share_comment'} @gen.coroutine def get_comment_list(share_id, skip=0, limit=None): cursor = ShareCommentDocument.find({ 'share': DBRef(ShareDocument.meta['collection'], ObjectId(share_id)) }).sort([('comment_time', pymongo.ASCENDING)]).skip(skip) if limit is not None: cursor = cursor.limit(limit) comment_list = yield ShareCommentDocument.to_list(cursor) for i, comment in enumerate(comment_list): comment['floor'] = skip + 1 + i comment['author'] = yield UserDocument.translate_dbref( comment['author']) if 'replyeder' in comment: comment['replyeder'] = yield UserDocument.translate_dbref( comment['replyeder']) raise gen.Return(comment_list) @gen.coroutine def get_comment_times(share_id): comment_times = yield ShareCommentDocument.find({ 'share': DBRef(ShareDocument.meta['collection'], ObjectId(share_id)) }).count() raise gen.Return(comment_times) @gen.coroutine def insert_one(document): comment_id = yield ShareCommentDocument.insert(document) comment_times = yield ShareCommentDocument.get_comment_times( document['share'].id) yield ShareDocument.update({'_id': ObjectId(document['share'].id)}, {'$set': { 'comment_times': comment_times }}) raise gen.Return(comment_id) @gen.coroutine def delete_one(comment_id): comment = yield ShareCommentDocument.find_one( {'_id': ObjectId(comment_id)}) if comment: yield ShareCommentDocument.remove({'_id': ObjectId(comment_id)}) comment_times = yield ShareCommentDocument.get_comment_times( comment['share'].id) yield ShareDocument.update( {'_id': ObjectId(comment['share'].id)}, {'$set': { 'comment_times': comment_times }}) yield MessageDocument.remove({ 'data': DBRef(ShareCommentDocument.meta['collection'], ObjectId(comment_id)) }) raise gen.Return()
class LeaveMessageDocument(Document): '''留言 :Variables: - `user`: 被留言者 - `author`: 留言者 - `leave_time`: 留言时间 - `private`: 是不是私密的 - `content`: 留言内容 - `replyeder`: 被回复者 ''' user = ReferenceField(UserDocument, required=True) author = ReferenceField(UserDocument, required=True) leave_time = DateTimeField(required=True) private = BooleanField(required=True, default=False) content = StringField(required=True, max_length=5000) replyeder = ReferenceField(UserDocument) meta = {'collection': 'profile_leave_message'} @gen.coroutine def get_leave_message_number(user_id, visitor_id): '''得到留给某人的留言的总个数''' query = { 'user': DBRef(UserDocument.meta['collection'], ObjectId(user_id)), '$or': [{ 'private': False }, { 'private': True, 'author': DBRef(UserDocument.meta['collection'], ObjectId(visitor_id)) }, { 'private': True, 'user': DBRef(UserDocument.meta['collection'], ObjectId(visitor_id)) }] } count = yield LeaveMessageDocument.find(query).count() raise gen.Return(count) @gen.coroutine def get_leave_message_list(user_id, visitor_id, skip=0, limit=None): '''得到某人得到的留言''' query = { 'user': DBRef(UserDocument.meta['collection'], ObjectId(user_id)), '$or': [{ 'private': False }, { 'private': True, 'author': DBRef(UserDocument.meta['collection'], ObjectId(visitor_id)) }, { 'private': True, 'user': DBRef(UserDocument.meta['collection'], ObjectId(visitor_id)) }] } cursor = LeaveMessageDocument.find(query).sort([ ('leave_time', pymongo.ASCENDING) ]).skip(skip) if limit is not None: cursor = cursor.limit(limit) translate = LeaveMessageDocument.translate_dbref_in_document_list leave_message_list = yield LeaveMessageDocument.to_list(cursor) leave_message_list = yield translate(leave_message_list) # message_sum = yield LeaveMessageDocument.get_leave_message_number( # user_id, visitor_id) # for i, leave_message in enumerate(leave_message_list): # leave_message['floor'] = message_sum - i - skip for i, leave_message in enumerate(leave_message_list): leave_message['floor'] = skip + 1 + i raise gen.Return(leave_message_list)
class ShareDocument(Document): '''分享 :Variables: - `title`: 分享标题 - `category`: 类别 - `filename`: 文件标题 - `content_type`: 文件类型, 根据文件头判断出文件类型, 而不是文件名称, 存储的是MIME, 在后续处理里边更新该属性 - `passed`: 审核是否通过 - `description`: 描述 - `uploader`: 上传者 - `upload_time`: 上传时间 - `cost`: 下载需要多少金币 - `like_times`: 点赞次数 - `comment_times`: 评论次数 - `download_times`: 下载次数 - `score`: 评分 - `origin_file`: 在后续处理里边更新该属性 - `mime`: 文件真正的格式,保存的是content_type,如果不存在那就说明没 判断出来 ''' title = StringField(required=True, max_length=1000) category = StringField(required=True) filename = StringField(required=True, max_length=500) content_type = StringField(required=True, max_length=100) passed = BooleanField(required=True, default=True) description = StringField(required=True, max_length=10**5) uploader = ReferenceField(UserDocument, required=True) upload_time = DateTimeField(required=True) cost = IntegerField(required=True, min_value=0) like_times = IntegerField(required=True, default=0) comment_times = IntegerField(required=True, default=0) download_times = IntegerField(required=True, default=0) score = FloatField(required=True, default=-1) origin_file = GridFileField() mime = StringField() meta = {'collection': 'share'} @gen.coroutine def get_share(share_id, user_id=None): share = yield ShareDocument.find_one({'_id': ObjectId(share_id)}) if share: share = yield ShareDocument.translate_dbref_in_document(share) share['like_list'] = yield ShareLikeDocument.get_like_list( share['_id'], limit=10) fs = ShareDocument.get_gridfs() gridout = yield fs.get(ObjectId(share['origin_file'])) share['size'] = gridout.length if user_id is not None: share['liked'] = yield ShareLikeDocument.is_liked( share_id, user_id) raise gen.Return(share) @gen.coroutine def get_share_list(category=None, sort='time', skip=0, limit=None): def score(share): ''' 公式为: score = like_times + comment_times/2 + read_times/5 即: 1 * download_times = 2 * like_times = 5 * comment_times ''' return (share['download_times'] + share['like_times'] / 2.0 + share['comment_times'] / 5.0) assert sort in ['time', 'popularity', 'score'] query = {"passed": True} if category is not None: query.update({'category': category}) cursor = ShareDocument.find(query) if sort != 'popularity': _sort = 'upload_time' if sort == 'time' else 'score' cursor = cursor.sort([(_sort, pymongo.DESCENDING)]).skip(skip) if limit is not None: cursor = cursor.limit(limit) share_list = yield ShareDocument.to_list(cursor) else: share_list = yield ShareDocument.to_list(cursor) share_list.sort(cmp=lambda x, y: -1 if score(x) < score(y) else 1, reverse=True) if limit is not None: share_list = share_list[skip:skip + limit] else: share_list = share_list[skip:] share_list = yield ShareDocument.translate_dbref_in_document_list( share_list) for share in share_list: share['like_list'] = yield ShareLikeDocument.get_like_list( share['_id'], limit=10) raise gen.Return(share_list) @gen.coroutine def get_recommend_share_list(share_id, size=10): '''根据某一话题推荐话题''' share_list = [] share = yield ShareDocument.find_one({'_id': ObjectId(share_id)}) if share: query = { '_id': { '$ne': ObjectId(share_id) }, 'category': share['category'], "passed": True } count = yield ShareDocument.find(query).count() if count > size: skip = random.randint(0, count - size) cursor = ShareDocument.find(query).skip(skip).limit(size) else: cursor = ShareDocument.find(query) share_list = yield ShareDocument.to_list(cursor) raise gen.Return(share_list) @gen.coroutine def get_share_number(category=None): '''得到某一类下分享总数''' query = {'passed': True} if category is not None: query.update({'category': category}) count = yield ShareDocument.find(query).count() raise gen.Return(count) @gen.coroutine def get_uploader_number(category=None): '''得到某一类下上传者总数''' query = {'passed': True} if category is not None: query.update({'category': category}) cursor = ShareDocument.aggregate([{ '$match': query }, { '$group': { '_id': '$uploader' } }]) num = 0 while (yield cursor.fetch_next): cursor.next_object() num += 1 raise gen.Return(num) @gen.coroutine def get_uploader_list(skip=0, limit=None): '''按照上传者上传数量大->小得到上传者''' piplines = [{ '$match': { 'passed': True } }, { '$group': { '_id': '$uploader', 'upload_times': { '$sum': 1 } } }, { '$sort': { 'upload_times': -1 } }, { '$skip': skip }] if limit is not None: piplines.append({'$limit': limit}) cursor = ShareDocument.aggregate(piplines) r = [] while (yield cursor.fetch_next): r.append(cursor.next_object()) translate = ShareDocument.translate_dbref_in_document_list uploader_list = yield translate(r) for uploader in uploader_list: uploader['uploader'] = uploader['_id'] raise gen.Return(uploader_list)
class MessageDocument(Document): '''消息系统中的消息 :Variables: - `sender`: 发送者, 系统消息发送者不存在, 用户之间的消息必须存在, 哪些是系统消息, 见MessageTopic - `recipient`: 接收者 - `message_type`: 消息类型 - `time`: 消息产生的时间 - `received`: 是否被接收, 前端是否已接收, 接收后未必已读 - `read`: 接收者是否已经阅读 - `data`: 相关的数据 ''' sender = ReferenceField(UserDocument) recipient = ReferenceField(UserDocument, required=True) message_type = StringField( required=True, candidate=[ 'comment:status', 'comment:topic', 'comment:market_goods', 'comment:market_need', 'comment:activity', 'reply:status', 'reply:topic', 'reply:surround_shop', 'reply:surround_goods', 'reply:market_goods', 'reply:market_need', 'reply:activity', 'reply:news', 'reply:leavemessage', 'like:status', 'like:topic', 'like:market_goods', 'like:market_need', 'like:activity' ].extend(MessageTopic.all_topic)) time = DateTimeField(required=True) received = BooleanField(required=True, default=False) read = BooleanField(required=True, default=False) data = ReferenceField() meta = {'collection': 'message'} @gen.coroutine def get_message_list(recipient_id, message_topic=None, read=None, skip=0, limit=None): '''得到消息列表''' query = MessageDocument.get_query(recipient_id, message_topic) if read is not None: assert isinstance(read, bool) query.update({'read': read}) cursor = MessageDocument.find(query).sort([('time', pymongo.DESCENDING) ]).skip(skip) if limit is not None: cursor = cursor.limit(limit) message_list = yield MessageDocument.to_list(cursor) for message in message_list: if 'sender' in message: message['sender'] = yield UserDocument.translate_dbref( message['sender']) message['recipient'] = yield UserDocument.translate_dbref( message['recipient']) if 'data' not in message: continue if str(message['data'].collection) == str( StatusDocument.meta['collection']): message['data'] = yield StatusDocument.get_status( message['data'].id) continue message['data'] = yield Document.translate_dbref(message['data']) if message['data']: message['data'] = yield Document.translate_dbref_in_document( message['data'], depth=2) if 'status' in message['data']: message['data'][ 'status'] = yield StatusDocument.get_status( message['data']['status']['_id']) raise gen.Return(message_list) @gen.coroutine def set_read(recipient_id, message_topic=None): '''将消息设置为已读''' query = MessageDocument.get_query(recipient_id, message_topic) yield MessageDocument.update( query, {'$set': { 'received': True, 'read': True }}, multi=True) raise gen.Return() def set_read_sync(recipient_id, message_topic=None): '''将消息设置为已读''' query = MessageDocument.get_query(recipient_id, message_topic) MessageDocument.get_collection(True).update( query, {'$set': { 'received': True, 'read': True }}, multi=True) def set_received(recipient_id, message_topic=None): '''将消息设置为已接受''' query = MessageDocument.get_query(recipient_id, message_topic) MessageDocument.get_collection(True).update( query, {'$set': { 'received': True }}, multi=True) def get_query(recipient_id, message_topic=None): '''得到查询''' query = { 'recipient': DBRef(UserDocument.meta['collection'], ObjectId(recipient_id)) } if message_topic is not None: if message_topic == MessageTopic._COMMENT_AND_REPLY: query.update( {'message_type': { '$regex': '(comment|reply):.*' }}) elif message_topic == MessageTopic.COMMENT: query.update({'message_type': {'$regex': 'comment:.*'}}) elif message_topic == MessageTopic.REPLY: query.update({'message_type': {'$regex': 'reply:.*'}}) elif message_topic == MessageTopic.LIKE: query.update({'message_type': {'$regex': 'like:.*'}}) elif message_topic == MessageTopic._FRIENDS_DYNAMIC: query.update({ 'message_type': { '$in': [ MessageTopic.STATUS_NEW, MessageTopic.TOPIC_NEW, MessageTopic.SHARE_NEW ] } }) else: query.update({'message_type': message_topic}) return query def get_message_number(recipient_id, message_topic=None, read=None): '''得到相关消息的数量''' query = MessageDocument.get_query(recipient_id, message_topic) if read is not None: assert isinstance(read, bool) query.update({'read': read}) count = MessageDocument.get_collection( pymongo=True).find(query).count() return count def has_unreceived(recipient_id): '''是否有未读的消息''' message = MessageDocument.get_collection(pymongo=True).find_one({ 'recipient': DBRef(UserDocument.meta['collection'], ObjectId(recipient_id)), 'received': False, 'read': False }) return True if message else False def get_unread_message_numbers(recipient_id): '''得到未读的消息个数''' unread_message_numbers = { MessageTopic._FRIENDS_DYNAMIC: MessageDocument.get_message_number(recipient_id, MessageTopic._FRIENDS_DYNAMIC, read=False), MessageTopic._COMMENT_AND_REPLY: MessageDocument.get_message_number(recipient_id, MessageTopic._COMMENT_AND_REPLY, read=False), MessageTopic.LIKE: MessageDocument.get_message_number(recipient_id, MessageTopic.LIKE, read=False), MessageTopic.CHAT_MESSAGE_NEW: ChatMessageDocument.get_message_number(recipient_id, read=False), MessageTopic.LEAVE_MESSAGE_NEW: MessageDocument.get_message_number(recipient_id, MessageTopic.LEAVE_MESSAGE_NEW, read=False), MessageTopic.FRIEND_REQUEST_NEW: MessageDocument.get_message_number(recipient_id, MessageTopic.FRIEND_REQUEST_NEW, read=False) } return unread_message_numbers