Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / management / commands / user-modify.py @ a442c81d

History | View | Annotate | Download (13.7 kB)

1
# Copyright 2012, 2013, 2014 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
import string
35
from datetime import datetime
36

    
37
from optparse import make_option
38

    
39
from django.core import management
40
from django.db import transaction
41
from django.core.management.base import BaseCommand, CommandError
42
from django.contrib.auth.models import Group
43
from django.core.exceptions import ValidationError
44
from django.core.validators import validate_email
45

    
46
from astakos.im.models import AstakosUser
47
from astakos.im import activation_backends
48
from ._common import (remove_user_permission, add_user_permission, is_uuid)
49

    
50
activation_backend = activation_backends.get_backend()
51

    
52

    
53
class Command(BaseCommand):
54
    args = "<user ID> (or --all)"
55
    help = "Modify a user's attributes"
56

    
57
    option_list = BaseCommand.option_list + (
58
        make_option('--all',
59
                    action='store_true',
60
                    default=False,
61
                    help=("Operate on all users. Currently only setting "
62
                          "base quota is supported in this mode. Can be "
63
                          "combined with `--exclude'.")),
64
        make_option('--exclude',
65
                    help=("If `--all' is given, exclude users given as a "
66
                          "list of uuids: uuid1,uuid2,uuid3")),
67
        make_option('--invitations',
68
                    dest='invitations',
69
                    metavar='NUM',
70
                    help="Update user's invitations"),
71
        make_option('--level',
72
                    dest='level',
73
                    metavar='NUM',
74
                    help="Update user's level"),
75
        make_option('--password',
76
                    dest='password',
77
                    metavar='PASSWORD',
78
                    help="Set user's password"),
79
        make_option('--renew-token',
80
                    action='store_true',
81
                    dest='renew_token',
82
                    default=False,
83
                    help="Renew the user's token"),
84
        make_option('--renew-password',
85
                    action='store_true',
86
                    dest='renew_password',
87
                    default=False,
88
                    help="Renew the user's password"),
89
        make_option('--set-admin',
90
                    action='store_true',
91
                    dest='admin',
92
                    default=False,
93
                    help="Give user admin rights"),
94
        make_option('--set-noadmin',
95
                    action='store_true',
96
                    dest='noadmin',
97
                    default=False,
98
                    help="Revoke user's admin rights"),
99
        make_option('--set-active',
100
                    action='store_true',
101
                    dest='active',
102
                    default=False,
103
                    help="Change user's state to active"),
104
        make_option('--set-inactive',
105
                    action='store_true',
106
                    dest='inactive',
107
                    default=False,
108
                    help="Change user's state to inactive"),
109
        make_option('--inactive-reason',
110
                    dest='inactive_reason',
111
                    help="Reason user got inactive"),
112
        make_option('--add-group',
113
                    dest='add-group',
114
                    help="Add user group"),
115
        make_option('--delete-group',
116
                    dest='delete-group',
117
                    help="Delete user group"),
118
        make_option('--add-permission',
119
                    dest='add-permission',
120
                    help="Add user permission"),
121
        make_option('--delete-permission',
122
                    dest='delete-permission',
123
                    help="Delete user permission"),
124
        make_option('--accept',
125
                    dest='accept',
126
                    action='store_true',
127
                    help="Accept user"),
128
        make_option('--verify',
129
                    dest='verify',
130
                    action='store_true',
131
                    help="Verify user email"),
132
        make_option('--reject',
133
                    dest='reject',
134
                    action='store_true',
135
                    help="Reject user"),
136
        make_option('--reject-reason',
137
                    dest='reject_reason',
138
                    help="Reason user got rejected"),
139
        make_option('--sign-terms',
140
                    default=False,
141
                    action='store_true',
142
                    help="Sign terms"),
143
        make_option('-f', '--no-confirm',
144
                    action='store_true',
145
                    default=False,
146
                    dest='force',
147
                    help="Do not ask for confirmation"),
148
        make_option('--set-email',
149
                    dest='set-email',
150
                    help="Change user's email"),
151
        make_option('--delete',
152
                    dest='delete',
153
                    action='store_true',
154
                    help="Delete a non-accepted user"),
155
    )
156

    
157
    @transaction.commit_on_success
158
    def handle(self, *args, **options):
159
        if options['all']:
160
            if not args:
161
                return self.handle_all_users(*args, **options)
162
            else:
163
                raise CommandError("Please provide a user ID or --all")
164

    
165
        if len(args) != 1:
166
            raise CommandError("Please provide a user ID or --all")
167

    
168
        if options["exclude"] is not None:
169
            m = "Option --exclude is meaningful only combined with --all."
170
            raise CommandError(m)
171

    
172
        if args[0].isdigit():
173
            try:
174
                user = AstakosUser.objects.select_for_update().\
175
                    get(id=int(args[0]))
176
            except AstakosUser.DoesNotExist:
177
                raise CommandError("Invalid user ID")
178
        elif is_uuid(args[0]):
179
            try:
180
                user = AstakosUser.objects.get(uuid=args[0])
181
            except AstakosUser.DoesNotExist:
182
                raise CommandError("Invalid user UUID")
183
        else:
184
            raise CommandError(("Invalid user identification: "
185
                                "you should provide a valid user ID "
186
                                "or a valid user UUID"))
187

    
188
        if options.get('admin'):
189
            user.is_superuser = True
190
        elif options.get('noadmin'):
191
            user.is_superuser = False
192

    
193
        if options.get('reject'):
194
            reject_reason = options.get('reject_reason', None)
