mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-04-05 03:00:15 -04:00
Change moderator adding to an invite system.
This commit is contained in:
@@ -456,7 +456,7 @@ comment_visits_period = 600
|
||||
agents =
|
||||
# subreddit ratelimits
|
||||
sr_banned_quota = 10000
|
||||
sr_moderator_quota = 10000
|
||||
sr_moderator_invite_quota = 10000
|
||||
sr_contributor_quota = 10000
|
||||
sr_wikibanned_quota = 10000
|
||||
sr_wikicontributor_quota = 10000
|
||||
|
||||
@@ -505,6 +505,7 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
|
||||
_sr_friend_types = (
|
||||
'moderator',
|
||||
'moderator_invite',
|
||||
'contributor',
|
||||
'banned',
|
||||
'wikibanned',
|
||||
@@ -553,6 +554,7 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
# Log this action
|
||||
if new and type in self._sr_friend_types:
|
||||
action = dict(banned='unbanuser', moderator='removemoderator',
|
||||
moderator_invite='uninvitemoderator',
|
||||
wikicontributor='removewikicontributor',
|
||||
wikibanned='wikiunbanned',
|
||||
contributor='removecontributor').get(type, None)
|
||||
@@ -584,6 +586,11 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
container = VByName('container').run(container)
|
||||
if not container:
|
||||
return
|
||||
|
||||
if type == "moderator" and not c.user_is_admin:
|
||||
# attempts to add moderators now create moderator invites.
|
||||
type = "moderator_invite"
|
||||
|
||||
fn = getattr(container, 'add_' + type)
|
||||
|
||||
# The user who made the request must be an admin or a moderator
|
||||
@@ -612,11 +619,21 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
elif form.has_errors("name", errors.USER_DOESNT_EXIST, errors.NO_USER):
|
||||
return
|
||||
|
||||
if type == "moderator_invite" and container.is_moderator(friend):
|
||||
c.errors.add(errors.ALREADY_MODERATOR, field="name")
|
||||
form.set_error(errors.ALREADY_MODERATOR, "name")
|
||||
return
|
||||
|
||||
if type == "moderator":
|
||||
container.remove_moderator_invite(friend)
|
||||
|
||||
new = fn(friend)
|
||||
|
||||
# Log this action
|
||||
if new and type in self._sr_friend_types:
|
||||
action = dict(banned='banuser', moderator='addmoderator',
|
||||
action = dict(banned='banuser',
|
||||
moderator='addmoderator',
|
||||
moderator_invite='invitemoderator',
|
||||
wikicontributor='wikicontributor',
|
||||
contributor='addcontributor',
|
||||
wikibanned='wikibanned').get(type, None)
|
||||
@@ -634,14 +651,16 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
|
||||
cls = dict(friend=FriendList,
|
||||
moderator=ModList,
|
||||
moderator_invite=ModList,
|
||||
contributor=ContributorList,
|
||||
wikicontributor=WikiMayContributeList,
|
||||
banned=BannedList, wikibanned=WikiBannedList).get(type)
|
||||
userlist = cls()
|
||||
form.set_inputs(name = "")
|
||||
form.set_html(".status:first", _("added"))
|
||||
form.set_html(".status:first", userlist.executed_message(type))
|
||||
if new and cls:
|
||||
user_row = cls().user_row(friend)
|
||||
jquery("#" + type + "-table").show(
|
||||
user_row = userlist.user_row(type, friend)
|
||||
jquery("." + type + "-table").show(
|
||||
).find("table").insert_table_rows(user_row)
|
||||
|
||||
if new:
|
||||
@@ -654,6 +673,20 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
c.user.add_friend_note(friend, note)
|
||||
form.set_html('.status', _("saved"))
|
||||
|
||||
@validatedForm(VUser(),
|
||||
VModhash(),
|
||||
ip=ValidIP())
|
||||
@api_doc(api_section.subreddits)
|
||||
def POST_accept_moderator_invite(self, form, jquery, ip):
|
||||
if not c.site.remove_moderator_invite(c.user):
|
||||
return
|
||||
|
||||
ModAction.create(c.site, c.user, "acceptmoderatorinvite")
|
||||
c.site.add_moderator(c.user)
|
||||
Subreddit.special_reddits(c.user, "moderator", _update=True)
|
||||
notify_user_added("accept_moderator_invite", c.user, c.user, c.site)
|
||||
jquery.refresh()
|
||||
|
||||
@validatedForm(VUser('curpass', default=''),
|
||||
VModhash(),
|
||||
password = VPassword(['curpass', 'curpass']),
|
||||
|
||||
@@ -109,6 +109,7 @@ error_list = dict((
|
||||
('DEVELOPER_ALREADY_ADDED', _('already added')),
|
||||
('TOO_MANY_DEVELOPERS', _('too many developers')),
|
||||
('BAD_HASH', _("i don't believe you.")),
|
||||
('ALREADY_MODERATOR', _('that user is already a moderator')),
|
||||
))
|
||||
errors = Storage([(e, e) for e in error_list.keys()])
|
||||
|
||||
|
||||
@@ -520,7 +520,7 @@ class UserListJsonTemplate(ThingJsonTemplate):
|
||||
def thing_attr(self, thing, attr):
|
||||
if attr == "users":
|
||||
res = []
|
||||
for a in thing.users:
|
||||
for a in thing.user_rows:
|
||||
r = a.render()
|
||||
res.append(r)
|
||||
return res
|
||||
|
||||
@@ -2788,53 +2788,57 @@ class UserList(Templated):
|
||||
"""base class for generating a list of users"""
|
||||
form_title = ''
|
||||
table_title = ''
|
||||
table_headers = None
|
||||
type = ''
|
||||
container_name = ''
|
||||
cells = ('user', 'sendmessage', 'remove')
|
||||
_class = ""
|
||||
destination = "friend"
|
||||
remove_action = "unfriend"
|
||||
editable_fn = None
|
||||
|
||||
def __init__(self, editable=True):
|
||||
self.editable = editable
|
||||
Templated.__init__(self)
|
||||
|
||||
def user_row(self, user):
|
||||
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"""
|
||||
editable = self.editable
|
||||
|
||||
if self.editable_fn and not self.editable_fn(user):
|
||||
editable = False
|
||||
|
||||
return UserTableItem(user, self.type, self.cells, self.container_name,
|
||||
return UserTableItem(user, row_type, self.cells, self.container_name,
|
||||
editable, self.remove_action)
|
||||
|
||||
@property
|
||||
def users(self, site = None):
|
||||
def _user_rows(self, row_type, uids, editable_fn=None):
|
||||
"""Generates a UserTableItem wrapped list of the Account
|
||||
objects which should be present in this UserList."""
|
||||
uids = self.user_ids()
|
||||
|
||||
if uids:
|
||||
users = Account._byID(uids, True, return_dict = False)
|
||||
return [self.user_row(u) for u in users]
|
||||
users = Account._byID(uids, True, return_dict = False)
|
||||
rows = []
|
||||
for u in users:
|
||||
editable = editable_fn(u) if editable_fn else self.editable
|
||||
rows.append(self.user_row(row_type, u, editable))
|
||||
return rows
|
||||
else:
|
||||
return []
|
||||
|
||||
@property
|
||||
def user_rows(self):
|
||||
return self._user_rows(self.type, self.user_ids())
|
||||
|
||||
def user_ids(self):
|
||||
"""virtual method for fetching the list of ids of the Accounts
|
||||
to be listing in this UserList instance"""
|
||||
raise NotImplementedError
|
||||
|
||||
def can_remove_self(self):
|
||||
return False
|
||||
|
||||
@property
|
||||
def container_name(self):
|
||||
return c.site._fullname
|
||||
|
||||
def executed_message(self, row_type):
|
||||
return _("added")
|
||||
|
||||
|
||||
class FriendList(UserList):
|
||||
"""Friend list on /pref/friends"""
|
||||
@@ -2860,13 +2864,13 @@ class FriendList(UserList):
|
||||
def user_ids(self):
|
||||
return c.user.friends
|
||||
|
||||
def user_row(self, user):
|
||||
def user_row(self, row_type, user, editable=True):
|
||||
if not getattr(self, "friend_rels", None):
|
||||
return UserList.user_row(self, user)
|
||||
return UserList.user_row(self, row_type, user, editable)
|
||||
else:
|
||||
rel = self.friend_rels[user._id]
|
||||
return UserTableItem(user, self.type, self.cells, self.container_name,
|
||||
True, self.remove_action, rel)
|
||||
return UserTableItem(user, row_type, self.cells, self.container_name,
|
||||
editable, self.remove_action, rel)
|
||||
|
||||
@property
|
||||
def container_name(self):
|
||||
@@ -2916,23 +2920,35 @@ class ContributorList(UserList):
|
||||
class ModList(UserList):
|
||||
"""Moderator list for a reddit."""
|
||||
type = 'moderator'
|
||||
remove_self_action = _('leave')
|
||||
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')
|
||||
remove_self_confirm = _('stop being a moderator?')
|
||||
remove_self_final = _('you are no longer a moderator')
|
||||
|
||||
@property
|
||||
def form_title(self):
|
||||
return _('add moderator')
|
||||
|
||||
@property
|
||||
def table_title(self):
|
||||
return _("moderators of %(reddit)s") % dict(reddit = c.site.name)
|
||||
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)
|
||||
|
||||
def editable_fn(self, user):
|
||||
@property
|
||||
def has_invite(self):
|
||||
return c.user_is_loggedin and c.site.is_moderator_invite(c.user)
|
||||
|
||||
def moderator_editable(self, user):
|
||||
if not c.user_is_loggedin:
|
||||
return False
|
||||
elif c.user_is_admin:
|
||||
@@ -2940,6 +2956,14 @@ class ModList(UserList):
|
||||
else:
|
||||
return c.site.can_demod(c.user, user)
|
||||
|
||||
@property
|
||||
def user_rows(self):
|
||||
return self._user_rows(self.type, self.user_ids(), self.moderator_editable)
|
||||
|
||||
@property
|
||||
def invited_user_rows(self):
|
||||
return self._user_rows(self.invite_type, c.site.moderator_invite_ids(), self.moderator_editable)
|
||||
|
||||
def user_ids(self):
|
||||
return c.site.moderators
|
||||
|
||||
|
||||
@@ -23,15 +23,27 @@
|
||||
from pylons import request
|
||||
from pylons.i18n import _
|
||||
|
||||
from r2.models import Message
|
||||
from r2.models import Account, Message
|
||||
from r2.lib.db import queries
|
||||
|
||||
|
||||
user_added_messages = {
|
||||
"moderator": {
|
||||
"moderator_invite": {
|
||||
"pm": {
|
||||
"subject": _("you are a moderator"),
|
||||
"msg": _("you have been added as a moderator to [%(title)s](%(url)s)."),
|
||||
"subject": _("invitation to moderate %(url)s"),
|
||||
"msg": _("**gadzooks! you are invited to become a moderator of [%(title)s](%(url)s)!**\n\n"
|
||||
"*to accept*, visit the [moderators page for %(url)s](%(url)s/about/moderators) and click \"accept\".\n\n"
|
||||
"*otherwise,* if you did not expect to receive this, you can simply ignore this invitation or report it."),
|
||||
},
|
||||
"modmail": {
|
||||
"subject": _("moderator invited"),
|
||||
"msg": _("%(user)s has been invited by %(author)s to moderate %(url)s."),
|
||||
},
|
||||
},
|
||||
"accept_moderator_invite": {
|
||||
"modmail": {
|
||||
"subject": _("moderator added"),
|
||||
"msg": _("%(user)s has accepted an invitation to become moderator of %(url)s."),
|
||||
},
|
||||
},
|
||||
"contributor": {
|
||||
@@ -71,10 +83,12 @@ def notify_user_added(rel_type, author, user, target):
|
||||
if "pm" in msgs and author != user:
|
||||
subject = msgs["pm"]["subject"] % d
|
||||
msg = msgs["pm"]["msg"] % d
|
||||
if rel_type == "banned":
|
||||
if not user.has_interacted_with(target):
|
||||
return
|
||||
|
||||
if rel_type == "banned" and not user.has_interacted_with(target):
|
||||
return
|
||||
|
||||
if rel_type in ("banned", "moderator_invite"):
|
||||
# send the message from the subreddit
|
||||
item, inbox_rel = Message._new(author, user, subject, msg, request.ip,
|
||||
sr=target, from_sr=True)
|
||||
else:
|
||||
@@ -85,6 +99,12 @@ def notify_user_added(rel_type, author, user, target):
|
||||
if "modmail" in msgs:
|
||||
subject = msgs["modmail"]["subject"] % d
|
||||
msg = msgs["modmail"]["msg"] % d
|
||||
item, inbox_rel = Message._new(author, target, subject, msg, request.ip,
|
||||
sr=target, from_sr=True)
|
||||
|
||||
if rel_type == "moderator_invite":
|
||||
modmail_author = Account.system_user()
|
||||
else:
|
||||
modmail_author = author
|
||||
|
||||
item, inbox_rel = Message._new(modmail_author, target, subject, msg,
|
||||
request.ip, sr=target)
|
||||
queries.new_message(item, inbox_rel)
|
||||
|
||||
@@ -49,6 +49,7 @@ class ModAction(tdb_cassandra.UuidThing, Printable):
|
||||
|
||||
actions = ('banuser', 'unbanuser', 'removelink', 'approvelink',
|
||||
'removecomment', 'approvecomment', 'addmoderator',
|
||||
'invitemoderator', 'uninvitemoderator', 'acceptmoderatorinvite',
|
||||
'removemoderator', 'addcontributor', 'removecontributor',
|
||||
'editsettings', 'editflair', 'distinguish', 'marknsfw',
|
||||
'wikibanned', 'wikicontributor', 'wikiunbanned',
|
||||
@@ -62,6 +63,9 @@ class ModAction(tdb_cassandra.UuidThing, Printable):
|
||||
'approvecomment': _('approve comment'),
|
||||
'addmoderator': _('add moderator'),
|
||||
'removemoderator': _('remove moderator'),
|
||||
'invitemoderator': _('invite moderator'),
|
||||
'uninvitemoderator': _('uninvite moderator'),
|
||||
'acceptmoderatorinvite': _('accept moderator invite'),
|
||||
'addcontributor': _('add contributor'),
|
||||
'removecontributor': _('remove contributor'),
|
||||
'editsettings': _('edit settings'),
|
||||
@@ -87,6 +91,9 @@ class ModAction(tdb_cassandra.UuidThing, Printable):
|
||||
'approvecomment': _('approved'),
|
||||
'addmoderator': _('added moderator'),
|
||||
'removemoderator': _('removed moderator'),
|
||||
'invitemoderator': _('invited moderator'),
|
||||
'uninvitemoderator': _('uninvited moderator'),
|
||||
'acceptmoderatorinvite': _('accepted moderator invitation'),
|
||||
'addcontributor': _('added approved contributor'),
|
||||
'removecontributor': _('removed approved contributor'),
|
||||
'editsettings': _('edited settings'),
|
||||
|
||||
@@ -427,8 +427,9 @@ class Subreddit(Thing, Printable):
|
||||
elif self.type in ('public', 'restricted', 'archived'):
|
||||
return True
|
||||
elif c.user_is_loggedin:
|
||||
#private requires contributorship
|
||||
return self.is_contributor(user) or self.is_moderator(user)
|
||||
return (self.is_contributor(user) or
|
||||
self.is_moderator(user) or
|
||||
self.is_moderator_invite(user))
|
||||
|
||||
def can_demod(self, bully, victim):
|
||||
# This works because the is_*() functions return the relation
|
||||
@@ -1225,6 +1226,7 @@ Subreddit._specials.update(dict(friends = Friends,
|
||||
class SRMember(Relation(Subreddit, Account)): pass
|
||||
Subreddit.__bases__ += (
|
||||
UserRel('moderator', SRMember),
|
||||
UserRel('moderator_invite', SRMember),
|
||||
UserRel('contributor', SRMember),
|
||||
UserRel('subscriber', SRMember, disable_ids_fn=True),
|
||||
UserRel('banned', SRMember),
|
||||
|
||||
BIN
r2/r2/public/static/addmoderator.png
Executable file
BIN
r2/r2/public/static/addmoderator.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 758 B |
@@ -4879,6 +4879,10 @@ dd { margin-left: 20px; }
|
||||
background-image: url(../shield.png); /* SPRITE */
|
||||
}
|
||||
|
||||
.moderator.accept-invite .main:before {
|
||||
background-image: url(../addmoderator.png); /* SPRITE */
|
||||
}
|
||||
|
||||
.titlebox form.leavecontributor-button:before {
|
||||
background-image: url(../pencil.png); /* SPRITE */
|
||||
}
|
||||
@@ -5670,6 +5674,9 @@ tr.gold-accent + tr > td {
|
||||
.modactions.approvecomment,
|
||||
.modactions.addmoderator,
|
||||
.modactions.removemoderator,
|
||||
.modactions.invitemoderator,
|
||||
.modactions.uninvitemoderator,
|
||||
.modactions.acceptmoderatorinvite,
|
||||
.modactions.addcontributor,
|
||||
.modactions.removecontributor,
|
||||
.modactions.editsettings,
|
||||
@@ -5701,10 +5708,13 @@ tr.gold-accent + tr > td {
|
||||
.modactions.approvecomment {
|
||||
background-image: url(../modactions_approvecomment.png); /* SPRITE */
|
||||
}
|
||||
.modactions.addmoderator {
|
||||
.modactions.addmoderator,
|
||||
.modactions.invitemoderator,
|
||||
.modactions.acceptmoderatorinvite {
|
||||
background-image: url(../modactions_addmoderator.png); /* SPRITE */
|
||||
}
|
||||
.modactions.removemoderator {
|
||||
.modactions.removemoderator,
|
||||
.modactions.uninvitemoderator {
|
||||
background-image: url(../modactions_removemoderator.png); /* SPRITE */
|
||||
}
|
||||
.modactions.addcontributor {
|
||||
|
||||
1
r2/r2/public/static/modactions_acceptmoderatorinvite.png
Symbolic link
1
r2/r2/public/static/modactions_acceptmoderatorinvite.png
Symbolic link
@@ -0,0 +1 @@
|
||||
addmoderator.png
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 758 B After Width: | Height: | Size: 16 B |
1
r2/r2/public/static/modactions_addmoderator.png
Symbolic link
1
r2/r2/public/static/modactions_addmoderator.png
Symbolic link
@@ -0,0 +1 @@
|
||||
addmoderator.png
|
||||
|
Before Width: | Height: | Size: 758 B After Width: | Height: | Size: 16 B |
64
r2/r2/templates/modlist.html
Normal file
64
r2/r2/templates/modlist.html
Normal file
@@ -0,0 +1,64 @@
|
||||
## 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="printablebuttons.html" import="ynbutton" />
|
||||
<%namespace file="userlist.html" import="add_form, userlist"/>
|
||||
<%namespace file="utils.html" import="error_field"/>
|
||||
|
||||
<div class="${thing._class} usertable">
|
||||
%if thing.can_remove_self:
|
||||
${ynbutton(op=thing.remove_action,
|
||||
title=_("leave"),
|
||||
executed=_("you are no longer a moderator"),
|
||||
question=_("stop being a moderator?"),
|
||||
format=_('you are a moderator of this subreddit. %(action)s'),
|
||||
format_arg='action',
|
||||
_class=thing.type + ' remove-self',
|
||||
hidden_data=dict(
|
||||
id=c.user._fullname,
|
||||
type=thing.type,
|
||||
container=thing.container_name))}
|
||||
%endif
|
||||
|
||||
%if thing.has_invite:
|
||||
${ynbutton(op=thing.invite_action,
|
||||
title=_("accept"),
|
||||
executed=_("you are now a moderator. welcome to the team!"),
|
||||
question=_("become a moderator of %s?" % ("/r/" + c.site.name)),
|
||||
format=_('you are invited to become a moderator. %(action)s'),
|
||||
format_arg='action',
|
||||
_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.editable:
|
||||
<%call expr="add_form(thing.invite_form_title, thing.destination, thing.invite_type, thing.container_name, verb=_('invite'))">
|
||||
${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)}
|
||||
</div>
|
||||
@@ -21,57 +21,44 @@
|
||||
###############################################################################
|
||||
|
||||
<%namespace file="utils.html" import="error_field"/>
|
||||
<%namespace file="printablebuttons.html" import="ynbutton" />
|
||||
<% from r2.lib.template_helpers import static %>
|
||||
|
||||
<div class="${thing._class} usertable">
|
||||
%if thing.can_remove_self():
|
||||
${ynbutton(op=thing.remove_action,
|
||||
title=thing.remove_self_action,
|
||||
executed=thing.remove_self_final,
|
||||
question=thing.remove_self_confirm,
|
||||
format=thing.remove_self_title,
|
||||
format_arg='action',
|
||||
_class=thing.type + ' remove-self',
|
||||
hidden_data=dict(
|
||||
id=c.user._fullname,
|
||||
type=thing.type,
|
||||
container=thing.container_name))}
|
||||
%endif
|
||||
<%def name="add_form(title, dest, add_type, container_name, verb=None)">
|
||||
<form action="/post/${dest}"
|
||||
method="post" class="pretty-form medium-text"
|
||||
onsubmit="return post_form(this, '${dest}')"
|
||||
id="${add_type}">
|
||||
<h1>${title}</h1>
|
||||
|
||||
%if thing.addable:
|
||||
<form action="/post/${thing.destination}"
|
||||
method="post" class="pretty-form medium-text"
|
||||
onsubmit="return post_form(this, '${thing.destination}');"
|
||||
id="${thing.type}">
|
||||
<h1>${thing.form_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}">
|
||||
<input type="text" name="name" id="name">
|
||||
<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>
|
||||
|
||||
<input type="hidden" name="action" value="add"/>
|
||||
<input type="hidden" name="container" value="${thing.container_name}"/>
|
||||
<input type="hidden" name="type" value="${thing.type}"/>
|
||||
<input type="text" name="name" id="name"/>
|
||||
<button class="btn" type="submit">${_("add")}</button>
|
||||
<span class="status"></span>
|
||||
${error_field("USER_DOESNT_EXIST", "name")}
|
||||
</form>
|
||||
%endif
|
||||
|
||||
<div id="${thing.type}-table"
|
||||
${"style='display:none'" if not thing.users else ""}>
|
||||
<h1>
|
||||
${thing.table_title}
|
||||
<%def name="userlist(title, row_type, rows, headers=None)">
|
||||
<div class="${row_type}-table">
|
||||
<h1>
|
||||
${title}
|
||||
</h1>
|
||||
|
||||
<table>
|
||||
%if getattr(thing, "table_headers", None):
|
||||
%if headers:
|
||||
<tr>
|
||||
%for header in thing.table_headers:
|
||||
%for header in headers:
|
||||
<th>${header}</th>
|
||||
%endfor
|
||||
</tr>
|
||||
%endif
|
||||
%if thing.users:
|
||||
%for item in thing.users:
|
||||
%if rows:
|
||||
%for item in rows:
|
||||
${item}
|
||||
%endfor
|
||||
%else:
|
||||
@@ -79,6 +66,12 @@
|
||||
%endif
|
||||
</table>
|
||||
</div>
|
||||
</%def>
|
||||
|
||||
<div class="${thing._class} usertable">
|
||||
%if thing.editable:
|
||||
${add_form(thing.form_title, thing.destination, thing.type, thing.container_name)}
|
||||
%endif
|
||||
|
||||
${userlist(thing.table_title, thing.type, thing.user_rows, thing.table_headers)}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user