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

1099.1.1 by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick).
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
1294.1.1 by William Grant
Add UserEditView, a non-AJAX partial replacement of UserSettingsView.
20
import formencode
21
import formencode.validators
22
from genshi.filters import HTMLFormFiller
23
1755 by William Grant
Add a form to create a user.
24
from ivle.database import User
25
import ivle.date
26
from ivle.pulldown_subj import enrol_user
1375 by William Grant
Add a user list -- as yet unlinked.
27
from ivle.webapp import ApplicationRoot
1755 by William Grant
Add a form to create a user.
28
from ivle.webapp.base.forms import BaseFormView, URLNameValidator
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
29
from ivle.webapp.base.xhtml import XHTMLView
1099.1.99 by William Grant
Require that plugins providing media subclass MediaPlugin.
30
from ivle.webapp.base.plugins import ViewPlugin, MediaPlugin
1294.3.2 by William Grant
Router->Publisher
31
from ivle.webapp.admin.publishing import root_to_user, user_url
1099.1.1 by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick).
32
1375 by William Grant
Add a user list -- as yet unlinked.
33
34
class UsersView(XHTMLView):
35
    """A list of all IVLE users."""
36
    template = 'templates/users.html'
1497 by Matt Giuca
Added Users tab to drop-down menu, for admins only.
37
    tab = 'users'
1472 by William Grant
Add a 'Users' breadcrumb.
38
    breadcrumb_text = 'Users'
1375 by William Grant
Add a user list -- as yet unlinked.
39
40
    def authorize(self, req):
1504 by Matt Giuca
ivle/webapp/admin/user.py: Fixed crash when visiting admin-only user pages while logged out (None dereference).
41
        return req.user and req.user.admin
1375 by William Grant
Add a user list -- as yet unlinked.
42
43
    def populate(self, req, ctx):
44
        ctx['req'] = req
45
        ctx['users'] = req.store.find(User).order_by(User.login)
46
47
1294.1.1 by William Grant
Add UserEditView, a non-AJAX partial replacement of UserSettingsView.
48
class UserEditSchema(formencode.Schema):
49
    nick = formencode.validators.UnicodeString(not_empty=True)
50
    email = formencode.validators.Email(not_empty=False,
51
                                        if_missing=None)
52
1681 by William Grant
Refactor UserEditView to use BaseFormView.
53
class UserEditView(BaseFormView):
1294.1.1 by William Grant
Add UserEditView, a non-AJAX partial replacement of UserSettingsView.
54
    """A form to change a user's details."""
55
    template = 'templates/user-edit.html'
1498 by Matt Giuca
user.py: All user pages are now in the tab "users", so they show the user icon
56
    tab = 'users'
1294.1.1 by William Grant
Add UserEditView, a non-AJAX partial replacement of UserSettingsView.
57
    permission = 'edit'
58
1681 by William Grant
Refactor UserEditView to use BaseFormView.
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
1294.1.1 by William Grant
Add UserEditView, a non-AJAX partial replacement of UserSettingsView.
73
74
    def populate(self, req, ctx):
1681 by William Grant
Refactor UserEditView to use BaseFormView.
75
        super(UserEditView, self).populate(req, ctx)
1294.1.7 by William Grant
Display account/password expiry times on +edit.
76
        ctx['format_datetime'] = ivle.date.make_date_nice
77
        ctx['format_datetime_short'] = ivle.date.format_datetime_for_paragraph
1813 by Matt Giuca
ivle.webapp.admin.user: Fixed call to req.user.get_svn_url (now takes 1 argument, as of r1810).
78
        ctx['svn_url'] = req.user.get_svn_url(req.config)
1782 by Matt Giuca
Added an entry on the user settings page to display the user's Subversion password. This was previously only possible through an arcane console command. Updated documentation. This fixes Launchpad bug #528450.
79
        ctx['svn_pass'] = req.user.svn_pass
1294.1.7 by William Grant
Display account/password expiry times on +edit.
80
1294.1.1 by William Grant
Add UserEditView, a non-AJAX partial replacement of UserSettingsView.
81
1294.1.9 by William Grant
Add a UserAdminView, to set fullname/studentid/admin.
82
class UserAdminSchema(formencode.Schema):
83
    admin = formencode.validators.StringBoolean(if_missing=False)
1503 by David Coles
Admin: Allow enabling and disabling of users in admin UI
84
    disabled = formencode.validators.StringBoolean(if_missing=False)
1294.1.9 by William Grant
Add a UserAdminView, to set fullname/studentid/admin.
85
    fullname = formencode.validators.UnicodeString(not_empty=True)
86
    studentid = formencode.validators.UnicodeString(not_empty=False,
87
                                                    if_missing=None
88
                                                    )
89
1680 by William Grant
Refactor UserAdminView to use BaseFormView.
90
class UserAdminView(BaseFormView):
1294.1.9 by William Grant
Add a UserAdminView, to set fullname/studentid/admin.
91
    """A form for admins to change more of a user's details."""
92
    template = 'templates/user-admin.html'
1498 by Matt Giuca
user.py: All user pages are now in the tab "users", so they show the user icon
93
    tab = 'users'
1294.1.9 by William Grant
Add a UserAdminView, to set fullname/studentid/admin.
94
95
    def authorize(self, req):
96
        """Only allow access if the requesting user is an admin."""
1504 by Matt Giuca
ivle/webapp/admin/user.py: Fixed crash when visiting admin-only user pages while logged out (None dereference).
97
        return req.user and req.user.admin
1294.1.9 by William Grant
Add a UserAdminView, to set fullname/studentid/admin.
98
1680 by William Grant
Refactor UserAdminView to use BaseFormView.
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
125
1294.1.9 by William Grant
Add a UserAdminView, to set fullname/studentid/admin.
126
    def populate(self, req, ctx):
