~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: 2010-02-25 08:21:47 UTC
  • Revision ID: matt.giuca@gmail.com-20100225082147-tus03ah630n74156
ProjectSet view: Prettied up the group management interface, including fixing delete icons.

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