Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (12.9 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

    
139
    )
140

    
141
    @commit_on_success_strict()
142
    def handle(self, *args, **options):
143
        if len(args) != 1:
144
            raise CommandError("Please provide a user ID")
145

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

    
161
        if options.get('admin'):
162
            user.is_superuser = True
163
        elif options.get('noadmin'):
164
            user.is_superuser = False
165

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

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

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

    
196
        if options.get('active'):
197
            res = activation_backend.activate_user(user)
198
            if res.is_error():
199
                print "Failed to activate.", res.message
200
            else:
201
                print "Account %s activated" % user.username
202

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

    
212
        invitations = options.get('invitations')
213
        if invitations is not None:
214
            user.invitations = int(invitations)
215

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

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

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

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

    
265
        level = options.get('level')
266
        if level is not None:
267
            user.level = int(level)
268

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

    
273
        password = None
274
        if options['renew_password']:
275
            password = AstakosUser.objects.make_random_password()
276
            user.set_password(password)
277

    
278
        if options['renew_token']:
279
            user.renew_token()
280

    
281
        try:
282
            user.save()
283
        except ValidationError, e:
284
            raise CommandError(e)
285

    
286
        if password:
287
            self.stdout.write('User\'s new password: %s\n' % password)
288

    
289
        set_base_quota = options.get('set_base_quota')
290
        if set_base_quota is not None:
291
            resource, capacity = set_base_quota
292
            self.set_limit(user, resource, capacity, False)
293

    
294
    def set_limit(self, user, resource, capacity, force):
295
        style = None
296
        if capacity != 'default':
297
            try:
298
                capacity, style = units.parse_with_style(capacity)
299
            except:
300
                m = "Please specify capacity as a decimal integer or 'default'"
301
                raise CommandError(m)
302

    
303
        try:
304
            quota, default_capacity = user.get_resource_policy(resource)
305
        except Resource.DoesNotExist:
306
            raise CommandError("No such resource: %s" % resource)
307

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

    
324
        if capacity == 'default':
325
            try:
326
                quotas.remove_base_quota(user, resource)
327
            except Exception as e:
328
                import traceback
329
                traceback.print_exc()
330
                raise CommandError("Failed to remove policy: %s" % e)
331
        else:
332
            try:
333
                quotas.add_base_quota(user, resource, capacity)
334
            except Exception as e:
335
                raise CommandError("Failed to add policy: %s" % e)