1680 by William Grant
Refactor UserAdminView to use BaseFormView.
127
        super(UserAdminView, self).populate(req, ctx)
128
129
        # Disable the admin checkbox if editing oneself
1501 by Matt Giuca
User administration page: Do not let an admin user change their own admin checkbox (disable and don't let it change). This would be bad.
130
        ctx['disable_admin'] = self.context is req.user
1294.1.9 by William Grant
Add a UserAdminView, to set fullname/studentid/admin.
131
1294.1.2 by William Grant
Add a non-AJAX password change view.
132
class PasswordChangeView(XHTMLView):
1294.1.5 by William Grant
Add a view for admins to reset other users' passwords.
133
    """A form to change a user's password, with knowledge of the old one."""
1294.1.2 by William Grant
Add a non-AJAX password change view.
134
    template = 'templates/user-password-change.html'
1498 by Matt Giuca
user.py: All user pages are now in the tab "users", so they show the user icon
135
    tab = 'users'
1294.1.2 by William Grant
Add a non-AJAX password change view.
136
    permission = 'edit'
137
1294.1.4 by William Grant
Forbid access to +changepassword if there is no passhash.
138
    def authorize(self, req):
139
        """Only allow access if the requesting user holds the permission,
140
           and the target user has a password set. Otherwise we might be
141
           clobbering external authn.
142
        """
143
        return super(PasswordChangeView, self).authorize(req) and \
144
               self.context.passhash is not None
145
1294.1.2 by William Grant
Add a non-AJAX password change view.
146
    def populate(self, req, ctx):
147
        error = None
148
        if req.method == 'POST':
149
            data = dict(req.get_fieldstorage())
150
            if data.get('old_password') is None or \
151
               not self.context.authenticate(data.get('old_password')):
152
                error = 'Incorrect password.'
153
            elif data.get('new_password') != data.get('new_password_again'):
154
                error = 'New passwords do not match.'
155
            elif not data.get('new_password'):
156
                error = 'New password cannot be empty.'
157
            else:
158
                self.context.password = data['new_password']
159
                req.store.commit()
160
                req.throw_redirect(req.uri)
161
1294.1.5 by William Grant
Add a view for admins to reset other users' passwords.
162
        ctx['req'] = req
163
        ctx['user'] = self.context
164
        ctx['error'] = error
165
166
class PasswordResetView(XHTMLView):
167
    """A form to reset a user's password, without knowledge of the old one."""
168
    template = 'templates/user-password-reset.html'
1498 by Matt Giuca
user.py: All user pages are now in the tab "users", so they show the user icon
169
    tab = 'users'
1294.1.5 by William Grant
Add a view for admins to reset other users' passwords.
170
171
    def authorize(self, req):
172
        """Only allow access if the requesting user is an admin."""
1504 by Matt Giuca
ivle/webapp/admin/user.py: Fixed crash when visiting admin-only user pages while logged out (None dereference).
173
        return req.user and req.user.admin
1294.1.5 by William Grant
Add a view for admins to reset other users' passwords.
174
175
    def populate(self, req, ctx):
176
        error = None
177
        if req.method == 'POST':
178
            data = dict(req.get_fieldstorage())
179
            if data.get('new_password') != data.get('new_password_again'):
180
                error = 'New passwords do not match.'
181
            elif not data.get('new_password'):
182
                error = 'New password cannot be empty.'
183
            else:
184
                self.context.password = data['new_password']
185
                req.store.commit()
186
                req.throw_redirect(req.uri)
187
1294.1.2 by William Grant
Add a non-AJAX password change view.
188
        ctx['user'] = self.context
189
        ctx['error'] = error
190
1755 by William Grant
Add a form to create a user.
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
1099.1.99 by William Grant
Require that plugins providing media subclass MediaPlugin.
229
class Plugin(ViewPlugin, MediaPlugin):
1099.1.1 by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick).
230
    """
231
    The Plugin class for the user plugin.
232
    """
1294.2.19 by William Grant
Port ivle.webapp.admin.user's views to the new dispatch system.
233
1294.2.70 by William Grant
Split out ivle.webapp.admin's routes into annotated functions in ivle.webapp.traversal.
234
    forward_routes = (root_to_user,)
235
    reverse_routes = (user_url,)
1755 by William Grant
Add a form to create a user.
236
    views = [(ApplicationRoot, ('users', '+index'), UsersView),
237
             (ApplicationRoot, ('users', '+new'), UserNewView),
1679 by William Grant
Remove unused UserRESTView and associated infrastructure.
238
             (User, '+index', UserEditView),
239
             (User, '+admin', UserAdminView),
240
             (User, '+changepassword', PasswordChangeView),
241
             (User, '+resetpassword', PasswordResetView),
1294.2.19 by William Grant
Port ivle.webapp.admin.user's views to the new dispatch system.
242
             ]
1099.1.61 by William Grant
Port ivle.webapp.admin.user's media to the new framework.
243
1497 by Matt Giuca
Added Users tab to drop-down menu, for admins only.
244
    tabs = [
245
        ('users', 'Users', 'Display and edit all users',
1507 by William Grant
Shift the Users link to between Subjects and Help.
246
         'users.png', 'users', 90, True)
1497 by Matt Giuca
Added Users tab to drop-down menu, for admins only.
247
    ]
248
1294.2.138 by William Grant
Publish users in public mode.
249
    public_forward_routes = forward_routes
250
    public_reverse_routes = reverse_routes
251
1099.1.61 by William Grant
Port ivle.webapp.admin.user's media to the new framework.
252
    media = 'user-media'