231
231
"""Find a user in a store by login name."""
232
232
return store.find(cls, cls.login == unicode(login)).one()
234
def get_svn_url(self, config, req):
234
def get_svn_url(self, config):
235
235
"""Get the subversion repository URL for this user or group."""
236
login = req.user.login
237
url = urlparse.urlsplit(config['urls']['svn_addr'])
238
url = urlparse.urlunsplit(url[:1] + (login+'@'+url[1],) + url[2:])
236
url = config['urls']['svn_addr']
239
237
path = 'users/%s' % self.login
240
238
return urlparse.urljoin(url, path)
301
299
return self.offerings.find(Offering.semester_id == Semester.id,
302
300
Semester.year == unicode(year),
303
Semester.semester == unicode(semester)).one()
301
Semester.url_name == unicode(semester)).one()
305
303
class Semester(Storm):
306
304
"""A semester in which subjects can be run."""
321
321
__init__ = _kwarg_init
323
323
def __repr__(self):
324
return "<%s %s/%s>" % (type(self).__name__, self.year, self.semester)
324
return "<%s %s/%s>" % (type(self).__name__, self.year, self.code)
326
326
class Offering(Storm):
327
327
"""An offering of a subject in a particular semester."""
612
612
return "<%s '%s' in %r>" % (type(self).__name__, self.short_name,
613
613
self.project_set.offering)
615
def can_submit(self, principal, user):
615
def can_submit(self, principal, user, late=False):
617
@param late: If True, does not take the deadline into account.
616
619
return (self in principal.get_projects() and
617
not self.has_deadline_passed(user))
620
(late or not self.has_deadline_passed(user)))
619
def submit(self, principal, path, revision, who):
622
def submit(self, principal, path, revision, who, late=False):
620
623
"""Submit a Subversion path and revision to a project.
622
625
@param principal: The owner of the Subversion repository, and the
624
627
@param path: A path within that repository to submit.
625
628
@param revision: The revision of that path to submit.
626
629
@param who: The user who is actually making the submission.
630
@param late: If True, will not raise a DeadlinePassed exception even
631
after the deadline. (Default False.)
629
if not self.can_submit(principal, who):
634
if not self.can_submit(principal, who, late=late):
630
635
raise DeadlinePassed()
632
637
a = Assessed.get(Store.of(self), principal, self)
735
740
Semester.id == Offering.semester_id,
736
741
(not active_only) or (Semester.state == u'current'))
738
def get_svn_url(self, config, req):
743
def get_svn_url(self, config):
739
744
"""Get the subversion repository URL for this user or group."""
740
login = req.user.login
741
url = urlparse.urlsplit(config['urls']['svn_addr'])
742
url = urlparse.urlunsplit(url[:1] + (login+'@'+url[1],) + url[2:])
745
url = config['urls']['svn_addr']
743
746
path = 'groups/%s_%s_%s_%s' % (
744
747
self.project_set.offering.subject.short_name,
745
748
self.project_set.offering.semester.year,
746
self.project_set.offering.semester.semester,
749
self.project_set.offering.semester.url_name,
749
752
return urlparse.urljoin(url, path)
864
867
id = Int(name="extensionid", primary=True)
865
868
assessed_id = Int(name="assessedid")
866
869
assessed = Reference(assessed_id, Assessed.id)
867
deadline = DateTime()
868
871
approver_id = Int(name="approver")
869
872
approver = Reference(approver_id, User.id)
870
873
notes = Unicode()
912
915
return "/files/%s/%s/%s?r=%d" % (user.login,
913
916
self.assessed.checkout_location, submitpath, self.revision)
915
def get_svn_url(self, req):
918
def get_svn_url(self, config):
916
919
"""Get subversion URL for this submission"""
917
920
princ = self.assessed.principal
918
base = princ.get_svn_url(req.config, req)
921
base = princ.get_svn_url(config)
919
922
if self.path.startswith(os.sep):
920
923
return os.path.join(base,
921
924
urllib.quote(self.path[1:].encode('utf-8')))
923
926
return os.path.join(base, urllib.quote(self.path.encode('utf-8')))
925
def get_svn_checkout_command(self, req):
926
svn_url = self.get_svn_url(req)
927
return "svn export -r%d '%s'"%(self.revision, svn_url)
928
def get_svn_export_command(self, req):
929
"""Returns a Unix shell command to export a submission"""
930
svn_url = self.get_svn_url(req.config)
931
_, ext = os.path.splitext(svn_url)
932
username = (req.user.login if req.user.login.isalnum() else
933
"'%s'"%req.user.login)
934
# Export to a file or directory relative to the current directory,
935
# with the student's login name, appended with the submitted file's
937
export_path = self.assessed.principal.short_name + ext
938
return "svn export --username %s -r%d '%s' %s"%(req.user.login,
939
self.revision, svn_url, export_path)
930
942
def test_and_normalise_path(path):
945
957
raise SubmissionError("Path must not contain '\\n', '[' or ']'")
946
958
return os.path.normpath(path)
962
"""True if the project was submitted late."""
963
return self.days_late > 0
967
"""The number of days the project was submitted late (rounded up), or
969
# XXX: Need to respect extensions.
971
(self.date_submitted - self.assessed.project.deadline).days + 1)
948
973
# WORKSHEETS AND EXERCISES #
950
975
class Exercise(Storm):