Allow multiple messages in a single request to be marked as (un)read.

This commit is contained in:
Bryce Boe
2012-01-03 15:07:05 -08:00
committed by Keith Mitchell
parent 619e158584
commit a18e5e0e22
5 changed files with 67 additions and 34 deletions

View File

@@ -56,6 +56,7 @@ from r2.lib.filters import safemarkdown
from r2.lib.scraper import str_to_image
import csv
from collections import defaultdict
from datetime import datetime, timedelta
from md5 import md5
import urllib
@@ -1511,29 +1512,43 @@ class ApiController(RedditController):
def POST_uncollapse_message(self, things):
self.collapse_handler(things, False)
def unread_handler(self, thing, unread):
if not thing:
return
# if the message has a recipient, try validating that
# desitination first (as it is cheaper and more common)
queries.set_unread(thing, c.user, unread)
# if the message is for a subreddit, check that next
if hasattr(thing, "sr_id"):
sr = thing.subreddit_slow
if sr and sr.is_moderator(c.user):
queries.set_unread(thing, sr, unread)
def unread_handler(self, things, unread):
if not things:
if (errors.TOO_MANY_THING_IDS, 'id') in c.errors:
return abort(413)
else:
return abort(400)
thing_groups = defaultdict(list)
# Group things by subreddit or type
for thing in things:
if isinstance(thing, Message):
if hasattr(thing, 'sr_id') and thing.sr_id:
thing_groups[thing.sr_id].append(thing)
else:
thing_groups['Message'].append(thing)
else:
thing_groups['Comment'].append(thing)
# Batch set items as unread
for sr_id, things in thing_groups.items():
if sr_id not in ('Comment', 'Message'):
queries.set_unread(things, things[0].subreddit_slow, unread)
else:
queries.set_unread(things, c.user, unread)
@noresponse(VUser(),
VModhash(),
thing = VByName('id'))
def POST_unread_message(self, thing):
self.unread_handler(thing, True)
things = VByName('id', multiple=True, limit=25))
def POST_unread_message(self, things):
self.unread_handler(things, True)
@noresponse(VUser(),
VModhash(),
thing = VByName('id'))
def POST_read_message(self, thing):
self.unread_handler(thing, False)
things = VByName('id', multiple=True, limit=25))
def POST_read_message(self, things):
self.unread_handler(things, False)
@noresponse(VUser(),
VModhash(),

View File

@@ -34,6 +34,7 @@ error_list = dict((
('USERNAME_TAKEN_DEL', _('that username is taken by a deleted account')),
('USER_BLOCKED', _("you can't send to a user that you have blocked")),
('NO_THING_ID', _('id not specified')),
('TOO_MANY_THING_IDS', _('you provided too many ids')),
('NOT_AUTHOR', _("you can't do that")),
('NOT_USER', _("you are not logged in as that user")),
('DELETED_LINK', _('the link you are commenting on has been deleted')),

View File

@@ -540,10 +540,14 @@ def fullname_regex(thing_cls = None, multiple = False):
class VByName(Validator):
# Lookup tdb_sql.Thing or tdb_cassandra.Thing objects by fullname.
splitter = re.compile('[ ,]+')
def __init__(self, param, thing_cls = None, multiple = False,
error = errors.NO_THING_ID, backend='sql', **kw):
def __init__(self, param, thing_cls=None, multiple=False, limit=None,
error=errors.NO_THING_ID, backend='sql', **kw):
# Limit param only applies when multiple is True
if not multiple and limit is not None:
raise TypeError('multiple must be True when limit is set')
self.re = fullname_regex(thing_cls)
self.multiple = multiple
self.limit = limit
self._error = error
self.backend = backend
@@ -554,6 +558,8 @@ class VByName(Validator):
# tdb_cassandra.Thing objects can't use the regex
if items and self.multiple:
items = [item for item in self.splitter.split(items)]
if self.limit and len(items) > self.limit:
return self.set_error(errors.TOO_MANY_THING_IDS)
if items:
try:
return tdb_cassandra.Thing._by_fullname(items, return_dict=False)
@@ -563,6 +569,8 @@ class VByName(Validator):
if items and self.multiple:
items = [item for item in self.splitter.split(items)
if item and self.re.match(item)]
if self.limit and len(items) > self.limit:
return self.set_error(errors.TOO_MANY_THING_IDS)
if items and (self.multiple or self.re.match(items)):
try:
return Thing._by_fullname(items, return_dict=False,

View File

@@ -724,20 +724,24 @@ def new_message(message, inbox_rels):
add_message(message)
def set_unread(message, to, unread):
def set_unread(messages, to, unread):
# Maintain backwards compatability
messages = tup(messages)
if isinstance(to, Subreddit):
for i in ModeratorInbox.set_unread(message, unread):
for i in ModeratorInbox.set_unread(messages, unread):
kw = dict(insert_items = i) if unread else dict(delete_items = i)
add_queries([get_unread_subreddit_messages(i._thing1)], **kw)
else:
for i in Inbox.set_unread(message, unread, to = to):
# All messages should be of the same type
for i in Inbox.set_unread(messages, unread, to=to):
kw = dict(insert_items = i) if unread else dict(delete_items = i)
if isinstance(message, Comment) and not unread:
if isinstance(messages[0], Comment) and not unread:
add_queries([get_unread_comments(i._thing1)], **kw)
add_queries([get_unread_selfreply(i._thing1)], **kw)
elif i._name == 'selfreply':
add_queries([get_unread_selfreply(i._thing1)], **kw)
elif isinstance(message, Comment):
elif isinstance(messages[0], Comment):
add_queries([get_unread_comments(i._thing1)], **kw)
else:
add_queries([get_unread_messages(i._thing1)], **kw)

View File

@@ -1273,15 +1273,19 @@ class Inbox(MultiRelation('inbox',
return i
@classmethod
def set_unread(cls, thing, unread, to = None):
inbox_rel = cls.rel(Account, thing.__class__)
def set_unread(cls, things, unread, to=None):
things = tup(things)
if len(set(type(x) for x in things)) != 1:
raise TypeError('things must only be of a single type')
thing_ids = [x._id for x in things]
inbox_rel = cls.rel(Account, things[0].__class__)
if to:
inbox = inbox_rel._query(inbox_rel.c._thing2_id == thing._id,
eager_load = True)
else:
inbox = inbox_rel._query(inbox_rel.c._thing2_id == thing._id,
inbox = inbox_rel._query(inbox_rel.c._thing2_id == thing_ids,
inbox_rel.c._thing1_id == to._id,
eager_load = True)
eager_load=True)
else:
inbox = inbox_rel._query(inbox_rel.c._thing2_id == thing_ids,
eager_load=True)
res = []
for i in inbox:
if i:
@@ -1320,9 +1324,10 @@ class ModeratorInbox(Relation(Subreddit, Message)):
return i
@classmethod
def set_unread(cls, thing, unread):
inbox = cls._query(cls.c._thing2_id == thing._id,
eager_load = True)
def set_unread(cls, things, unread):
things = tup(things)
thing_ids = [x._id for x in things]
inbox = cls._query(cls.c._thing2_id == thing_ids, eager_load=True)
res = []
for i in inbox:
if i: