~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-02-24 01:32:50 UTC
  • Revision ID: grantw@unimelb.edu.au-20100224013250-3pfbslg7a5i2eb8g
Refactor UserAdminView to use BaseFormView.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# IVLE - Informatics Virtual Learning Environment
 
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: Matt Giuca, Will Grant
 
19
 
 
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.forms import BaseFormView
 
26
from ivle.webapp.base.xhtml import XHTMLView
 
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
 
30
import ivle.date
 
31
 
 
32
 
 
33
class UsersView(XHTMLView):
 
34
    """A list of all IVLE users."""
 
35
    template = 'templates/users.html'
 
36
    tab = 'users'
 
37
    breadcrumb_text = 'Users'
 
38
 
 
39
    def authorize(self, req):
 
40
        return req.user and 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
 
 
47
class UserEditSchema(formencode.Schema):
 
48
    nick = formencode.validators.UnicodeString(not_empty=True)
 
49
    email = formencode.validators.Email(not_empty=False,
 
50
                                        if_missing=None)
 
51
 
 
52
class UserEditView(XHTMLView):
 
53
    """A form to change a user's details."""
 
54
    template = 'templates/user-edit.html'
 
55
    tab = 'users'
 
56
    permission = 'edit'
 
57
 
 
58
    def filter(self, stream, ctx):
 
59
        return stream | HTMLFormFiller(data=ctx['data'])
 
60
 
 
61
    def populate(self, req, ctx):
 
62
        if req.method == 'POST':
 
63
            data = dict(req.get_fieldstorage())
 
64
            try:
 
65
                validator = UserEditSchema()
 
66
                data = validator.to_python(data, state=req)
 
67
                self.context.nick = data['nick']
 
68
                self.context.email = unicode(data['email']) if data['email'] \
 
69
                                     else None
 
70
                req.store.commit()
 
71
                req.throw_redirect(req.uri)
 
72
            except formencode.Invalid, e:
 
73
                errors = e.unpack_errors()
 
74
        else:
 
75
            data = {'nick': self.context.nick,
 
76
                    'email': self.context.email
 
77
                   }
 
78
            errors = {}
 
79
 
 
80
        ctx['format_datetime'] = ivle.date.make_date_nice
 
81
        ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
 
82
 
 
83
        ctx['req'] = req
 
84
        ctx['user'] = self.context
 
85
        ctx['data'] = data
 
86
        ctx['errors'] = errors
 
87
 
 
88
class UserAdminSchema(formencode.Schema):
 
89
    admin = formencode.validators.StringBoolean(if_missing=False)
 
90
    disabled = formencode.validators.StringBoolean(if_missing=False)
 
91
    fullname = formencode.validators.UnicodeString(not_empty=True)
 
92
    studentid = formencode.validators.UnicodeString(not_empty=False,
 
93
                                                    if_missing=None
 
94
                                                    )
 
95
 
 
96
class UserAdminView(BaseFormView):
 
97
    """A form for admins to change more of a user's details."""
 
98
    template = 'templates/user-admin.html'
 
99
    tab = 'users'
 
100
 
 
101
    def authorize(self, req):
 
102
        """Only allow access if the requesting user is an admin."""
 
103
        return req.user and req.user.admin
 
104
 
 
105
    @property
 
106
    def validator(self):
 
107
        return UserAdminSchema()
 
108
 
 
109
    def get_default_data(self, req):
 
110
        return {'admin': self.context.admin,
 
111
                'disabled': self.context.state == u'disabled',
 
112
                'fullname': self.context.fullname,
 
113
                'studentid': self.context.studentid,
 
114
                }
 
115
 
 
116
    def save_object(self, req, data):
 
117
        if self.context is req.user:
 
118
            # Admin checkbox is disabled -- assume unchanged
 
119
            data['admin'] = self.context.admin
 
120
            data['disabled'] = self.context.state == u'disabled'
 
121
        else:
 
122
            self.context.admin = data['admin']
 
123
            if self.context.state in (u'enabled', u'disabled'):
 
124
                self.context.state = (u'disabled' if data['disabled']
 
125
                        else u'enabled')
 
126
        self.context.fullname = data['fullname'] \
 
127
                                if data['fullname'] else None
 
128
        self.context.studentid = data['studentid'] \
 
129
                                 if data['studentid'] else None
 
130
        return self.context
 
131
 
 
132
 
 
133
    def populate(self, req, ctx):
 
134
        super(UserAdminView, self).populate(req, ctx)
 
135
 
 
136
        # Disable the admin checkbox if editing oneself
 
137
        ctx['disable_admin'] = self.context is req.user
 
138
 
 
139
class PasswordChangeView(XHTMLView):
 
140
    """A form to change a user's password, with knowledge of the old one."""
 
141
    template = 'templates/user-password-change.html'
 
142
    tab = 'users'
 
143
    permission = 'edit'
 
144
 
 
145
    def authorize(self, req):
 
146
        """Only allow access if the requesting user holds the permission,
 
147
           and the target user has a password set. Otherwise we might be
 
148
           clobbering external authn.
 
149
        """
 
150
        return super(PasswordChangeView, self).authorize(req) and \
 
151
               self.context.passhash is not None
 
152
 
 
153
    def populate(self, req, ctx):
 
154
        error = None
 
155
        if req.method == 'POST':
 
156
            data = dict(req.get_fieldstorage())
 
157
            if data.get('old_password') is None or \
 
158
               not self.context.authenticate(data.get('old_password')):
 
159
                error = 'Incorrect password.'
 
160
            elif data.get('new_password') != data.get('new_password_again'):
 
161
                error = 'New passwords do not match.'
 
162
            elif not data.get('new_password'):
 
163
                error = 'New password cannot be empty.'
 
164
            else:
 
165
                self.context.password = data['new_password']
 
166
                req.store.commit()
 
167
                req.throw_redirect(req.uri)
 
168
 
 
169
        ctx['req'] = req
 
170
        ctx['user'] = self.context
 
171
        ctx['error'] = error
 
172
 
 
173
class PasswordResetView(XHTMLView):
 
174
    """A form to reset a user's password, without knowledge of the old one."""
 
175
    template = 'templates/user-password-reset.html'
 
176
    tab = 'users'
 
177
 
 
178
    def authorize(self, req):
 
179
        """Only allow access if the requesting user is an admin."""
 
180
        return req.user and req.user.admin
 
181
 
 
182
    def populate(self, req, ctx):
 
183
        error = None
 
184
        if req.method == 'POST':
 
185
            data = dict(req.get_fieldstorage())
 
186
            if data.get('new_password') != data.get('new_password_again'):
 
187
                error = 'New passwords do not match.'
 
188
            elif not data.get('new_password'):
 
189
                error = 'New password cannot be empty.'
 
190
            else:
 
191
                self.context.password = data['new_password']
 
192
                req.store.commit()
 
193
                req.throw_redirect(req.uri)
 
194
 
 
195
        ctx['user'] = self.context
 
196
        ctx['error'] = error
 
197
 
 
198
class Plugin(ViewPlugin, MediaPlugin):
 
199
    """
 
200
    The Plugin class for the user plugin.
 
201
    """
 
202
 
 
203
    forward_routes = (root_to_user,)
 
204
    reverse_routes = (user_url,)
 
205
    views = [(ApplicationRoot, 'users', UsersView),
 
206
             (User, '+index', UserEditView),
 
207
             (User, '+admin', UserAdminView),
 
208
             (User, '+changepassword', PasswordChangeView),
 
209
             (User, '+resetpassword', PasswordResetView),
 
210
             ]
 
211
 
 
212
    tabs = [
 
213
        ('users', 'Users', 'Display and edit all users',
 
214
         'users.png', 'users', 90, True)
 
215
    ]
 
216
 
 
217
    public_forward_routes = forward_routes
 
218
    public_reverse_routes = reverse_routes
 
219
 
 
220
    media = 'user-media'