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

« back to all changes in this revision

Viewing changes to ivle/webapp/admin/user.py

  • Committer: William Grant
  • Date: 2010-07-03 01:38:41 UTC
  • Revision ID: grantw@unimelb.edu.au-20100703013841-6ifl1wsn4xj4w72k
External media directories with None as the path whitelist now permit all paths. This lets us include complicated dependencies more easily.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
import formencode.validators
22
22
from genshi.filters import HTMLFormFiller
23
23
 
24
 
from ivle.webapp.base.rest import JSONRESTView, require_permission
 
24
from ivle.database import User
 
25
import ivle.date
 
26
from ivle.pulldown_subj import enrol_user
 
27
from ivle.webapp import ApplicationRoot
 
28
from ivle.webapp.base.forms import BaseFormView, URLNameValidator
25
29
from ivle.webapp.base.xhtml import XHTMLView
26
30
from ivle.webapp.base.plugins import ViewPlugin, MediaPlugin
27
 
from ivle.webapp.errors import NotFound, Unauthorized
28
 
import ivle.database
29
 
import ivle.date
30
 
import ivle.util
31
 
 
32
 
# List of fields returned as part of the user JSON dictionary
33
 
# (as returned by the get_user action)
34
 
user_fields_list = (
35
 
    "login", "state", "unixid", "email", "nick", "fullname",
36
 
    "admin", "studentid", "acct_exp", "pass_exp", "last_login",
37
 
    "svn_pass"
38
 
)
39
 
 
40
 
class UserRESTView(JSONRESTView):
41
 
    """
42
 
    A REST interface to the user object.
43
 
    """
44
 
    def __init__(self, req, login):
45
 
        super(UserRESTView, self).__init__(self, req, login)
46
 
        self.context = ivle.database.User.get_by_login(req.store, login)
47
 
        if self.context is None:
48
 
            raise NotFound()
49
 
 
50
 
    @require_permission('view')
51
 
    def GET(self, req):
52
 
        # XXX Check Caps
53
 
        user = ivle.util.object_to_dict(user_fields_list, self.context)
54
 
        # Convert time stamps to nice strings
55
 
        for k in 'pass_exp', 'acct_exp', 'last_login':
56
 
            if user[k] is not None:
57
 
                user[k] = unicode(user[k])
58
 
 
59
 
        user['local_password'] = self.context.passhash is not None
60
 
        return user
 
31
from ivle.webapp.admin.publishing import root_to_user, user_url
 
32
 
 
33
 
 
34
class UsersView(XHTMLView):
 
35
    """A list of all IVLE users."""
 
36
    template = 'templates/users.html'
 
37
    tab = 'users'
 
38
    breadcrumb_text = 'Users'
 
39
 
 
40
    def authorize(self, req):
 
41
        return req.user and req.user.admin
 
42
 
 
43
    def populate(self, req, ctx):
 
44
        ctx['req'] = req
 
45
        ctx['users'] = req.store.find(User).order_by(User.login)
 
46
 
61
47
 
62
48
class UserEditSchema(formencode.Schema):
63
49
    nick = formencode.validators.UnicodeString(not_empty=True)
64
50
    email = formencode.validators.Email(not_empty=False,
65
51
                                        if_missing=None)
66
52
 
67
 
class UserEditView(XHTMLView):
 
53
class UserEditView(BaseFormView):
68
54
    """A form to change a user's details."""
69
55
    template = 'templates/user-edit.html'
70
 
    tab = 'settings'
 
56
    tab = 'users'
71
57
    permission = 'edit'
72
58
 
73
 
    def __init__(self, req, login):
74
 
        self.context = ivle.database.User.get_by_login(req.store, login)
75
 
        if self.context is None:
76
 
            raise NotFound()
77
 
 
78
 
    def filter(self, stream, ctx):
79
 
        return stream | HTMLFormFiller(data=ctx['data'])
 
59
    @property
 
60
    def validator(self):
 
61
        return UserEditSchema()
 
62
 
 
63
    def get_default_data(self, req):
 
64
        return {'nick': self.context.nick,
 
65
                'email': self.context.email
 
66
                }
 
67
 
 
68
    def save_object(self, req, data):
 
69
        self.context.nick = data['nick']
 
70
        self.context.email = unicode(data['email']) if data['email'] \
 
71
                             else None
 
72
        return self.context
80
73
 
81
74
    def populate(self, req, ctx):
82
 
        if req.method == 'POST':
83
 
            data = dict(req.get_fieldstorage())
84
 
            try:
85
 
                validator = UserEditSchema()
86
 
                data = validator.to_python(data, state=req)
