Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (14.1 kB)

1
# Copyright 2012 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

    
36
from optparse import make_option
37

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

    
45
from synnefo.util import units
46
from astakos.im.models import AstakosUser, AstakosUserQuota
47
from astakos.im import quotas
48
from astakos.im import activation_backends
49
from ._common import (remove_user_permission, add_user_permission, is_uuid,
50
                      show_resource_value)
51

    
52
activation_backend = activation_backends.get_backend()
53

    
54

    
55
class Command(BaseCommand):
56
    args = "<user ID>"
57
    help = "Modify a user's attributes"
58

    
59
    option_list = BaseCommand.option_list + (
60
        make_option('--invitations',
61
                    dest='invitations',
62
                    metavar='NUM',
63
                    help="Update user's invitations"),
64
        make_option('--level',
65
                    dest='level',
66
                    metavar='NUM',
67
                    help="Update user's level"),
68
        make_option('--password',
69
                    dest='password',
70
                    metavar='PASSWORD',
71
                    help="Set user's password"),
72
        make_option('--renew-token',
73
                    action='store_true',
74
                    dest='renew_token',
75
                    default=False,
76
                    help="Renew the user's token"),
77
        make_option('--renew-password',
78
                    action='store_true',
79
                    dest='renew_password',
80
                    default=False,
81
                    help="Renew the user's password"),
82
        make_option('--set-admin',
83
                    action='store_true',
84
                    dest='admin',
85
                    default=False,
86
                    help="Give user admin rights"),
87
        make_option('--set-noadmin',
88
                    action='store_true',
89
                    dest='noadmin',
90
                    default=False,
91
                    help="Revoke user's admin rights"),
92
        make_option('--set-active',
93
                    action='store_true',
94
                    dest='active',
95
                    default=False,
96
                    help="Change user's state to active"),
97
        make_option('--set-inactive',
98
                    action='store_true',
99
                    dest='inactive',
100
                    default=False,
101
                    help="Change user's state to inactive"),
102
        make_option('--inactive-reason',
103
                    dest='inactive_reason',
104
                    help="Reason user got inactive"),
105
        make_option('--add-group',
106
                    dest='add-group',
107
                    help="Add user group"),
108
        make_option('--delete-group',
109
                    dest='delete-group',
110
                    help="Delete user group"),
111
        make_option('--add-permission',
112
                    dest='add-permission',
113
                    help="Add user permission"),
114
        make_option('--delete-permission',
115
                    dest='delete-permission',
116
                    help="Delete user permission"),
117
        make_option('--accept',
118
                    dest='accept',
119
                    action='store_true',
120
                    help="Accept user"),
121
        make_option('--verify',
122
                    dest='verify',
123
                    action='store_true',
124
                    help="Verify user email"),
125
        make_option('--reject',
126
                    dest='reject',
127
                    action='store_true',
128
                    help="Reject user"),
129
        make_option('--reject-reason',
130
                    dest='reject_reason',
131
                    help="Reason user got rejected"),
132
        make_option('--set-base-quota',
133
                    dest='set_base_quota',
134
                    metavar='<resource> <capacity>',
135
                    nargs=2,
136
                    help=("Set base quota for a specified resource. "
137
                          "The special value 'default' sets the user base "
138
                          "quota to the default value.")
139
                    ),
140
        make_option('-f', '--no-confirm',
141
                    action='store_true',
142
                    default=False,
143
                    dest='force',
144
                    help="Do not ask for confirmation"),
145
        make_option('--set-email',
146
                    dest='set-email',
147
                    help="Change user's email"),
148
        make_option('--delete',
149
                    dest='delete',
150
                    action='store_true',
151
                    help="Delete user"),
152
    )
153

    
154
    @transaction.commit_on_success
155
    def handle(self, *args, **options):
156
        if len(args) != 1:
157
            raise CommandError("Please provide a user ID")
158

    
159
        if args[0].isdigit():
160
            try:
161
                user = AstakosUser.objects.get(id=int(args[0]))
162
            except AstakosUser.DoesNotExist:
163
                raise CommandError("Invalid user ID")
164
        elif is_uuid(args[0]):
165
            try:
166
                user = AstakosUser.objects.get(uuid=args[0])
167
            except AstakosUser.DoesNotExist:
168
                raise CommandError("Invalid user UUID")
169
        else:
170
            raise CommandError(("Invalid user identification: "
171
                                "you should provide a valid user ID "
172
                                "or a valid user UUID"))
173

    
174
        if options.get('admin'):
175
            user.is_superuser = True
176
        elif options.get('noadmin'):
177
            user.is_superuser = False
178

    
179
        if options.get('reject'):
180
            reject_reason = options.get('reject_reason', None)
181
            res = activation_backend.handle_moderation(
182
                user,
183
                accept=False,
184
                reject_reason=reject_reason)
185
            activation_backend.send_result_notifications(res, user)
186
            if res.is_error():
187
                print "Failed to reject.", res.message
188
            else:
189
                print "Account rejected"
190

    
191
        if options.get('verify'):
192
            res = activation_backend.handle_verification(
193
                user,
194
                user.verification_code)
195
            #activation_backend.send_result_notifications(res, user)
196
            if res.is_error():
197
                print "Failed to verify.", res.message
198
            else:
199
                print "Account verified (%s)" % res.status_display()
200

    
201
        if options.get('accept'):
202
            res = activation_backend.handle_moderation(user, accept=True)
203
            activation_backend.send_result_notifications(res, user)
204
            if res.is_error():
205
                print "Failed to accept.", res.message
206
            else:
