Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
...
  • 5 commits
  • 4 files changed
  • 0 commit comments
  • 1 contributor
Showing with 177 additions and 88 deletions.
  1. +0 −11 r2/r2/controllers/api.py
  2. +23 −1 r2/r2/controllers/listingcontroller.py
  3. +18 −20 r2/r2/lib/db/queries.py
  4. +136 −56 r2/r2/models/link.py
View
11 r2/r2/controllers/api.py
@@ -360,7 +360,6 @@ def POST_submit(self, form, jquery, url, selftext, kind, title,
cheater = (errors.CHEATER, None) in c.errors)
if save:
r = l._save(c.user)
- queries.new_savehide(r)
#set the ratelimiter
if should_ratelimit:
@@ -908,7 +907,6 @@ def POST_report(self, thing):
# auto-hide links that are reported
elif isinstance(thing, Link):
r = thing._hide(c.user)
- queries.new_savehide(r)
# TODO: be nice to be able to remove comments that are reported
# from a user's inbox so they don't have to look at them.
elif isinstance(thing, Comment):
@@ -1734,8 +1732,6 @@ def POST_distinguish(self, form, jquery, thing, how):
def POST_save(self, thing):
if not thing: return
r = thing._save(c.user)
- if r:
- queries.new_savehide(r)
@noresponse(VUser(),
VModhash(),
@@ -1744,8 +1740,6 @@ def POST_save(self, thing):
def POST_unsave(self, thing):
if not thing: return
r = thing._unsave(c.user)
- if r:
- queries.new_savehide(r)
def collapse_handler(self, things, collapse):
if not things:
@@ -1839,8 +1833,6 @@ def POST_read_message(self, things):
def POST_hide(self, thing):
if not thing: return
r = thing._hide(c.user)
- if r:
- queries.new_savehide(r)
@noresponse(VUser(),
VModhash(),
@@ -1849,8 +1841,6 @@ def POST_hide(self, thing):
def POST_unhide(self, thing):
if not thing: return
r = thing._unhide(c.user)
- if r:
- queries.new_savehide(r)
@validatedForm(VUser(),
@@ -1979,7 +1969,6 @@ def GET_bookmarklet(self, action, uh, links):
elif action == 'save':
link = max(links, key = lambda x: x._score)
r = link._save(c.user)
- queries.new_savehide(r)
return self.redirect("/static/css_%sd.png" % action)
return self.redirect("/static/css_submit.png")
View
24 r2/r2/controllers/listingcontroller.py
@@ -546,6 +546,20 @@ def menus(self):
res.append(ProfileSortMenu(default = self.sort))
if self.sort not in ("hot", "new"):
res.append(TimeMenu(default = self.time))
+ if self.where == 'saved' and c.user.gold:
+ srnames = LinkSavesBySubreddit.get_saved_subreddits(self.vuser)
+ srnames += CommentSavesBySubreddit.get_saved_subreddits(self.vuser)
+ srnames = sorted(list(set(srnames)))
+ if len(srnames) > 1:
+ sr_buttons = [NavButton(_('all'), None, opt='sr',
+ css_class='primary')]
+ for srname in srnames:
+ sr_buttons.append(NavButton(srname, srname, opt='sr'))
+ base_path = request.path
+ sr_menu = NavMenu(sr_buttons, base_path=base_path,
+ title=_('filter by subreddit'),
+ type='lightdrop')
+ res.append(sr_menu)
return res
def title(self):
@@ -615,7 +629,15 @@ def query(self):
q = queries.get_hidden(self.vuser)
elif self.where == 'saved':
- q = queries.get_saved(self.vuser)
+ srname = request.get.get('sr')
+ if srname and c.user.gold:
+ try:
+ sr_id = Subreddit._by_name(srname)._id
+ except NotFound:
+ sr_id = None
+ else:
+ sr_id = None
+ q = queries.get_saved(self.vuser, sr_id)
elif c.user_is_sponsor and self.where == 'promoted':
q = queries.get_promoted_links(self.vuser._id)
View
38 r2/r2/lib/db/queries.py
@@ -20,7 +20,7 @@
# Inc. All Rights Reserved.
###############################################################################
-from r2.models import Account, Link, Comment, Vote, SaveHide, Report
+from r2.models import Account, Link, Comment, Vote, Report
from r2.models import Message, Inbox, Subreddit, ModContribSR, ModeratorInbox, MultiReddit
from r2.lib.db.thing import Thing, Merge
from r2.lib.db.operators import asc, desc, timeago
@@ -527,13 +527,25 @@ def get_liked(user):
def get_disliked(user):
return rel_query(vote_rel, user, '-1')
-@cached_userrel_query
+@cached_query(UserQueryCache, sort=[desc('action_date')])
+def get_hidden_links(user_id):
+ return
+
def get_hidden(user):
- return rel_query(SaveHide, user, 'hide')
+ return get_hidden_links(user)
-@cached_userrel_query
-def get_saved(user):
- return rel_query(SaveHide, user, 'save')
+@cached_query(UserQueryCache, sort=[desc('action_date')])
+def get_saved_links(user_id, sr_id):
+ return
+
+@cached_query(UserQueryCache, sort=[desc('action_date')])
+def get_saved_comments(user_id, sr_id):
+ return
+
+def get_saved(user, sr_id=None):
+ sr_id = sr_id or 'none'
+ queries = [get_saved_links(user, sr_id), get_saved_comments(user, sr_id)]
+ return MergedCachedQuery(queries)
@cached_srrel_query
def get_subreddit_messages(sr):
@@ -984,18 +996,6 @@ def set_unread(messages, to, unread, mutator=None):
if not mutator:
m.send()
-def new_savehide(rel):
- user = rel._thing1
- name = rel._name
- with CachedQueryMutator() as m:
- if name == 'save':
- m.insert(get_saved(user), [rel])
- elif name == 'unsave':
- m.delete(get_saved(user), [rel])
- elif name == 'hide':
- m.insert(get_hidden(user), [rel])
- elif name == 'unhide':
- m.delete(get_hidden(user), [rel])
def changed(things, boost_only=False):
"""Indicate to search that a given item should be updated in the index"""
@@ -1295,8 +1295,6 @@ def update_user(user):
get_sent(user),
get_liked(user),
get_disliked(user),
- get_saved(user),
- get_hidden(user),
get_submitted(user, 'new', 'all'),
get_comments(user, 'new', 'all')]
for q in results:
View
192 r2/r2/models/link.py
@@ -35,8 +35,10 @@
from mako.filters import url_escape
from r2.lib.strings import strings, Score
from r2.lib.db import tdb_cassandra
+from r2.lib.db.tdb_cassandra import NotFoundException, view_of
from r2.models.subreddit import MultiReddit
from r2.models.promo import PROMOTE_STATUS, get_promote_srid
+from r2.models.query_cache import CachedQueryMutator
from pylons import c, g, request
from pylons.i18n import ungettext, _
@@ -161,13 +163,11 @@ def _saved(cls, user, link):
return cls._somethinged(SaveHide, user, link, 'save')
def _save(self, user):
- # dual-write CassandraSaves
- CassandraSave._save(user, self)
+ LinkSavesByAccount._save(user, self)
return self._something(SaveHide, user, self._saved, 'save')
def _unsave(self, user):
- # dual-write CassandraSaves
- CassandraSave._unsave(user, self)
+ LinkSavesByAccount._unsave(user, self)
return self._unsomething(user, self._saved, 'save')
@classmethod
@@ -182,11 +182,11 @@ def _hidden(cls, user, link):
return cls._somethinged(SaveHide, user, link, 'hide')
def _hide(self, user):
- CassandraHide._hide(user, self)
+ LinkHidesByAccount._hide(user, self)
return self._something(SaveHide, user, self._hidden, 'hide')
def _unhide(self, user):
- CassandraHide._unhide(user, self)
+ LinkHidesByAccount._unhide(user, self)
return self._unsomething(user, self._hidden, 'hide')
def link_domain(self):
@@ -340,8 +340,8 @@ def add_props(cls, user, wrapped):
if user_is_loggedin:
try:
- saved = CassandraSave._fast_query(user, wrapped)
- hidden = CassandraHide._fast_query(user, wrapped)
+ saved = LinkSavesByAccount.fast_query(user, wrapped)
+ hidden = LinkHidesByAccount.fast_query(user, wrapped)
except tdb_cassandra.TRANSIENT_EXCEPTIONS as e:
g.log.warning("Cassandra save/hide lookup failed: %r", e)
saved = hidden = {}
@@ -1236,79 +1236,159 @@ def keep_item(self, wrapped):
class SaveHide(Relation(Account, Link)): pass
class Click(Relation(Account, Link)): pass
-class SimpleRelation(tdb_cassandra.Relation):
- _use_db = False
- _read_consistency_level = tdb_cassandra.CL.ONE
+class _SaveHideByAccount(tdb_cassandra.DenormalizedRelation):
@classmethod
- def _create(cls, user, link, write_consistency_level = None):
- n = cls(thing1_id = user._id36,
- thing2_id = link._id36)
- n._commit(write_consistency_level=write_consistency_level)
- return n
+ def value_for(cls, thing1, thing2, opaque):
+ return ''
@classmethod
- def _uncreate(cls, user, link):
- try:
- cls._fast_query(user, link)._destroy()
- except tdb_cassandra.NotFound:
- pass
+ def _cached_queries(cls, user, thing):
+ return []
+ @classmethod
+ def _savehide(cls, user, things):
+ things = tup(things)
+ now = datetime.now(g.tz)
+ with CachedQueryMutator() as m:
+ for thing in things:
+ # action_date is only used by the cached queries as the sort
+ # value, we don't want to write it. Report.new(link) needs to
+ # incr link.reported but will fail if the link is dirty.
+ thing.__setattr__('action_date', now, make_dirty=False)
+ for q in cls._cached_queries(user, thing):
+ m.insert(q, [thing])
+ cls.create(user, things)
-class CassandraSave(SimpleRelation):
- _use_db = True
- _cf_name = 'Save'
- _connection_pool = 'main'
+ @classmethod
+ def _unsavehide(cls, user, things):
+ things = tup(things)
+ with CachedQueryMutator() as m:
+ for thing in things:
+ for q in cls._cached_queries(user, thing):
+ m.delete(q, [thing])
+ cls.destroy(user, things)
- _thing1_cls = Account
- _thing2_cls = Link
+class _ThingSavesByAccount(_SaveHideByAccount):
@classmethod
- def _save(cls, *a, **kw):
- return cls._create(*a, **kw)
+ def _save(cls, user, things):
+ cls._savehide(user, things)
@classmethod
- def _unsave(cls, *a, **kw):
- return cls._uncreate(*a, **kw)
+ def _unsave(cls, user, things):
+ cls._unsavehide(user, things)
- def _on_create(self):
- # it's okay if these indices get lost
- wcl = tdb_cassandra.CL.ONE
- SavesByAccount._set_values(self.thing1_id,
- {self._id: self._id},
- write_consistency_level=wcl)
+class LinkSavesByAccount(_ThingSavesByAccount):
+ _use_db = True
+ _last_modified_name = 'Save'
+ _views = []
- return SimpleRelation._on_create(self)
+ @classmethod
+ def _cached_queries(cls, user, thing):
+ from r2.lib.db import queries
+ return [queries.get_saved_links(user, 'none'),
+ queries.get_saved_links(user, thing.sr_id)]
- def _on_destroy(self):
- sba = SavesByAccount._byID(self.thing1_id)
- del sba[self._id]
- sba._commit()
- return SimpleRelation._on_destroy(self)
+class CommentSavesByAccount(_ThingSavesByAccount):
+ _use_db = True
+ _last_modified_name = 'CommentSave'
+ _views = []
-class CassandraHide(SimpleRelation):
+ @classmethod
+ def _cached_queries(cls, user, thing):
+ from r2.lib.db import queries
+ return [queries.get_saved_comments(user, 'none'),
+ queries.get_saved_comments(user, thing.sr_id)]
+
+
+class _ThingHidesByAccount(_SaveHideByAccount):
+ @classmethod
+ def _hide(cls, user, things):
+ cls._savehide(user, things)
+
+ @classmethod
+ def _unhide(cls, user, things):
+ cls._unsavehide(user, things)
+
+
+class LinkHidesByAccount(_ThingHidesByAccount):
_use_db = True
- _cf_name = 'Hide'
- _ttl = 7*24*60*60
- _connection_pool = 'main'
+ _last_modified_name = 'Hide'
+ _views = []
- _thing1_cls = Account
- _thing2_cls = Link
+ @classmethod
+ def _cached_queries(cls, user, thing):
+ from r2.lib.db import queries
+ return [queries.get_hidden_links(user)]
+
+
+class _ThingSavesBySubreddit(tdb_cassandra.View):
+ @classmethod
+ def _rowkey(cls, user, thing):
+ return user._id36
+
+ @classmethod
+ def _column(cls, user, thing):
+ return {utils.to36(thing.sr_id): ''}
+
+ @classmethod
+ def get_saved_subreddits(cls, user):
+ rowkey = user._id36
+ try:
+ columns = cls._cf.get(rowkey)
+ except NotFoundException:
+ return []
+
+ sr_id36s = columns.keys()
+ srs = Subreddit._byID36(sr_id36s, return_dict=False, data=True)
+ return sorted([sr.name for sr in srs])
+
+ @classmethod
+ def create(cls, user, things, opaque):
+ for thing in things:
+ rowkey = cls._rowkey(user, thing)
+ column = cls._column(user, thing)
+ cls._set_values(rowkey, column)
+
+ @classmethod
+ def _check_empty(cls, user, sr_id):
+ return False
@classmethod
- def _hide(cls, *a, **kw):
- return cls._create(*a, **kw)
+ def destroy(cls, user, things):
+ # See if thing's sr is present anymore
+ sr_ids = set([thing.sr_id for thing in things])
+ for sr_id in set(sr_ids):
+ if cls._check_empty(user, sr_id):
+ cls._cf.remove(user._id36, [utils.to36(sr_id)])
+
+
+@view_of(LinkSavesByAccount)
+class LinkSavesBySubreddit(_ThingSavesBySubreddit):
+ _use_db = True
@classmethod
- def _unhide(cls, *a, **kw):
- return cls._uncreate(*a, **kw)
+ def _check_empty(cls, user, sr_id):
+ from r2.lib.db import queries
+ q = queries.get_saved_links(user, sr_id)
+ q.fetch()
+ return not q.data
-class SavesByAccount(tdb_cassandra.View):
+
+@view_of(CommentSavesByAccount)
+class CommentSavesBySubreddit(_ThingSavesBySubreddit):
_use_db = True
- _cf_name = 'SavesByAccount'
- _connection_pool = 'main'
+
+ @classmethod
+ def _check_empty(cls, user, sr_id):
+ from r2.lib.db import queries
+ q = queries.get_saved_comments(user, sr_id)
+ q.fetch()
+ return not q.data
+
class Inbox(MultiRelation('inbox',
Relation(Account, Comment),

No commit comments for this range

Something went wrong with that request. Please try again.