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

465 by mattgiuca
Added new app: userservice, which is an ajax service for user management
1
# IVLE
2
# Copyright (C) 2007-2008 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
# App: userservice
19
# Author: Matt Giuca
20
# Date: 14/2/2008
21
478 by mattgiuca
scripts/usrmgr-server: Renamed actions from dashes to underscores.
22
# Provides an Ajax service for handling user management requests.
23
# This includes when a user logs in for the first time.
24
486 by mattgiuca
caps: Added a few new capabilities.
25
### Actions ###
26
27
# The one-and-only path segment to userservice determines the action being
28
# undertaken.
29
# All actions require that you are logged in.
30
# All actions require method = POST, unless otherwise stated.
31
32
# userservice/activate_me
33
# Required cap: None
34
# declaration = "I accept the IVLE Terms of Service"
35
# Activate the currently-logged-in user's account. Requires that "declaration"
36
# is as above, and that the user's state is "no_agreement".
37
38
# TODO
39
# userservice/enable_user
40
# Required cap: CAP_UPDATEUSER
41
# Enable a user whose account has been disabled. Does not work for
42
# no_agreement or pending users.
43
# login = Login name of user to enable.
44
45
# TODO
46
# userservice/disable_user
47
# Required cap: CAP_UPDATEUSER
48
# Disable a user's account. Does not work for no_agreement or pending users.
49
# login = Login name of user to disable.
50
930 by dcoles
Userservice: Added get_enrolments handler to allow a JSON query of a students
51
# userservice/get_enrolments
52
# Required cap: None (for yourself)
53
# Returns a JSON encoded listing of a students is enrollments
54
981 by dcoles
Groups: Added in support for creating groups in the database through
55
# PROJECTS AND GROUPS
56
1001 by dcoles
Groups: Added the view half of the group admin panel. This lets people with the
57
# userservice/get_project_groups
58
# Required cap: None
59
# Returns all the project groups in an offering grouped by project set
60
# Required:
61
#   offeringid
62
981 by dcoles
Groups: Added in support for creating groups in the database through
63
# userservice/create_project_set
64
# Required cap: CAP_MANAGEPROJECTS
984 by dcoles
Groups: Added userservice/create_project call. You can now create a project in
65
# Creates a project set for a offering
981 by dcoles
Groups: Added in support for creating groups in the database through
66
# Required:
67
#   offeringid, max_students_per_group
984 by dcoles
Groups: Added userservice/create_project call. You can now create a project in
68
# Returns:
69
#   projectsetid
981 by dcoles
Groups: Added in support for creating groups in the database through
70
71
# userservice/create_project
72
# Required cap: CAP_MANAGEPROJECTS
73
# Creates a project in a specific project set
74
# Required:
75
#   projectsetid
76
# Optional:
984 by dcoles
Groups: Added userservice/create_project call. You can now create a project in
77
#   synopsis, url, deadline
78
# Returns:
79
#   projectid
981 by dcoles
Groups: Added in support for creating groups in the database through
80
81
# userservice/create_group
82
# Required cap: CAP_MANAGEGROUPS
83
# Creates a project group in a specific project set
84
# Required:
85
#   projectsetid, groupnm
86
# Optional:
87
#   nick
88
1004 by dcoles
Groups: Now you can add people to a group as well as creating groups from the
89
# userservice/get_group_membership
90
# Required cap: None
91
# Returns two lists. One of people in the group and one of people not in the 
92
# group (but enroled in the offering)
93
# Required:
94
#   groupid
95
981 by dcoles
Groups: Added in support for creating groups in the database through
96
# userservice/assign_to_group
97
# Required cap: CAP_MANAGEGROUPS
98
# Assigns a user to a project group
1004 by dcoles
Groups: Now you can add people to a group as well as creating groups from the
99
# Required: login, groupid
981 by dcoles
Groups: Added in support for creating groups in the database through
100
465 by mattgiuca
Added new app: userservice, which is an ajax service for user management
101
import os
102
import sys
1080.1.80 by William Grant
www/apps/userservice: Port create_group to Storm.
103
import datetime
465 by mattgiuca
Added new app: userservice, which is an ajax service for user management
104
105
import cjson
106
1080.1.7 by matt.giuca
The new ivle.database.User class is now used in Request and usrmgt, which
107
import ivle.database
1101 by William Grant
Privileges (apart from admin) are now offering-local, not global.
108
from ivle import (util, chat)
1099.1.161 by William Grant
Move ivle.dispatch.login.get_user_details() to ivle.webapp.security.
109
from ivle.webapp.security import get_user_details
1080.1.73 by William Grant
www/apps/userservice: create_user now creates and enrols the User itself, not
110
import ivle.pulldown_subj
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
111
1606 by William Grant
Restrict privileges on group-related userservice actions to users with admin_groups on the offering.
112
from ivle.rpc.decorators import require_method, require_admin
1080.1.90 by William Grant
ivle.rpc.decorators: Add (new package, too). Has a couple of decorators to
113
1080.1.12 by me at id
ivle.auth.autherror: Remove, moving AuthError into ivle.auth itself.
114
from ivle.auth import AuthError, authenticate
1078 by chadnickbok
Updated the settings page to require the old password
115
import urllib
116
1099.1.132 by William Grant
Direct port of userservice to the new framework.
117
from ivle.webapp.base.views import BaseView
118
from ivle.webapp.base.plugins import ViewPlugin
1099.1.134 by William Grant
Replace most userservice req.throw_error()s with new exceptions.
119
from ivle.webapp.errors import NotFound, BadRequest, Unauthorized
1294.2.65 by William Grant
Port userservice.
120
from ivle.webapp import ApplicationRoot
1099.1.132 by William Grant
Direct port of userservice to the new framework.
121
465 by mattgiuca
Added new app: userservice, which is an ajax service for user management
122
# The user must send this declaration message to ensure they acknowledge the
123
# TOS
124
USER_DECLARATION = "I accept the IVLE Terms of Service"
125
1099.1.132 by William Grant
Direct port of userservice to the new framework.
126
class UserServiceView(BaseView):
1294.2.65 by William Grant
Port userservice.
127
    subpath_allowed = True