207
                print "Account accepted and activated"
208

    
209
        if options.get('active'):
210
            res = activation_backend.activate_user(user)
211
            if res.is_error():
212
                print "Failed to activate.", res.message
213
            else:
214
                print "Account %s activated" % user.username
215

    
216
        elif options.get('inactive'):
217
            res = activation_backend.deactivate_user(
218
                user,
219
                reason=options.get('inactive_reason', None))
220
            if res.is_error():
221
                print "Failed to deactivate,", res.message
222
            else:
223
                print "Account %s deactivated" % user.username
224

    
225
        invitations = options.get('invitations')
226
        if invitations is not None:
227
            user.invitations = int(invitations)
228

    
229
        groupname = options.get('add-group')
230
        if groupname is not None:
231
            try:
232
                group = Group.objects.get(name=groupname)
233
                user.groups.add(group)
234
            except Group.DoesNotExist, e:
235
                self.stdout.write(
236
                    "Group named %s does not exist\n" % groupname)
237

    
238
        groupname = options.get('delete-group')
239
        if groupname is not None:
240
            try:
241
                group = Group.objects.get(name=groupname)
242
                user.groups.remove(group)
243
            except Group.DoesNotExist, e:
244
                self.stdout.write(
245
                    "Group named %s does not exist\n" % groupname)
246

    
247
        pname = options.get('add-permission')
248
        if pname is not None:
249
            try:
250
                r, created = add_user_permission(user, pname)
251
                if created:
252
                    self.stdout.write(
253
                        'Permission: %s created successfully\n' % pname)
254
                if r > 0:
255
                    self.stdout.write(
256
                        'Permission: %s added successfully\n' % pname)
257
                elif r == 0:
258
                    self.stdout.write(
259
                        'User has already permission: %s\n' % pname)
260
            except Exception, e:
261
                raise CommandError(e)
262

    
263
        pname = options.get('delete-permission')
264
        if pname is not None and not user.has_perm(pname):
265
            try:
266
                r = remove_user_permission(user, pname)
267
                if r < 0:
268
                    self.stdout.write(
269
                        'Invalid permission codename: %s\n' % pname)
270
                elif r == 0:
271
                    self.stdout.write('User has not permission: %s\n' % pname)
272
                elif r > 0:
273
                    self.stdout.write(
274
                        'Permission: %s removed successfully\n' % pname)
275
            except Exception, e:
276
                raise CommandError(e)
277

    
278
        level = options.get('level')
279
        if level is not None:
280
            user.level = int(level)
281

    
282
        password = options.get('password')
283
        if password is not None:
284
            user.set_password(password)
285

    
286
        password = None
287
        if options['renew_password']:
288
            password = AstakosUser.objects.make_random_password()
289
            user.set_password(password)
290

    
291
        if options['renew_token']:
292
            user.renew_token()
293

    
294
        try:
295
            user.save()
296
        except ValidationError, e:
297
            raise CommandError(e)
298

    
299
        if password:
300
            self.stdout.write('User\'s new password: %s\n' % password)
301

    
302
        force = options['force']
303

    
304
        set_base_quota = options.get('set_base_quota')
305
        if set_base_quota is not None:
306
            resource, capacity = set_base_quota
307
            self.set_limit(user, resource, capacity, force)
308

    
309
        delete = options.get('delete')
310
        if delete:
311
            management.call_command('user-show', str(user.pk),
312
                                    list_quotas=True)
313
            m = "Are you sure you want to permanently delete the user " \
314
                "(yes/no) ? "
315

    
316
            self.stdout.write("\n")
317
            confirm = raw_input(m)
318
            if confirm == "yes":
319
                user.delete()
320

    
321
        # Change users email address
322
        newemail = options.get('set-email', None)
323
        if newemail is not None:
324
            newemail = newemail.strip()
325
            try:
326
                validate_email(newemail)
327
            except ValidationError:
328
                m = "Invalid email address."
329
                raise CommandError(m)
330

    
331
            if AstakosUser.objects.user_exists(newemail):
332
                m = "A user with this email address already exists."
333
                raise CommandError(m)
334

    
335
            user.email = newemail
336
            user.save()
337

    
338
    def set_limit(self, user, resource, capacity, force):
339
        style = None
340
        if capacity != 'default':
341
            try:
342
                capacity, style = units.parse_with_style(capacity)
343
            except:
344
                m = "Please specify capacity as a decimal integer or 'default'"
345
                raise CommandError(m)
346

    
347
        try:
348
            quota = user.get_resource_policy(resource)
349
        except AstakosUserQuota.DoesNotExist:
350
            raise CommandError("No such resource: %s" % resource)
351

    
352
        default_capacity = quota.resource.uplimit
353
        if not force:
354
            s_default = show_resource_value(default_capacity, resource, style)
355
            s_current = show_resource_value(quota.capacity, resource, style)
356
            s_capacity = (show_resource_value(capacity, resource, style)
357
                          if capacity != 'default' else capacity)
358
            self.stdout.write("user: %s (%s)\n" % (user.uuid, user.username))
359
            self.stdout.write("default capacity: %s\n" % s_default)
360
            self.stdout.write("current capacity: %s\n" % s_current)
361
            self.stdout.write("new capacity: %s\n" % s_capacity)
362
            self.stdout.write("Confirm? (y/n) ")
363
            response = raw_input()
364
            if string.lower(response) not in ['y', 'yes']:
365
                self.stdout.write("Aborted.\n")
366
                return
367

    
368
        if capacity == 'default':
369
            capacity = default_capacity
370
        quotas.update_base_quota(quota, capacity)