示例#1
0
文件: shell.py 项目: mrozekma/Sprint
def info(context):
	revisionHash, revisionDate, revisionRelative = getRevisionInfo()
	print "Sprint tool, revision %s" % link(revisionHash, gitURL % {'hash': revisionHash})
	if isDevMode():
		print clr("Development mode", 'red')
	else:
		print clr("Production mode", 'green')
	loadTime = getLoadtime()
	print "Started %s" % clr(loadTime)
	print "Up for %s" % clr(timesince(loadTime))
示例#2
0
def footer(handler):
	print "</div>"
	print "<br style=\"clear:both\">"
	print "</div>"
	print "</div>"

	print "</div>"

	revisionHash, revisionDate, revisionRelative = getRevisionInfo()
	print "<div class=\"footer_timestamp\">"
	print "Current system time: %s<br>" % getNow()
	print "Current revision:",
	if isDevMode():
		print "<span style=\"color: #f00;\">Development build</span><br>"
	else:
		print "<a href=\"%s\">%s</a>" % (gitURL % {'hash': revisionHash}, revisionHash),
		print "(<span title=\"%s\">%s</span>)<br>" % (revisionDate, revisionRelative)
	print "</div>"

	print "<script src=\"/static/less.js\" type=\"text/javascript\"></script>" # In case any less <link>s were in the body
	print "</body>"
	print "</html>"
示例#3
0
文件: users.py 项目: mrozekma/Sprint
def user(handler, username):
	user = User.load(username = username)
	if not user:
		ErrorBox.die('User', "No user named <b>%s</b>" % stripTags(username))

	Markdown.head('form#message-form .body pre code')
	print "<script src=\"/static/jquery.typing-0.2.0.min.js\" type=\"text/javascript\"></script>"
	print "<script src=\"/static/users.js\" type=\"text/javascript\"></script>"
	Chart.include()
	undelay(handler)

	handler.title(user.safe.username)
	handler.replace('$bodytitle$', '', 1)
	print "<img src=\"%s\" class=\"gravatar\">" % user.getAvatar(64)
	print "<h1>%s</h1>" % user.safe.username
	if isDevMode(handler):
		print "<div class=\"debugtext\">User ID: %d</div>" % user.id
	print "<div class=\"clear\"></div>"

	if handler.session['user'] and handler.session['user'].hasPrivilege('Admin'):
		print "<h3>Admin</h3>"
		print "<form method=\"post\" action=\"/admin/users\">"
		print "<input type=\"hidden\" name=\"username\" value=\"%s\">" % user.username
		print "<button type=\"submit\" class=\"btn\" name=\"action\" value=\"resetpw\">Reset password</button>"
		print "<button type=\"submit\" class=\"btn\" name=\"action\" value=\"impersonate\">Impersonate</button>"
		print "<button type=\"submit\" class=\"btn\" name=\"action\" value=\"sessions\">Manage sessions</button>"
		print "<button type=\"submit\" class=\"btn\" name=\"action\" value=\"privileges\">Manage privileges</button>"
		print "</form>"

	if user == handler.session['user']:
		print "<h3>Avatar</h3>"
		if user.hasLocalAvatar():
			print "Your avatar is currently <a href=\"/users/%s/avatar/set\">locally hosted</a>" % user.username
		else:
			print "Your avatar can be changed at <a href=\"http://gravatar.com/\" target=\"_new\">http://gravatar.com/</a>. It must be associated with the e-mail <b>%s</b>, and be rated PG. You can also host an avatar <a href=\"/users/%s/avatar/set\">locally</a>, if necessary" % (user.getEmail(), user.username)

		print "<h3>Authentication</h3>"
		print "Your sprint tool password can be changed <a href=\"/resetpw\">here</a>.",
		if settings.kerberosRealm:
			print "You can also use your %s kerberos password to login" % settings.kerberosRealm,
		print "<br><br>"
		if user.hotpKey == '':
			print "You also have the option to use two-factor authentication via <a href=\"http://en.wikipedia.org/wiki/HOTP\">HOTP</a>. You can use <a href=\"http://support.google.com/a/bin/answer.py?hl=en&answer=1037451\">Google Authenticator</a> to generate verification codes<br><br>"
			print "<form method=\"post\" action=\"/security/two-factor\">"
			print "<button type=\"submit\" class=\"btn danger\" name=\"action\" value=\"enable\">Enable two-factor authentication</button>"
			print "</form>"
		else:
			print "You are currently using two-factor authentication<br><br>"
			print "<form method=\"post\" action=\"/security/two-factor\">"
			print "<button type=\"submit\" class=\"btn danger\" name=\"action\" value=\"enable\">Reset HOTP key</button>"
			print "<button type=\"submit\" class=\"btn danger\" name=\"action\" value=\"disable\">Disable two-factor authentication</button>"
			print "</form>"

		print "<h3>Messages</h3>"
		print "Your inbox and sent messages can be viewed <a href=\"/messages/inbox\">here</a><br>"

	print "<h3>Last seen</h3>"
	if not user.lastseen:
		print "Never"
	elif dateToTs(getNow()) - user.lastseen < 60:
		print "Just now"
	else:
		print "%s ago" % timesince(tsToDate(user.lastseen))

	if handler.session['user'] and handler.session['user'] != user:
		print "<h3>Message</h3>"
		print "<small>(Messages are formatted in <a target=\"_blank\" href=\"/help/markdown\">markdown</a>)</small>"
		print "<form id=\"message-form\" method=\"post\" action=\"/messages/send\">"
		print "<input type=\"hidden\" name=\"userid\" value=\"%d\">" % user.id
		print "<textarea name=\"body\" class=\"large\"></textarea>"
		print "<div class=\"body markdown\"><div id=\"preview\"></div></div>"
		print Button('Send').post().positive()
		print "</form>"

	print "<h3>Project distribution</h3>"
	sprints = filter(lambda s: user in s.members, Sprint.loadAllActive())
	sprintHours = map(lambda s: (s, Availability(s).getAllForward(getNow(), user)), sprints)
	projectHours = map(lambda (p, g): (p, sum(hours for sprint, hours in g)), groupby(sprintHours, lambda (s, a): s.project))

	# For now at least, don't show projects with no hours
	projectHours = filter(lambda (p, h): h > 0, projectHours)
	if len(projectHours) > 0:
		chart = Chart('chart')
		chart.title.text = ''
		chart.tooltip.formatter = "function() {return '<b>' + this.point.name + '</b>: ' + this.point.y + '%';}"
		chart.plotOptions.pie.allowPointSelect = True
		chart.plotOptions.pie.cursor = 'pointer'
		chart.plotOptions.pie.dataLabels.enabled = False
		chart.plotOptions.pie.showInLegend = True
		chart.credits.enabled = False
		chart.series = seriesList = []

		series = {
			'type': 'pie',
			'name': '',
			'data': []
		}
		seriesList.append(series)

		total = sum(hours for project, hours in projectHours)
		for project, hours in projectHours:
			series['data'].append([project.name, float("%2.2f" % (100 * hours / total))])

		chart.js()
		chart.placeholder()
	else:
		print "Not a member of any active sprints"
