~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-26 06:30:50 UTC
  • Revision ID: grantw@unimelb.edu.au-20100226063050-nwkscx3qsvigtv31
Fix diffservice and svnlogservice to create authentication-capable pysvn.Clients, so they don't crash if credentials aren't cached.

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