195
            res = activation_backend.handle_moderation(
196
                user,
197
                accept=False,
198
                reject_reason=reject_reason)
199
            activation_backend.send_result_notifications(res, user)
200
            if res.is_error():
201
                self.stderr.write("Failed to reject: %s" % res.message)
202
            else:
203
                self.stderr.write("Account rejected")
204

    
205
        if options.get('verify'):
206
            res = activation_backend.handle_verification(
207
                user,
208
                user.verification_code)
209
            #activation_backend.send_result_notifications(res, user)
210
            if res.is_error():
211
                self.stderr.write("Failed to verify: %s" % res.message)
212
            else:
213
                self.stderr.write("Account verified (%s)"
214
                                  % res.status_display())
215

    
216
        if options.get('accept'):
217
            res = activation_backend.handle_moderation(user, accept=True)
218
            activation_backend.send_result_notifications(res, user)
219
            if res.is_error():
220
                self.stderr.write("Failed to accept: %s" % res.message)
221
            else:
222
                self.stderr.write("Account accepted and activated")
223

    
224
        if options.get('active'):
225
            res = activation_backend.activate_user(user)
226
            if res.is_error():
227
                self.stderr.write("Failed to activate: %s" % res.message)
228
            else:
229
                self.stderr.write("Account %s activated" % user.username)
230

    
231
        elif options.get('inactive'):
232
            res = activation_backend.deactivate_user(
233
                user,
234
                reason=options.get('inactive_reason', None))
235
            if res.is_error():
236
                self.stderr.write("Failed to deactivate: %s" % res.message)
237
            else:
238
                self.stderr.write("Account %s deactivated" % user.username)
239

    
240
        invitations = options.get('invitations')
241
        if invitations is not None:
242
            user.invitations = int(invitations)
243

    
244
        groupname = options.get('add-group')
245
        if groupname is not None:
246
            try:
247
                group = Group.objects.get(name=groupname)
248
                user.groups.add(group)
249
            except Group.DoesNotExist, e:
250
                self.stderr.write(
251
                    "Group named %s does not exist\n" % groupname)
252

    
253
        groupname = options.get('delete-group')
254
        if groupname is not None:
255
            try:
256
                group = Group.objects.get(name=groupname)
257
                user.groups.remove(group)
258
            except Group.DoesNotExist, e:
259
                self.stderr.write(
260
                    "Group named %s does not exist\n" % groupname)
261

    
262
        pname = options.get('add-permission')
263
        if pname is not None:
264
            try:
265
                r, created = add_user_permission(user, pname)
266
                if created:
267
                    self.stderr.write(
268
                        'Permission: %s created successfully\n' % pname)
269
                if r > 0:
270
                    self.stderr.write(
271
                        'Permission: %s added successfully\n' % pname)
272
                elif r == 0:
273
                    self.stderr.write(
274
                        'User has already permission: %s\n' % pname)
275
            except Exception, e:
276
                raise CommandError(e)
277

    
278
        pname = options.get('delete-permission')
279
        if pname is not None and not user.has_perm(pname):
280
            try:
281
                r = remove_user_permission(user, pname)
282
                if r < 0:
283
                    self.stderr.write(
284
                        'Invalid permission codename: %s\n' % pname)
285
                elif r == 0:
286
                    self.stderr.write('User has not permission: %s\n' % pname)
287
                elif r > 0:
288
                    self.stderr.write(
289
                        'Permission: %s removed successfully\n' % pname)
290
            except Exception, e:
291
                raise CommandError(e)
292

    
293
        level = options.get('level')
294
        if level is not None:
295
            user.level = int(level)
296

    
297
        password = options.get('password')
298
        if password is not None:
299
            user.set_password(password)
300

    
301
        password = None
302
        if options['renew_password']:
303
            password = AstakosUser.objects.make_random_password()
304
            user.set_password(password)
305

    
306
        if options['renew_token']:
307
            user.renew_token()
308

    
309
        if options['sign_terms']:
310
            user.has_signed_terms = True
311
            user.date_signed_terms = datetime.now()
312

    
313
        try:
314
            user.save()
315
        except ValidationError, e:
316
            raise CommandError(e)
317

    
318
        if password:
319
            self.stdout.write('User\'s new password: %s\n' % password)
320

    
321
        force = options['force']
322
        delete = options.get('delete')
323
        if delete:
324
            if user.is_accepted():
325
                m = "Cannot delete. User %s is accepted." % user
326
                raise CommandError(m)
327
            management.call_command('user-show', str(user.pk),
328
                                    list_quotas=True)
329

    
330
            if not force:
331
                self.stdout.write("About to delete user %s. " % user.uuid)
332
                self.confirm()
333
            user.delete()
334

    
335
        # Change users email address
336
        newemail = options.get('set-email', None)
337
        if newemail is not None:
338
            newemail = newemail.strip()
339
            try:
340
                validate_email(newemail)
341
            except ValidationError:
342
                m = "Invalid email address."
343
                raise CommandError(m)
344

    
345
            if AstakosUser.objects.user_exists(newemail):
346
                m = "A user with this email address already exists."
347
                raise CommandError(m)
348

    
349
            user.set_email(newemail)
350
            user.save()
351

    
352
    def confirm(self):
353
        self.stdout.write("Confirm? [y/N] ")
354
        try:
355
            response = raw_input()
356
        except EOFError:
357
            response = "ABORT"
358
        if string.lower(response) not in ['y', 'yes']:
359
            self.stderr.write("Aborted.\n")
360
            exit()
361

    
362
    def handle_all_users(self, *args, **options):
363
        pass