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

« back to all changes in this revision

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

  • Committer: Matt Giuca
  • Date: 2009-05-19 02:54:08 UTC
  • mfrom: (1258 trunk)
  • mto: This revision was merged to the branch mainline in revision 1322.
  • Revision ID: matt.giuca@gmail.com-20090519025408-19c7cjl7w6ot6frm
MergedĀ fromĀ trunk.

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
import ivle.chat
 
35
 
 
36
 
 
37
class SubmitView(XHTMLView):
 
38
    """A view to submit a Subversion repository path for a project."""
 
39
    template = 'submit.html'
 
40
    tab = 'files'
 
41
    permission = 'submit_project'
 
42
 
 
43
    def __init__(self, req, name, path=u"/"):
 
44
        # We need to work out which entity owns the repository, so we look
 
45
        # at the first two path segments. The first tells us the type.
 
46
        self.context = self.get_repository_owner(req.store, name)
 
47
 
 
48
        # Ensure that the path is absolute (required for SVNAuthzFile).
 
49
        # XXX Re-convert to unicode (os.path.normpath(u"/") returns a str).
 
50
        self.path = os.path.join(u"/", unicode(os.path.normpath(path)))
 
51
 
 
52
        if self.context is None:
 
53
            raise NotFound()
 
54
 
 
55
        self.offering = self.get_offering()
 
56
 
 
57
    def get_repository_owner(self, store, name):
 
58
        """Return the owner of the repository given the name and a Store."""
 
59
        raise NotImplementedError()
 
60
 
 
61
    def get_offering(self):
 
62
        """Return the offering that this path can be submitted to."""
 
63
        raise NotImplementedError()
 
64
 
 
65
    def populate(self, req, ctx):
 
66
        if req.method == 'POST':
 
67
            data = dict(req.get_fieldstorage())
 
68
            if 'revision' not in data:
 
69
                raise BadRequest('No revision selected.')
 
70
 
 
71
            try:
 
72
                revision = int(data['revision'])
 
73
            except ValueError:
 
74
                raise BadRequest('Revision must be an integer.')
 
75
 
 
76
            if 'project' not in data:
 
77
                raise BadRequest('No project selected.')
 
78
 
 
79
            try:
 
80
                projectid = int(data['project'])
 
81
            except ValueError:
 
82
                raise BadRequest('Project must be an integer.')
 
83
 
 
84
            project = req.store.find(Project, Project.id == projectid).one()
 
85
 
 
86
            # This view's offering will be the sole offering for which the
 
87
            # path is permissible. We need to check that.
 
88
            if project.project_set.offering is not self.offering:
 
89
                raise BadRequest('Path is not permissible for this offering')
 
90
 
 
91
            if project is None:
 
92
                raise BadRequest('Specified project does not exist')
 
93
 
 
94
            project.submit(self.context, self.path, revision, req.user)
 
95
 
 
96
            # The Subversion configuration needs to be updated, to grant
 
97
            # tutors and lecturers access to this submission. We have to 
 
98
            # commit early so usrmgt-server can see the new submission.
 
99
            req.store.commit()
 
100
 
 
101
            # Instruct usrmgt-server to rebuild the SVN group authz file.
 
102
            msg = {'rebuild_svn_group_config': {}}
 
103
            usrmgt = ivle.chat.chat(req.config['usrmgt']['host'],
 
104
                                    req.config['usrmgt']['port'],
 
105
                                    msg,
 
106
                                    req.config['usrmgt']['magic'],
 
107
                                    )
 
108
 
 
109
            if usrmgt.get('response') in (None, 'failure'):
 
110
                raise Exception("Failure creating repository: " + str(usrmgt))
 
111
 
 
112
            # Instruct usrmgt-server to rebuild the SVN user authz file.
 
113
            msg = {'rebuild_svn_config': {}}
 
114
            usrmgt = ivle.chat.chat(req.config['usrmgt']['host'],
 
115
                                    req.config['usrmgt']['port'],
 
116
                                    msg,
 
117
                                    req.config['usrmgt']['magic'],
 
118
                                    )
 
119
 
 
120
            if usrmgt.get('response') in (None, 'failure'):
 
121
                raise Exception("Failure creating repository: " + str(usrmgt))
 
122
 
 
123
            self.template = 'submitted.html'
 
124
            ctx['project'] = project
 
125
 
 
126
        ctx['req'] = req
 
127
        ctx['principal'] = self.context
 
128
        ctx['offering'] = self.offering
 
129
        ctx['path'] = self.path
 
130
        ctx['now'] = datetime.datetime.now()
 
131
        ctx['format_datetime'] = ivle.date.make_date_nice
 
132
        ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
 
133
 
 
134
 
 
135
class UserSubmitView(SubmitView):
 
136
    def get_repository_owner(self, store, name):
 
137
        '''Resolve the user name into a user.'''
 
138
        return User.get_by_login(store, name)
 
139
 
 
140
    def get_offering(self):
 
141
        return Store.of(self.context).find(Offering,
 
142
            Offering.id == Enrolment.offering_id,
 
143
            Enrolment.user_id == self.context.id,
 
144
            Offering.semester_id == Semester.id,
 
145
            Semester.state == u'current',
 
146
            Offering.subject_id == Subject.id,
 
147
            Subject.short_name == self.path.split('/')[1],
 
148
            ).one()
 
149
 
 
150
 
 
151
class GroupSubmitView(SubmitView):
 
152
    def get_repository_owner(self, store, name):
 
153
        '''Resolve the subject_year_semester_group name into a group.'''
 
154
        namebits = name.split('_', 3)
 
155
        if len(namebits) != 4:
 
156
            return None
 
157
 
 
158
        # Find the project group with the given name in any project set in the
 
159
        # offering of the given subject in the semester with the given year
 
160
        # and semester.
 
161
        return store.find(ProjectGroup,
 
162
            ProjectGroup.name == namebits[3],
 
163
            ProjectGroup.project_set_id == ProjectSet.id,
 
164
            ProjectSet.offering_id == Offering.id,
 
165
            Offering.subject_id == Subject.id,
 
166
            Subject.short_name == namebits[0],
 
167
            Offering.semester_id == Semester.id,
 
168
            Semester.year == namebits[1],
 
169
            Semester.semester == namebits[2]).one()
 
170
 
 
171
    def get_offering(self):
 
172
        return self.context.project_set.offering
 
173
 
 
174
 
 
175
class Plugin(ViewPlugin):
 
176
    urls = [
 
177
        ('+submit/users/:name', UserSubmitView),
 
178
        ('+submit/groups/:name', GroupSubmitView),
 
179
        ('+submit/users/:name/*path', UserSubmitView),
 
180
        ('+submit/groups/:name/*path', GroupSubmitView),
 
181
    ]