mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-04-27 03:00:12 -04:00
/about: Paginate banned and contibutors.
This commit is contained in:
@@ -160,6 +160,9 @@ def make_map():
|
||||
connect('/about/:location', controller='front',
|
||||
action='spamlisting',
|
||||
requirements=dict(location='reports|spam|modqueue|unmoderated'))
|
||||
connect('/about/:where', controller='userlistlisting',
|
||||
requirements=dict(where='contributors|banned|wikibanned|wikicontributors|moderators'),
|
||||
action='listing')
|
||||
connect('/about/:location', controller='front', action='editreddit',
|
||||
location='about')
|
||||
connect('/comments', controller='comments', action='listing')
|
||||
@@ -175,6 +178,8 @@ def make_map():
|
||||
mc('/t/:timereddit/*rest', controller='redirect',
|
||||
action='timereddit_redirect')
|
||||
|
||||
mc('/prefs/:where', controller='userlistlisting',
|
||||
action='listing', requirements=dict(where='blocked|friends'))
|
||||
mc('/prefs/:location', controller='forms', action='prefs',
|
||||
location='options')
|
||||
|
||||
|
||||
@@ -45,11 +45,7 @@ api('morechildren', MoreCommentJsonTemplate)
|
||||
api('reddit', RedditJsonTemplate)
|
||||
api('panestack', PanestackJsonTemplate)
|
||||
api('listing', ListingJsonTemplate)
|
||||
api('modlist', UserListJsonTemplate)
|
||||
api('userlist', UserListJsonTemplate)
|
||||
api('contributorlist', UserListJsonTemplate)
|
||||
api('bannedlist', UserListJsonTemplate)
|
||||
api('friendlist', UserListJsonTemplate)
|
||||
api('userlisting', UserListingJsonTemplate)
|
||||
api('usertableitem', UserTableItemJsonTemplate)
|
||||
api('account', AccountJsonTemplate)
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ def load_controllers():
|
||||
from listingcontroller import NewController
|
||||
from listingcontroller import RisingController
|
||||
from listingcontroller import BrowseController
|
||||
from listingcontroller import UserListListingController
|
||||
from listingcontroller import MessageController
|
||||
from listingcontroller import RedditsController
|
||||
from listingcontroller import ByIDController
|
||||
|
||||
@@ -44,13 +44,21 @@ from r2.lib import hooks
|
||||
from r2.lib.utils import get_title, sanitize_url, timeuntil, set_last_modified
|
||||
from r2.lib.utils import query_string, timefromnow, randstr
|
||||
from r2.lib.utils import timeago, tup
|
||||
from r2.lib.pages import (EnemyList, FriendList, ContributorList, ModList,
|
||||
BannedList, WikiBannedList, WikiMayContributeList,
|
||||
BoringPage, FormPage, CssError, UploadedImage,
|
||||
from r2.lib.pages import (BoringPage, FormPage, CssError, UploadedImage,
|
||||
ClickGadget, UrlParser, WrappedUser)
|
||||
from r2.lib.pages import FlairList, FlairCsv, FlairTemplateEditor, \
|
||||
FlairSelector
|
||||
from r2.lib.pages import PrefApps
|
||||
from r2.lib.pages import (
|
||||
BannedTableItem,
|
||||
ContributorTableItem,
|
||||
FriendTableItem,
|
||||
InvitedModTableItem,
|
||||
ModTableItem,
|
||||
WikiBannedTableItem,
|
||||
WikiMayContributeTableItem,
|
||||
)
|
||||
|
||||
from r2.lib.pages.things import (
|
||||
default_thing_wrapper,
|
||||
hot_links_by_url_listing,
|
||||
@@ -866,22 +874,28 @@ class ApiController(RedditController):
|
||||
if type in ('banned', 'wikibanned'):
|
||||
container.add_rel_note(type, friend, note)
|
||||
|
||||
cls = dict(friend=FriendList,
|
||||
moderator=ModList,
|
||||
moderator_invite=ModList,
|
||||
contributor=ContributorList,
|
||||
wikicontributor=WikiMayContributeList,
|
||||
banned=BannedList, wikibanned=WikiBannedList).get(type)
|
||||
userlist = cls()
|
||||
row_cls = dict(friend=FriendTableItem,
|
||||
moderator=ModTableItem,
|
||||
moderator_invite=InvitedModTableItem,
|
||||
contributor=ContributorTableItem,
|
||||
wikicontributor=WikiMayContributeTableItem,
|
||||
banned=BannedTableItem,
|
||||
wikibanned=WikiBannedTableItem).get(type)
|
||||
|
||||
form.set_inputs(name = "")
|
||||
if note:
|
||||
form.set_inputs(note = "")
|
||||
form.removeClass("edited")
|
||||
form.set_html(".status:first", userlist.executed_message(type))
|
||||
if new and cls:
|
||||
user_row = userlist.user_row(type, friend)
|
||||
jquery("." + type + "-table").show(
|
||||
).find("table").insert_table_rows(user_row)
|
||||
|
||||
if new and row_cls:
|
||||
new._thing2 = friend
|
||||
user_row = row_cls(new)
|
||||
form.set_html(".status:first", user_row.executed_message)
|
||||
rev_types = ["moderator", "moderator_invite", "friend"]
|
||||
index = 0 if user_row.type not in rev_types else -1
|
||||
table = jquery("." + type + "-table").show().find("table")
|
||||
table.insert_table_rows(user_row, index=index)
|
||||
table.find(".notfound").hide()
|
||||
|
||||
if new:
|
||||
notify_user_added(type, c.user, friend, container)
|
||||
|
||||
@@ -651,42 +651,14 @@ class FrontController(RedditController):
|
||||
return pane
|
||||
|
||||
def _edit_normal_reddit(self, location, created):
|
||||
# moderator is either reddit's moderator or an 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))
|
||||
|
||||
if is_moderator_with_perms('config') and location == 'edit':
|
||||
if (location == 'edit' and
|
||||
(c.user_is_admin or c.site.is_moderator_with_perms(c.user, 'config'))):
|
||||
pane = PaneStack()
|
||||
if created == 'true':
|
||||
pane.append(InfoBar(message=strings.sr_created))
|
||||
c.allow_styles = True
|
||||
c.site = Subreddit._byID(c.site._id, data=True, stale=False)
|
||||
pane.append(CreateSubreddit(site=c.site))
|
||||
elif location == 'moderators':
|
||||
pane = ModList(editable=is_unlimited_moderator)
|
||||
elif is_moderator_with_perms('access') and location == 'banned':
|
||||
pane = BannedList(editable=is_moderator_with_perms('access'))
|
||||
elif is_moderator_with_perms('wiki') and location == 'wikibanned':
|
||||
pane = WikiBannedList(editable=is_moderator_with_perms('wiki'))
|
||||
elif (is_moderator_with_perms('wiki')
|
||||
and location == 'wikicontributors'):
|
||||
pane = WikiMayContributeList(
|
||||
editable=is_moderator_with_perms('wiki'))
|
||||
elif (location == 'contributors' and
|
||||
# On public reddits, only moderators can see the whitelist.
|
||||
# On private reddits, all contributors can see each other.
|
||||
(c.site.type != 'public' or
|
||||
(c.user_is_loggedin and
|
||||
(c.site.is_moderator_with_perms(c.user, 'access')
|
||||
or c.user_is_admin)))):
|
||||
pane = ContributorList(
|
||||
editable=is_moderator_with_perms('access'))
|
||||
elif (location == 'stylesheet'
|
||||
and c.site.can_change_stylesheet(c.user)
|
||||
and not g.css_killswitch):
|
||||
@@ -706,17 +678,14 @@ class FrontController(RedditController):
|
||||
c.site.stylesheet_contents)
|
||||
pane = SubredditStylesheetSource(stylesheet_contents=stylesheet)
|
||||
elif location == 'traffic' and (c.site.public_traffic or
|
||||
(is_moderator or c.user.employee)):
|
||||
(c.site.is_moderator(c.user) or c.user.employee)):
|
||||
pane = trafficpages.SubredditTraffic()
|
||||
elif (location == "about") and is_api():
|
||||
return self.redirect(add_sr('about.json'), code=301)
|
||||
else:
|
||||
return self.abort404()
|
||||
|
||||
is_wiki_action = location in ['wikibanned', 'wikicontributors']
|
||||
|
||||
return EditReddit(content=pane,
|
||||
show_wiki_actions=is_wiki_action,
|
||||
location=location,
|
||||
extension_handling=False).render()
|
||||
|
||||
@@ -1324,11 +1293,6 @@ class FormsController(RedditController):
|
||||
infotext = None
|
||||
if not location or location == 'options':
|
||||
content = PrefOptions(done=request.GET.get('done'))
|
||||
elif location == 'friends':
|
||||
content = PaneStack()
|
||||
infotext = strings.friends % Friends.path
|
||||
content.append(FriendList())
|
||||
content.append(EnemyList())
|
||||
elif location == 'update':
|
||||
if verified:
|
||||
infotext = strings.email_verified
|
||||
|
||||
@@ -29,7 +29,7 @@ from r2.config.extensions import is_api
|
||||
from r2.lib.pages import *
|
||||
from r2.lib.pages.things import wrap_links
|
||||
from r2.lib.menus import TimeMenu, SortMenu, RecSortMenu, ProfileSortMenu
|
||||
from r2.lib.menus import ControversyTimeMenu
|
||||
from r2.lib.menus import ControversyTimeMenu, menu
|
||||
from r2.lib.rising import get_rising
|
||||
from r2.lib.wrapped import Wrapped
|
||||
from r2.lib.normalized_hot import normalized_hot
|
||||
@@ -115,6 +115,7 @@ class ListingController(RedditController):
|
||||
show_chooser=self.show_chooser,
|
||||
nav_menus=self.menus,
|
||||
title=self.title(),
|
||||
infotext=self.infotext,
|
||||
robots=getattr(self, "robots", None),
|
||||
**self.render_params).render()
|
||||
|
||||
@@ -1129,6 +1130,209 @@ class CommentsController(ListingController):
|
||||
c.profilepage = True
|
||||
return ListingController.GET_listing(self, **env)
|
||||
|
||||
class UserListListingController(ListingController):
|
||||
builder_cls = UserListBuilder
|
||||
allow_stylesheets = False
|
||||
skip = False
|
||||
|
||||
@property
|
||||
def infotext(self):
|
||||
if self.where == 'friends':
|
||||
return strings.friends % Friends.path
|
||||
elif self.where == 'blocked':
|
||||
return _("To block a user click 'block user' below a message"
|
||||
" from a user you wish to block from messaging you.")
|
||||
|
||||
@property
|
||||
def render_params(self):
|
||||
params = {}
|
||||
is_wiki_action = self.where in ["wikibanned", "wikicontributors"]
|
||||
params["show_wiki_actions"] = is_wiki_action
|
||||
return params
|
||||
|
||||
@property
|
||||
def render_cls(self):
|
||||
if self.where in ["friends", "blocked"]:
|
||||
return PrefsPage
|
||||
return Reddit
|
||||
|
||||
def moderator_wrap(self, rel, invited=False):
|
||||
rel._permission_class = ModeratorPermissionSet
|
||||
cls = ModTableItem if not invited else InvitedModTableItem
|
||||
return cls(rel, editable=self.editable)
|
||||
|
||||
@property
|
||||
def builder_wrapper(self):
|
||||
if self.where == 'banned':
|
||||
cls = BannedTableItem
|
||||
elif self.where == 'moderators':
|
||||
return self.moderator_wrap
|
||||
elif self.where == 'wikibanned':
|
||||
cls = WikiBannedTableItem
|
||||
elif self.where == 'contributors':
|
||||
cls = ContributorTableItem
|
||||
elif self.where == 'wikicontributors':
|
||||
cls = WikiMayContributeTableItem
|
||||
elif self.where == 'friends':
|
||||
cls = FriendTableItem
|
||||
elif self.where == 'blocked':
|
||||
cls = EnemyTableItem
|
||||
return lambda rel : cls(rel, editable=self.editable)
|
||||
|
||||
def title(self):
|
||||
return menu[self.where]
|
||||
|
||||
def rel(self):
|
||||
if self.where in ['friends', 'blocked']:
|
||||
return Friend
|
||||
return SRMember
|
||||
|
||||
def name(self):
|
||||
return self._names.get(self.where)
|
||||
|
||||
_names = {
|
||||
'friends': 'friend',
|
||||
'blocked': 'enemy',
|
||||
'moderators': 'moderator',
|
||||
'contributors': 'contributor',
|
||||
'banned': 'banned',
|
||||
'wikibanned': 'wikibanned',
|
||||
'wikicontributors': 'wikicontributor',
|
||||
}
|
||||
|
||||
def query(self):
|
||||
rel = self.rel()
|
||||
if self.where in ["friends", "blocked"]:
|
||||
thing1_id = c.user._id
|
||||
else:
|
||||
thing1_id = c.site._id
|
||||
reversed_types = ["friends", "moderators", "blocked"]
|
||||
sort = desc if self.where not in reversed_types else asc
|
||||
q = rel._query(rel.c._thing1_id == thing1_id,
|
||||
rel.c._name == self.name(),
|
||||
sort=sort('_date'),
|
||||
data=True)
|
||||
if self.jump_to_val:
|
||||
thing2_id = self.user._id if self.user else None
|
||||
q._filter(rel.c._thing2_id == thing2_id)
|
||||
return q
|
||||
|
||||
def listing(self):
|
||||
listing = self.listing_cls(self.builder_obj,
|
||||
addable=self.editable,
|
||||
show_jump_to=self.show_jump_to,
|
||||
jump_to_value=self.jump_to_val,
|
||||
show_not_found=self.show_not_found,
|
||||
nextprev=self.paginated,
|
||||
has_add_form=self.editable)
|
||||
return listing.listing()
|
||||
|
||||
def invited_mod_listing(self):
|
||||
query = SRMember._query(SRMember.c._name == 'moderator_invite',
|
||||
SRMember.c._thing1_id == c.site._id,
|
||||
sort=asc('_date'), data=True)
|
||||
wrapper = lambda rel: self.moderator_wrap(rel, invited=True)
|
||||
b = self.builder_cls(query,
|
||||
keep_fn=self.keep_fn(),
|
||||
wrap=wrapper,
|
||||
skip=False,
|
||||
num=0)
|
||||
return InvitedModListing(b, nextprev=False).listing()
|
||||
|
||||
def content(self):
|
||||
is_api = c.render_style in extensions.API_TYPES
|
||||
if self.where == 'moderators' and self.editable and not is_api:
|
||||
# Do not stack the invited mod list in api mode
|
||||
# to allow for api compatibility with older api users.
|
||||
content = PaneStack()
|
||||
content.append(self.listing_obj)
|
||||
content.append(self.invited_mod_listing())
|
||||
elif self.where == 'friends' and is_api:
|
||||
content = PaneStack()
|
||||
content.append(self.listing_obj)
|
||||
empty_builder = IDBuilder([])
|
||||
# Append an empty UserList on the api for backwards
|
||||
# compatibility with the old blocked list.
|
||||
content.append(UserListing(empty_builder, nextprev=False).listing())
|
||||
else:
|
||||
content = self.listing_obj
|
||||
return content
|
||||
|
||||
@require_oauth2_scope("read")
|
||||
@validate(user=VAccountByName('user'))
|
||||
@base_listing
|
||||
def GET_listing(self, where, user=None, **kw):
|
||||
allow_on_fake_sr = ["blocked", "friends"]
|
||||
if isinstance(c.site, FakeSubreddit) and not where in allow_on_fake_sr:
|
||||
return self.abort404()
|
||||
|
||||
self.where = where
|
||||
|
||||
has_mod_access = ((c.user_is_loggedin and
|
||||
c.site.is_moderator_with_perms(c.user, 'access'))
|
||||
or c.user_is_admin)
|
||||
|
||||
if not c.user_is_loggedin and where not in ['contributors', 'moderators']:
|
||||
abort(403)
|
||||
|
||||
self.listing_cls = None
|
||||
self.editable = True
|
||||
self.paginated = True
|
||||
self.jump_to_val = request.GET.get('user')
|
||||
self.show_not_found = bool(self.jump_to_val)
|
||||
|
||||
if where == 'contributors':
|
||||
# On public reddits, only moderators may see the whitelist.
|
||||
if c.site.type == 'public' and not has_mod_access:
|
||||
abort(403)
|
||||
# Used for subreddits like /r/lounge
|
||||
if c.site.hide_subscribers:
|
||||
abort(403)
|
||||
self.listing_cls = ContributorListing
|
||||
self.editable = has_mod_access
|
||||
|
||||
elif where == 'banned':
|
||||
if not has_mod_access:
|
||||
abort(403)
|
||||
self.listing_cls = BannedListing
|
||||
|
||||
elif where == 'wikibanned':
|
||||
if not c.site.is_moderator_with_perms(c.user, 'wiki'):
|
||||
abort(403)
|
||||
self.listing_cls = WikiBannedListing
|
||||
|
||||
elif where == 'wikicontributors':
|
||||
if not c.site.is_moderator_with_perms(c.user, 'wiki'):
|
||||
abort(403)
|
||||
self.listing_cls = WikiMayContributeListing
|
||||
|
||||
elif where == 'moderators':
|
||||
self.editable = ((c.user_is_loggedin and
|
||||
c.site.is_unlimited_moderator(c.user)) or
|
||||
c.user_is_admin)
|
||||
self.listing_cls = ModListing
|
||||
self.paginated = False
|
||||
|
||||
elif where == 'friends':
|
||||
self.listing_cls = FriendListing
|
||||
self.paginated = False
|
||||
|
||||
elif where == 'blocked':
|
||||
self.listing_cls = EnemyListing
|
||||
self.paginated = False
|
||||
self.show_not_found = True
|
||||
|
||||
if not self.listing_cls:
|
||||
abort(404)
|
||||
|
||||
self.user = user
|
||||
self.show_jump_to = self.paginated
|
||||
|
||||
if not self.paginated:
|
||||
kw['num'] = 0
|
||||
|
||||
check_cheating('site')
|
||||
return self.build_listing(**kw)
|
||||
|
||||
class GildedController(ListingController):
|
||||
title_text = _("gilded comments")
|
||||
|
||||
@@ -688,6 +688,15 @@ class ListingJsonTemplate(ThingJsonTemplate):
|
||||
def kind(self, wrapped):
|
||||
return "Listing"
|
||||
|
||||
class UserListingJsonTemplate(ListingJsonTemplate):
|
||||
def raw_data(self, thing):
|
||||
if not thing.nextprev:
|
||||
return {"children": self.rendered_data(thing)}
|
||||
return ListingJsonTemplate.raw_data(self, thing)
|
||||
|
||||
def kind(self, wrapped):
|
||||
return "Listing" if wrapped.nextprev else "UserList"
|
||||
|
||||
class UserListJsonTemplate(ThingJsonTemplate):
|
||||
_data_attrs_ = dict(
|
||||
children="users",
|
||||
@@ -722,7 +731,7 @@ class UserTableItemJsonTemplate(ThingJsonTemplate):
|
||||
(c.user.gold and thing.type == "friend")):
|
||||
d["note"] = getattr(thing.rel, 'note', '')
|
||||
if thing.type == "moderator":
|
||||
permissions = thing.rel.permissions.iteritems()
|
||||
permissions = thing.permissions.items()
|
||||
d["mod_permissions"] = [perm for perm, has in permissions if has]
|
||||
return d
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ menu = MenuHandler(hot = _('hot'),
|
||||
apps = _("apps"),
|
||||
feeds = _("RSS feeds"),
|
||||
friends = _("friends"),
|
||||
blocked = _("blocked"),
|
||||
update = _("password/email"),
|
||||
delete = _("delete"),
|
||||
otp = _("two-factor authentication"),
|
||||
|
||||
@@ -866,10 +866,10 @@ class PrefsPage(Reddit):
|
||||
|
||||
extension_handling = False
|
||||
|
||||
def __init__(self, show_sidebar = False, *a, **kw):
|
||||
def __init__(self, show_sidebar = False, title=None, *a, **kw):
|
||||
title = title or "%s (%s)" % (_("preferences"), c.site.name.strip(' '))
|
||||
Reddit.__init__(self, show_sidebar = show_sidebar,
|
||||
title = "%s (%s)" %(_("preferences"),
|
||||
c.site.name.strip(' ')),
|
||||
title=title,
|
||||
*a, **kw)
|
||||
|
||||
def build_toolbars(self):
|
||||
@@ -880,6 +880,7 @@ class PrefsPage(Reddit):
|
||||
buttons.append(NamedButton('feeds'))
|
||||
|
||||
buttons.extend([NamedButton('friends'),
|
||||
NamedButton('blocked'),
|
||||
NamedButton('update')])
|
||||
|
||||
if c.user_is_loggedin and c.user.name in g.admins:
|
||||
@@ -2908,27 +2909,117 @@ class WrappedUser(CachedTemplate):
|
||||
fullname = user._fullname,
|
||||
user_deleted = user._deleted)
|
||||
|
||||
# Classes for dealing with friend/moderator/contributor/banned lists
|
||||
|
||||
|
||||
class UserTableItem(Templated):
|
||||
"""A single row in a UserList of type 'type' and of name
|
||||
'container_name' for a given user. The provided list of 'cells'
|
||||
will determine what order the different columns are rendered in."""
|
||||
def __init__(self, user, type, cellnames, container_name, editable,
|
||||
remove_action, rel=None):
|
||||
type = ''
|
||||
remove_action = 'unfriend'
|
||||
cells = ('user', 'sendmessage', 'remove')
|
||||
|
||||
@property
|
||||
def executed_message(self):
|
||||
return _("added")
|
||||
|
||||
def __init__(self, user, editable=True, **kw):
|
||||
self.user = user
|
||||
self.type = type
|
||||
self.cells = cellnames
|
||||
self.rel = rel
|
||||
self.container_name = container_name
|
||||
self.editable = editable
|
||||
self.remove_action = remove_action
|
||||
Templated.__init__(self)
|
||||
self.editable = editable
|
||||
Templated.__init__(self, **kw)
|
||||
|
||||
def __repr__(self):
|
||||
return '<UserTableItem "%s">' % self.user.name
|
||||
|
||||
class TrafficTableItem(UserTableItem):
|
||||
type = "traffic_viewer"
|
||||
remove_action = "rm_traffic_viewer"
|
||||
|
||||
@property
|
||||
def container_name(self):
|
||||
return self.link._fullname
|
||||
|
||||
class RelTableItem(UserTableItem):
|
||||
def __init__(self, rel, **kw):
|
||||
self._id = rel._id
|
||||
self.rel = rel
|
||||
UserTableItem.__init__(self, rel._thing2, **kw)
|
||||
|
||||
@property
|
||||
def container_name(self):
|
||||
return c.site._fullname
|
||||
|
||||
class FriendTableItem(RelTableItem):
|
||||
type = 'friend'
|
||||
|
||||
@property
|
||||
def cells(self):
|
||||
if c.user.gold:
|
||||
return ('user', 'sendmessage', 'note', 'age', 'remove')
|
||||
return ('user', 'sendmessage', 'remove')
|
||||
|
||||
@property
|
||||
def container_name(self):
|
||||
return c.user._fullname
|
||||
|
||||
class EnemyTableItem(RelTableItem):
|
||||
type = 'enemy'
|
||||
cells = ('user', 'remove')
|
||||
|
||||
@property
|
||||
def container_name(self):
|
||||
return c.user._fullname
|
||||
|
||||
class BannedTableItem(RelTableItem):
|
||||
type = 'banned'
|
||||
cells = ('user', 'sendmessage', 'remove', 'note')
|
||||
|
||||
@property
|
||||
def executed_message(self):
|
||||
return _("banned")
|
||||
|
||||
class WikiBannedTableItem(BannedTableItem):
|
||||
type = 'wikibanned'
|
||||
|
||||
class ContributorTableItem(RelTableItem):
|
||||
type = 'contributor'
|
||||
|
||||
class WikiMayContributeTableItem(RelTableItem):
|
||||
type = 'wikicontributor'
|
||||
|
||||
class InvitedModTableItem(RelTableItem):
|
||||
type = 'moderator_invite'
|
||||
cells = ('user', 'permissions', 'permissionsctl')
|
||||
|
||||
@property
|
||||
def executed_message(self):
|
||||
return _("invited")
|
||||
|
||||
def is_editable(self, user):
|
||||
if not c.user_is_loggedin:
|
||||
return False
|
||||
elif c.user_is_admin:
|
||||
return True
|
||||
return c.site.is_unlimited_moderator(c.user)
|
||||
|
||||
def __init__(self, rel, editable=True, **kw):
|
||||
if editable:
|
||||
self.cells += ('remove',)
|
||||
editable = self.is_editable(rel._thing2)
|
||||
self.permissions = ModeratorPermissions(rel._thing2, self.type,
|
||||
rel.get_permissions(),
|
||||
editable=editable)
|
||||
RelTableItem.__init__(self, rel, editable=editable, **kw)
|
||||
|
||||
class ModTableItem(InvitedModTableItem):
|
||||
type = 'moderator'
|
||||
|
||||
@property
|
||||
def executed_message(self):
|
||||
return _("added")
|
||||
|
||||
def is_editable(self, user):
|
||||
if not c.user_is_loggedin:
|
||||
return False
|
||||
elif c.user_is_admin:
|
||||
return True
|
||||
return c.user != user and c.site.can_demod(c.user, user)
|
||||
|
||||
class FlairPane(Templated):
|
||||
def __init__(self, num, after, reverse, name, user):
|
||||
# Make sure c.site isn't stale before rendering.
|
||||
@@ -3205,11 +3296,7 @@ class UserList(Templated):
|
||||
Templated.__init__(self)
|
||||
|
||||
def user_row(self, row_type, user, editable=True):
|
||||
"""Convenience method for constructing a UserTableItem
|
||||
instance of the user with type, container_name, etc. of this
|
||||
UserList instance"""
|
||||
return UserTableItem(user, row_type, self.cells, self.container_name,
|
||||
editable, self.remove_action)
|
||||
raise NotImplementedError
|
||||
|
||||
def _user_rows(self, row_type, uids, editable_fn=None):
|
||||
"""Generates a UserTableItem wrapped list of the Account
|
||||
@@ -3242,216 +3329,6 @@ class UserList(Templated):
|
||||
def executed_message(self, row_type):
|
||||
return _("added")
|
||||
|
||||
|
||||
class FriendList(UserList):
|
||||
"""Friend list on /pref/friends"""
|
||||
type = 'friend'
|
||||
|
||||
def __init__(self, editable = True):
|
||||
if c.user.gold:
|
||||
self.friend_rels = c.user.friend_rels()
|
||||
self.cells = ('user', 'sendmessage', 'note', 'age', 'remove')
|
||||
self._class = "gold-accent rounded"
|
||||
self.table_headers = (_('user'), '', _('note'), _('friendship'), '')
|
||||
|
||||
UserList.__init__(self)
|
||||
|
||||
@property
|
||||
def form_title(self):
|
||||
return _('add a friend')
|
||||
|
||||
@property
|
||||
def table_title(self):
|
||||
return _('your friends')
|
||||
|
||||
def user_ids(self):
|
||||
return c.user.friends
|
||||
|
||||
def user_row(self, row_type, user, editable=True):
|
||||
if not getattr(self, "friend_rels", None):
|
||||
return UserList.user_row(self, row_type, user, editable)
|
||||
else:
|
||||
rel = self.friend_rels[user._id]
|
||||
return UserTableItem(user, row_type, self.cells, self.container_name,
|
||||
editable, self.remove_action, rel)
|
||||
|
||||
@property
|
||||
def container_name(self):
|
||||
return c.user._fullname
|
||||
|
||||
|
||||
class EnemyList(UserList):
|
||||
"""Blacklist on /pref/friends"""
|
||||
type = 'enemy'
|
||||
cells = ('user', 'remove')
|
||||
|
||||
def __init__(self, editable=True, addable=False):
|
||||
UserList.__init__(self, editable, addable)
|
||||
|
||||
@property
|
||||
def table_title(self):
|
||||
return _('blocked users')
|
||||
|
||||
def user_ids(self):
|
||||
return c.user.enemies
|
||||
|
||||
@property
|
||||
def container_name(self):
|
||||
return c.user._fullname
|
||||
|
||||
|
||||
class ContributorList(UserList):
|
||||
"""Contributor list on a restricted/private reddit."""
|
||||
type = 'contributor'
|
||||
|
||||
@property
|
||||
def form_title(self):
|
||||
return _("add approved submitter")
|
||||
|
||||
@property
|
||||
def table_title(self):
|
||||
return _("approved submitters for %(reddit)s") % dict(reddit = c.site.name)
|
||||
|
||||
def user_ids(self):
|
||||
if c.site.hide_subscribers:
|
||||
return [] # /r/lounge has too many subscribers to load without timing out,
|
||||
# and besides, some people might not want this list to be so
|
||||
# easily accessible.
|
||||
else:
|
||||
return c.site.contributors
|
||||
|
||||
class ModList(UserList):
|
||||
"""Moderator list for a reddit."""
|
||||
type = 'moderator'
|
||||
invite_type = 'moderator_invite'
|
||||
invite_action = 'accept_moderator_invite'
|
||||
form_title = _('add moderator')
|
||||
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')
|
||||
if editable:
|
||||
self.cells += ('remove',)
|
||||
|
||||
@property
|
||||
def table_title(self):
|
||||
return _("moderators of /r/%(reddit)s") % {"reddit": c.site.name}
|
||||
|
||||
def executed_message(self, row_type):
|
||||
if row_type == "moderator_invite":
|
||||
return _("invited")
|
||||
else:
|
||||
return _("added")
|
||||
|
||||
@property
|
||||
def can_force_add(self):
|
||||
return c.user_is_admin
|
||||
|
||||
@property
|
||||
def can_remove_self(self):
|
||||
return c.user_is_loggedin and c.site.is_moderator(c.user)
|
||||
|
||||
@property
|
||||
def has_invite(self):
|
||||
return c.user_is_loggedin and c.site.is_moderator_invite(c.user)
|
||||
|
||||
def moderator_editable(self, user, row_type):
|
||||
if not c.user_is_loggedin:
|
||||
return False
|
||||
elif c.user_is_admin:
|
||||
return True
|
||||
elif row_type == self.type:
|
||||
return c.user != user and 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)
|
||||
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(),
|
||||
lambda u: self.moderator_editable(u, self.type))
|
||||
|
||||
@property
|
||||
def invited_user_rows(self):
|
||||
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 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"""
|
||||
type = 'banned'
|
||||
|
||||
def __init__(self, *k, **kw):
|
||||
UserList.__init__(self, *k, **kw)
|
||||
rels = getattr(c.site, 'each_%s' % self.type)
|
||||
self.rels = OrderedDict((rel._thing2_id, rel) for rel in rels(data=True))
|
||||
self.cells += ('note',)
|
||||
|
||||
def user_row(self, row_type, user, editable=True):
|
||||
rel = self.rels.get(user._id, None)
|
||||
return UserTableItem(user, row_type, self.cells, self.container_name,
|
||||
editable, self.remove_action, rel)
|
||||
|
||||
@property
|
||||
def form_title(self):
|
||||
return _('ban users')
|
||||
|
||||
@property
|
||||
def table_title(self):
|
||||
return _('banned users')
|
||||
|
||||
def user_ids(self):
|
||||
return self.rels.keys()
|
||||
|
||||
class WikiBannedList(BannedList):
|
||||
"""List of users banned from editing a given wiki"""
|
||||
type = 'wikibanned'
|
||||
|
||||
class WikiMayContributeList(UserList):
|
||||
"""List of users allowed to contribute to a given wiki"""
|
||||
type = 'wikicontributor'
|
||||
|
||||
@property
|
||||
def form_title(self):
|
||||
return _('add a wiki contributor')
|
||||
|
||||
@property
|
||||
def table_title(self):
|
||||
return _('wiki page contributors')
|
||||
|
||||
def user_ids(self):
|
||||
return c.site.wikicontributor
|
||||
|
||||
|
||||
class DetailsPage(LinkInfoPage):
|
||||
extension_handling= False
|
||||
|
||||
@@ -4337,6 +4214,9 @@ class ModeratorPermissions(Templated):
|
||||
Templated.__init__(self, permissions_type=permissions_type,
|
||||
editable=editable, embedded=embedded)
|
||||
|
||||
def items(self):
|
||||
return self.permissions.iteritems()
|
||||
|
||||
class ListingChooser(Templated):
|
||||
def __init__(self):
|
||||
Templated.__init__(self)
|
||||
|
||||
@@ -37,6 +37,7 @@ from r2.lib.db.sorts import epoch_seconds
|
||||
from r2.lib.menus import menu
|
||||
from r2.lib.menus import NavButton, NamedButton, PageNameNav, NavMenu
|
||||
from r2.lib.pages.pages import Reddit, TimeSeriesChart, UserList, TabbedPane
|
||||
from r2.lib.pages import TrafficTableItem
|
||||
from r2.lib.promote import cost_per_mille, cost_per_click
|
||||
from r2.lib.template_helpers import format_number
|
||||
from r2.lib.utils import Storage, to_date, timedelta_by_name
|
||||
@@ -764,6 +765,9 @@ class TrafficViewerList(UserList):
|
||||
def container_name(self):
|
||||
return self.link._fullname
|
||||
|
||||
def user_row(self, row_type, user, editable=True):
|
||||
return TrafficTableItem(user)
|
||||
|
||||
|
||||
class SubredditTrafficReport(Templated):
|
||||
def __init__(self):
|
||||
|
||||
@@ -737,3 +737,12 @@ class UserMessageBuilder(MessageBuilder):
|
||||
return conversation(self.user, self.parent)
|
||||
return user_messages(self.user)
|
||||
|
||||
class UserListBuilder(QueryBuilder):
|
||||
def thing_lookup(self, rels):
|
||||
accounts = Account._byID([rel._thing2_id for rel in rels], data=True)
|
||||
for rel in rels:
|
||||
rel._thing2 = accounts.get(rel._thing2_id)
|
||||
return rels
|
||||
|
||||
def wrap_items(self, rels):
|
||||
return [self.wrap(rel) for rel in rels]
|
||||
|
||||
@@ -26,6 +26,7 @@ from vote import *
|
||||
from report import *
|
||||
from subreddit import DefaultSR, AllSR, Frontpage
|
||||
from pylons import i18n, request, g
|
||||
from pylons.i18n import _
|
||||
|
||||
from r2.lib.wrapped import Wrapped
|
||||
from r2.lib import utils
|
||||
@@ -107,6 +108,156 @@ class ModActionListing(TableListing): pass
|
||||
|
||||
class WikiRevisionListing(TableListing): pass
|
||||
|
||||
class UserListing(TableListing):
|
||||
type = ''
|
||||
_class = ''
|
||||
title = ''
|
||||
form_title = ''
|
||||
destination = 'friend'
|
||||
has_add_form = True
|
||||
headers = None
|
||||
|
||||
def __init__(self,
|
||||
builder,
|
||||
show_jump_to=False,
|
||||
show_not_found=False,
|
||||
jump_to_value=None,
|
||||
addable=True, **kw):
|
||||
self.addable = addable
|
||||
self.show_not_found = show_not_found
|
||||
self.show_jump_to = show_jump_to
|
||||
self.jump_to_value = jump_to_value
|
||||
TableListing.__init__(self, builder, **kw)
|
||||
|
||||
@property
|
||||
def container_name(self):
|
||||
return c.site._fullname
|
||||
|
||||
class FriendListing(UserListing):
|
||||
type = 'friend'
|
||||
|
||||
@property
|
||||
def _class(self):
|
||||
return '' if not c.user.gold else 'gold-accent rounded'
|
||||
|
||||
@property
|
||||
def headers(self):
|
||||
if c.user.gold:
|
||||
return (_('user'), '', _('note'), _('friendship'), '')
|
||||
|
||||
@property
|
||||
def form_title(self):
|
||||
return _('add a friend')
|
||||
|
||||
@property
|
||||
def container_name(self):
|
||||
return c.user._fullname
|
||||
|
||||
|
||||
class EnemyListing(UserListing):
|
||||
type = 'enemy'
|
||||
has_add_form = False
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return _('blocked users')
|
||||
|
||||
@property
|
||||
def container_name(self):
|
||||
return c.user._fullname
|
||||
|
||||
class BannedListing(UserListing):
|
||||
type = 'banned'
|
||||
|
||||
@property
|
||||
def form_title(self):
|
||||
return _("ban users")
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return _("users banned from"
|
||||
" /r/%(subreddit)s") % dict(subreddit=c.site.name)
|
||||
|
||||
class WikiBannedListing(BannedListing):
|
||||
type = 'wikibanned'
|
||||
|
||||
@property
|
||||
def form_title(self):
|
||||
return _("ban wiki contibutors")
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return _("wiki contibutors banned from"
|
||||
" /r/%(subreddit)s") % dict(subreddit=c.site.name)
|
||||
|
||||
class ContributorListing(UserListing):
|
||||
type = 'contributor'
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return _("approved submitters for"
|
||||
" /r/%(subreddit)s") % dict(subreddit=c.site.name)
|
||||
|
||||
@property
|
||||
def form_title(self):
|
||||
return _("add approved submitter")
|
||||
|
||||
class WikiMayContributeListing(ContributorListing):
|
||||
type = 'wikicontributor'
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return _("approved wiki contributors"
|
||||
" for /r/%(subreddit)s") % dict(subreddit=c.site.name)
|
||||
|
||||
@property
|
||||
def form_title(self):
|
||||
return _("add approved wiki contributor")
|
||||
|
||||
class InvitedModListing(UserListing):
|
||||
type = 'moderator_invite'
|
||||
form_title = _('invite moderator')
|
||||
remove_self_title = _('you are a moderator of this subreddit. %(action)s')
|
||||
|
||||
def sort_moderators(self, items):
|
||||
items = [(item, item.rel.get_permissions()) for item in items]
|
||||
for item, permissions in items:
|
||||
if permissions is None or permissions.is_superuser():
|
||||
yield item
|
||||
for item, permissions in items:
|
||||
if permissions is not None and not permissions.is_superuser():
|
||||
yield item
|
||||
|
||||
def get_items(self, **kw):
|
||||
things, prev, next, bcount, acount = UserListing.get_items(self, **kw)
|
||||
things = list(self.sort_moderators(things))
|
||||
return things, prev, next, bcount, acount
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return _("invited moderators for"
|
||||
" %(subreddit)s") % dict(subreddit=c.site.name)
|
||||
|
||||
class ModListing(InvitedModListing):
|
||||
type = 'moderator'
|
||||
form_title = _('force add moderator')
|
||||
|
||||
@property
|
||||
def has_add_form(self):
|
||||
return c.user_is_admin
|
||||
|
||||
@property
|
||||
def can_remove_self(self):
|
||||
return c.user_is_loggedin and c.site.is_moderator(c.user)
|
||||
|
||||
@property
|
||||
def has_invite(self):
|
||||
return c.user_is_loggedin and c.site.is_moderator_invite(c.user)
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return _("moderators of /r/%(subreddit)s") % dict(subreddit=c.site.name)
|
||||
|
||||
class LinkListing(Listing):
|
||||
def __init__(self, *a, **kw):
|
||||
Listing.__init__(self, *a, **kw)
|
||||
|
||||
@@ -8231,6 +8231,16 @@ body.with-listing-chooser {
|
||||
}
|
||||
}
|
||||
|
||||
.user-jumped-to {
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border: 1px solid #DDF;
|
||||
display: inline-block;
|
||||
margin-top: 10px;
|
||||
padding: 10px 15px;
|
||||
background-color: #EEF;
|
||||
}
|
||||
|
||||
.submit_text {
|
||||
display: none;
|
||||
max-height: 250px;
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
###############################################################################
|
||||
|
||||
<%namespace file="printablebuttons.html" import="ynbutton" />
|
||||
<%namespace file="userlist.html" import="add_form, userlist"/>
|
||||
<%namespace file="userlisting.html" import="add_form, listing"/>
|
||||
<%namespace file="utils.html" import="error_field"/>
|
||||
|
||||
<div class="${thing._class} usertable">
|
||||
%if thing.can_remove_self:
|
||||
${ynbutton(op=thing.remove_action,
|
||||
${ynbutton(op='unfriend',
|
||||
title=_("leave"),
|
||||
executed=_("you are no longer a moderator"),
|
||||
question=_("stop being a moderator?"),
|
||||
@@ -40,7 +40,7 @@
|
||||
%endif
|
||||
|
||||
%if thing.has_invite:
|
||||
${ynbutton(op=thing.invite_action,
|
||||
${ynbutton(op='accept_moderator_invite',
|
||||
title=_("accept"),
|
||||
executed=_("you are now a moderator. welcome to the team!"),
|
||||
question=_("become a moderator of %s?" % ("/r/" + c.site.name)),
|
||||
@@ -49,16 +49,10 @@
|
||||
_class=thing.type + ' accept-invite')}
|
||||
%endif
|
||||
|
||||
%if thing.can_force_add:
|
||||
${add_form(thing.form_title, thing.destination, thing.type, thing.container_name)}
|
||||
%endif
|
||||
%if thing.addable:
|
||||
<%call expr="add_form(thing.invite_form_title, thing.destination, thing.invite_type, thing.container_name, verb=_('invite'))">
|
||||
%if thing.addable and thing.has_add_form:
|
||||
<%call expr="add_form(thing.form_title, thing.destination, thing.type, thing.container_name, verb=_('add'))">
|
||||
${error_field("ALREADY_MODERATOR", "name")}
|
||||
</%call>
|
||||
%endif
|
||||
%if thing.editable:
|
||||
${userlist(_("pending invitations"), thing.invite_type, thing.invited_user_rows, thing.table_headers)}
|
||||
%endif
|
||||
${userlist(thing.table_title, thing.type, thing.user_rows, thing.table_headers)}
|
||||
${listing()}
|
||||
</div>
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<%!
|
||||
from r2.lib.strings import strings, Score
|
||||
from r2.lib.pages import WrappedUser, ModList, UserText
|
||||
from r2.lib.pages import WrappedUser, UserText
|
||||
%>
|
||||
|
||||
<%namespace file="utils.html" import="plain_link, thing_timestamp, text_with_links"/>
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
|
||||
<%!
|
||||
from r2.lib.strings import strings, Score
|
||||
from r2.lib.pages import WrappedUser, ModList, SubscribeButton
|
||||
from r2.lib.pages import WrappedUser, SubscribeButton
|
||||
from r2.models.listing import ModListing
|
||||
%>
|
||||
|
||||
<%namespace file="utils.html" import="plain_link, thing_timestamp, text_with_links"/>
|
||||
@@ -41,7 +42,7 @@
|
||||
|
||||
%if thing.sr.moderator:
|
||||
<div class="leavemoderator">
|
||||
${text_with_links(ModList.remove_self_title % dict(action='(%(action)s)'),
|
||||
${text_with_links(ModListing.remove_self_title % dict(action='(%(action)s)'),
|
||||
_sr_path=True,
|
||||
action=dict(
|
||||
## TRANSLATORS: this label links to the edit moderators page.
|
||||
|
||||
138
r2/r2/templates/userlisting.html
Normal file
138
r2/r2/templates/userlisting.html
Normal file
@@ -0,0 +1,138 @@
|
||||
## 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-2013
|
||||
## reddit Inc. All Rights Reserved.
|
||||
###############################################################################
|
||||
|
||||
<%!
|
||||
from r2.models import Sub
|
||||
%>
|
||||
<%namespace file="utils.html" import="error_field, plain_link" />
|
||||
|
||||
<%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 friend-add"
|
||||
onsubmit="return post_form(this, '${dest}')"
|
||||
id="${add_type}">
|
||||
<h1>${title}</h1>
|
||||
|
||||
<input type="hidden" name="action" value="add">
|
||||
<input type="hidden" name="container" value="${container_name}">
|
||||
<input type="hidden" name="type" value="${add_type}">
|
||||
%if add_type in ("banned", "wikibanned"):
|
||||
<label for="name">${_('who to ban?')} </label>
|
||||
<input type="text" onfocus="$(this).parent('form').addClass('edited')" class="friend-name" name="name" id="name">
|
||||
<span class="ban-reason">
|
||||
<label for="note">${_('why the ban?')}</label>
|
||||
<input type="text" maxlength="300" name="note" id="note">
|
||||
<span>${_('(will not be visible to user)')}</span>
|
||||
</span>
|
||||
%else:
|
||||
<input type="text" name="name" id="name">
|
||||
%endif
|
||||
%if add_type == "moderator_invite":
|
||||
${ModeratorPermissions(None, 'moderator_invite',
|
||||
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")}
|
||||
%if caller:
|
||||
${caller.body()}
|
||||
%endif
|
||||
</form>
|
||||
</%def>
|
||||
|
||||
<%def name="listing()">
|
||||
<div class="${thing.type}-table"
|
||||
style="${'display:none' if not thing.things and not thing.show_not_found else ''}">
|
||||
<h1>
|
||||
${thing.title}
|
||||
</h1>
|
||||
|
||||
<table>
|
||||
%if thing.headers:
|
||||
<tr>
|
||||
%for header in thing.headers:
|
||||
<th>${header}</th>
|
||||
%endfor
|
||||
</tr>
|
||||
%endif
|
||||
%if thing.things:
|
||||
%for item in thing.things:
|
||||
${item}
|
||||
%endfor
|
||||
%else:
|
||||
<tr class="notfound"><td>${_('No items found') if thing.show_not_found else ''}</td></tr>
|
||||
%endif
|
||||
</table>
|
||||
</div>
|
||||
|
||||
%if thing.nextprev and (thing.prev or thing.next):
|
||||
<p class="nextprev"> ${_("view more:")} 
|
||||
%if thing.prev:
|
||||
${plain_link(_("first"), thing.first, _sr_path = (c.site != Sub), rel="nofollow first")}
|
||||
<span class="separator"></span>
|
||||
${plain_link(unsafe("‹ " + _("prev")), thing.prev, _sr_path = (c.site != Sub), rel="nofollow prev")}
|
||||
%endif
|
||||
%if thing.prev and thing.next:
|
||||
<span class="separator"></span>
|
||||
%endif
|
||||
%if thing.next:
|
||||
${plain_link(unsafe(_("next") + " ›"), thing.next, _sr_path = (c.site != Sub), rel="nofollow next")}
|
||||
%endif
|
||||
</p>
|
||||
%endif
|
||||
|
||||
</%def>
|
||||
|
||||
<div class="${thing._class} usertable">
|
||||
%if thing.addable and thing.has_add_form:
|
||||
${add_form(thing.form_title, thing.destination, thing.type, thing.container_name)}
|
||||
%endif
|
||||
|
||||
%if thing.show_jump_to:
|
||||
<h1>${_('jump to')}</h1>
|
||||
<form class="pretty-form medium-text">
|
||||
<label for="user">${_('username')} </label>
|
||||
<input type="text" id="user" name="user"
|
||||
%if thing.jump_to_value:
|
||||
value="${thing.jump_to_value}"
|
||||
%endif
|
||||
>
|
||||
<button type="submit">${_('go')}</button>
|
||||
</form>
|
||||
%endif
|
||||
|
||||
${listing()}
|
||||
|
||||
%if thing.jump_to_value:
|
||||
<p class="nextprev">
|
||||
${plain_link(_("show all"), request.path, rel="nofollow")}
|
||||
</p>
|
||||
%endif
|
||||
|
||||
</div>
|
||||
@@ -78,7 +78,7 @@
|
||||
${timesince(thing.rel._date)}
|
||||
</span>
|
||||
%elif thing.name == "permissions":
|
||||
${thing.rel}
|
||||
${thing.permissions}
|
||||
%elif thing.name == "permissionsctl":
|
||||
%if thing.editable:
|
||||
<span class="permissions-edit">
|
||||
|
||||
Reference in New Issue
Block a user