1099.1.132 by William Grant
Direct port of userservice to the new framework.
128
129
    def authorize(self, req):
1099.1.127 by William Grant
Implement ToS acceptance in the new login machinery. Now implemented through
130
        # XXX: activate_me isn't called by a valid user, so is special for now.
1099.1.132 by William Grant
Direct port of userservice to the new framework.
131
        if req.path == 'activate_me' and get_user_details(req) is not None:
132
            return True
133
        return req.user is not None
134
135
    def render(self, req):
136
        # The path determines which "command" we are receiving
137
        fields = req.get_fieldstorage()
138
        try:
139
            func = actions_map[self.path]
140
        except KeyError:
141
            raise NotFound()
142
        func(req, fields)
143
1294.2.65 by William Grant
Port userservice.
144
    @property
145
    def path(self):
146
        return os.path.join(*self.subpath) if self.subpath else ''
147
148
1099.1.132 by William Grant
Direct port of userservice to the new framework.
149
class Plugin(ViewPlugin):
1294.2.65 by William Grant
Port userservice.
150
    views = [(ApplicationRoot, 'userservice', UserServiceView)]
465 by mattgiuca
Added new app: userservice, which is an ajax service for user management
151
1080.1.90 by William Grant
ivle.rpc.decorators: Add (new package, too). Has a couple of decorators to
152
@require_method('POST')
486 by mattgiuca
caps: Added a few new capabilities.
153
def handle_activate_me(req, fields):
465 by mattgiuca
Added new app: userservice, which is an ajax service for user management
154
    """Create the jail, svn, etc, for the currently logged in user (this is
155
    put in the queue for usermgt to do).
156
    This will block until usermgt returns, which could take seconds to minutes
157
    in the extreme. Therefore, it is designed to be called by Ajax, with a
158
    nice "Please wait" message on the frontend.
159
160
    This will signal that the user has accepted the terms of the license
161
    agreement, and will result in the user's database status being set to
162
    "enabled". (Note that it will be set to "pending" for the duration of the
163
    handling).
164
165
    As such, it takes a single POST field, "declaration", which
166
    must have the value, "I accept the IVLE Terms of Service".
167
    (Otherwise users could navigate to /userservice/createme without
168
    "accepting" the terms - at least this way requires them to acknowledge
169
    their acceptance). It must only be called through a POST request.
170
    """
