Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (13.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.management.base import BaseCommand, CommandError
39
from django.contrib.auth.models import Group
40
from django.core.exceptions import ValidationError
41

    
42
from synnefo.util import units
43
from astakos.im.models import AstakosUser, Resource
44
from astakos.im import quotas
45
from astakos.im import activation_backends
46
from ._common import (remove_user_permission, add_user_permission, is_uuid,
47
                      show_resource_value)
48
from snf_django.lib.db.transaction import commit_on_success_strict
49

    
50
activation_backend = activation_backends.get_backend()
51

    
52

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

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

    
145
    @commit_on_success_strict()
146
    def handle(self, *args, **options):
147
        if len(args) != 1:
148
            raise CommandError("Please provide a user ID")
149

    
150
        if args[0].isdigit():
151
            try:
152
                user = AstakosUser.objects.get(id=int(args[0]))
153
            except AstakosUser.DoesNotExist:
154
                raise CommandError("Invalid user ID")
155
        elif is_uuid(args[0]):
156
            try:
157
                user = AstakosUser.objects.get(uuid=args[0])
158
            except AstakosUser.DoesNotExist:
159
                raise CommandError("Invalid user UUID")
160
        else:
161
            raise CommandError(("Invalid user identification: "
162
                                "you should provide a valid user ID "
163
                                "or a valid user UUID"))
164

    
165
        if options.get('admin'):
166
            user.is_superuser = True
167
        elif options.get('noadmin'):
168
            user.is_superuser = False
169

    
170
        if options.get('reject'):
171
            reject_reason = options.get('reject_reason', None)
172
            res = activation_backend.handle_moderation(
173
                user,
174
                accept=False,
175
                reject_reason=reject_reason)
176
            activation_backend.send_result_notifications(res, user)
177
            if res.is_error():
178
                print "Failed to reject.", res.message
179
            else:
180
                print "Account rejected"
181

    
182
        if options.get('verify'):
183
            res = activation_backend.handle_verification(
184
                user,
185
                user.verification_code)
186
            #activation_backend.send_result_notifications(res, user)
187
            if res.is_error():
188
                print "Failed to verify.", res.message
189
            else:
190
                print "Account verified (%s)" % res.status_display()
191

    
192
        if options.get('accept'):
193
            res = activation_backend.handle_moderation(user, accept=True)
194
            activation_backend.send_result_notifications(res, user)
195
            if res.is_error():
196
                print "Failed to accept.", res.message
197
            else:
198
                print "Account accepted and activated"
199

    
200
        if options.get('active'):
201
            res = activation_backend.activate_user(user)
202
            if res.is_error():
203
                print "Failed to activate.", res.message
204
            else:
205
                print "Account %s activated" % user.username
206

    
207
        elif options.get('inactive'):
208
            res = activation_backend.deactivate_user(
209
                user,
210
                reason=options.get('inactive_reason', None))
211
            if res.is_error():
212
                print "Failed to deactivate,", res.message
213
            else:
214
                print "Account %s deactivated" % user.username
215

    
216
        invitations = options.get('invitations')
217
        if invitations is not None:
218
            user.invitations = int(invitations)
219

    
220
        groupname = options.get('add-group')
221
        if groupname is not None:
222
            try:
223
                group = Group.objects.get(name=groupname)
224
                user.groups.add(group)
225
            except Group.DoesNotExist, e:
226
                self.stdout.write(
227
                    "Group named %s does not exist\n" % groupname)
228

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

    
238
        pname = options.get('add-permission')
239
        if pname is not None:
240
            try:
241
                r, created = add_user_permission(user, pname)
242
                if created:
243
                    self.stdout.write(
244
                        'Permission: %s created successfully\n' % pname)
245
                if r > 0:
246
                    self.stdout.write(
247
                        'Permission: %s added successfully\n' % pname)
248
                elif r == 0:
249
                    self.stdout.write(
250
                        'User has already permission: %s\n' % pname)
251
            except Exception, e:
252
                raise CommandError(e)
253

    
254
        pname = options.get('delete-permission')
255
        if pname is not None and not user.has_perm(pname):
256
            try:
257
                r = remove_user_permission(user, pname)
258
                if r < 0:
259
                    self.stdout.write(
260
                        'Invalid permission codename: %s\n' % pname)
261
                elif r == 0:
262
                    self.stdout.write('User has not permission: %s\n' % pname)
263
                elif r > 0:
264
                    self.stdout.write(
265
                        'Permission: %s removed successfully\n' % pname)
266
            except Exception, e:
267
                raise CommandError(e)
268

    
269
        level = options.get('level')
270
        if level is not None:
271
            user.level = int(level)
272

    
273
        password = options.get('password')
274
        if password is not None:
275
            user.set_password(password)
276

    
277
        password = None
278
        if options['renew_password']:
279
            password = AstakosUser.objects.make_random_password()
280
            user.set_password(password)
281

    
282
        if options['renew_token']:
283
            user.renew_token()
284

    
285
        try:
286
            user.save()
287
        except ValidationError, e:
288
            raise CommandError(e)
289

    
290
        if password:
291
            self.stdout.write('User\'s new password: %s\n' % password)
292

    
293
        force = options['force']
294

    
295
        set_base_quota = options.get('set_base_quota')
296
        if set_base_quota is not None:
297
            resource, capacity = set_base_quota
298
            self.set_limit(user, resource, capacity, force)
299

    
300
    def set_limit(self, user, resource, capacity, force):
301
        style = None
302
        if capacity != 'default':
303
            try:
304
                capacity, style = units.parse_with_style(capacity)
305
            except:
306
                m = "Please specify capacity as a decimal integer or 'default'"
307
                raise CommandError(m)
308

    
309
        try:
310
            quota, default_capacity = user.get_resource_policy(resource)
311
        except Resource.DoesNotExist:
312
            raise CommandError("No such resource: %s" % resource)
313

    
314
        if not force:
315
            s_default = show_resource_value(default_capacity, resource, style)
316
            s_current = (show_resource_value(quota.capacity, resource, style)
317
                         if quota is not None else 'default')
318
            s_capacity = (show_resource_value(capacity, resource, style)
319
                          if capacity != 'default' else capacity)
320
            self.stdout.write("user: %s (%s)\n" % (user.uuid, user.username))
321
            self.stdout.write("default capacity: %s\n" % s_default)
322
            self.stdout.write("current capacity: %s\n" % s_current)
323
            self.stdout.write("new capacity: %s\n" % s_capacity)
324
            self.stdout.write("Confirm? (y/n) ")
325
            response = raw_input()
326
            if string.lower(response) not in ['y', 'yes']:
327
                self.stdout.write("Aborted.\n")
328
                return
329

    
330
        if capacity == 'default':
331
            try:
332
                quotas.remove_base_quota(user, resource)
333
            except Exception as e:
334
                import traceback
335
                traceback.print_exc()
336
                raise CommandError("Failed to remove policy: %s" % e)
337
        else:
338
            try:
339
                quotas.add_base_quota(user, resource, capacity)
340
            except Exception as e:
341
                raise CommandError("Failed to add policy: %s" % e)