87
 
                self.context.nick = data['nick']
88
 
                self.context.email = unicode(data['email']) if data['email'] \
89
 
                                     else None
90
 
                req.store.commit()
91
 
                req.throw_redirect(req.uri)
92
 
            except formencode.Invalid, e:
93
 
                errors = e.unpack_errors()
94
 
        else:
95
 
            data = {'nick': self.context.nick,
96
 
                    'email': self.context.email
97
 
                   }
98
 
            errors = {}
99
 
 
 
75
        super(UserEditView, self).populate(req, ctx)
100
76
        ctx['format_datetime'] = ivle.date.make_date_nice
101
77
        ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
 
78
        ctx['svn_url'] = req.user.get_svn_url(req.config, req)
 
79
        ctx['svn_pass'] = req.user.svn_pass
102
80
 
103
 
        ctx['req'] = req
104
 
        ctx['user'] = self.context
105
 
        ctx['data'] = data
106
 
        ctx['errors'] = errors
107
81
 
108
82
class UserAdminSchema(formencode.Schema):
109
83
    admin = formencode.validators.StringBoolean(if_missing=False)
 
84
    disabled = formencode.validators.StringBoolean(if_missing=False)
110
85
    fullname = formencode.validators.UnicodeString(not_empty=True)
111
86
    studentid = formencode.validators.UnicodeString(not_empty=False,
112
87
                                                    if_missing=None
113
88
                                                    )
114
89
 
115
 
class UserAdminView(XHTMLView):
 
90
class UserAdminView(BaseFormView):
116
91
    """A form for admins to change more of a user's details."""
117
92
    template = 'templates/user-admin.html'
118
 
    tab = 'settings'
119
 
 
120
 
    def __init__(self, req, login):
121
 
        self.context = ivle.database.User.get_by_login(req.store, login)
122
 
        if self.context is None:
123
 
            raise NotFound()
 
93
    tab = 'users'
124
94
 
125
95
    def authorize(self, req):
126
96
        """Only allow access if the requesting user is an admin."""
127
 
        return req.user.admin
128
 
 
129
 
    def filter(self, stream, ctx):
130
 
        return stream | HTMLFormFiller(data=ctx['data'])
 
97
        return req.user and req.user.admin
 
98
 
 
99
    @property
 
100
    def validator(self):
 
101
        return UserAdminSchema()
 
102
 
 
103
    def get_default_data(self, req):
 
104
        return {'admin': self.context.admin,
 
105
                'disabled': self.context.state == u'disabled',
 
106
                'fullname': self.context.fullname,
 
107
                'studentid': self.context.studentid,
 
108
                }
 
109
 
 
110
    def save_object(self, req, data):
 
111
        if self.context is req.user:
 
112
            # Admin checkbox is disabled -- assume unchanged
 
113
            data['admin'] = self.context.admin
 
114
            data['disabled'] = self.context.state == u'disabled'
 
115
        else:
 
116
            self.context.admin = data['admin']
 
117
            if self.context.state in (u'enabled', u'disabled'):
 
118
                self.context.state = (u'disabled' if data['disabled']
 
119
                        else u'enabled')
 
120
        self.context.fullname = data['fullname'] \
 
121
                                if data['fullname'] else None
 
122
        self.context.studentid = data['studentid'] \
 
123
                                 if data['studentid'] else None
 
124
        return self.context
131
125
 
132
126
    def populate(self, req, ctx):
133
 
        if req.method == 'POST':
134
 
            data = dict(req.get_fieldstorage())
135
 
            try:
136
 
                validator = UserAdminSchema()
137
 
                data = validator.to_python(data, state=req)
138
 
 
139
 
                self.context.admin = data['admin']
140
 
                self.context.fullname = data['fullname'] \
141
 
                                        if data['fullname'] else None
142
 
                self.context.studentid = data['studentid'] \
143
 
                                         if data['studentid'] else None
144
 
                req.store.commit()
145
 
                req.throw_redirect(req.uri)
146
 
            except formencode.Invalid, e:
147
 
                errors = e.unpack_errors()
148
 
        else:
149
 
            data = {'admin': self.context.admin,
150
 
                    'fullname': self.context.fullname,
151
 
                    'studentid': self.context.studentid,
152
 
                   }
153
 
            errors = {}
154
 
 
155
 
        ctx['req'] = req
156
 
        ctx['user'] = self.context
157
 
        ctx['data'] = data
158
 
        ctx['errors'] = errors
 
127
        super(UserAdminView, self).populate(req, ctx)
 
128
 
 
129
        # Disable the admin checkbox if editing oneself
 
