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

« back to all changes in this revision

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

  • Committer: Matt Giuca
  • Date: 2009-12-01 04:27:58 UTC
  • mfrom: (1164.2.46 sphinx-docs)
  • Revision ID: matt.giuca@gmail.com-20091201042758-wuxd9bdec00c283i
Merged sphinx-docs branch. This adds Sphinx documentation for the entire IVLE system (for system administrators and developers), and removes all of our random old document files (all either irrelevant, or moved into the Sphinx docs nicely). Currently incomplete, but ready to merge.

Show diffs side-by-side

added added

removed removed

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