Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (13.5 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 snf_django.management.commands import SynnefoCommand, 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(SynnefoCommand):
54
    args = "<user ID> (or --all)"
55
    help = "Modify a user's attributes"
56

    
57
    option_list = SynnefoCommand.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
                print "Failed to reject.", res.message
202
            else:
203
                print "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
                print "Failed to verify.", res.message
212
            else:
213
                print "Account verified (%s)" % res.status_display()
214

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
347
            user.set_email(newemail)
348
            user.save()
349

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

    
360
    def handle_all_users(self, *args, **options):
361
        pass