~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/webapp/submit/__init__.py

  • Committer: William Grant
  • Date: 2009-04-07 03:48:23 UTC
  • mfrom: (1165.1.46 submissions)
  • Revision ID: grantw@unimelb.edu.au-20090407034823-snd6wa5p6otzq073
Allow students to submit projects from personal or group repositories.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# IVLE
 
2
# Copyright (C) 2007-2009 The University of Melbourne
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 
 
18
# Author: Will Grant
 
19
 
 
20
"""Project submissions user interface."""
 
21
 
 
22
import os.path
 
23
import datetime
 
24
 
 
25
from storm.locals import Store
 
26
 
 
27
from ivle.database import (User, ProjectGroup, Offering, Subject, Semester,
 
28
                           ProjectSet, Project, Enrolment)
 
29
from ivle.webapp.errors import NotFound, BadRequest
 
30
from ivle.webapp.base.xhtml import XHTMLView
 
31
from ivle.webapp.base.plugins import ViewPlugin
 
32
 
 
33
import ivle.date
 
34
 
 
35
 
 
36
class SubmitView(XHTMLView):
 
37
    """A view to submit a Subversion repository path for a project."""
 
38
    template = 'submit.html'
 
39
    tab = 'files'
 
40
    permission = 'submit_project'
 
41
 
 
42
    def __init__(self, req, name, path):
 
43
        # We need to work out which entity owns the repository, so we look
 
44
        # at the first two path segments. The first tells us the type.
 
45
        self.context = self.get_repository_owner(req.store, name)
 
46
        self.path = os.path.normpath(path)
 
47
 
 
48
        if self.context is None:
 
49
            raise NotFound()
 
50
 
 
51
        self.offering = self.get_offering()
 
52
 
 
53
    def get_repository_owner(self, store, name):
 
54
        """Return the owner of the repository given the name and a Store."""
 
55
        raise NotImplementedError()
 
56
 
 
57
    def get_offering(self):
 
58
        """Return the offering that this path can be submitted to."""
 
59
        raise NotImplementedError()
 
60
 
 
61
    def populate(self, req, ctx):
 
62
        if req.method == 'POST':
 
63
            data = dict(req.get_fieldstorage())
 
64
            if 'revision' not in data:
 
65
                raise BadRequest('No revision selected.')
 
66
 
 
67
            try:
 
68
                revision = int(data['revision'])
 
69
            except ValueError:
 
70
                raise BadRequest('Revision must be an integer.')
 
71
 
 
72
            if 'project' not in data:
 
73
                raise BadRequest('No project selected.')
 
74
 
 
75
            try:
 
76
                projectid = int(data['project'])
 
77
            except ValueError:
 
78
                raise BadRequest('Project must be an integer.')
 
79
 
 
80
            project = req.store.find(Project, Project.id == projectid).one()
 
81
 
 
82
            # This view's offering will be the sole offering for which the
 
83
            # path is permissible. We need to check that.
 
84
            if project.project_set.offering is not self.offering:
 
85
                raise BadRequest('Path is not permissible for this offering')
 
86
 
 
87
            if project is None:
 
88
                raise BadRequest('Specified project does not exist')
 
89
 
 
90
            project.submit(self.context, self.path, revision, req.user)
 
91
 
 
92
            self.template = 'submitted.html'
 
93
            ctx['project'] = project
 
94
 
 
95
        ctx['req'] = req
 
96
        ctx['principal'] = self.context
 
97
        ctx['offering'] = self.offering
 
98
        ctx['path'] = self.path
 
99
        ctx['now'] = datetime.datetime.now()
 
100
        ctx['format_datetime'] = ivle.date.format_datetime_for_paragraph
 
101
 
 
102
 
 
103
class UserSubmitView(SubmitView):
 
104
    def get_repository_owner(self, store, name):
 
105
        '''Resolve the user name into a user.'''
 
106
        return User.get_by_login(store, name)
 
107
 
 
108
    def get_offering(self):
 
109
        return Store.of(self.context).find(Offering,
 
110
            Offering.id == Enrolment.offering_id,
 
111
            Enrolment.user_id == self.context.id,
 
112
            Offering.semester_id == Semester.id,
 
113
            Semester.state == u'current',
 
114
            Offering.subject_id == Subject.id,
 
115
            Subject.short_name == self.path.split('/')[0],
 
116
            ).one()
 
117
 
 
118
 
 
119
class GroupSubmitView(SubmitView):
 
120
    def get_repository_owner(self, store, name):
 
121
        '''Resolve the subject_year_semester_group name into a group.'''
 
122
        namebits = name.split('_', 3)
 
123
        if len(namebits) != 4:
 
124
            return None
 
125
 
 
126
        # Find the project group with the given name in any project set in the
 
127
        # offering of the given subject in the semester with the given year
 
128
        # and semester.
 
129
        return store.find(ProjectGroup,
 
130
            ProjectGroup.name == namebits[3],
 
131
            ProjectGroup.project_set_id == ProjectSet.id,
 
132
            ProjectSet.offering_id == Offering.id,
 
133
            Offering.subject_id == Subject.id,
 
134
            Subject.short_name == namebits[0],
 
135
            Offering.semester_id == Semester.id,
 
136
            Semester.year == namebits[1],
 
137
            Semester.semester == namebits[2]).one()
 
138
 
 
139
    def get_offering(self):
 
140
        return self.context.project_set.offering
 
141
 
 
142
 
 
143
class Plugin(ViewPlugin):
 
144
    urls = [
 
145
        ('+submit/users/:name/*path', UserSubmitView),
 
146
        ('+submit/groups/:name/*path', GroupSubmitView),
 
147
    ]