def adminPrivilegesPost(handler, p_grant): handler.title("Privileges") requirePriv(handler, 'Admin') p_grant = {name: privs.keys() for name, privs in p_grant.iteritems()} privNames = set() for privs in p_grant.values(): privNames |= set(privs) if not privNames <= set(privList.keys()): ErrorBox.die("Update privileges", "Unrecognized privilege name") for user in User.loadAll(): for priv in privList: privs = p_grant.get(user.username, []) has = user.hasPrivilege(priv) if has and priv not in privs: print "Revoking %s from %s<br>" % (priv, user.username) user.privileges.remove(priv) Event.revokePrivilege(handler, user, priv) elif not has and priv in privs: print "Granting %s to %s<br>" % (priv, user.username) user.privileges.add(priv) Event.grantPrivilege(handler, user, priv, False) user.save() print "Done"
def adminPrivileges(handler, username = None): handler.title("Privileges") requirePriv(handler, 'Admin') undelay(handler) users = User.loadAll(orderby = 'username') counts = {name: len(filter(lambda user: name in user.privileges, users)) for name in privList} if username: print "<style type=\"text/css\">" print "table.granttable tr[username=%s] {" % username print " background-color: #faa;" print "}" print "</style>" print "<h3>List</h3>" print "<table border=\"0\" cellspacing=\"4\">" print "<tr><th>Name</th><th>Grants</th><th>Description</th></tr>" for name, desc in privList.iteritems(): print "<tr><td>%s</td><td>%d</td><td>%s</td></tr>" % (name, counts[name] if name in counts else 0, desc) print "</table>" print "<h3>Grants</h3>" print "<form method=\"post\" action=\"/admin/privileges\">" print "<table border=\"0\" cellspacing=\"0\" cellpadding=\"2\" class=\"granttable\">" print "<tr><td> </td>%s</tr>" % ''.join("<td>%s</td>" % name for name in privList) for user in users: print "<tr username=\"%s\">" % user.username print "<td>%s</td>" % user.username for name in privList: print "<td><input type=\"checkbox\" name=\"grant[%s][%s]\"%s></td>" % (user.username, name, ' checked' if user.hasPrivilege(name) else '') print "</tr>" print "<tr><td> </td><td colspan=\"3\">%s</td></tr>" % Button('Save', type = 'submit').positive() print "</table>" print "</form>"
def adminSessionsPost(handler, p_key, p_action, p_value = None): handler.title('Sessions') requirePriv(handler, 'Admin') print "<script src=\"/static/admin-sessions.js\" type=\"text/javascript\"></script>" if not p_key in Session.getIDs(): ErrorBox.die("Retrieve session", "No session exists with key <b>%s</b>" % stripTags(p_key)) session = Session.load(p_key) for case in switch(p_action): if case('reassign'): handler.title('Reassign Session') if p_value: user = User.load(int(p_value)) if not user: ErrorBox.die("Load user", "No user exists with ID <b>%s</b>" % stripTags(p_value)) session['user'] = user redirect('/admin/sessions') else: print "<form method=\"post\" action=\"/admin/sessions\">" print "<input type=\"hidden\" name=\"action\" value=\"reassign\">" print "<input type=\"hidden\" name=\"key\" value=\"%s\">" % p_key print "<select id=\"selectUser\" name=\"value\">" for user in sorted(User.loadAll()): print "<option value=\"%d\">%s</option>" % (user.id, user.safe.username) print "</select><br>" print Button('Reassign', type = 'submit').positive() print Button('Cancel', id = 'cancel-button', type = 'button', url = '/admin/sessions').negative() print "</form>" break if case('destroy'): Session.destroy(p_key) redirect('/admin/sessions') break break
def adminUsers(handler): handler.title('User Management') requirePriv(handler, 'Admin') print "<style type=\"text/css\">" print "table.list td.right > * {width: 400px;}" print "table.list td.right button {width: 200px;}" # Half of the above value print "</style>" undelay(handler) print "<h3>New User</h3>" print "<form method=\"post\" action=\"/admin/users\">" print "<input type=\"hidden\" name=\"action\" value=\"new\">" print "<table class=\"list\">" print "<tr><td class=\"left\">Username:</td><td class=\"right\"><input type=\"text\" name=\"username\"></td></tr>" print "<tr><td class=\"left\">Privileges:</td><td class=\"right\"><div>" for name, desc in privList.iteritems(): print "<input type=\"checkbox\" name=\"privileges[]\" id=\"priv_%s\" value=\"%s\"%s><label for=\"priv_%s\">%s — %s</label><br>" % (name, name, ' checked' if name in privDefaults else '', name, name, desc) print "</div></td></tr>" if settings.smtpServer: print "<tr><td class=\"left\">Contact:</td><td class=\"right\"><div><input type=\"checkbox\" name=\"send_welcome\" id=\"send_welcome\" checked><label for=\"send_welcome\">Send welcome e-mail</label></div></td></tr>" print "<tr><td class=\"left\"> </td><td class=\"right\">" print Button('Save', id = 'save-button', type = 'submit').positive() print Button('Cancel', type = 'button', url = '/admin').negative() print "</td></tr>" print "</table>" print "</form><br>" print "<h3>Current Users</h3>" users = User.loadAll(orderby = 'username') print "<div class=\"user-list\">" for user in users: print "<div class=\"user-list-entry\"><a href=\"/users/%s\"><img src=\"%s\"></a><br>%s</div>" % (user.username, user.getAvatar(64), user.safe.username) print "</div>" print "<div class=\"clear\"></div>"
def users(handler): handler.title('Users') users = User.loadAll(orderby = 'username') print "<div class=\"user-list\">" for user in users: print "<div class=\"user-list-entry\"><a href=\"/users/%s\"><img src=\"%s\"></a><br>%s</div>" % (user.username, user.getAvatar(64), user.safe.username) print "</div>" print "<div class=\"clear\"></div>"
def newSprint(handler, project): id = int(project) handler.title('New Sprint') requirePriv(handler, 'User') project = Project.load(id) if not project: ErrorBox.die('Invalid project', "No project with ID <b>%d</b>" % id) sprints = project.getSprints() print "<style type=\"text/css\">" print "table.list td.right > * {width: 400px;}" print "table.list td.right button {width: 200px;}" # Half of the above value print "#select-members {padding-right: 5px;}" print "</style>" print "<script src=\"/static/sprints-new.js\" type=\"text/javascript\"></script>" print InfoBox('', id = 'post-status') print "<form method=\"post\" action=\"/sprints/new\">" print "<table class=\"list\">" print "<tr><td class=\"left\">Project:</td><td class=\"right\">" print "<select id=\"select-project\" name=\"project\">" for thisProject in Project.loadAll(): print "<option value=\"%d\"%s>%s</option>" % (thisProject.id, ' selected' if thisProject == project else '', thisProject.safe.name) print "</select>" print "</td></tr>" print "<tr><td class=\"left\">Name:</td><td class=\"right\"><input type=\"text\" name=\"name\" class=\"defaultfocus\"></td></tr>" print "<tr><td class=\"left\">Planning:</td><td class=\"right\"><input type=\"text\" name=\"start\" class=\"date\" value=\"%s\"></td></tr>" % Weekday.today().strftime('%m/%d/%Y') print "<tr><td class=\"left\">Wrapup:</td><td class=\"right\"><input type=\"text\" name=\"end\" class=\"date\"></td></tr>" print "<tr><td class=\"left no-bump\">Members:</td><td class=\"right\">" print "<select name=\"members[]\" id=\"select-members\" multiple>" # Default to last sprint's members members = {handler.session['user']} if sprints: members |= sprints[-1].members for user in sorted(User.loadAll()): if user.hasPrivilege('User'): print "<option value=\"%d\"%s>%s</option>" % (user.id, ' selected' if user in members else '', user.safe.username) print "</select>" print "</td></tr>" print "<tr><td class=\"left no-bump\">Options:</td><td class=\"right\">" print "<div><input type=\"checkbox\" name=\"private\" id=\"flag-private\"><label for=\"flag-private\">Private – Only sprint members can view tasks</label></div>" print "<div><input type=\"checkbox\" name=\"hidden\" id=\"flag-hidden\"><label for=\"flag-hidden\">Hidden – Only sprint members can see the sprint</label></div>" print "</td></tr>" print "<tr><td class=\"left\"> </td><td class=\"right\">" print Button('Save', id = 'save-button', type = 'button').positive() print Button('Cancel', id = 'cancel-button', type = 'button').negative() print "</td></tr>" print "</table>" print "</form>"
def sendResetEmail(handler): handler.title('Reset password') if handler.session['user']: redirect('/resetpw') if not settings.smtpServer: ErrorBox.die("Sprint is not configured for sending e-mail. You will need to contact an administrator to reset your password") print "A reset link will be send to your e-mail address. You can also contact an administrator to reset your password.<br><br>" print "<form method=\"post\" action=\"/resetpw/:mail\">" print "<table class=\"list\">" print "<tr><td class=\"left\">Username:</td><td><select name=\"username\">" for user in User.loadAll(orderby = 'username'): print "<option value=\"%s\">%s</option>" % (user.safe.username, user.safe.username) print "</select></td></tr>" print "<tr><td> </td><td>" print Button('Send e-mail', type = 'submit').positive() print "</td></tr>" print "</table>"
def oldResetKeys(): if 'reset-keys' not in db()['cron']: db()['cron']['reset-keys'] = {} with db()['cron'].change('reset-keys') as data: for user in User.loadAll(): if user.resetkey: if user.id in data: if user.resetkey == data[user.id]: user.resetkey = None user.save() del data[user.id] print "<b>%s</b>: Key expired<br>" % user.safe.username else: data[user.id] = user.resetkey print "<b>%s</b>: New key marked<br>" % user.safe.username else: data[user.id] = user.resetkey print "<b>%s</b>: New key marked<br>" % user.safe.username else: if user.id in data: del data[user.id] print "<b>%s</b>: Key consumed; removed old mark<br>" % user.safe.username
def showInfo(handler, id): requirePriv(handler, 'User') id = int(id) sprint = Sprint.load(id) if not sprint or sprint.isHidden(handler.session['user']): ErrorBox.die('Sprints', "No sprint with ID <b>%d</b>" % id) elif not sprint.canView(handler.session['user']): ErrorBox.die('Private', "You must be a sprint member to view this sprint") tasks = sprint.getTasks() editable = sprint.owner == handler.session['user'] # Info can be edited even after the sprint closes handler.title(sprint.safe.name) drawNavArrows(sprint, handler.session['user'], 'info') print "<script type=\"text/javascript\">" print "var sprintid = %d;" % id print "var startMin = '%s';" % min(tsToDate(sprint.start), getNow()).strftime('%m/%d/%Y') print "var endMin = '%s';" % min(tsToDate(sprint.end), getNow()).strftime('%m/%d/%Y') print "</script>" print InfoBox('Loading...', id = 'post-status', close = True) print tabs(sprint, 'info') print "<form method=\"post\" action=\"/sprints/info?id=%d\">" % sprint.id print "<b>Name</b><br>" if editable: print "<input type=\"text\" name=\"name\" class=\"name\" value=\"%s\"><br><br>" % sprint.safe.name else: print "%s<br><br>" % sprint.safe.name print "<b>Duration</b><br>" if editable: print "<input type=\"text\" name=\"start\" class=\"date\" value=\"%s\">" % (tsToDate(sprint.start).strftime('%m/%d/%Y')), else: print tsToDate(sprint.start).strftime('%m/%d/%Y'), print '-', if editable: print "<input type=\"text\" name=\"end\" class=\"date\" value=\"%s\">" % (tsToDate(sprint.end).strftime('%m/%d/%Y')), else: print tsToDate(sprint.end).strftime('%m/%d/%Y'), print "<br><br>" print "<b>Sprint goals</b><br>" for goal in sprint.getGoals(): if editable: print "<input type=\"text\" class=\"goal\" style=\"background-image: url(/static/images/tag-%s.png)\" name=\"goals[%d]\" goalid=\"%d\" value=\"%s\"><br>" % (goal.color, goal.id, goal.id, goal.safe.name) numTasks = len(filter(lambda task: task.goal == goal, tasks)) if numTasks > 0: print "<div class=\"clear-goal-tasks\" id=\"clear-tasks-%d\"><input type=\"checkbox\" id=\"clear-tasks-check-%d\" name=\"clear[]\" value=\"%d\"><label for=\"clear-tasks-check-%d\">Clear the %s currently assigned to this goal (%s will no longer contribute to a sprint goal)</label></div>" % (goal.id, goal.id, goal.id, goal.id, pluralize(numTasks, 'task', 'tasks'), 'it' if numTasks == 1 else 'they') elif goal.name: print "<img class=\"bumpdown\" src=\"/static/images/tag-%s.png\"> %s<br>" % (goal.color, goal.safe.name) print "</table>" print "<br>" print "<b>Members</b><br>" if editable: print "<select name=\"members[]\" id=\"select-members\" multiple>" for user in sorted(User.loadAll()): if user.hasPrivilege('User') or user in sprint.members: print "<option value=\"%d\"%s>%s</option>" % (user.id, ' selected' if user in sprint.members else '', user.safe.username) print "</select>" else: print ', '.join(member.str('scrummaster' if member == sprint.owner else 'member') for member in sorted(sprint.members)) print "<br><br>" print "<b>Options</b><br>" if editable: print "<div><input type=\"checkbox\" name=\"private\" id=\"flag-private\"%s%s><label for=\"flag-private\">Private – Only sprint members can view tasks</label></div>" % (' checked' if 'private' in sprint.flags else '', ' disabled' if 'hidden' in sprint.flags else '') print "<div><input type=\"checkbox\" name=\"hidden\" id=\"flag-hidden\"%s><label for=\"flag-hidden\">Hidden – Only sprint members can see the sprint</label></div>" % (' checked' if 'hidden' in sprint.flags else '') else: if 'hidden' in sprint.flags: print "<img src=\"/static/images/shield.png\" class=\"option\"> Hidden" elif 'private' in sprint.flags: print "<img src=\"/static/images/lock.png\" class=\"option\"> Private" print "<br>" if editable: print Button('Save', id = 'save-button', type = 'button').positive() print "</form>"
def adminLog(handler, page = 1, users = None, types = None): PAGE_LEN = 100 PAGINATION_BOXES = 12 handler.title('Log') requirePriv(handler, 'Admin') LogEntry.cacheAll() entries = LogEntry.loadAll(orderby = '-timestamp') filtered = (users is not None) or (types is not None) users = set(User.load(int(id)) for id in users) if users else (User.loadAll(orderby = 'username') + [None]) # if not all(users): # ErrorBox.die("Unrecognized user ID(s)") types = [str(type) for type in types] if types else LogEntry.getTypes() if 'error' in types: errorCounter.reset() if filtered: entries = filter(lambda entry: entry.user in users and entry.type in types, entries) page = int(page) pages = max(len(entries) / PAGE_LEN, 1) if page < 1: page = 1 if page > pages: page = pages print "<form method=\"get\" action=\"/admin/log\">" print "<select name=\"users[]\" multiple size=\"10\">" for user in User.loadAll(orderby = 'username'): print "<option value=\"%d\"%s>%s</option>" % (user.id, ' selected' if user in users else '', user.safe.username) print "<option value=\"0\"%s>(anonymous)</option>" % (' selected' if None in users else '') print "</select>" print "<select name=\"types[]\" multiple size=\"10\">" for type in LogEntry.getTypes(): print "<option value=\"%s\"%s>%s</option>" % (type, ' selected' if type in types else '', type) print "</select>" print "<br>" print Button('Update', type = 'submit') print "</form>" firstPage, lastPage = max(1, page - (PAGINATION_BOXES - 1)), min(pages, page + (PAGINATION_BOXES - 1)) while lastPage - firstPage > ((PAGINATION_BOXES - 1) - sum([firstPage > 1, firstPage > 2, lastPage < pages, lastPage < pages - 1])): if abs(firstPage - page) >= abs(lastPage - page): firstPage += 1 else: lastPage -= 1 link = "/admin/log?page=%d" + ''.join("&users[]=%d" % (user.id if user else 0) for user in users) + ''.join("&types[]=%s" % type for type in types) print "<div class=\"pagination\">" print "<ul>" if page == 1: print "<li class=\"disabled\"><a href=\"#\">«</a></li>" else: print "<li><a href=\"%s\">«</a></li>" % (link % (page - 1)) if firstPage > 1: print "<li><a href=\"%s\">1</a></li>" % (link % 1) if firstPage > 2: print "<li class=\"disabled\"><a href=\"#\">...</a></li>" for i in range(firstPage, lastPage + 1): print "<li%s><a href=\"%s\">%d</a></li>" % (' class="active"' if i == page else '', link % i, i) if lastPage < pages: if lastPage < pages - 1: print "<li class=\"disabled\"><a href=\"#\">...</a></li>" print "<li><a href=\"%s\">%d</a></li>" % (link % pages, pages) if page == pages: print "<li class=\"disabled\"><a href=\"#\">»</a></li>" else: print "<li><a href=\"%s\">»</a></li>" % (link % (page + 1)) print "</ul>" print "</div>" print "<br>" for entry in entries[((page - 1) * PAGE_LEN):(page * PAGE_LEN)]: print "<div class=\"logentry\">" print "<div class=\"gravatar\">" print "<img class=\"gravatar\" src=\"%s\">" % (entry.user.getAvatar() if entry.user else User.getBlankAvatar()) print "</div>" print "<div>" print "<b><span class=\"label logtype-%s\">%s</span> at %s</b><br>" % (entry.type.split('.')[0], entry.type, entry.location) print "%s by %s<br>" % (tsToDate(entry.timestamp), "%s (%s)" % (entry.user.username, entry.ip) if entry.user else entry.ip) print "<pre>%s</pre>" % (entry.text or ' ') print "</div>" print "</div>" print "<div class=\"clear\"></div>"