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

1165.1.8 by William Grant
Start a submission UI in ivle.webapp.submit.
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
1165.1.13 by William Grant
Add an initial project selection UI to SubmitView.
22
import os.path
1165.1.17 by William Grant
Disable project radio buttons if they are closed.
23
import datetime
1165.1.13 by William Grant
Add an initial project selection UI to SubmitView.
24
1165.1.22 by William Grant
Detect the permitted offering for the given submission URL and restrict to that.
25
from storm.locals import Store
26
1165.1.8 by William Grant
Start a submission UI in ivle.webapp.submit.
27
from ivle.database import (User, ProjectGroup, Offering, Subject, Semester,
1165.1.22 by William Grant
Detect the permitted offering for the given submission URL and restrict to that.
28
                           ProjectSet, Project, Enrolment)
1165.1.20 by William Grant
Add a POST handler to SubmitView, which does the actual submission.
29
from ivle.webapp.errors import NotFound, BadRequest
1165.1.8 by William Grant
Start a submission UI in ivle.webapp.submit.
30
from ivle.webapp.base.xhtml import XHTMLView
31
from ivle.webapp.base.plugins import ViewPlugin
1294.4.13 by David Coles
Ported Submit to object publisher framework
32
from ivle.webapp import ApplicationRoot
1165.1.8 by William Grant
Start a submission UI in ivle.webapp.submit.
33
1165.1.16 by William Grant
Show the deadline for each project when submitting.
34
import ivle.date
1165.5.8 by William Grant
Rebuild SVN authz files on submission.
35
import ivle.chat
1165.1.16 by William Grant
Show the deadline for each project when submitting.
36
1165.1.8 by William Grant
Start a submission UI in ivle.webapp.submit.
37
38
class SubmitView(XHTMLView):
39
    """A view to submit a Subversion repository path for a project."""
40
    template = 'submit.html'
41
    tab = 'files'
42
    permission = 'submit_project'
1294.4.13 by David Coles
Ported Submit to object publisher framework
43
    subpath_allowed = True
44
45
    def __init__(self, req, context, subpath):
46
        super(SubmitView, self).__init__(req, context, subpath)
47
48
        if len(subpath) < 1:
49
            raise NotFound()
50
        name = subpath[0]
1165.1.8 by William Grant
Start a submission UI in ivle.webapp.submit.
51
        # We need to work out which entity owns the repository, so we look
52
        # at the first two path segments. The first tells us the type.
1165.1.9 by William Grant
Split SubmitView.__init__ into new subclasses, {User,Group}SubmitView.
53
        self.context = self.get_repository_owner(req.store, name)
1244 by William Grant
Ensure that the path is absolute when submitting a project.
54
1165.1.8 by William Grant
Start a submission UI in ivle.webapp.submit.
55
        if self.context is None:
56
            raise NotFound()
57
1165.1.28 by William Grant
Don't crash when the principal cannot be determined.
58
        self.offering = self.get_offering()
59
1165.1.9 by William Grant
Split SubmitView.__init__ into new subclasses, {User,Group}SubmitView.
60
    def get_repository_owner(self, store, name):
61
        """Return the owner of the repository given the name and a Store."""
62
        raise NotImplementedError()
63
1165.1.22 by William Grant
Detect the permitted offering for the given submission URL and restrict to that.
64
    def get_offering(self):
65
        """Return the offering that this path can be submitted to."""
66
        raise NotImplementedError()
67
1165.1.8 by William Grant
Start a submission UI in ivle.webapp.submit.
68
    def populate(self, req, ctx):
1165.1.20 by William Grant
Add a POST handler to SubmitView, which does the actual submission.
69
        if req.method == 'POST':
70
            data = dict(req.get_fieldstorage())
1165.1.25 by William Grant
Take the revision to submit from the query string.
71
            if 'revision' not in data:
1165.1.41 by William Grant
Give more human-readable 400 messages for submission.
72
                raise BadRequest('No revision selected.')
1165.1.25 by William Grant
Take the revision to submit from the query string.
73
74
            try:
75
                revision = int(data['revision'])
76
            except ValueError:
1165.1.41 by William Grant
Give more human-readable 400 messages for submission.
77
                raise BadRequest('Revision must be an integer.')
1165.1.25 by William Grant
Take the revision to submit from the query string.
78
1165.1.20 by William Grant
Add a POST handler to SubmitView, which does the actual submission.
79
            if 'project' not in data:
1165.1.41 by William Grant
Give more human-readable 400 messages for submission.
80
                raise BadRequest('No project selected.')
1165.1.20 by William Grant
Add a POST handler to SubmitView, which does the actual submission.
81
82
            try:
83
                projectid = int(data['project'])
84
            except ValueError:
1165.1.41 by William Grant
Give more human-readable 400 messages for submission.
85
                raise BadRequest('Project must be an integer.')
1165.1.20 by William Grant
Add a POST handler to SubmitView, which does the actual submission.
86
87
            project = req.store.find(Project, Project.id == projectid).one()
88
1165.1.24 by William Grant
400 if a non-matching project is POSTed.
89
            # This view's offering will be the sole offering for which the
90
            # path is permissible. We need to check that.
91
            if project.project_set.offering is not self.offering:
92
                raise BadRequest('Path is not permissible for this offering')
93
1165.1.20 by William Grant
Add a POST handler to SubmitView, which does the actual submission.
94
            if project is None:
