mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-01-30 01:08:32 -05:00
Add permissions editing to the edit moderators page.
This commit is contained in:
@@ -562,6 +562,11 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
'wikicontributor',
|
||||
)
|
||||
|
||||
_sr_friend_types_with_permissions = (
|
||||
'moderator',
|
||||
'moderator_invite',
|
||||
)
|
||||
|
||||
@noresponse(VUser(),
|
||||
VModhash(),
|
||||
nuser = VExistingUname('name'),
|
||||
@@ -613,16 +618,55 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
if type == "friend" and c.user.gold:
|
||||
c.user.friend_rels_cache(_update=True)
|
||||
|
||||
@validatedForm(VSrModerator(), VModhash(),
|
||||
target=VExistingUname('name'),
|
||||
type_and_permissions=VPermissions('type', 'permissions'))
|
||||
@api_doc(api_section.users)
|
||||
def POST_setpermissions(self, form, jquery, target, type_and_permissions):
|
||||
if form.has_errors('name', errors.USER_DOESNT_EXIST, errors.NO_USER):
|
||||
return
|
||||
if form.has_errors('type', errors.INVALID_PERMISSION_TYPE):
|
||||
return
|
||||
if form.has_errors('permissions', errors.INVALID_PERMISSIONS):
|
||||
return
|
||||
|
||||
type, permissions = type_and_permissions
|
||||
update = None
|
||||
|
||||
if type in ("moderator", "moderator_invite"):
|
||||
if not c.user_is_admin:
|
||||
if type == "moderator" and not c.site.can_demod(c.user, target):
|
||||
abort(403, 'forbidden')
|
||||
if (type == "moderator_invite"
|
||||
and not c.site.is_unlimited_moderator(c.user)):
|
||||
abort(403, 'forbidden')
|
||||
if type == "moderator":
|
||||
rel = c.site.get_moderator(target)
|
||||
if type == "moderator_invite":
|
||||
rel = c.site.get_moderator_invite(target)
|
||||
rel.set_permissions(permissions)
|
||||
rel._commit()
|
||||
update = rel.encoded_permissions
|
||||
ModAction.create(c.site, c.user, action='setpermissions',
|
||||
target=target, details='permission_' + type,
|
||||
description=update)
|
||||
|
||||
if update:
|
||||
row = form.closest('tr')
|
||||
editor = row.find('.permissions').data('PermissionEditor')
|
||||
editor.onCommit(update)
|
||||
|
||||
@validatedForm(VUser(),
|
||||
VModhash(),
|
||||
ip = ValidIP(),
|
||||
friend = VExistingUname('name'),
|
||||
container = nop('container'),
|
||||
type = VOneOf('type', ('friend',) + _sr_friend_types),
|
||||
type_and_permissions = VPermissions('type', 'permissions'),
|
||||
note = VLength('note', 300))
|
||||
@api_doc(api_section.users)
|
||||
def POST_friend(self, form, jquery, ip, friend,
|
||||
container, type, note):
|
||||
container, type, type_and_permissions, note):
|
||||
"""
|
||||
Complement to POST_unfriend: handles friending as well as
|
||||
privilege changes on subreddits.
|
||||
@@ -670,6 +714,14 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
elif form.has_errors("name", errors.USER_DOESNT_EXIST, errors.NO_USER):
|
||||
return
|
||||
|
||||
if type in self._sr_friend_types_with_permissions:
|
||||
if form.has_errors('type', errors.INVALID_PERMISSION_TYPE):
|
||||
return
|
||||
if form.has_errors('permissions', errors.INVALID_PERMISSIONS):
|
||||
return
|
||||
else:
|
||||
permissions = None
|
||||
|
||||
if type == "moderator_invite" and container.is_moderator(friend):
|
||||
c.errors.add(errors.ALREADY_MODERATOR, field="name")
|
||||
form.set_error(errors.ALREADY_MODERATOR, "name")
|
||||
@@ -678,7 +730,7 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
if type == "moderator":
|
||||
container.remove_moderator_invite(friend)
|
||||
|
||||
new = fn(friend)
|
||||
new = fn(friend, permissions=type_and_permissions[1])
|
||||
|
||||
# Log this action
|
||||
if new and type in self._sr_friend_types:
|
||||
@@ -726,13 +778,15 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
ip=ValidIP())
|
||||
@api_doc(api_section.subreddits)
|
||||
def POST_accept_moderator_invite(self, form, jquery, ip):
|
||||
rel = c.site.get_moderator_invite(c.user)
|
||||
if not c.site.remove_moderator_invite(c.user):
|
||||
c.errors.add(errors.NO_INVITE_FOUND)
|
||||
form.set_error(errors.NO_INVITE_FOUND, None)
|
||||
return
|
||||
|
||||
permissions = rel.get_permissions()
|
||||
ModAction.create(c.site, c.user, "acceptmoderatorinvite")
|
||||
c.site.add_moderator(c.user)
|
||||
c.site.add_moderator(c.user, permissions=rel.get_permissions())
|
||||
notify_user_added("accept_moderator_invite", c.user, c.user, c.site)
|
||||
jquery.refresh()
|
||||
|
||||
|
||||
@@ -42,10 +42,12 @@ class UserRelManager(object):
|
||||
rel._permission_class = self.permission_class
|
||||
return rel
|
||||
|
||||
def add(self, thing, user, **attrs):
|
||||
def add(self, thing, user, permissions=None, **attrs):
|
||||
if self.get(thing, user):
|
||||
return None
|
||||
r = self.relation(thing, user, self.name, **attrs)
|
||||
if permissions is not None:
|
||||
r.set_permissions(permissions)
|
||||
r._commit()
|
||||
r._permission_class = self.permission_class
|
||||
return r
|
||||
|
||||
@@ -117,6 +117,8 @@ error_list = dict((
|
||||
('BID_LIVE', _('you cannot edit the bid of a live ad')),
|
||||
('TOO_MANY_CAMPAIGNS', _('you have too many campaigns for that promotion')),
|
||||
('BAD_JSONP_CALLBACK', _('that jsonp callback contains invalid characters')),
|
||||
('INVALID_PERMISSION_TYPE', _("permissions don't apply to that type of user")),
|
||||
('INVALID_PERMISSIONS', _('invalid permissions string')),
|
||||
))
|
||||
errors = Storage([(e, e) for e in error_list.keys()])
|
||||
|
||||
|
||||
@@ -2968,6 +2968,16 @@ class ModList(UserList):
|
||||
invite_form_title = _('invite moderator')
|
||||
remove_self_title = _('you are a moderator of this subreddit. %(action)s')
|
||||
|
||||
def __init__(self, editable=True):
|
||||
super(ModList, self).__init__(editable=editable)
|
||||
self.perms_by_type = {
|
||||
self.type: c.site.moderators_with_perms(),
|
||||
self.invite_type: c.site.moderator_invites_with_perms(),
|
||||
}
|
||||
self.cells = ('user', 'permissions', 'permissionsctl', 'sendmessage')
|
||||
if editable:
|
||||
self.cells += ('remove',)
|
||||
|
||||
@property
|
||||
def table_title(self):
|
||||
return _("moderators of /r/%(reddit)s") % {"reddit": c.site.name}
|
||||
@@ -2990,24 +3000,50 @@ class ModList(UserList):
|
||||
def has_invite(self):
|
||||
return c.user_is_loggedin and c.site.is_moderator_invite(c.user)
|
||||
|
||||
def moderator_editable(self, user):
|
||||
def moderator_editable(self, user, row_type):
|
||||
if not c.user_is_loggedin:
|
||||
return False
|
||||
elif c.user_is_admin:
|
||||
return True
|
||||
else:
|
||||
elif row_type == self.type:
|
||||
return c.site.can_demod(c.user, user)
|
||||
elif row_type == self.invite_type:
|
||||
return c.site.is_unlimited_moderator(c.user)
|
||||
else:
|
||||
return False
|
||||
|
||||
def user_row(self, row_type, user, editable=True):
|
||||
perms = ModeratorPermissions(
|
||||
user, row_type, self.perms_by_type[row_type].get(user._id),
|
||||
editable=editable and self.moderator_editable(user, row_type))
|
||||
return UserTableItem(user, row_type, self.cells, self.container_name,
|
||||
editable, self.remove_action, rel=perms)
|
||||
|
||||
@property
|
||||
def user_rows(self):
|
||||
return self._user_rows(self.type, self.user_ids(), self.moderator_editable)
|
||||
return self._user_rows(
|
||||
self.type, self.user_ids(),
|
||||
lambda u: self.moderator_editable(u, self.type))
|
||||
|
||||
@property
|
||||
def invited_user_rows(self):
|
||||
return self._user_rows(self.invite_type, c.site.moderator_invite_ids())
|
||||
return self._user_rows(
|
||||
self.invite_type, self.invited_user_ids(),
|
||||
lambda u: self.moderator_editable(u, self.invite_type))
|
||||
|
||||
def _sort_user_ids(self, row_type):
|
||||
for user_id, perms in self.perms_by_type[row_type].iteritems():
|
||||
if perms is None:
|
||||
yield user_id
|
||||
for user_id, perms in self.perms_by_type[row_type].iteritems():
|
||||
if perms is not None:
|
||||
yield user_id
|
||||
|
||||
def user_ids(self):
|
||||
return c.site.moderators
|
||||
return list(self._sort_user_ids(self.type))
|
||||
|
||||
def invited_user_ids(self):
|
||||
return list(self._sort_user_ids(self.invite_type))
|
||||
|
||||
class BannedList(UserList):
|
||||
"""List of users banned from a given reddit"""
|
||||
@@ -3865,7 +3901,6 @@ class GoldInfoPage(BoringPage):
|
||||
}
|
||||
BoringPage.__init__(self, *args, **kwargs)
|
||||
|
||||
|
||||
class Goldvertisement(Templated):
|
||||
def __init__(self):
|
||||
Templated.__init__(self)
|
||||
@@ -3883,3 +3918,11 @@ class LinkCommentsSettings(Templated):
|
||||
self.can_edit = (c.user_is_loggedin
|
||||
and (c.user_is_admin or
|
||||
link.subreddit_slow.is_moderator(c.user)))
|
||||
|
||||
class ModeratorPermissions(Templated):
|
||||
def __init__(self, user, permissions_type, permissions,
|
||||
editable=False, embedded=False):
|
||||
self.user = user
|
||||
self.permissions = permissions
|
||||
Templated.__init__(self, permissions_type=permissions_type,
|
||||
editable=editable, embedded=embedded)
|
||||
|
||||
@@ -144,6 +144,14 @@ def js_config(extra_config=None):
|
||||
"clicktracker_url": g.clicktracker_url,
|
||||
"uitracker_url": g.uitracker_url,
|
||||
"static_root": static(''),
|
||||
"permissions": {
|
||||
"info": {
|
||||
"moderator": ModeratorPermissionSet.info,
|
||||
"moderator_invite": ModeratorPermissionSet.info,
|
||||
},
|
||||
"all_msg": _("full permissions"),
|
||||
"none_msg": _("no permissions"),
|
||||
},
|
||||
}
|
||||
|
||||
if extra_config:
|
||||
|
||||
@@ -2106,3 +2106,24 @@ class VOAuth2RefreshToken(Validator):
|
||||
return token
|
||||
else:
|
||||
return None
|
||||
|
||||
class VPermissions(Validator):
|
||||
types = dict(
|
||||
moderator=ModeratorPermissionSet,
|
||||
moderator_invite=ModeratorPermissionSet,
|
||||
)
|
||||
|
||||
def __init__(self, type_param, permissions_param, *a, **kw):
|
||||
Validator.__init__(self, (type_param, permissions_param), *a, **kw)
|
||||
|
||||
def run(self, type, permissions):
|
||||
permission_class = self.types.get(type)
|
||||
if not permission_class:
|
||||
self.set_error(errors.INVALID_PERMISSION_TYPE, field=self.param[0])
|
||||
return (None, None)
|
||||
try:
|
||||
perm_set = permission_class.loads(permissions, validate=True)
|
||||
except ValueError:
|
||||
self.set_error(errors.INVALID_PERMISSIONS, field=self.param[1])
|
||||
return (None, None)
|
||||
return type, perm_set
|
||||
|
||||
@@ -56,7 +56,7 @@ class ModAction(tdb_cassandra.UuidThing, Printable):
|
||||
'editsettings', 'editflair', 'distinguish', 'marknsfw',
|
||||
'wikibanned', 'wikicontributor', 'wikiunbanned',
|
||||
'removewikicontributor', 'wikirevise', 'wikipermlevel',
|
||||
'ignorereports', 'unignorereports')
|
||||
'ignorereports', 'unignorereports', 'setpermissions')
|
||||
|
||||
_menu = {'banuser': _('ban user'),
|
||||
'unbanuser': _('unban user'),
|
||||
@@ -82,7 +82,8 @@ class ModAction(tdb_cassandra.UuidThing, Printable):
|
||||
'wikirevise': _('wiki revise page'),
|
||||
'wikipermlevel': _('wiki page permissions'),
|
||||
'ignorereports': _('ignore reports'),
|
||||
'unignorereports': _('unignore reports')}
|
||||
'unignorereports': _('unignore reports'),
|
||||
'setpermissions': _('permissions')}
|
||||
|
||||
_text = {'banuser': _('banned'),
|
||||
'wikibanned': _('wiki banned'),
|
||||
@@ -108,7 +109,8 @@ class ModAction(tdb_cassandra.UuidThing, Printable):
|
||||
'distinguish': _('distinguished'),
|
||||
'marknsfw': _('marked nsfw'),
|
||||
'ignorereports': _('ignored reports'),
|
||||
'unignorereports': _('unignored reports')}
|
||||
'unignorereports': _('unignored reports'),
|
||||
'setpermissions': _('changed permissions on')}
|
||||
|
||||
_details_text = {# approve comment/link
|
||||
'unspam': _('unspam'),
|
||||
@@ -152,7 +154,10 @@ class ModAction(tdb_cassandra.UuidThing, Printable):
|
||||
'flair_clear_template': _('clear flair templates'),
|
||||
# distinguish/nsfw
|
||||
'remove': _('remove'),
|
||||
'ignore_reports': _('ignore reports')}
|
||||
'ignore_reports': _('ignore reports'),
|
||||
# permissions
|
||||
'permission_moderator': _('set permissions on moderator'),
|
||||
'permission_moderator_invite': _('set permissions on moderator invitation')}
|
||||
|
||||
# This stuff won't change
|
||||
cache_ignore = set(['subreddit', 'target']).union(Printable.cache_ignore)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
from __future__ import with_statement
|
||||
|
||||
import base64
|
||||
import collections
|
||||
import datetime
|
||||
import hashlib
|
||||
|
||||
@@ -82,7 +83,7 @@ class PermissionSet(dict):
|
||||
return ','.join('-+'[bool(v)] + k for k, v in sorted(self.iteritems()))
|
||||
|
||||
def is_superuser(self):
|
||||
return super(PermissionSet, self).get(self.ALL)
|
||||
return bool(super(PermissionSet, self).get(self.ALL))
|
||||
|
||||
def is_valid(self):
|
||||
if not self.info:
|
||||
@@ -295,6 +296,16 @@ class Subreddit(Thing, Printable):
|
||||
def moderators(self):
|
||||
return self.moderator_ids()
|
||||
|
||||
def moderators_with_perms(self):
|
||||
return collections.OrderedDict(
|
||||
(r._thing2_id, r.get_permissions())
|
||||
for r in self.each_moderator())
|
||||
|
||||
def moderator_invites_with_perms(self):
|
||||
return collections.OrderedDict(
|
||||
(r._thing2_id, r.get_permissions())
|
||||
for r in self.each_moderator_invite())
|
||||
|
||||
@property
|
||||
def stylesheet_is_static(self):
|
||||
"""Is the subreddit using the newer static file based stylesheets?"""
|
||||
@@ -520,13 +531,13 @@ class Subreddit(Thing, Printable):
|
||||
self.is_moderator_invite(user))
|
||||
|
||||
def can_demod(self, bully, victim):
|
||||
# This works because the is_*() functions return the relation
|
||||
# when True. So we can compare the dates on the relations.
|
||||
bully_rel = self.is_moderator(bully)
|
||||
victim_rel = self.is_moderator(victim)
|
||||
if bully_rel is None or victim_rel is None:
|
||||
return False
|
||||
return bully_rel._date <= victim_rel._date
|
||||
bully_rel = self.get_moderator(bully)
|
||||
victim_rel = self.get_moderator(victim)
|
||||
return (
|
||||
bully_rel is not None
|
||||
and victim_rel is not None
|
||||
and bully_rel.is_superuser() # limited mods can't demod
|
||||
and bully_rel._date <= victim_rel._date)
|
||||
|
||||
@classmethod
|
||||
def load_subreddits(cls, links, return_dict = True, stale=False):
|
||||
@@ -907,15 +918,18 @@ class Subreddit(Thing, Printable):
|
||||
|
||||
def is_limited_moderator(self, user):
|
||||
rel = self.is_moderator(user)
|
||||
return rel and rel.permissions is not None
|
||||
return bool(rel and not rel.is_superuser())
|
||||
|
||||
def is_unlimited_moderator(self, user):
|
||||
rel = self.is_moderator(user)
|
||||
return bool(rel and rel.is_superuser())
|
||||
|
||||
def update_moderator_permissions(self, user, **kwargs):
|
||||
"""Grants or denies permissions to this moderator.
|
||||
|
||||
Does nothing if the given user is not a moderator.
|
||||
|
||||
Args are named parameters with bool or None values (use None to disable
|
||||
granting or denying the permission).
|
||||
Does nothing if the given user is not a moderator. Args are named
|
||||
parameters with bool or None values (use None to all back to the default
|
||||
for a permission).
|
||||
"""
|
||||
rel = self.get_moderator(user)
|
||||
if rel:
|
||||
|
||||
@@ -6410,3 +6410,44 @@ body.gold .buttons li.comment-save-button { display: inline; }
|
||||
width: 250px;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.permissions {
|
||||
display: inline-block;
|
||||
font-size: small;
|
||||
text-align: right;
|
||||
width: 44ex;
|
||||
}
|
||||
#moderator_invite .permissions { width: 30ex; }
|
||||
.permissions > form { display: none; }
|
||||
|
||||
.permission-summary {
|
||||
display: inline-block;
|
||||
font-size: small;
|
||||
border: 1px solid white;
|
||||
}
|
||||
.permission-summary.edited { border: dashed 1px black; }
|
||||
.permission-bit.added { font-weight: bold; }
|
||||
.permission-bit.removed { text-decoration: line-through; }
|
||||
.permission-bit.none { font-style: italic; }
|
||||
|
||||
.permissions-edit { font-size: x-small; }
|
||||
|
||||
.permission-selector {
|
||||
border: 1px solid black;
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
width: 24ex;
|
||||
}
|
||||
.permission-selector.active { display: block; }
|
||||
.permission-selector label {
|
||||
display: block; text-align: left;
|
||||
padding: 0px 2px 1px 2px;
|
||||
}
|
||||
.permission-selector label:first-child { border-bottom: 1px solid black; }
|
||||
.permission-selector label:hover { background-color: #bbb; }
|
||||
.permission-selector label.disabled { background-color: #ddd; }
|
||||
.permission-selector form { text-align: right; }
|
||||
.permission-selector .status, .permission-selector .error {
|
||||
text-align: left;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ r.setup = function(config) {
|
||||
$(function() {
|
||||
r.login.ui.init()
|
||||
r.analytics.init()
|
||||
r.ui.HelpBubble.init()
|
||||
r.ui.init()
|
||||
r.interestbar.init()
|
||||
r.apps.init()
|
||||
r.wiki.init()
|
||||
|
||||
@@ -565,8 +565,10 @@ $.fn.insert_table_rows = function(rows, index) {
|
||||
/* insert cells */
|
||||
$.map(thing.cells, function(cell) {
|
||||
$(row.insertCell(row.cells.length))
|
||||
.html($.unsafe(cell));
|
||||
.html($.unsafe(cell))
|
||||
.trigger("insert-cell");
|
||||
});
|
||||
$(row).trigger("insert-row");
|
||||
/* reveal! */
|
||||
$(row).fadeIn();
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ function open_menu(menu) {
|
||||
function close_menus(event) {
|
||||
$(".drop-choices.inuse").not(".active")
|
||||
.removeClass("inuse");
|
||||
$(".drop-choices.active").removeClass("active");
|
||||
$(".drop-choices.active").removeClass("active").trigger("close_menu")
|
||||
|
||||
// Clear any flairselectors that may have been opened.
|
||||
$(".flairselector").empty();
|
||||
|
||||
@@ -202,3 +202,218 @@ r.ui.HelpBubble.prototype = $.extend(new r.ui.Base(), {
|
||||
this.timeout = setTimeout($.proxy(this, 'hide'), this.hideDelay)
|
||||
}
|
||||
})
|
||||
|
||||
r.ui.PermissionEditor = function(el) {
|
||||
r.ui.Base.call(this, el)
|
||||
var params = {}
|
||||
this.$el.find('input[type="hidden"]').each(function(idx, el) {
|
||||
params[el.name] = el.value
|
||||
})
|
||||
var permission_type = params.type
|
||||
var name = params.name
|
||||
this.form_id = permission_type + "-permissions-" + name
|
||||
this.permission_info = r.config.permissions.info[permission_type]
|
||||
this.sorted_perm_keys = $.map(this.permission_info,
|
||||
function(v, k) { return k })
|
||||
this.sorted_perm_keys.sort()
|
||||
this.original_perms = this._parsePerms(params.permissions)
|
||||
this.embedded = this.$el.find("form").length == 0
|
||||
this.$menu = null
|
||||
if (this.embedded) {
|
||||
this.$permissions_field = this.$el.find('input[name="permissions"]')
|
||||
this.$menu_controller = this.$el.siblings('.permissions-edit')
|
||||
} else {
|
||||
this.$menu_controller = this.$el.closest('tr').find('.permissions-edit')
|
||||
}
|
||||
this.$menu_controller.find('a').click($.proxy(this, 'show'))
|
||||
this.updateSummary()
|
||||
}
|
||||
r.ui.PermissionEditor.init = function() {
|
||||
function activate(target) {
|
||||
$(target).find('.permissions').each(function(idx, el) {
|
||||
$(el).data('PermissionEditor', new r.ui.PermissionEditor(el))
|
||||
})
|
||||
}
|
||||
activate('body')
|
||||
for (var permission_type in r.config.permissions.info) {
|
||||
$('.' + permission_type + '-table')
|
||||
.on('insert-row', 'tr', function(e) { activate(this) })
|
||||
}
|
||||
}
|
||||
r.ui.PermissionEditor.prototype = $.extend(new r.ui.Base(), {
|
||||
_parsePerms: function(permspec) {
|
||||
var perms = {}
|
||||
permspec.split(",").forEach(function(str) {
|
||||
perms[str.substring(1)] = str[0] == "+"
|
||||
})
|
||||
return perms.all ? {"all": true} : perms
|
||||
},
|
||||
|
||||
_serializePerms: function(perms) {
|
||||
if (perms.all) {
|
||||
return "+all"
|
||||
} else {
|
||||
var parts = []
|
||||
for (var perm in perms) {
|
||||
parts.push((perms[perm] ? "+" : "-") + perm)
|
||||
}
|
||||
return parts.join(",")
|
||||
}
|
||||
},
|
||||
|
||||
_getNewPerms: function() {
|
||||
if (!this.$menu) {
|
||||
return null
|
||||
}
|
||||
var perms = {}
|
||||
this.$menu.find('input[type="checkbox"]').each(function(idx, el) {
|
||||
perms[$(el).attr("name")] = $(el).prop("checked")
|
||||
})
|
||||
return perms
|
||||
},
|
||||
|
||||
_makeMenuLabel: function(perm) {
|
||||
var update = $.proxy(this, "updateSummary")
|
||||
var info = this.permission_info[perm]
|
||||
var $input = $('<input type="checkbox">')
|
||||
.attr("name", perm)
|
||||
.prop("checked", this.original_perms[perm])
|
||||
var $label = $('<label>')
|
||||
.append($input)
|
||||
.click(function(e) { e.stopPropagation() })
|
||||
if (perm == "all") {
|
||||
$input.change(function() {
|
||||
var disabled = $input.is(":checked")
|
||||
$label.siblings()
|
||||
.toggleClass("disabled", disabled)
|
||||
.find('input[type="checkbox"]').prop("disabled", disabled)
|
||||
update()
|
||||
})
|
||||
$label.append(
|
||||
document.createTextNode(r.config.permissions.all_msg))
|
||||
} else if (info) {
|
||||
$input.change(update)
|
||||
$label.append(document.createTextNode(info.title))
|
||||
$label.attr("title", info.description)
|
||||
}
|
||||
return $label
|
||||
},
|
||||
|
||||
show: function(e) {
|
||||
close_menus(e)
|
||||
this.$menu = $('<div class="permission-selector drop-choices">')
|
||||
this.$menu.append(this._makeMenuLabel("all"))
|
||||
for (var i in this.sorted_perm_keys) {
|
||||
this.$menu.append(this._makeMenuLabel(this.sorted_perm_keys[i]))
|
||||
}
|
||||
|
||||
this.$menu
|
||||
.on("close_menu", $.proxy(this, "hide"))
|
||||
.find("input").first().change().end()
|
||||
if (!this.embedded) {
|
||||
var $form = this.$el.find("form").clone()
|
||||
$form.attr("id", this.form_id)
|
||||
$form.click(function(e) { e.stopPropagation() })
|
||||
this.$menu.append('<hr>', $form)
|
||||
this.$permissions_field =
|
||||
this.$menu.find('input[name="permissions"]')
|
||||
}
|
||||
this.$menu_controller.parent().append(this.$menu)
|
||||
open_menu(this.$menu_controller[0])
|
||||
return false
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if (this.$menu) {
|
||||
this.$menu.remove()
|
||||
this.$menu = null
|
||||
this.updateSummary()
|
||||
}
|
||||
},
|
||||
|
||||
_renderBit: function(perm) {
|
||||
var info = this.permission_info[perm]
|
||||
var text
|
||||
if (perm == "all") {
|
||||
text = r.config.permissions.all_msg
|
||||
} else if (info) {
|
||||
text = info.title
|
||||
} else {
|
||||
text = perm
|
||||
}
|
||||
var $span = $('<span class="permission-bit"/>').text(text)
|
||||
if (info) {
|
||||
$span.attr("title", info.description)
|
||||
}
|
||||
return $span
|
||||
},
|
||||
|
||||
updateSummary: function() {
|
||||
var new_perms = this._getNewPerms()
|
||||
var spans = []
|
||||
if (new_perms && new_perms.all) {
|
||||
spans.push(this._renderBit("all")
|
||||
.toggleClass("added", this.original_perms.all != true))
|
||||
} else {
|
||||
if (this.original_perms.all) {
|
||||
if (!this.embedded || !new_perms) {
|
||||
spans.push(this._renderBit("all")
|
||||
.toggleClass("removed",
|
||||
!this.embedded && new_perms != null))
|
||||
}
|
||||
} else {
|
||||
for (var perm in this.original_perms) {
|
||||
if (this.original_perms[perm]) {
|
||||
if (this.embedded && !(new_perms && !new_perms[perm])) {
|
||||
spans.push(this._renderBit(perm))
|
||||
}
|
||||
if (!this.embedded) {
|
||||
spans.push(this._renderBit(perm)
|
||||
.toggleClass("removed",
|
||||
new_perms != null
|
||||
&& !new_perms[perm]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (new_perms) {
|
||||
for (var perm in new_perms) {
|
||||
if (this.permission_info[perm] && new_perms[perm]
|
||||
&& !this.original_perms[perm]) {
|
||||
spans.push(this._renderBit(perm)
|
||||
.toggleClass("added", !this.embedded))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!spans.length) {
|
||||
spans.push($('<span class="permission-bit">')
|
||||
.text(r.config.permissions.none_msg)
|
||||
.addClass("none"))
|
||||
}
|
||||
var $new_summary = $('<div class="permission-summary">')
|
||||
for (var i = 0; i < spans.length; i++) {
|
||||
if (i > 0) {
|
||||
$new_summary.append(", ")
|
||||
}
|
||||
$new_summary.append(spans[i])
|
||||
}
|
||||
$new_summary.toggleClass("edited", this.$menu != null)
|
||||
this.$el.find(".permission-summary").replaceWith($new_summary)
|
||||
|
||||
if (new_perms && this.$permissions_field) {
|
||||
this.$permissions_field.val(this._serializePerms(new_perms))
|
||||
}
|
||||
},
|
||||
|
||||
onCommit: function(perms) {
|
||||
this.$el.find('input[name="permissions"]').val(perms)
|
||||
this.original_perms = this._parsePerms(perms)
|
||||
this.hide()
|
||||
}
|
||||
})
|
||||
|
||||
r.ui.init = function() {
|
||||
r.ui.HelpBubble.init()
|
||||
r.ui.PermissionEditor.init()
|
||||
}
|
||||
|
||||
57
r2/r2/templates/moderatorpermissions.html
Normal file
57
r2/r2/templates/moderatorpermissions.html
Normal file
@@ -0,0 +1,57 @@
|
||||
## The contents of this file are subject to the Common Public Attribution
|
||||
## License Version 1.0. (the "License"); you may not use this file except in
|
||||
## compliance with the License. You may obtain a copy of the License at
|
||||
## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
|
||||
## License Version 1.1, but Sections 14 and 15 have been added to cover use of
|
||||
## software over a computer network and provide for limited attribution for the
|
||||
## Original Developer. In addition, Exhibit A has been modified to be
|
||||
## consistent with Exhibit B.
|
||||
##
|
||||
## Software distributed under the License is distributed on an "AS IS" basis,
|
||||
## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
||||
## the specific language governing rights and limitations under the License.
|
||||
##
|
||||
## The Original Code is reddit.
|
||||
##
|
||||
## The Original Developer is the Initial Developer. The Initial Developer of
|
||||
## the Original Code is reddit Inc.
|
||||
##
|
||||
## All portions of the code written by reddit are Copyright (c) 2006-2012
|
||||
## reddit Inc. All Rights Reserved.
|
||||
###############################################################################
|
||||
|
||||
<%namespace file="utils.html" import="error_field"/>
|
||||
|
||||
<%def name="form_content()">
|
||||
%if not thing.embedded:
|
||||
<input type="hidden" name="name"
|
||||
value="${thing.user.name if thing.user else ''}" />
|
||||
%endif
|
||||
<input type="hidden" name="type" value="${thing.permissions_type}">
|
||||
<input type="hidden" name="permissions"
|
||||
value="${thing.permissions.dumps() if thing.permissions else '+all'}">
|
||||
%if not thing.embedded:
|
||||
${error_field("USER_DOESNT_EXIST", "name")}
|
||||
${error_field("NO_USER", "name")}
|
||||
%endif
|
||||
${error_field("INVALID_PERMISSION_TYPE", "type")}
|
||||
${error_field("INVALID_PERMISSIONS", "permissions")}
|
||||
%if not thing.embedded:
|
||||
<span class="status"></span>
|
||||
%endif
|
||||
</%def>
|
||||
|
||||
<div class="permissions">
|
||||
%if thing.embedded:
|
||||
${form_content()}
|
||||
%else:
|
||||
<form action="/post/setpermissions" method="post"
|
||||
class="setpermissions pretty-form medium-text"
|
||||
onsubmit="return post_form(this, 'setpermissions')">
|
||||
${form_content()}
|
||||
<button type="submit">${_('save')}</button>
|
||||
</form>
|
||||
%endif
|
||||
<div class="permission-summary">
|
||||
</div>
|
||||
</div>
|
||||
@@ -24,6 +24,8 @@
|
||||
<% from r2.lib.template_helpers import static %>
|
||||
|
||||
<%def name="add_form(title, dest, add_type, container_name, verb=None)">
|
||||
<% from r2.models import ModeratorPermissionSet %>
|
||||
<% from r2.lib.pages import ModeratorPermissions %>
|
||||
<form action="/post/${dest}"
|
||||
method="post" class="pretty-form medium-text"
|
||||
onsubmit="return post_form(this, '${dest}')"
|
||||
@@ -34,6 +36,15 @@
|
||||
<input type="hidden" name="container" value="${container_name}">
|
||||
<input type="hidden" name="type" value="${add_type}">
|
||||
<input type="text" name="name" id="name">
|
||||
%if add_type == "moderator_invite":
|
||||
${ModeratorPermissions(None, 'moderator',
|
||||
ModeratorPermissionSet(all=True),
|
||||
editable=True, embedded=True)}
|
||||
 
|
||||
<span class="permissions-edit">
|
||||
(<a href="javascript:void(0)">${_('change')}</a>)
|
||||
</span>
|
||||
%endif
|
||||
<button class="btn" type="submit">${verb or _("add")}</button>
|
||||
<span class="status"></span>
|
||||
${error_field("USER_DOESNT_EXIST", "name")}
|
||||
|
||||
@@ -75,5 +75,13 @@
|
||||
<span title="${thing.rel._date.strftime('%Y-%m-%d %H:%M:%S')}">
|
||||
${timesince(thing.rel._date)}
|
||||
</span>
|
||||
%elif thing.name == "permissions":
|
||||
${thing.rel}
|
||||
%elif thing.name == "permissionsctl":
|
||||
%if thing.editable:
|
||||
<span class="permissions-edit">
|
||||
(<a href="javascript:void(0)">${_('change')}</a>)
|
||||
</span>
|
||||
%endif
|
||||
%endif
|
||||
</%def>
|
||||
|
||||
Reference in New Issue
Block a user