~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: 2009-12-10 09:47:38 UTC
  • Revision ID: grantw@unimelb.edu.au-20091210094738-pa4yrieyb9ynigej
Clean up and correct the admin scripts documentation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
# Author: Matt Giuca, Will Grant
19
19
 
20
 
from ivle.webapp.base.rest import JSONRESTView
 
20
import formencode
 
21
import formencode.validators
 
22
from genshi.filters import HTMLFormFiller
 
23
 
 
24
from ivle.webapp import ApplicationRoot
 
25
from ivle.webapp.base.rest import JSONRESTView, require_permission
21
26
from ivle.webapp.base.xhtml import XHTMLView
22
 
from ivle.webapp.base.plugins import BasePlugin
 
27
from ivle.webapp.base.plugins import ViewPlugin, MediaPlugin
 
28
from ivle.webapp.admin.publishing import root_to_user, user_url
 
29
from ivle.database import User
23
30
import ivle.database
 
31
import ivle.date
24
32
import ivle.util
25
33
 
 
34
 
 
35
class UsersView(XHTMLView):
 
36
    """A list of all IVLE users."""
 
37
    template = 'templates/users.html'
 
38
 
 
39
    def authorize(self, req):
 
40
        return req.user.admin
 
41
 
 
42
    def populate(self, req, ctx):
 
43
        ctx['req'] = req
 
44
        ctx['users'] = req.store.find(User).order_by(User.login)
 
45
 
 
46
 
26
47
# List of fields returned as part of the user JSON dictionary
27
48
# (as returned by the get_user action)
28
49
user_fields_list = (
29
50
    "login", "state", "unixid", "email", "nick", "fullname",
30
 
    "rolenm", "studentid", "acct_exp", "pass_exp", "last_login",
 
51
    "admin", "studentid", "acct_exp", "pass_exp", "last_login",
31
52
    "svn_pass"
32
53
)
33
54
 
35
56
    """
36
57
    A REST interface to the user object.
37
58
    """
38
 
    def __init__(self, req, login):
39
 
        super(UserRESTView, self).__init__(self, req, login)
40
 
        self.context = ivle.database.User.get_by_login(req.store, login)
41
59
 
 
60
    @require_permission('view')
42
61
    def GET(self, req):
43
62
        # XXX Check Caps
44
63
        user = ivle.util.object_to_dict(user_fields_list, self.context)
50
69
        user['local_password'] = self.context.passhash is not None
51
70
        return user
52
71
 
53
 
    def PATCH(self, req, data):
54
 
        # XXX Check Caps
55
 
        # XXX Admins can set extra fields
56
 
        # Note: Cannot change password here (use change_password named op)
57
 
 
58
 
        for f in user_fields_list:
59
 
            try:
60
 
                field = data[f]
61
 
                if isinstance(field, str):
62
 
                    field = unicode(field)
63
 
                setattr(self.context, f, field)
64
 
            except KeyError:
65
 
                continue
66
 
 
67
 
class UserSettingsView(XHTMLView):
68
 
    template = 'user-settings.html'
69
 
    appname = 'settings'
70
 
 
71
 
    def __init__(self, req, login):
72
 
        self.context = ivle.database.User.get_by_login(req.store, login)
73
 
 
74
 
    def populate(self, req, ctx):
75
 
        if not self.context:
76
 
            raise NotFound()
77
 
 
78
 
        req.scripts = [
79
 
            "/media/settings/settings.js",
80
 
            "/media/common/json2.js",
81
 
            "/media/common/util.js",
82
 
        ]
83
 
        req.scripts_init = [
84
 
            "revert_settings"
85
 
        ]
86
 
        ctx['login'] = self.context.login
87
 
 
88
 
class Plugin(BasePlugin):
 
72
class UserEditSchema(formencode.Schema):
 
73
    nick = formencode.validators.UnicodeString(not_empty=True)
 
74
    email = formencode.validators.Email(not_empty=False,
 
75
                                        if_missing=None)
 
76
 
 
77
class UserEditView(XHTMLView):
 
78
    """A form to change a user's details."""
 
79
    template = 'templates/user-edit.html'
 
80
    tab = 'settings'
 
81
    permission = 'edit'
 
82
 
 
83
    def filter(self, stream, ctx):
 
84
        return stream | HTMLFormFiller(data=ctx['data'])
 
85
 
 
86
    def populate(self, req, ctx):
 
87
        if req.method == 'POST':
 
88
            data = dict(req.get_fieldstorage())
 
89
            try:
 
90
                validator = UserEditSchema()
 
91
                data = validator.to_python(data, state=req)
 
92
                self.context.nick = data['nick']
 
93
                self.context.email = unicode(data['email']) if data['email'] \
 
94
                                     else None
 
95
                req.store.commit()
 
96
                req.throw_redirect(req.uri)
 
97
            except formencode.Invalid, e:
 
