Statistics
| Branch: | Tag: | Revision:

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

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 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 snf_django.management.commands import SynnefoCommand
49
from ._common import (remove_user_permission, add_user_permission, is_uuid)
50

    
51
activation_backend = activation_backends.get_backend()
52

    
53

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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