Skip to content

Commit

Permalink
Moderation log on ModSR and MultiReddit.
Browse files Browse the repository at this point in the history
  • Loading branch information
bsimpson63 authored and spladug committed Feb 2, 2012
1 parent 4157f4e commit 6f3c20a
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 32 deletions.
50 changes: 35 additions & 15 deletions r2/r2/controllers/front.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
################################################################################
from validator import *
from pylons.i18n import _, ungettext
from reddit_base import RedditController, base_listing, base_cassandra_listing
from reddit_base import RedditController, base_listing, paginated_listing
from r2 import config
from r2.models import *
from r2.lib.pages import *
Expand All @@ -36,6 +36,7 @@
from r2.lib.emailer import has_opted_out, Email
from r2.lib.db.operators import desc
from r2.lib.db import queries
from r2.lib.db.tdb_cassandra import MultiColumnQuery
from r2.lib.strings import strings
from r2.lib.solrsearch import RelatedSearchQuery, SubredditSearchQuery
from r2.lib.indextank import IndextankQuery, IndextankException, InvalidIndextankQuery
Expand Down Expand Up @@ -362,16 +363,14 @@ def GET_stylesheet(self):
else:
return self.abort404()

def _make_moderationlog(self, num, after, reverse, count, mod=None, action=None):
def _make_moderationlog(self, srs, num, after, reverse, count, mod=None, action=None):

if mod and action:
query = c.site.get_modactions(mod=mod, action=None)

query = Subreddit.get_modactions(srs, mod=mod, action=None)
def keep_fn(ma):
return ma.action == action
else:
query = c.site.get_modactions(mod=mod, action=action)

query = Subreddit.get_modactions(srs, mod=mod, action=action)
def keep_fn(ma):
return True

Expand All @@ -383,27 +382,47 @@ def keep_fn(ma):
pane = listing.listing()
return pane

@base_cassandra_listing
@paginated_listing(max_page_size=500, backend='cassandra')
@validate(mod=VAccountByName('mod'),
action=VOneOf('type', ModAction.actions))
def GET_moderationlog(self, num, after, reverse, count, mod, action):
if not c.user_is_loggedin:
return self.abort404()

is_moderator = c.user_is_loggedin and c.site.is_moderator(c.user) or c.user_is_admin
if isinstance(c.site, ModSR) or isinstance(c.site, MultiReddit):
if isinstance(c.site, ModSR):
srs = Subreddit._byID(c.site.sr_ids(), return_dict=False)
else:
srs = Subreddit._byID(c.site.sr_ids, return_dict=False)

# check that user is mod on all requested srs
if not Subreddit.user_mods_all(c.user, srs) and not c.user_is_admin:
return self.abort404()

if not is_moderator:
# grab all moderators
mod_ids = set(Subreddit.get_all_mod_ids(srs))
mods = Account._byID(mod_ids, data=True)

pane = self._make_moderationlog(srs, num, after, reverse, count,
mod=mod, action=action)
elif isinstance(c.site, FakeSubreddit):
return self.abort404()
else:
if not c.site.is_moderator(c.user) and not c.user_is_admin:
return self.abort404()
mod_ids = c.site.moderators
mods = Account._byID(mod_ids, data=True)

pane = self._make_moderationlog(c.site, num, after, reverse, count,
mod=mod, action=action)

panes = PaneStack()
pane = self._make_moderationlog(num, after, reverse, count,
mod=mod, action=action)
panes.append(pane)

action_buttons = [NavButton(_('all'), None, opt='type', css_class='primary')]
for a in ModAction.actions:
action_buttons.append(NavButton(ModAction._menu[a], a, opt='type'))

mod_ids = c.site.moderators
mods = Account._byID(mod_ids)

mod_buttons = [NavButton(_('all'), None, opt='mod', css_class='primary')]
for mod_id in mod_ids:
mod = mods[mod_id]
Expand All @@ -413,7 +432,8 @@ def GET_moderationlog(self, num, after, reverse, count, mod, action):
title=_('filter by action'), type='lightdrop', css_class='modaction-drop'),
NavMenu(mod_buttons, base_path=base_path,
title=_('filter by moderator'), type='lightdrop')]
return EditReddit(content=panes, nav_menus=menus, extension_handling=False).render()
return EditReddit(content=panes, nav_menus=menus,
extension_handling=False).render()