130
        ctx['disable_admin'] = self.context is req.user
159
131
 
160
132
class PasswordChangeView(XHTMLView):
161
133
    """A form to change a user's password, with knowledge of the old one."""
162
134
    template = 'templates/user-password-change.html'
163
 
    tab = 'settings'
 
135
    tab = 'users'
164
136
    permission = 'edit'
165
137
 
166
 
    def __init__(self, req, login):
167
 
        self.context = ivle.database.User.get_by_login(req.store, login)
168
 
        if self.context is None:
169
 
            raise NotFound()
170
 
 
171
138
    def authorize(self, req):
172
139
        """Only allow access if the requesting user holds the permission,
173
140
           and the target user has a password set. Otherwise we might be
199
166
class PasswordResetView(XHTMLView):
200
167
    """A form to reset a user's password, without knowledge of the old one."""
201
168
    template = 'templates/user-password-reset.html'
202
 
    tab = 'settings'
203
 
 
204
 
    def __init__(self, req, login):
205
 
        self.context = ivle.database.User.get_by_login(req.store, login)
206
 
        if self.context is None:
207
 
            raise NotFound()
 
169
    tab = 'users'
208
170
 
209
171
    def authorize(self, req):
210
172
        """Only allow access if the requesting user is an admin."""
211
 
        return req.user.admin
 
173
        return req.user and req.user.admin
212
174
 
213
175
    def populate(self, req, ctx):
214
176
        error = None
226
188
        ctx['user'] = self.context
227
189
        ctx['error'] = error
228
190
 
 
191
 
 
192
class UserNewSchema(formencode.Schema):
 
193
    login = URLNameValidator() # XXX: Validate uniqueness.
 
194
    admin = formencode.validators.StringBoolean(if_missing=False)
 
195
    fullname = formencode.validators.UnicodeString(not_empty=True)
 
196
    studentid = formencode.validators.UnicodeString(not_empty=False,
 
197
                                                    if_missing=None
 
198
                                                    )
 
199
    email = formencode.validators.Email(not_empty=False,
 
200
                                        if_missing=None)
 
201
 
 
202
 
 
203
class UserNewView(BaseFormView):
 
204
    """A form for admins to create new users."""
 
205
    template = 'templates/user-new.html'
 
206
    tab = 'users'
 
207
 
 
208
    def authorize(self, req):
 
209
        """Only allow access if the requesting user is an admin."""
 
210
        return req.user and req.user.admin
 
211
 
 
212
    @property
 
213
    def validator(self):
 
214
        return UserNewSchema()
 
215
 
 
216
    def get_default_data(self, req):
 
217
        return {}
 
218
 
 
219
    def save_object(self, req, data):
 
220
        data['nick'] = data['fullname']
 
221
        data['email'] = unicode(data['email']) if data['email'] else None
 
222
        userobj = User(**data)
 
223
        req.store.add(userobj)
 
224
        enrol_user(req.config, req.store, userobj)
 
225
 
 
226
        return userobj
 
227
 
 
228
 
229
229
class Plugin(ViewPlugin, MediaPlugin):
230
230
    """
231
231
    The Plugin class for the user plugin.
232
232
    """
233
 
    # Magic attribute: urls
234
 
    # Sequence of pairs/triples of
235
 
    # (regex str, handler class, kwargs dict)
236
 
    # The kwargs dict is passed to the __init__ of the view object
237
 
    urls = [
238
 
        ('~:login/+edit', UserEditView),
239
 
        ('~:login/+admin', UserAdminView),
240
 
        ('~:login/+changepassword', PasswordChangeView),
241
 
        ('~:login/+resetpassword', PasswordResetView),
242
 
        ('api/~:login', UserRESTView),
 
233
 
 
234
    forward_routes = (root_to_user,)
 
235
    reverse_routes = (user_url,)
 
236
    views = [(ApplicationRoot, ('users', '+index'), UsersView),
 
237
             (ApplicationRoot, ('users', '+new'), UserNewView),
 
238
             (User, '+index', UserEditView),
 
239
             (User, '+admin', UserAdminView),
 
240
             (User, '+changepassword', PasswordChangeView),
 
241
             (User, '+resetpassword', PasswordResetView),
 
242
             ]
 
243
 
 
244
    tabs = [
 
245
        ('users', 'Users', 'Display and edit all users',
 
246
         'users.png', 'users', 90, True)
243
247
    ]
244
248
 
 
249
    public_forward_routes = forward_routes
 
250
    public_reverse_routes = reverse_routes
 
251
 
245
252
    media = 'user-media'