From dc5cc92962add3e431fca6b4ae26422f6423a097 Mon Sep 17 00:00:00 2001 From: Logan Hanks Date: Wed, 12 Dec 2012 17:10:32 -0800 Subject: [PATCH] Add moderator permission for flair. --- r2/r2/controllers/api.py | 28 ++++++++++++++++------------ r2/r2/controllers/front.py | 14 +++++++++++--- r2/r2/lib/pages/pages.py | 14 +++++++++----- r2/r2/lib/pages/things.py | 4 +--- r2/r2/lib/validator/validator.py | 8 -------- r2/r2/models/builder.py | 24 +++++++++++++++++++----- 6 files changed, 56 insertions(+), 36 deletions(-) diff --git a/r2/r2/controllers/api.py b/r2/r2/controllers/api.py index 4e8046495..533e989cb 100755 --- a/r2/r2/controllers/api.py +++ b/r2/r2/controllers/api.py @@ -2513,7 +2513,7 @@ class ApiController(RedditController, OAuth2ResourceController): form.set_html(".status", _('saved')) @require_oauth2_scope("modflair") - @validatedForm(VFlairManager(), + @validatedForm(VSrModerator(perms='flair'), VModhash(), user = VFlairAccount("name"), link = VFlairLink('link'), @@ -2528,7 +2528,8 @@ class ApiController(RedditController, OAuth2ResourceController): else: site = Subreddit._byID(link.sr_id, data=True) # make sure c.user has permission to set flair on this link - if not c.user_is_admin and not site.is_moderator(c.user): + if not (c.user_is_admin + or site.is_moderator_with_perms(c.user, 'flair')): abort(403, 'forbidden') else: flair_type = USER_FLAIR @@ -2587,7 +2588,7 @@ class ApiController(RedditController, OAuth2ResourceController): form.set_html('.status', _('saved')) @require_oauth2_scope("modflair") - @validatedForm(VFlairManager(), + @validatedForm(VSrModerator(perms='flair'), VModhash(), user = VFlairAccount("name")) @api_doc(api_section.flair) @@ -2609,7 +2610,7 @@ class ApiController(RedditController, OAuth2ResourceController): jquery('.tagline .id-%s' % user._fullname).parent().html(unflair) @require_oauth2_scope("modflair") - @validate(VFlairManager(), + @validate(VSrModerator(perms='flair'), VModhash(), flair_csv = nop('flair_csv')) @api_doc(api_section.flair) @@ -2687,7 +2688,7 @@ class ApiController(RedditController, OAuth2ResourceController): @require_oauth2_scope("modflair") @validatedForm( - VFlairManager(), + VSrModerator(perms='flair'), VModhash(), flair_enabled = VBoolean("flair_enabled"), flair_position = VOneOf("flair_position", ("left", "right")), @@ -2734,7 +2735,7 @@ class ApiController(RedditController, OAuth2ResourceController): return BoringPage(_("API"), content = flair).render() @require_oauth2_scope("modflair") - @validatedForm(VFlairManager(), + @validatedForm(VSrModerator(perms='flair'), VModhash(), flair_template = VFlairTemplateByID('flair_template_id'), text = VFlairText('text'), @@ -2804,7 +2805,7 @@ class ApiController(RedditController, OAuth2ResourceController): details='flair_template') @require_oauth2_scope("modflair") - @validatedForm(VFlairManager(), + @validatedForm(VSrModerator(perms='flair'), VModhash(), flair_template = VFlairTemplateByID('flair_template_id')) @api_doc(api_section.flair) @@ -2816,7 +2817,7 @@ class ApiController(RedditController, OAuth2ResourceController): details='flair_delete_template') @require_oauth2_scope("modflair") - @validatedForm(VFlairManager(), VModhash(), + @validatedForm(VSrModerator(perms='flair'), VModhash(), flair_type = VOneOf('flair_type', (USER_FLAIR, LINK_FLAIR), default=USER_FLAIR)) @api_doc(api_section.flair) @@ -2836,7 +2837,8 @@ class ApiController(RedditController, OAuth2ResourceController): else: site = Subreddit._byID(link.sr_id, data=True) return FlairSelector(link=link, site=site).render() - if user and not (c.user_is_admin or c.site.is_moderator(c.user)): + if user and not (c.user_is_admin + or c.site.is_moderator_with_perms(c.user, 'flair')): # ignore user parameter if c.user is not mod/admin user = None return FlairSelector(user=user).render() @@ -2874,7 +2876,8 @@ class ApiController(RedditController, OAuth2ResourceController): flair_template = None text = None - if not site.is_moderator(c.user) and not c.user_is_admin: + if not (c.user_is_admin + or site.is_moderator_with_perms(c.user, 'flair')): if not self_assign_enabled: # TODO: serve error to client g.log.debug('flair self-assignment not permitted') @@ -2900,7 +2903,8 @@ class ApiController(RedditController, OAuth2ResourceController): setattr(user, 'flair_%s_css_class' % site._id, css_class) user._commit() - if ((site.is_moderator(c.user) or c.user_is_admin) + if ((c.user_is_admin + or site.is_moderator_with_perms(c.user, 'flair')) and c.user != user): ModAction.create(site, c.user, action='editflair', target=user, details='flair_edit') @@ -2922,7 +2926,7 @@ class ApiController(RedditController, OAuth2ResourceController): link._commit() changed(link) - if ((site.is_moderator(c.user) or c.user_is_admin)): + if c.user_is_admin or site.is_moderator_with_perms(c.user, 'flair'): ModAction.create(site, c.user, action='editflair', target=link, details='flair_edit') diff --git a/r2/r2/controllers/front.py b/r2/r2/controllers/front.py index 73677868d..786d2c710 100755 --- a/r2/r2/controllers/front.py +++ b/r2/r2/controllers/front.py @@ -590,7 +590,15 @@ class FrontController(RedditController, OAuth2ResourceController): def _edit_normal_reddit(self, location, num, after, reverse, count, created, name, user): # moderator is either reddit's moderator or an admin - is_moderator = c.user_is_loggedin and c.site.is_moderator(c.user) or c.user_is_admin + moderator_rel = c.user_is_loggedin and c.site.get_moderator(c.user) + is_moderator = c.user_is_admin or moderator_rel + is_unlimited_moderator = c.user_is_admin or ( + moderator_rel and moderator_rel.is_superuser()) + is_moderator_with_perms = lambda *perms: ( + c.user_is_admin + or moderator_rel and all(moderator_rel.has_permission(perm) + for perm in perms)) + extension_handling = False if is_moderator and location == 'edit': pane = PaneStack() @@ -600,7 +608,7 @@ class FrontController(RedditController, OAuth2ResourceController): c.site = Subreddit._byID(c.site._id, data=True, stale=False) pane.append(CreateSubreddit(site = c.site)) elif location == 'moderators': - pane = ModList(editable = is_moderator) + pane = ModList(editable=is_unlimited_moderator) elif is_moderator and location == 'banned': pane = BannedList(editable = is_moderator) elif is_moderator and location == 'wikibanned': @@ -640,7 +648,7 @@ class FrontController(RedditController, OAuth2ResourceController): extension_handling = "private" elif (is_moderator or c.user_is_sponsor) and location == 'traffic': pane = trafficpages.SubredditTraffic() - elif is_moderator and location == 'flair': + elif is_moderator_with_perms('flair') and location == 'flair': c.allow_styles = True pane = FlairPane(num, after, reverse, name, user) elif c.user_is_sponsor and location == 'ads': diff --git a/r2/r2/lib/pages/pages.py b/r2/r2/lib/pages/pages.py index 5fc75f4d3..ba3bc1e2a 100755 --- a/r2/r2/lib/pages/pages.py +++ b/r2/r2/lib/pages/pages.py @@ -274,8 +274,9 @@ class Reddit(Templated): NamedButton("spam", css_class="reddit-spam")] if is_single_subreddit: - buttons += [NamedButton("banned", css_class="reddit-ban"), - NamedButton("flair", css_class="reddit-flair")] + buttons.append(NamedButton("banned", css_class="reddit-ban")) + if c.site.is_moderator_with_perms(c.user, 'flair'): + buttons.append(NamedButton("flair", css_class="reddit-flair")) buttons += [NamedButton("log", css_class="reddit-moderationlog"), NamedButton("unmoderated", css_class="reddit-unmoderated")] @@ -2509,7 +2510,8 @@ class WrappedUser(CachedTemplate): if include_flair_selector: if (not getattr(c.site, 'flair_self_assign_enabled', True) - and not (c.user_is_admin or c.site.is_moderator(c.user))): + and not (c.user_is_admin + or c.site.is_moderator_with_perms(c.user, 'flair'))): include_flair_selector = False target = None @@ -2734,7 +2736,8 @@ class FlairPrefs(CachedTemplate): class FlairSelectorLinkSample(CachedTemplate): def __init__(self, link, site, flair_template): flair_position = getattr(site, 'link_flair_position', 'right') - admin = bool(c.user_is_admin or site.is_moderator(c.user)) + admin = bool(c.user_is_admin + or site.is_moderator_with_perms(c.user, 'flair')) CachedTemplate.__init__( self, title=link.title, @@ -2752,7 +2755,8 @@ class FlairSelector(CachedTemplate): user = c.user if site is None: site = c.site - admin = bool(c.user_is_admin or site.is_moderator(c.user)) + admin = bool(c.user_is_admin + or site.is_moderator_with_perms(c.user, 'flair')) if link: flair_type = LINK_FLAIR diff --git a/r2/r2/lib/pages/things.py b/r2/r2/lib/pages/things.py index 5fc059a17..f4e74ef5d 100644 --- a/r2/r2/lib/pages/things.py +++ b/r2/r2/lib/pages/things.py @@ -87,8 +87,6 @@ class LinkButtons(PrintableButtons): else: show_unmarknsfw = False - show_flair = thing.can_ban or is_author - # do we show the delete button? show_delete = is_author and delete and not thing._deleted # disable the delete button for live sponsored links @@ -128,7 +126,7 @@ class LinkButtons(PrintableButtons): show_distinguish = show_distinguish, show_marknsfw = show_marknsfw, show_unmarknsfw = show_unmarknsfw, - show_flair = show_flair, + show_flair = thing.can_flair, show_comments = comments, # promotion promoted = thing.promoted, diff --git a/r2/r2/lib/validator/validator.py b/r2/r2/lib/validator/validator.py index 984ea6fe0..bd7ba7275 100644 --- a/r2/r2/lib/validator/validator.py +++ b/r2/r2/lib/validator/validator.py @@ -873,14 +873,6 @@ class VSrModerator(Validator): abort(403, "forbidden") return self.set_error('MODERATOR_REQUIRED', code=403) -class VFlairManager(VSrModerator): - """Validates that a user is permitted to manage flair for a subreddit. - - Currently this is the same as VSrModerator. It's a separate class to act as - a placeholder if we ever need to give mods a way to delegate this aspect of - subreddit administration.""" - pass - class VCanDistinguish(VByName): def run(self, thing_name, how): if c.user_is_admin: diff --git a/r2/r2/models/builder.py b/r2/r2/models/builder.py index 89a8c4b3d..06369e01c 100755 --- a/r2/r2/models/builder.py +++ b/r2/r2/models/builder.py @@ -84,11 +84,17 @@ class Builder(object): subreddits = Subreddit.load_subreddits(items, stale=self.stale) - if not user: - can_ban_set = set() - else: - can_ban_set = set(id for (id,sr) in subreddits.iteritems() - if sr.can_ban(user)) + can_ban_set = set() + can_flair_set = set() + can_own_flair_set = set() + if user: + for sr_id, sr in subreddits.iteritems(): + if sr.can_ban(user): + can_ban_set.add(sr_id) + if sr.is_moderator_with_perms(user, 'flair'): + can_flair_set.add(sr_id) + if sr.link_flair_self_assign_enabled: + can_own_flair_set.add(sr_id) #get likes/dislikes try: @@ -222,6 +228,7 @@ class Builder(object): w.show_reports = False w.show_spam = False w.can_ban = False + w.can_flair = False w.use_big_modbuttons = self.spam_listing if (c.user_is_admin @@ -255,6 +262,13 @@ class Builder(object): w.show_reports = True w.use_big_modbuttons = True + if (c.user_is_admin + or (user and hasattr(item, 'sr_id') + and (item.sr_id in can_flair_set + or (w.author and w.author._id == user._id + and item.sr_id in can_own_flair_set)))): + w.can_flair = True + # recache the user object: it may be None if user is not logged in, # whereas now we are happy to have the UnloggedUser object user = c.user