1099.1.127 by William Grant
Implement ToS acceptance in the new login machinery. Now implemented through
171
1099.1.137 by William Grant
Actually set user in userservice/activate_me.
172
    user = get_user_details(req)
173
486 by mattgiuca
caps: Added a few new capabilities.
174
    try:
1099.1.136 by William Grant
Remove some useless try-except blocks that just raise a 500.
175
        declaration = fields.getfirst('declaration')
176
    except AttributeError:
177
        declaration = None      # Will fail next test
178
    if declaration != USER_DECLARATION:
179
        raise BadRequest()
180
181
    # Make sure the user's status is "no_agreement", and set status to
182
    # pending, within the one transaction. This ensures we only do this
183
    # one time.
184
    try:
185
        # Check that the user's status is "no_agreement".
186
        # (Both to avoid redundant calls, and to stop disabled users from
187
        # re-enabling their accounts).
188
        if user.state != "no_agreement":
189
            raise BadRequest("You have already agreed to the terms.")
190
        # Write state "pending" to ensure we don't try this again
191
        user.state = u"pending"
1080.1.7 by matt.giuca
The new ivle.database.User class is now used in Request and usrmgt, which
192
    except:
193
        req.store.rollback()
194
        raise
1099.1.136 by William Grant
Remove some useless try-except blocks that just raise a 500.
195
    req.store.commit()
196
197
    # Get the arguments for usermgt.activate_user from the session
198
    # (The user must have already logged in to use this app)
199
    args = {
200
        "login": user.login,
201
    }
202
    msg = {'activate_user': args}
203
204
    # Release our lock on the db so usrmgt can write
205
    req.store.rollback()
206
207
    # Try and contact the usrmgt server
208
    try:
1204 by William Grant
Use the config from the request, rather than ivle.conf, in userservice.
209
        response = chat.chat(req.config['usrmgt']['host'],
210
                             req.config['usrmgt']['port'],
211
                             msg,
212
                             req.config['usrmgt']['magic'],
213
                            )
1099.1.136 by William Grant
Remove some useless try-except blocks that just raise a 500.
214
    except cjson.DecodeError:
215
        # Gave back rubbish - set the response to failure
216
        response = {'response': 'usrmgt-failure'}
217
218
    # Get the staus of the users request
219
    try:
220
        status = response['response']
221
    except KeyError:
222
        status = 'failure'
223
224
    if status == 'okay':
225
        user.state = u"enabled"
226
    else:
227
        # Reset the user back to no agreement
228
        user.state = u"no_agreement"
229
230
    # Write the response
231
    req.content_type = "text/plain"
232
    req.write(cjson.encode(response))
486 by mattgiuca
caps: Added a few new capabilities.
233
930 by dcoles
Userservice: Added get_enrolments handler to allow a JSON query of a students
234
def handle_get_enrolments(req, fields):
235
    """
995 by wagrant
common.db: Add get_enrolment_groups. Will return group information for
236
    Retrieve a user's enrolment details. Each enrolment includes any group
237
    memberships for that offering.
930 by dcoles
Userservice: Added get_enrolments handler to allow a JSON query of a students
238
    """
239
    # For the moment we're only able to query ourselves
240
    fullpowers = False
241
242
    try:
1080.1.28 by me at id
www/apps/groups: Use User.active_enrolments rather than ivle.db.get_enrolment.
243
        user = ivle.database.User.get_by_login(req.store,
244
                    fields.getfirst('login'))
245
        if user is None:
930 by dcoles
Userservice: Added get_enrolments handler to allow a JSON query of a students
246
            raise AttributeError()
1080.1.28 by me at id
www/apps/groups: Use User.active_enrolments rather than ivle.db.get_enrolment.
247
        if not fullpowers and user != req.user:
1099.1.134 by William Grant
Replace most userservice req.throw_error()s with new exceptions.
248
            raise Unauthorized()
930 by dcoles
Userservice: Added get_enrolments handler to allow a JSON query of a students
249
    except AttributeError:
