Permalink
Browse files

Switched scrummaster to a per-sprint setting instead of per-project

  • Loading branch information...
1 parent 336dab1 commit fe636df00d5c5ef6bf17983f9ba8a9d1759ef57d @mrozekma committed May 13, 2012
Showing with 29 additions and 44 deletions.
  1. +1 −1 History.py
  2. +1 −4 Project.py
  3. +3 −1 Sprint.py
  4. +8 −0 db-templates/10.sql
  5. +2 −11 handlers/admin.py
  6. +0 −15 handlers/debug.py
  7. +4 −2 handlers/projects.py
  8. +9 −9 handlers/sprints.py
  9. +1 −1 handlers/tasks.py
View
@@ -8,7 +8,7 @@
def userStr(rev, arg = None):
user = arg or rev.creator
- return user.str('scrummaster' if user == rev.sprint.project.owner else 'member')
+ return user.str('scrummaster' if user == rev.sprint.owner else 'member')
def showHistory(tasks, describeTask):
if isinstance(tasks, Task):
View
@@ -5,13 +5,10 @@
from utils import stripTags
class Project(ActiveRecord):
- owner = ActiveRecord.idObjLink(User, 'ownerid')
-
# Test projects have negative IDs
- def __init__(self, ownerid, name, id = None):
+ def __init__(self, name, id = None):
ActiveRecord.__init__(self)
self.id = id
- self.ownerid = ownerid
self.name = name
def getSprints(self):
View
@@ -7,12 +7,14 @@
class Sprint(ActiveRecord):
project = ActiveRecord.idObjLink(Project, 'projectid')
+ owner = ActiveRecord.idObjLink(User, 'ownerid')
- def __init__(self, projectid, name, start, end, id = None):
+ def __init__(self, projectid, name, ownerid, start, end, id = None):
ActiveRecord.__init__(self)
self.id = id
self.projectid = projectid
self.name = name
+ self.ownerid = ownerid
self.start = start
self.end = end
self.members = ActiveRecord.loadLink(self, 'members', 'sprintid', User, 'userid')
View
@@ -0,0 +1,8 @@
+ALTER TABLE sprints ADD ownerid integer CONSTRAINT owner REFERENCES users(id);
+UPDATE sprints SET ownerid = (SELECT ownerid FROM projects WHERE id = projectid);
+
+-- Are you kidding, sqlite? You can't drop columns?
+ALTER TABLE projects RENAME TO projects_old;
+CREATE TABLE projects(id integer not null primary key autoincrement, name string);
+INSERT INTO projects SELECT id, name FROM projects_old;
+DROP TABLE projects_old;
View
@@ -171,12 +171,6 @@ def adminProjects(handler, request):
print "<form method=\"post\" action=\"/admin/projects\">"
print "<table class=\"list\">"
print "<tr><td class=\"left\">Name:</td><td class=\"right\"><input type=\"text\" name=\"name\"></td></tr>"
- print "<tr><td class=\"left\">Scrummaster:</td><td class=\"right\">"
- print "<select name=\"owner\">"
- for user in User.loadAll(orderby = 'username'):
- print "<option value=\"%s\"%s>%s</option>" % (user.username, ' selected' if user == handler.session['user'] else '', user.username)
- print "</select>"
- print "</td></tr>"
print "<tr><td class=\"left\">&nbsp;</td><td class=\"right\">"
print Button('Save', id = 'save-button', type = 'submit').positive()
print Button('Cancel', type = 'button', url = '/admin').negative()
@@ -185,17 +179,14 @@ def adminProjects(handler, request):
print "</form>"
@post('admin/projects')
-def adminProjectsPost(handler, request, p_owner, p_name):
+def adminProjectsPost(handler, request, p_name):
handler.title('Project Management')
requireAdmin(handler)
- owner = User.load(username = p_owner)
- if not owner:
- ErrorBox.die('Add Project', "No user named <b>%s</b>" % stripTags(p_owner))
if Project.load(name = p_name):
ErrorBox.die('Add Project', "There is already a project named <b>%s</b>" % stripTags(p_name))
- Project(owner.id, p_name).save()
+ Project(p_name).save()
delay(handler, SuccessBox("Added project <b>%s</b>" % stripTags(p_name), close = True))
redirect('/')
View
@@ -1,15 +0,0 @@
-from rorn.Session import Session
-
-from Table import LRTable
-from Project import Project
-
-@get('dbg')
-def index(handler, request):
- handler.title('Debugging Info')
- tbl = LRTable()
- tbl['Session'] = str(handler.session)
- tbl['Key'] = handler.session.key
- tbl['Cookie'] = handler.headers.getheader('Cookie') or 'None'
- tbl['User'] = handler.session['user']
- tbl['foo'] = Project.load(1).owner
- print tbl
View
@@ -39,9 +39,11 @@ def projectsList(handler, request):
print "</div>"
print "<div class=\"project-members\">"
- print "<div class=\"member scrummaster\">%s</div>" % project.owner.str('scrummaster')
+ scrummasters = set(sprint.owner for sprint in sprints)
+ for member in sorted(scrummasters):
+ print "<div class=\"member scrummaster\">%s</div>" % member.str('scrummaster')
for member in sorted(project.getMembers()):
- if member == project.owner: continue
+ if member in scrummasters: continue
print "<div class=\"member %s\">%s</div>" % ('active' if member in activeMembers or len(activeSprints) == 0 else 'inactive', member.str('member'))
print "</div>"
View
@@ -435,7 +435,7 @@ def showInfo(handler, request, id):
if not sprint:
ErrorBox.die('Sprints', "No sprint with ID <b>%d</b>" % id)
tasks = sprint.getTasks()
- editable = sprint.project.owner == handler.session['user'] # Info can be edited even after the sprint closes
+ editable = sprint.owner == handler.session['user'] # Info can be edited even after the sprint closes
handler.title(sprint.safe.name)
@@ -520,7 +520,7 @@ def die(msg):
if not sprint:
die("There is no sprint with ID %d" % id)
- if sprint.project.owner != handler.session['user']:
+ if sprint.owner != handler.session['user']:
die("You must be the scrummaster to modify sprint information")
if p_start:
@@ -557,8 +557,8 @@ def die(msg):
members = map(User.load, p_members) if p_members else []
if not all(members):
die("One or more members do not exist")
- if sprint.project.owner not in members:
- die("The scrummaster (%s) must be a sprint member" % project.owner)
+ if sprint.owner not in members:
+ die("The scrummaster (%s) must be a sprint member" % sprint.owner)
if (dateToTs(start) if start else sprint.start) > sprint.end:
die("Start date cannot be after end date")
@@ -568,7 +568,7 @@ def die(msg):
delMembers = list(set(sprint.members) - set(members))
for user in delMembers:
for task in filter(lambda task: task.assigned == user, sprint.getTasks()):
- task.assigned = sprint.project.owner
+ task.assigned = sprint.owner
task.creator = handler.session['user']
task.timestamp = dateToTs(getNow())
task.revise()
@@ -810,7 +810,7 @@ def newSprint(handler, request, project):
print "<tr><td class=\"left\">Members:</td><td class=\"right\">"
print "<select name=\"members[]\" id=\"select-members\" multiple>"
for user in sorted(User.loadAll()):
- print "<option value=\"%d\"%s>%s</option>" % (user.id, ' selected' if user == handler.session['user'] or user == project.owner else '', user.safe.username)
+ print "<option value=\"%d\"%s>%s</option>" % (user.id, ' selected' if user == handler.session['user'] or user == handler.session['user'] else '', user.safe.username)
print "</select>"
print "</td></tr>"
print "<tr><td class=\"left\">&nbsp;</td><td class=\"right\">"
@@ -862,10 +862,10 @@ def die(msg):
members = map(User.load, p_members) if p_members else []
if None in members:
die("Unknown username")
- if project.owner not in members:
- die("The scrummaster (%s) must be a sprint member" % project.owner)
+ if handler.session['user'] not in members:
+ die("The scrummaster (%s) must be a sprint member" % handler.session['user'])
- sprint = Sprint(project.id, p_name, dateToTs(start), dateToTs(end))
+ sprint = Sprint(project.id, p_name, handler.session['user'].id, dateToTs(start), dateToTs(end))
sprint.members += members
sprint.save()
# Make a default 'Miscellaneous' group so there's something to add tasks to
View
@@ -437,7 +437,7 @@ def newTaskImport(handler, request, group, source = None):
print "<option value=\"%d\"%s>%s</option>" % (g.id, ' selected' if g == task.group else '', g.name + ('' if g.name in existingNames else ' (NEW)'))
print "</select></td>"
print "<td><select name=\"assigned[%d]\">" % task.id
- assigned = task.assigned if task.assigned in sprint.members else sprint.project.owner
+ assigned = task.assigned if task.assigned in sprint.members else sprint.owner
for member in sprint.members:
print "<option value=\"%s\"%s>%s</option>" % (member.id, ' selected' if member == assigned else '', member.username)
print "</select></td>"

0 comments on commit fe636df

Please sign in to comment.