# coding: utf-8 import time import pymongo from base import * import bnw.core.bnw_objects as objs def get_user_bl(request, use_bl=False): """Return authed user blacklist or simply an empty list if user not authed. :param use_bl: default False. Whether we should return actual blacklist or just empty list. """ if use_bl and request.user: bl = request.user.get('blacklist', []) bl = [el[1] for el in bl if el[0] == 'user'] return bl else: return [] @defer.inlineCallbacks def set_subscriptions_info(request, messages): """Add 'subscribed' param for each message which indicate do the user subscribed on the message or not. Return updated list of messages (update in place actually!). For non-authed users return non-modified list. :param request: BnW request object. """ if not request.user: defer.returnValue(messages) user = request.user['name'] ids = [m['id'] for m in messages] subscriptions = yield objs.Subscription.find({ 'user': user, 'type': 'sub_message', 'target': {'$in': ids}}) sub_ids = [s['target'] for s in subscriptions] for msg in messages: msg['subscribed'] = True if msg['id'] in sub_ids else False defer.returnValue(messages) @defer.inlineCallbacks def showSearch(parameters, page, request): # FIXME: THIS COMMAND IS FUCKING SLOW SLOW SLOW AND WAS WRITTEN BY A # BRAIN-DAMAGED IDIOT messages = [x.filter_fields() for x in (yield objs.Message.find_sort( parameters, [('date', pymongo.DESCENDING)], limit=20, skip=page * 20))] messages = yield set_subscriptions_info(request, messages) messages.reverse() defer.returnValue(dict( ok=True, format="messages", cache=5, cache_public=True, messages=messages)) @defer.inlineCallbacks def showComment(commentid): comment = yield objs.Comment.find_one({'id': commentid}) if comment is None: defer.returnValue( dict(ok=False, desc='No such comment', cache=5, cache_public=True) ) defer.returnValue( dict(ok=True, format='comment', cache=5, cache_public=True, comment=comment.filter_fields(), )) @defer.inlineCallbacks def showComments(msgid, request, bl=None, after=''): message = yield objs.Message.find_one({'id': msgid}) if message is None: defer.returnValue(dict( ok=False, desc='No such message', cache=5, cache_public=True)) if request.user: user = request.user['name'] subscribed = yield objs.Subscription.count({ 'user': user, 'type': 'sub_message', 'target': msgid}) message['subscribed'] = bool(subscribed) qdict = {'message': msgid.upper()} if bl: qdict['user'] = {'$nin': bl} if after: after_comment = yield objs.Comment.find_one({'id':msgid+'/'+after.split('/')[-1]}) if after_comment: qdict['date'] = {'$gte': after_comment['date']} comments = yield objs.Comment.find_sort( qdict, [('date', pymongo.ASCENDING)], limit=10000) defer.returnValue(dict( ok=True, format='message_with_replies', cache=5, cache_public=True, msgid=msgid, message=message.filter_fields(), replies=[comment.filter_fields() for comment in comments])) @check_arg(message=MESSAGE_COMMENT_RE, page='[0-9]+') @defer.inlineCallbacks def cmd_show(request, message='', user='', tag='', club='', page='0', show='messages', replies=None, use_bl=False, after='', before=''): """Show messages by specified parameters.""" message = canonic_message_comment(message).upper() bl = get_user_bl(request, use_bl) if '/' in message: defer.returnValue((yield showComment(message))) if replies: if not message: defer.returnValue(dict( ok=False, desc="Error: 'replies' is allowed only with 'message'.", cache=3600)) defer.returnValue((yield showComments(message, request, bl, after))) else: if show not in ['messages', 'recommendations', 'all']: defer.returnValue(dict( ok=False, desc="Bad 'show' parameter value.")) parameters = [('tags', tag), ('clubs', club), ('id', message.upper())] parameters = dict(p for p in parameters if p[1]) if user: user = user.lower() if show == 'messages': user_spec = dict(user=user) elif show == 'recommendations': user_spec = dict(recommendations=user) else: user_spec = {'$or': [{'user': user}, { 'recommendations': user}]} parameters.update(user_spec) elif bl: parameters['user'] = {'$nin': bl} if before: befmsg = yield objs.Message.find_one({'id': before}) if befmsg: parameters['date'] = {'$lt': befmsg['date']} else: defer.returnValue(dict(ok=False, desc="Message to search before doesn't exist.")) if after: afmsg = yield objs.Message.find_one({'id': after}) if afmsg: parameters['date'] = {'$gt': afmsg['date']} else: defer.returnValue(dict(ok=False, desc="Message to search after doesn't exist.")) defer.returnValue((yield showSearch(parameters, int(page), request))) @require_auth @defer.inlineCallbacks def cmd_feed(request, page="0"): """ Показать ленту """ page = int(page) if page else 0 feed = yield objs.FeedElement.find_sort({'user': request.user['name']}, [('_id', pymongo.DESCENDING)], limit=20, skip=page * 20) messages = [x.filter_fields() for x in (yield objs.Message.find_sort({'id': {'$in': [f['message'] for f in feed] }}, [('date', pymongo.ASCENDING)]))] defer.returnValue( dict(ok=True, format="messages", messages=messages, desc='Your feed', cache=5) ) TODAY_REBUILD_PERIOD = 300 TODAY_MAP = 'function() { emit(this.message, 1); }' TODAY_REDUCE = 'function(k,vals) { var sum=0; for(var i in vals) sum += vals[i]; return sum; }' @defer.inlineCallbacks def cmd_today(request, use_bl=False): """ Показать обсуждаемое за последние 24 часа """ bl = get_user_bl(request, use_bl) last_rebuild = yield objs.GlobalState.find_one({'name': 'today_rebuild'}) if not last_rebuild: last_rebuild = {'name': 'today_rebuild', 'value': 0} rebuild = time.time() > TODAY_REBUILD_PERIOD + last_rebuild['value'] if rebuild: _ = yield objs.GlobalState.mupdate({'name': 'today_rebuild'}, {'name': 'today_rebuild', 'value': time.time()}, True) start = time.time() - 86400 _ = yield objs.Today.remove({}) result = yield objs.Comment.map_reduce(TODAY_MAP, TODAY_REDUCE, out='today', query={'date': {'$gte': start}}) print 'map_reduce result', result if (not rebuild) or result: for x in range(10): postids = [x['_id'] for x in (yield objs.Today.find_sort({}, [('value', -1)], limit=20))] if len(postids)>0: break qdict = {'id': {'$in': postids}} if bl: qdict['user'] = {'$nin': bl} dbposts = dict( (x['id'], x.filter_fields()) for x in (yield objs.Message.find(qdict))) messages = [dbposts[x] for x in postids if (x in dbposts)] messages = yield set_subscriptions_info(request, messages) messages.reverse() defer.returnValue( dict(ok=True, format="messages", messages=messages, desc='Today''s most discussed', cache=300) ) else: defer.returnValue(dict(ok=False, desc='Map/Reduce failed')) @defer.inlineCallbacks def cmd_today2(request): """ Показать обсуждаемое за последние 24 часа """ start = time.time() - 86400 messages = [x.filter_fields() for x in (yield objs.Message.find_sort({'date': {'$gte': start}}, [('replycount', pymongo.DESCENDING)], limit=20))] messages.reverse() defer.returnValue( dict(ok=True, format="messages", messages=messages, desc='Today''s most discussed', cache=300) )