98
                errors = e.unpack_errors()
 
99
        else:
 
100
            data = {'nick': self.context.nick,
 
101
                    'email': self.context.email
 
102
                   }
 
103
            errors = {}
 
104
 
 
105
        ctx['format_datetime'] = ivle.date.make_date_nice
 
106
        ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
 
107
 
 
108
        ctx['req'] = req
 
109
        ctx['user'] = self.context
 
110
        ctx['data'] = data
 
111
        ctx['errors'] = errors
 
112
 
 
113
class UserAdminSchema(formencode.Schema):
 
114
    admin = formencode.validators.StringBoolean(if_missing=False)
 
115
    fullname = formencode.validators.UnicodeString(not_empty=True)
 
116
    studentid = formencode.validators.UnicodeString(not_empty=False,
 
117
                                                    if_missing=None
 
118
                                                    )
 
119
 
 
120
class UserAdminView(XHTMLView):
 
121
    """A form for admins to change more of a user's details."""
 
122
    template = 'templates/user-admin.html'
 
123
    tab = 'settings'
 
124
 
 
125
    def authorize(self, req):
 
126
        """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'])
 
131
 
 
132
    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
 
159
 
 
160
class PasswordChangeView(XHTMLView):
 
161
    """A form to change a user's password, with knowledge of the old one."""
 
162
    template = 'templates/user-password-change.html'
 
163
    tab = 'settings'
 
164
    permission = 'edit'
 
165
 
 
166
    def authorize(self, req):
 
167
        """Only allow access if the requesting user holds the permission,
 
168
           and the target user has a password set. Otherwise we might be
 
169
           clobbering external authn.
 
170
        """
 
171
        return super(PasswordChangeView, self).authorize(req) and \
 
172
               self.context.passhash is not None
 
173
 
 
174
    def populate(self, req, ctx):
 
175
        error = None
 
176
        if req.method == 'POST':
 
177
            data = dict(req.get_fieldstorage())
 
178
            if data.get('old_password') is None or \
 
179
               not self.context.authenticate(data.get('old_password')):
 
180
                error = 'Incorrect password.'
 
181
            elif data.get('new_password') != data.get('new_password_again'):
 
182
                error = 'New passwords do not match.'
 
183
            elif not data.get('new_password'):
 
184
                error = 'New password cannot be empty.'
 
185
            else:
 
186
                self.context.password = data['new_password']
 
187
                req.store.commit()
 
188
                req.throw_redirect(req.uri)
 
189
 
 
190
        ctx['req'] = req
 
191
        ctx['user'] = self.context
 
192
        ctx['error'] = error
 
193
 
 
194
class PasswordResetView(XHTMLView):
 
195
    """A form to reset a user's password, without knowledge of the old one."""
 
196
    template = 'templates/user-password-reset.html'
 
197
    tab = 'settings'
 
198
 
 
199
    def authorize(self, req):
 
200
        """Only allow access if the requesting user is an admin."""
 
201
        return req.user.admin
 
202
 
 
203
    def populate(self, req, ctx):
 
204
        error = None
 
205
        if req.method == 'POST':
 
206
            data = dict(req.get_fieldstorage())
 
207
            if data.get('new_password') != data.get('new_password_again'):
 
208
                error = 'New passwords do not match.'
 
209
            elif not data.get('new_password'):
 
210
                error = 'New password cannot be empty.'
 
211
            else:
 
212
                self.context.password = data['new_password']
 
213
                req.store.commit()
 
214
                req.throw_redirect(req.uri)
 
215
 
 
216
        ctx['user'] = self.context
 
217
        ctx['error'] = error
 
218
 
 
219
class Plugin(ViewPlugin, MediaPlugin):
89
220
    """
90
221
    The Plugin class for the user plugin.
91
222
    """
92
 
    # Magic attribute: urls
93
 
    # Sequence of pairs/triples of
94
 
    # (regex str, handler class, kwargs dict)
95
 
    # The kwargs dict is passed to the __init__ of the view object
96
 
    urls = [
97
 
        ('users/:login/+settings', UserSettingsView),
98
 
        ('api/users/:login', UserRESTView),
99
 
    ]
 
223
 
 
224
    forward_routes = (root_to_user,)
 
225
    reverse_routes = (user_url,)
 
226
    views = [(ApplicationRoot, 'users', UsersView),
 
227
             (ivle.database.User, '+index', UserEditView),
 
228
             (ivle.database.User, '+admin', UserAdminView),
 
229
             (ivle.database.User, '+changepassword', PasswordChangeView),
 
230
             (ivle.database.User, '+resetpassword', PasswordResetView),
 
231
             (ivle.database.User, '+index', UserRESTView, 'api'),
 
232
             ]
 
233
 
 
234
    public_forward_routes = forward_routes
 
235
    public_reverse_routes = reverse_routes
 
236
 
 
237
    media = 'user-media'