250
        # If login not specified, update yourself
1080.1.28 by me at id
www/apps/groups: Use User.active_enrolments rather than ivle.db.get_enrolment.
251
        user = req.user
930 by dcoles
Userservice: Added get_enrolments handler to allow a JSON query of a students
252
1080.1.28 by me at id
www/apps/groups: Use User.active_enrolments rather than ivle.db.get_enrolment.
253
    dict_enrolments = []
254
    for e in user.active_enrolments:
255
        dict_enrolments.append({
256
            'offeringid':      e.offering.id,
1475 by William Grant
Give specialhome a link to each offering index.
257
            'url':             req.publisher.generate(e.offering),
1080.1.28 by me at id
www/apps/groups: Use User.active_enrolments rather than ivle.db.get_enrolment.
258
            'subj_code':       e.offering.subject.code,
259
            'subj_name':       e.offering.subject.name,
260
            'subj_short_name': e.offering.subject.short_name,
261
            'year':            e.offering.semester.year,
262
            'semester':        e.offering.semester.semester,
1080.1.81 by William Grant
ivle.database.Enrolment: Add a groups attribute, containing groups of which
263
            'groups':          [{'name': group.name,
264
                                 'nick': group.nick} for group in e.groups]
1080.1.28 by me at id
www/apps/groups: Use User.active_enrolments rather than ivle.db.get_enrolment.
265
        })
266
    response = cjson.encode(dict_enrolments)
930 by dcoles
Userservice: Added get_enrolments handler to allow a JSON query of a students
267
    req.content_type = "text/plain"
268
    req.write(response)
269
1001 by dcoles
Groups: Added the view half of the group admin panel. This lets people with the
270
def handle_get_project_groups(req, fields):
271
    """Required cap: None
272
    Returns all the project groups in an offering grouped by project set
273
    Required:
274
        offeringid
275
    """
276
277
    offeringid = fields.getfirst('offeringid')
278
    if offeringid is None:
1099.1.134 by William Grant
Replace most userservice req.throw_error()s with new exceptions.
279
        raise BadRequest("Required: offeringid")
1001 by dcoles
Groups: Added the view half of the group admin panel. This lets people with the
280
    try:
281
        offeringid = int(offeringid)
282
    except:
1099.1.134 by William Grant
Replace most userservice req.throw_error()s with new exceptions.
283
        raise BadRequest("offeringid must be an integer")
1080.1.76 by William Grant
ivle.database.Offering: Add project_sets referenceset.
284
285
    offering = req.store.get(ivle.database.Offering, offeringid)
286
1606 by William Grant
Restrict privileges on group-related userservice actions to users with admin_groups on the offering.
287
    if 'admin_groups' not in offering.get_permissions(req.user, req.config):
288
        raise Unauthorized()
289
1080.1.76 by William Grant
ivle.database.Offering: Add project_sets referenceset.
290
    dict_projectsets = []
1099.1.136 by William Grant
Remove some useless try-except blocks that just raise a 500.
291
    for p in offering.project_sets:
292
        dict_projectsets.append({
293
            'projectsetid': p.id,
294
            'max_students_per_group': p.max_students_per_group,
295
            'groups': [{'groupid': g.id,
296
                        'groupnm': g.name,
297
                        'nick': g.nick} for g in p.project_groups]
298
        })
1001 by dcoles
Groups: Added the view half of the group admin panel. This lets people with the
299
1080.1.76 by William Grant
ivle.database.Offering: Add project_sets referenceset.
300
    response = cjson.encode(dict_projectsets)
1001 by dcoles
Groups: Added the view half of the group admin panel. This lets people with the
301
    req.write(response)
302
1080.1.90 by William Grant
ivle.rpc.decorators: Add (new package, too). Has a couple of decorators to
303
@require_method('POST')
986 by dcoles
Groups: Added userservice/create_group call. You can now create a project in
304
def handle_create_group(req, fields):
305
    """Required cap: CAP_MANAGEGROUPS
306
    Creates a project group in a specific project set
307
    Required:
308
        projectsetid, groupnm
309
    Optional:
310
        nick
311
    Returns:
312
        groupid
313
    """