95
                raise BadRequest('Specified project does not exist')
96
1445.1.1 by William Grant
unicodeify the submit path, to avoid angering the Storm Gods.
97
            project.submit(self.context, unicode(self.path), revision, req.user)
1165.1.20 by William Grant
Add a POST handler to SubmitView, which does the actual submission.
98
1165.5.8 by William Grant
Rebuild SVN authz files on submission.
99
            # The Subversion configuration needs to be updated, to grant
100
            # tutors and lecturers access to this submission. We have to 
101
            # commit early so usrmgt-server can see the new submission.
102
            req.store.commit()
103
104
            # Instruct usrmgt-server to rebuild the SVN group authz file.
105
            msg = {'rebuild_svn_group_config': {}}
106
            usrmgt = ivle.chat.chat(req.config['usrmgt']['host'],
107
                                    req.config['usrmgt']['port'],
108
                                    msg,
109
                                    req.config['usrmgt']['magic'],
110
                                    )
111
112
            if usrmgt.get('response') in (None, 'failure'):
113
                raise Exception("Failure creating repository: " + str(usrmgt))
114
115
            # Instruct usrmgt-server to rebuild the SVN user authz file.
116
            msg = {'rebuild_svn_config': {}}
117
            usrmgt = ivle.chat.chat(req.config['usrmgt']['host'],
118
                                    req.config['usrmgt']['port'],
119
                                    msg,
120
                                    req.config['usrmgt']['magic'],
121
                                    )
122
123
            if usrmgt.get('response') in (None, 'failure'):
124
                raise Exception("Failure creating repository: " + str(usrmgt))
125
1165.1.43 by William Grant
Display an informative view on submission success.
126
            self.template = 'submitted.html'
127
            ctx['project'] = project
128
1165.1.27 by William Grant
Make the submit view significantly more readable.
129
        ctx['req'] = req
1165.1.13 by William Grant
Add an initial project selection UI to SubmitView.
130
        ctx['principal'] = self.context
1165.1.24 by William Grant
400 if a non-matching project is POSTed.
131
        ctx['offering'] = self.offering
1165.1.13 by William Grant
Add an initial project selection UI to SubmitView.
132
        ctx['path'] = self.path
1165.1.17 by William Grant
Disable project radio buttons if they are closed.
133
        ctx['now'] = datetime.datetime.now()
1179 by Matt Giuca
submit: Added tooltip for the due date (which displays the whole date, while
134
        ctx['format_datetime'] = ivle.date.make_date_nice
135
        ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
1294.4.13 by David Coles
Ported Submit to object publisher framework
136
    
137
    @property
138
    def path(self):
139
        return os.path.join('/', *self.subpath[1:]) if self.subpath else '/'
1165.1.8 by William Grant
Start a submission UI in ivle.webapp.submit.
140
1165.1.9 by William Grant
Split SubmitView.__init__ into new subclasses, {User,Group}SubmitView.
141
142
class UserSubmitView(SubmitView):
143
    def get_repository_owner(self, store, name):
144
        '''Resolve the user name into a user.'''
145
        return User.get_by_login(store, name)
146
1165.1.22 by William Grant
Detect the permitted offering for the given submission URL and restrict to that.
147
    def get_offering(self):
148
        return Store.of(self.context).find(Offering,
149
            Offering.id == Enrolment.offering_id,
150
            Enrolment.user_id == self.context.id,
151
            Offering.semester_id == Semester.id,
152
            Semester.state == u'current',
153
            Offering.subject_id == Subject.id,
1244 by William Grant
Ensure that the path is absolute when submitting a project.
154
            Subject.short_name == self.path.split('/')[1],
1165.1.22 by William Grant
Detect the permitted offering for the given submission URL and restrict to that.
155
            ).one()
156
1165.1.9 by William Grant
Split SubmitView.__init__ into new subclasses, {User,Group}SubmitView.
157
158
class GroupSubmitView(SubmitView):
159
    def get_repository_owner(self, store, name):
160
        '''Resolve the subject_year_semester_group name into a group.'''
161
        namebits = name.split('_', 3)
162
        if len(namebits) != 4:
163
            return None
164
165
        # Find the project group with the given name in any project set in the
166
        # offering of the given subject in the semester with the given year
167
        # and semester.
168
        return store.find(ProjectGroup,
169
            ProjectGroup.name == namebits[3],
170
            ProjectGroup.project_set_id == ProjectSet.id,
171
            ProjectSet.offering_id == Offering.id,
172
            Offering.subject_id == Subject.id,
173
            Subject.short_name == namebits[0],
174
            Offering.semester_id == Semester.id,
175
            Semester.year == namebits[1],
176
            Semester.semester == namebits[2]).one()
177
1165.1.22 by William Grant
Detect the permitted offering for the given submission URL and restrict to that.
178
    def get_offering(self):
179
        return self.context.project_set.offering
180
1165.1.9 by William Grant
Split SubmitView.__init__ into new subclasses, {User,Group}SubmitView.
181
1165.1.8 by William Grant
Start a submission UI in ivle.webapp.submit.
182
class Plugin(ViewPlugin):
1294.4.13 by David Coles
Ported Submit to object publisher framework
183
    views = [(ApplicationRoot, ('+submit', 'users'), UserSubmitView),
184
             (ApplicationRoot, ('+submit', 'groups'), GroupSubmitView)]
185