def _make_spamlisting(self, location, num, after, reverse, count):
if location == 'reports':
Expand Down
3 changes: 0 additions & 3 deletions r2/r2/controllers/reddit_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,9 +468,6 @@ def new_fn(self, before, **env):
def base_listing(fn):
return paginated_listing()(fn)

def base_cassandra_listing(fn):
return paginated_listing(backend='cassandra')(fn)

def is_trusted_origin(origin):
try:
origin = urlparse(origin)
Expand Down
31 changes: 22 additions & 9 deletions r2/r2/models/modaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def _on_create(self):
v.add_object(self)

@classmethod
def get_actions(cls, sr, mod=None, action=None, after=None, reverse=False, count=1000):
def get_actions(cls, srs, mod=None, action=None, after=None, reverse=False, count=1000):
"""
Get a ColumnQuery that yields ModAction objects according to
specified criteria.
Expand All @@ -160,15 +160,17 @@ def get_actions(cls, sr, mod=None, action=None, after=None, reverse=False, count
if not isinstance(after, cls):
after = None

srs = tup(srs)

if not mod and not action:
rowkey = sr._id36
q = ModActionBySR.query(rowkey, after=after, reverse=reverse, count=count)
rowkeys = [sr._id36 for sr in srs]
q = ModActionBySR.query(rowkeys, after=after, reverse=reverse, count=count)
elif mod and not action:
rowkey = '%s_%s' % (sr._id36, mod._id36)
q = ModActionBySRMod.query(rowkey, after=after, reverse=reverse, count=count)
rowkeys = ['%s_%s' % (sr._id36, mod._id36) for sr in srs]
q = ModActionBySRMod.query(rowkeys, after=after, reverse=reverse, count=count)
elif not mod and action:
rowkey = '%s_%s' % (sr._id36, action)
q = ModActionBySRAction.query(rowkey, after=after, reverse=reverse, count=count)
rowkeys = ['%s_%s' % (sr._id36, action) for sr in srs]
q = ModActionBySRAction.query(rowkeys, after=after, reverse=reverse, count=count)
else:
raise NotImplementedError("Can't query by both mod and action")

Expand All @@ -182,6 +184,13 @@ def get_extra_text(self):
text += ' %s' % self.description
return text

@staticmethod
def get_rgb(i, fade=0.8):
r = int(256 - (hash(str(i)) % 256)*(1-fade))
g = int(256 - (hash(str(i) + ' ') % 256)*(1-fade))
b = int(256 - (hash(str(i) + ' ') % 256)*(1-fade))
return (r, g, b)

@classmethod
def add_props(cls, user, wrapped):

Expand All @@ -198,7 +207,7 @@ def add_props(cls, user, wrapped):
targets = Thing._by_fullname(target_fullnames, data=True)
authors = Account._byID([t.author_id for t in targets.values() if hasattr(t, 'author_id')], data=True)
links = Link._byID([t.link_id for t in targets.values() if hasattr(t, 'link_id')], data=True)
subreddits = Subreddit._byID([t.sr_id for t in targets.values() if hasattr(t, 'sr_id')])
subreddits = Subreddit._byID([item.sr_id for item in wrapped], data=True)

# Assemble target links
target_links = {}
Expand Down Expand Up @@ -228,7 +237,7 @@ def add_props(cls, user, wrapped):
'author': author.name,
'on': _('on'),
'title': short_title}
path = target.make_permalink(link, subreddits[target.sr_id])
path = target.make_permalink(link, subreddits[link.sr_id])
target_links[fullname] = (text, path, title)
elif isinstance(target, Account):
target_accounts[fullname] = WrappedUser(target)
Expand All @@ -252,6 +261,10 @@ def add_props(cls, user, wrapped):
elif isinstance(target, Link) or isinstance(target, Comment):
item.target_text, item.target_path, item.target_title = target_links[item.target_fullname]

item.bgcolor = ModAction.get_rgb(item.sr_id)
item.sr_name = subreddits[item.sr_id].name
item.sr_path = subreddits[item.sr_id].path

Printable.add_props(user, wrapped)

class ModActionBySR(tdb_cassandra.View):
Expand Down
27 changes: 25 additions & 2 deletions r2/r2/models/subreddit.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,11 @@ def get_all_comments(self):
from r2.lib.db import queries
return queries.get_sr_comments(self)

def get_modactions(self, mod=None, action=None):
@classmethod
def get_modactions(cls, srs, mod=None, action=None):
# Get a query that will yield ModAction objects with mod and action
from r2.models import ModAction
return ModAction.get_actions(self, mod=mod, action=action)
return ModAction.get_actions(srs, mod=mod, action=action)

@classmethod
def add_props(cls, user, wrapped):
Expand Down Expand Up @@ -619,6 +620,28 @@ def __eq__(self, other):
def __ne__(self, other):
return not self.__eq__(other)

@staticmethod
def user_mods_all(user, srs):
# Get moderator SRMember relations for all in srs
# if a relation doesn't exist there will be a None entry in the
# returned dict
mod_rels = SRMember._fast_query(srs, user, 'moderator', data=False)
if None in mod_rels.values():
return False
else:
return True

@staticmethod
def get_all_mod_ids(srs):
from r2.lib.db.thing import Merge
srs = tup(srs)
queries = [SRMember._query(SRMember.c._thing1_id == sr._id,
SRMember.c._name == 'moderator') for sr in srs]
merged = Merge(queries)
# sr_ids = [sr._id for sr in srs]
# query = SRMember._query(SRMember.c._thing1_id == sr_ids, ...)
# is really slow
return [rel._thing2_id for rel in list(merged)]

class FakeSubreddit(Subreddit):
over_18 = False
Expand Down
6 changes: 6 additions & 0 deletions r2/r2/public/static/css/reddit.css
Original file line number Diff line number Diff line change
Expand Up @@ -4995,6 +4995,12 @@ tr.gold-accent + tr > td {
font-style: italic;
}

.modactionlisting td.subreddit {
white-space: nowrap;
padding-left: 0;
padding-right: 1.5em;
}

.modactions td {
font-size: small;
text-align: left;
Expand Down
18 changes: 15 additions & 3 deletions r2/r2/templates/modaction.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,27 @@

<%namespace file="utils.html" import="timestamp, plain_link"/>

<tr class="modactions">
<%
from pylons import c
from r2.models.subreddit import ModSR, MultiReddit
bgcolor = "rgb(255,255,255)"
is_multi = isinstance(c.site, ModSR) or isinstance(c.site, MultiReddit)
if is_multi and hasattr(thing, 'bgcolor'):
bgcolor = 'rgb(%s,%s,%s)' % thing.bgcolor
%>

<tr class="modactions" style="background-color: ${bgcolor}">
<td class="timestamp whitespace:nowrap">${timestamp(thing.date)}&#32;ago</td>
%if is_multi:
<td class="subreddit">${plain_link('/r/' + thing.sr_name, thing.sr_path + 'about/log', title=thing.sr_name)}</td>
%endif
<td class="whitespace:nowrap">${thing.mod}</td>
<td class="button">${thing.button}</td>
<td class="description">${thing.text}&#32;
%if hasattr(thing, 'target_text'):
${plain_link(thing.target_text, thing.target_path, title=thing.target_title, sr_path=False, cname=False, _class="subreddit hover")}
${plain_link(thing.target_text, thing.target_path, title=thing.target_title, sr_path=False, cname=False, _class="subreddit hover")}&#32;
%elif hasattr(thing, 'target_wrapped_user'):
${thing.target_wrapped_user}
${thing.target_wrapped_user}&#32;
%endif
%if hasattr(thing, 'details') and thing.details:
<em>(${thing.details})</em>
Expand Down

0 comments on commit 6f3c20a

Please sign in to comment.