示例#4
0
def showBacklog(handler, id, search = None, devEdit = False):
	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")

	# Redirect to search help page if searched for empty string
	if search == '':
		redirect('/help/search')

	handler.title(sprint.safe.name)
	drawNavArrows(sprint, handler.session['user'], '')

	tasks = sprint.getTasks()
	editable = sprint.canEdit(handler.session['user']) or (devEdit and isDevMode(handler))
	search = Search(sprint, search)

	print "<script src=\"/settings/sprints.js\" type=\"text/javascript\"></script>"

	print "<script type=\"text/javascript\">"
	print "var sprintid = %d;" % id
	print "var currentUser = %s;" % toJS(handler.session['user'].username if handler.session['user'] else None)
	print "var totalTasks = %d;" % len(tasks)

	# True is a placeholder for the dynamic tokens (status, assigned)
	print "var searchTokens = %s;" % toJS(filter(None, [search.getBaseString() if search.hasBaseString() else None] + [True] + ["%s:%s" % (filt.getKey(), filt.value) for filt in search.getAll() if filt.getKey() not in ('status', 'assigned')]))
	print "var searchDescriptions = %s;" % toJS(filter(None, ["matching %s" % search.getBaseString() if search.hasBaseString() else None] + [True] + [filt.description() for filt in search.getAll()]))

	print "TaskTable.init({link_hours_status: %s});" % toJS(not sprint.isPlanning())
	print "$('document').ready(function() {"
	if search.has('assigned'):
		print "    $('%s').addClass('selected');" % ', '.join("#filter-assigned a[assigned=\"%s\"]" % user.username for user in search.get('assigned').users + ([handler.session['user']] if search.get('assigned').currentUser else []))
	if search.has('status'):
		print "    $('%s').addClass('selected');" % ', '.join("#filter-status a[status=\"%s\"]" % status.name for status in search.get('status').statuses)
	print "    apply_filters();"
	print "});"
	print "</script>"

	print "<div id=\"selected-task-box\">"
	print "<span></span>"
	print Button('history', id = 'selected-history').positive()
	print Button('highlight', id = 'selected-highlight').positive()
	print Button('mass edit', id = 'selected-edit').positive()
	print Button('cancel', id = 'selected-cancel') #.negative()
	print "</div>"

	print "<div class=\"backlog-tabs\">"
	print tabs(sprint, 'backlog')
	print "<input type=\"text\" id=\"search\" value=\"%s\">" % search.getFullString().replace('"', '&quot;')
	print "</div>"

	undelay(handler)

	print InfoBox('Loading...', id = 'post-status', close = True)

	avail = Availability(sprint) if sprint.isActive() else None
	dayStart = Weekday.today().date()
	print "<div id=\"filter-assigned\">"
	print "<a class=\"fancy danger\" href=\"#\"><img src=\"/static/images/cross.png\">&nbsp;None</a>"
	for member in sorted(sprint.members):
		cls = ['fancy']
		if not sprint.isPlanning() and avail and avail.get(member, dayStart) == 0:
			cls.append('away')
		print "<a class=\"%s\" assigned=\"%s\" href=\"/sprints/%d?search=assigned:%s\"><img src=\"%s\">&nbsp;%s</a>" % (' '.join(cls), member.username, id, member.username, member.getAvatar(16), member.username)
	print "</div><br>"

	print "<div id=\"filter-status\">"
	print "<a class=\"fancy danger\" href=\"#\"><img src=\"/static/images/cross.png\">&nbsp;None</a>"
	for status in sorted(statuses.values()):
		print "<a class=\"fancy\" status=\"%s\" href=\"/sprints/%d?search=status:%s\"><img src=\"%s\">%s</a>" % (status.name, id, status.name.replace(' ', '-'), status.getIcon(), status.text)
	print "</div><br>"

	if handler.session['user'].hasPrivilege('Admin') and 'deleted' in sprint.flags:
		print "<form method=\"post\" action=\"/admin/projects/%d/cancel-deletion/%d\">" % (sprint.project.id, sprint.id)
		print WarningBox("This sprint is flagged for deletion during nightly cleanup. %s" % Button('Cancel').mini().post())
		print "</form>"
	if sprint.isPlanning():
		if sprint.isActive():
			print InfoBox("Today is <b>sprint planning</b> &mdash; tasks aren't finalized until the end of the day")
		else:
			daysTillPlanning = (tsToDate(sprint.start) - getNow()).days + 1
			print InfoBox("The sprint has <b>not begun</b> &mdash; planning is %s. All changes are considered to have been made midnight of plan day" % ('tomorrow' if daysTillPlanning == 1 else "in %d days" % daysTillPlanning))
	elif sprint.isReview():
		print InfoBox("Today is <b>sprint review</b> &mdash; this is the last day to make changes to the backlog. All open tasks will be deferred at the end of the day")
	elif not sprint.isOver():
		noHours = filter(lambda task: task.stillOpen() and task.hours == 0, tasks)
		if noHours != []:
			print WarningBox("There are <a href=\"/sprints/%d?search=status:not-started,in-progress,blocked hours:0\">open tasks with no hour estimate</a>" % sprint.id)

	tasks = search.filter(tasks)

	if isDevMode(handler):
		print Button('#all-tasks borders', "javascript:$('#all-tasks, #all-tasks tr td').css('border', '1px solid #f00').css('border-collapse', 'collapse');").negative()
		if not editable:
			print Button('make editable', "/sprints/%d?devEdit" % id).negative()
		elif devEdit:
			print Button('make uneditable', "/sprints/%d" % id).negative()

		print "<div class=\"debugtext\">"
		print "start: %d (%s)<br>" % (sprint.start, tsToDate(sprint.start))
		print "end: %d (%s)<br>" % (sprint.end, tsToDate(sprint.end))
		print "</div>"

	showing = ResponseWriter()
	print "<span id=\"task-count\"></span>"
	# save-search href set by update_task_count()
	print "<a class=\"save-search\"><img src=\"/static/images/save.png\" title=\"Save search\"></a>"
	print "<a class=\"cancel-search\" href=\"/sprints/%d\"><img src=\"/static/images/cross.png\" title=\"Clear search\"></a>" % id
	showing = showing.done()

	print TaskTable(sprint, editable = editable, tasks = tasks, tableID = 'all-tasks', dateline = showing, taskClasses = {task: ['highlight'] for task in (search.get('highlight').tasks if search.has('highlight') else [])}, debug = isDevMode(handler), groupActions = True, taskModActions = True, index = True, goal = True, status = True, name = True, assigned = True, historicalHours = True, hours = True, devEdit = devEdit)