314
    # Get required fields
1080.1.80 by William Grant
www/apps/userservice: Port create_group to Storm.
315
    projectsetid = fields.getfirst('projectsetid').value
316
    groupnm = fields.getfirst('groupnm').value
986 by dcoles
Groups: Added userservice/create_group call. You can now create a project in
317
    if projectsetid is None or groupnm is None:
1099.1.134 by William Grant
Replace most userservice req.throw_error()s with new exceptions.
318
        raise BadRequest("Required: projectsetid, groupnm")
1080.1.80 by William Grant
www/apps/userservice: Port create_group to Storm.
319
    groupnm = unicode(groupnm)
1004 by dcoles
Groups: Now you can add people to a group as well as creating groups from the
320
    try:
321
        projectsetid = int(projectsetid)
322
    except:
1099.1.134 by William Grant
Replace most userservice req.throw_error()s with new exceptions.
323
        raise BadRequest("projectsetid must be an integer")
324
1606 by William Grant
Restrict privileges on group-related userservice actions to users with admin_groups on the offering.
325
    projectset = req.store.get(ivle.database.ProjectSet, projectsetid)
326
    if projectset is None:
327
        raise BadRequest("Invalid projectsetid")
328
    if 'admin_groups' not in projectset.offering.get_permissions(
329
        req.user, req.config):
330
        raise Unauthorized()
331
986 by dcoles
Groups: Added userservice/create_group call. You can now create a project in
332
    # Get optional fields
1080.1.80 by William Grant
www/apps/userservice: Port create_group to Storm.
333
    nick = fields.getfirst('nick').value
334
    if nick is not None:
335
        nick = unicode(nick)