示例#5
0
文件: tasks.py 项目: nolandda/Sprint
def newTaskImport(handler, group, source=None, assigned=None):
    # 'assigned' is ignored, it's just in case the user gets here from a filtered backlog
    handler.title("New Tasks")
    requirePriv(handler, "User")
    id = int(group)

    print tabs.format(id).where("import")

    group = Group.load(id)
    if not group or group.sprint.isHidden(handler.session["user"]):
        ErrorBox.die("Invalid Group", "No group with ID <b>%d</b>" % id)

    sprint = group.sprint
    if not (sprint.isActive() or sprint.isPlanning()):
        ErrorBox.die("Sprint Closed", "Unable to modify inactive sprint")
    elif not sprint.canEdit(handler.session["user"]):
        ErrorBox.die("Permission Denied", "You don't have permission to modify this sprint")

    sprints = sprint.project.getSprints()
    sprintIdx = sprints.index(sprint)
    prevSprint = sprints[sprintIdx - 1] if sprintIdx > 0 else None

    if not source:
        print "Select a sprint to import from:<br><br>"
        print '<form method="get" action="/tasks/new/import">'
        print '<input type="hidden" name="group" value="%d">' % group.id
        print '<select name="source" id="import-source">'
        for projectIter in Project.getAllSorted(handler.session["user"], sprint.project):
            print '<optgroup label="%s">' % projectIter.safe.name
            for sprintIter in projectIter.getSprints():
                print '<option value="%d"%s>%s</option>' % (
                    sprintIter.id,
                    " selected" if sprintIter == prevSprint else "",
                    sprintIter.safe.name,
                )
            print "</optgroup>"
        print "</select>"
        print "<br><br>"
        print Button("Next").positive().post()
        print "</form>"
    else:
        id = int(source)
        source = Sprint.load(id)
        if not source:
            ErrorBox.die("Invalid Sprint", "No sprint with ID <b>%d</b>" % id)

        print '<script type="text/javascript">'
        nextURL = "/sprints/%d" % sprint.id
        if assigned:
            nextURL += "?search=assigned:%s" % stripTags(assigned.replace(" ", ","))
        print "next_url = %s;" % toJS(nextURL)
        print 'post_url = "/tasks/new/import?group=%d&source=%d";' % (group.id, source.id)
        print "scrummaster = %s;" % toJS(sprint.owner.username)
        print "TaskTable.init();"
        print "</script>"

        print '<b>Source sprint</b>: <a href="/sprints/%d">%s</a><br>' % (source.id, source.name)
        print '<b>Target sprint</b>: <a href="/sprints/%d">%s</a><br><br>' % (sprint.id, sprint.name)
        print "All incomplete tasks are listed here, with their current values from the source sprint. You can change any of the fields before importing. Only checked tasks will be imported<br><br>"

        assignedList = [sprint.owner] + list(sprint.members - {sprint.owner})
        print TaskTable(
            source,
            editable=True,
            assignedList=assignedList,
            checkbox=True,
            status=True,
            name=True,
            assigned=True,
            hours=True,
            debug=isDevMode(handler),
        )

        print InfoBox("Loading...", id="post-status", close=True)
        print Button("Import", id="save-button", type="button").positive()
        print Button("Cancel", id="cancel-button", type="button").negative()
        print "</form><br><br>"
示例#6
0
def dev(handler):
	if isDevMode(handler):
		print WarningBox('Under development', close = True)
	else:
		print WarningBox('This feature is still under development and is disabled')
		done()
示例#7
0
def header(handler, includes):
	print "<!DOCTYPE html>"
	print "<html>"
	print "<head>"
	print "<title>$title$</title>"
	print "<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/syntax-highlighting.css\">"
	print "<link rel=\"shortcut icon\" href=\"/static/images/favicon.ico\">"

	print "<script src=\"/static/jquery.js\" type=\"text/javascript\"></script>"
	print "<script src=\"/static/jquery-migrate-1.1.1.min.js\" type=\"text/javascript\"></script>"
	print "<link rel=\"stylesheet\" href=\"/static/jquery-ui-1.10.1.custom.css\">"
	print "<script src=\"/static/jquery-ui-1.10.1.custom.min.js\" type=\"text/javascript\"></script>"
	print "<link href=\"/static/jquery.contextMenu.css\" rel=\"stylesheet\" type=\"text/css\" />"
	print "<script src=\"/static/jquery.contextMenu.js\"></script>"
	print "<script src=\"/static/jquery.mousewheel-min.js\"></script>"
	print "<script src=\"/static/jquery.terminal-0.4.23.js\"></script>"
	print "<link href=\"/static/jquery.terminal.css\" rel=\"stylesheet\" type=\"text/css\" />"
	print "<script src=\"/static/jquery.ba-bbq.js\"></script>"

	print "<script src=\"/static/bootstrap-dropdown.js\" type=\"text/javascript\"></script>"
	print "<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/bootstrap.css\">"

	print "<link rel=\"stylesheet\" href=\"/static/chosen/chosen.css\" />"
	print "<script src=\"/static/chosen/chosen.jquery.js\" type=\"text/javascript\"></script>"

	print "<script src=\"/static/noty/jquery.noty.js\"></script>"
	print "<script src=\"/static/noty/layouts/bottomCenter.js\"></script>"
	print "<script src=\"/static/noty/themes/default.js\"></script>"
	print "<script src=\"/static/noty/themes/sprint.js\"></script>"

	print "<script src=\"/dyn.js\" type=\"text/javascript\"></script>"
	print "<script src=\"/static/script.js\" type=\"text/javascript\"></script>"
	print "<script src=\"/static/shell.js\" type=\"text/javascript\"></script>"

	print "<style type=\"text/css\">"
	if handler.session['user']:
		print ".username[username~=\"%s\"] {" % handler.session['user'].username
		print "    color: #C00;"
		print "    font-weight: bold;"
		print "}"
	print "</style>"

	for filename in includes['less']:
		print "<link rel=\"stylesheet/less\" type=\"text/css\" href=\"%s\" />" % filename
	# for filename in includes['css']:
		# print "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />" % filename
	for filename in includes['js']:
		print "<script src=\"%s\" type=\"text/javascript\"></script>" % filename

	print "<link rel=\"stylesheet/less\" type=\"text/css\" href=\"/static/style.less\">"
	print "<script type=\"text/javascript\">"
	print "less = {"
	print "    env: '%s'," % ('development' if isDevMode(handler) else 'production')
	print "    async: false,"
	print "    dumpLineNumbers: 'comments'"
	print "};"
	print "</script>"
	print "<script src=\"/static/less.js\" type=\"text/javascript\"></script>"

	changes = list(getChanges(handler, handler.path))
	if changes:
		print "<script src=\"/static/changelog.js\"></script>"
		print "<script type=\"text/javascript\">"
		print "$(document).ready(function() {"
		fmt = "%%(message)s<div style=\"text-align: right; font-size: 6pt\"><a target=\"_blank\" href=\"%s\">%%(hash)s</a></div>" % gitURL
		for change in changes:
			print "    showChangelog(%s);" % toJS(fmt % {'hash': change.hash, 'message': change.message})
		print "});"
		print "</script>"

	print "</head>"
	print "<body>"
	print "<div id=\"shell\"></div>"
	print "<div id=\"frame\">"

	print "<div id=\"main_a\">"
	if handler.session['user']:
		print "<div class=\"avatar\">"
		print "<img class=\"avatar\" src=\"%s\">" % handler.session['user'].getAvatar()
		print "<div class=\"subavatar\">"
		if 'impersonator' in handler.session:
			print "<img class=\"subavatar\" src=\"%s\" onClick=\"unimpersonate();\" title=\"Unimpersonate\">" % handler.session['impersonator'].getAvatar()
		else:
			unreadMessages = Message.loadAll(userid = handler.session['user'].id, read = False)
			if len(unreadMessages) > 0:
				print "<a class=\"inbox\" href=\"/messages/inbox\">%d</a>" % len(unreadMessages)
		print "</div>"
		print "</div>"
	print "<div class=\"navigation\">"
	print "<div class=\"ident\">"
	if handler.session['user']:
		print "Logged in as %s" % handler.session['user']
	else:
		print "<a href=\"/login\">Not logged in</a>"
	print "</div>"

	if (option('dev') or isDevMode(handler)) and handler.session['user'] and handler.session['user'].hasPrivilege('Dev'):
		if isDevMode(handler):
			print "<div class=\"devwarning\" onClick=\"buildmode('production')\">"
			print "Development"
			print "</div>"
		else:
			print "<div class=\"prodwarning\" onClick=\"buildmode('development')\">"
			print "Production"
			print "</div>"

	print "<div class=\"topmenu\">"
	print menu.render(handler, handler.path)
	print "</div>"
	print "</div>"
	print "</div>"

	print "<div id=\"main_b\"></div>"

	print "<div id=\"main_c\">"

	if settings.systemMessage:
		print "<div class=\"sysmessage\">%s</div>" % settings.systemMessage

	print "<div id=\"main_d\">"

	print "<h1>$bodytitle$</h1>"