1006 by dcoles
Groups: Use db transactions for risky usermanagement operations. (Such as when
336
1099.1.136 by William Grant
Remove some useless try-except blocks that just raise a 500.
337
    group = ivle.database.ProjectGroup(name=groupnm,
1606 by William Grant
Restrict privileges on group-related userservice actions to users with admin_groups on the offering.
338
                                       project_set=projectset,
1099.1.136 by William Grant
Remove some useless try-except blocks that just raise a 500.
339
                                       nick=nick,
340
                                       created_by=req.user,
341
                                       epoch=datetime.datetime.now())
342
    req.store.add(group)
343
344
    # Create the group repository
345
    # Yes, this is ugly, and it would be nice to just pass in the groupid,
346
    # but the object isn't visible to the extra transaction in
347
    # usrmgt-server until we commit, which we only do once the repo is
348
    # created.
349
    offering = group.project_set.offering
350
351
    args = {
352
        "subj_short_name": offering.subject.short_name,
353
        "year": offering.semester.year,
354
        "semester": offering.semester.semester,
355
        "groupnm": group.name,
356
    }
357
    msg = {'create_group_repository': args}
358
359
    # Contact the usrmgt server
986 by dcoles
Groups: Added userservice/create_group call. You can now create a project in
360
    try:
1204 by William Grant
Use the config from the request, rather than ivle.conf, in userservice.
361
        usrmgt = chat.chat(req.config['usrmgt']['host'],
362
                           req.config['usrmgt']['port'],
363
                           msg,
364
                           req.config['usrmgt']['magic'],
365
                          )
1099.1.136 by William Grant
Remove some useless try-except blocks that just raise a 500.
366
    except cjson.DecodeError, e:
367
        raise Exception("Could not understand usrmgt server response:" +
368
                        e.message)
369
370
    if 'response' not in usrmgt or usrmgt['response']=='failure':
371
        raise Exception("Failure creating repository: " + str(usrmgt))
986 by dcoles
Groups: Added userservice/create_group call. You can now create a project in
372
373
    req.content_type = "text/plain"
1080.1.80 by William Grant
www/apps/userservice: Port create_group to Storm.
374
    req.write('')
981 by dcoles
Groups: Added in support for creating groups in the database through
375
1004 by dcoles
Groups: Now you can add people to a group as well as creating groups from the
376
def handle_get_group_membership(req, fields):
377
    """ Required cap: None
378
    Returns two lists. One of people in the group and one of people not in the 
379
    group (but enroled in the offering)
380
    Required:
381
        groupid, offeringid
382
    """
383
    # Get required fields
384
    groupid = fields.getfirst('groupid')
385
    offeringid = fields.getfirst('offeringid')
386
    if groupid is None or offeringid is None:
1099.1.134 by William Grant
Replace most userservice req.throw_error()s with new exceptions.
387
        raise BadRequest("Required: groupid, offeringid")
1004 by dcoles
Groups: Now you can add people to a group as well as creating groups from the
388
    try:
389
        groupid = int(groupid)
390
    except:
1099.1.134 by William Grant
Replace most userservice req.throw_error()s with new exceptions.
391
        raise BadRequest("groupid must be an integer")
1080.1.79 by William Grant
ivle.database.Offering: Add a members ReferenceSet.
392
    group = req.store.get(ivle.database.ProjectGroup, groupid)
393
1004 by dcoles
Groups: Now you can add people to a group as well as creating groups from the
394
    try:
395
        offeringid = int(offeringid)
396
    except:
1099.1.134 by William Grant
Replace most userservice req.throw_error()s with new exceptions.
397
        raise BadRequest("offeringid must be an integer")
1080.1.79 by William Grant
ivle.database.Offering: Add a members ReferenceSet.
398
    offering = req.store.get(ivle.database.Offering, offeringid)
399
1606 by William Grant
Restrict privileges on group-related userservice actions to users with admin_groups on the offering.
400
    if 'admin_groups' not in offering.get_permissions(req.user, req.config):
401
        raise Unauthorized()
1080.1.79 by William Grant
ivle.database.Offering: Add a members ReferenceSet.
402
403
    offeringmembers = [{'login': user.login,
404
                        'fullname': user.fullname
405
                       } for user in offering.members.order_by(
406
                            ivle.database.User.login)
407
                      ]
408
    groupmembers = [{'login': user.login,
409
                        'fullname': user.fullname
410
                       } for user in group.members.order_by(
411
                            ivle.database.User.login)
412
                      ]
413
1004 by dcoles
Groups: Now you can add people to a group as well as creating groups from the
414
    # Make sure we don't include members in both lists
415
    for member in groupmembers:
416
        if member in offeringmembers:
417
            offeringmembers.remove(member)
418
419
    response = cjson.encode(
420
        {'groupmembers': groupmembers, 'available': offeringmembers})
421
422
    req.content_type = "text/plain"
423
    req.write(response)
424
1080.1.90 by William Grant
ivle.rpc.decorators: Add (new package, too). Has a couple of decorators to
425
@require_method('POST')
989 by dcoles
Groups: Added userservice/assign_group call. This allows a user with the
426
def handle_assign_group(req, fields):
427
    """ Required cap: CAP_MANAGEGROUPS
428
    Assigns a user to a project group
429
    Required:
430
        login, groupid
431
    """
432
    # Get required fields
433
    login = fields.getfirst('login')
434
    groupid = fields.getfirst('groupid')
435
    if login is None or groupid is None:
1099.1.134 by William Grant
Replace most userservice req.throw_error()s with new exceptions.
436
        raise BadRequest("Required: login, groupid")
1080.1.84 by William Grant
wwww/apps/userservice: Create group memberships using Storm, not ivle.db.
437
438
    group = req.store.get(ivle.database.ProjectGroup, int(groupid))
439
    user = ivle.database.User.get_by_login(req.store, login)
440
1606 by William Grant
Restrict privileges on group-related userservice actions to users with admin_groups on the offering.
441
    if 'admin_groups' not in group.project_set.offering.get_permissions(
442
        req.user, req.config):
443
        raise Unauthorized()
444
1080.1.84 by William Grant
wwww/apps/userservice: Create group memberships using Storm, not ivle.db.
445
    # Add membership to database
446
    # We can't keep a transaction open until the end here, as usrmgt-server
447
    # needs to see the changes!
1099.1.136 by William Grant
Remove some useless try-except blocks that just raise a 500.
448
    group.members.add(user)
449
    req.store.commit()
450
451
    # Rebuild the svn config file
452
    # Contact the usrmgt server
453
    msg = {'rebuild_svn_group_config': {}}
989 by dcoles
Groups: Added userservice/assign_group call. This allows a user with the
454
    try:
1204 by William Grant
Use the config from the request, rather than ivle.conf, in userservice.
455
        usrmgt = chat.chat(req.config['usrmgt']['host'],
456
                           req.config['usrmgt']['port'],
457
                           msg,
458
                           req.config['usrmgt']['magic'],
459
                          )
1099.1.136 by William Grant
Remove some useless try-except blocks that just raise a 500.
460
    except cjson.DecodeError, e:
461
        raise Exception("Could not understand usrmgt server response: %s" +
462
                        e.message)
463
464
        if 'response' not in usrmgt or usrmgt['response']=='failure':
465
            raise Exception("Failure creating repository: " + str(usrmgt))
989 by dcoles
Groups: Added userservice/assign_group call. This allows a user with the
466
467
    return(cjson.encode({'response': 'okay'}))
981 by dcoles
Groups: Added in support for creating groups in the database through
468
1181 by William Grant
Allow revocation of group memberships by tutors and lecturers.
469
@require_method('POST')
470
def handle_unassign_group(req, fields):
471
    """Remove a user from a project group.
472
473
    The user is removed from the group in the database, and access to the
474
    group Subversion repository is revoked.
475
476
    Note that any checkouts will remain, although they will be unusable.
477
    """
478
479
    # Get required fields
480
    login = fields.getfirst('login')
481
    groupid = fields.getfirst('groupid')
482
    if login is None or groupid is None:
483
        raise BadRequest("Required: login, groupid")
484
485
    group = req.store.get(ivle.database.ProjectGroup, int(groupid))
486
    user = ivle.database.User.get_by_login(req.store, login)
487
1606 by William Grant
Restrict privileges on group-related userservice actions to users with admin_groups on the offering.
488
    if 'admin_groups' not in group.project_set.offering.get_permissions(
489
        req.user, req.config):
490
        raise Unauthorized()
491
1181 by William Grant
Allow revocation of group memberships by tutors and lecturers.
492
    # Remove membership from the database
493
    # We can't keep a transaction open until the end here, as usrmgt-server
494
    # needs to see the changes!
495
    group.members.remove(user)
496
    req.store.commit()
497
498
    # Rebuild the svn config file
499
    # Contact the usrmgt server
500
    msg = {'rebuild_svn_group_config': {}}
501
    try:
1204 by William Grant
Use the config from the request, rather than ivle.conf, in userservice.
502
        usrmgt = chat.chat(req.config['usrmgt']['host'],
503
                           req.config['usrmgt']['port'],
504
                           msg,
505
                           req.config['usrmgt']['magic'],
506
                          )
1181 by William Grant
Allow revocation of group memberships by tutors and lecturers.
507
    except cjson.DecodeError, e:
508
        raise Exception("Could not understand usrmgt server response: %s" +
509
                        e.message)
510
511
        if 'response' not in usrmgt or usrmgt['response']=='failure':
512
            raise Exception("Failure creating repository: " + str(usrmgt))
513
514
    return(cjson.encode({'response': 'okay'}))
515
536 by mattgiuca
apps/userservice: Generalised searching for actions (dict mapping action names to
516
# Map action names (from the path)
517
# to actual function objects
518
actions_map = {
519
    "activate_me": handle_activate_me,
930 by dcoles
Userservice: Added get_enrolments handler to allow a JSON query of a students
520
    "get_enrolments": handle_get_enrolments,
1001 by dcoles
Groups: Added the view half of the group admin panel. This lets people with the
521
    "get_project_groups": handle_get_project_groups,
1004 by dcoles
Groups: Now you can add people to a group as well as creating groups from the
522
    "get_group_membership": handle_get_group_membership,
986 by dcoles
Groups: Added userservice/create_group call. You can now create a project in
523
    "create_group": handle_create_group,
989 by dcoles
Groups: Added userservice/assign_group call. This allows a user with the
524
    "assign_group": handle_assign_group,
1181 by William Grant
Allow revocation of group memberships by tutors and lecturers.
525
    "unassign_group": handle_unassign_group,
536 by mattgiuca
apps/userservice: Generalised searching for actions (dict mapping action names to
526
}