Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (12 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 astakos.im.models import AstakosUser
43
from astakos.im import quotas
44
from astakos.im import activation_backends
45
from ._common import remove_user_permission, add_user_permission, is_uuid
46
from snf_django.lib.db.transaction import commit_on_success_strict
47

    
48
activation_backend = activation_backends.get_backend()
49

    
50

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

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

    
133
    )
134

    
135
    @commit_on_success_strict()
136
    def handle(self, *args, **options):
137
        if len(args) != 1:
138
            raise CommandError("Please provide a user ID")
139

    
140
        if args[0].isdigit():
141
            try:
142
                user = AstakosUser.objects.get(id=int(args[0]))
143
            except AstakosUser.DoesNotExist:
144
                raise CommandError("Invalid user ID")
145
        elif is_uuid(args[0]):
146
            try:
147
                user = AstakosUser.objects.get(uuid=args[0])
148
            except AstakosUser.DoesNotExist:
149
                raise CommandError("Invalid user UUID")
150
        else:
151
            raise CommandError(("Invalid user identification: "
152
                                "you should provide a valid user ID "
153
                                "or a valid user UUID"))
154

    
155
        if options.get('admin'):
156
            user.is_superuser = True
157
        elif options.get('noadmin'):
158
            user.is_superuser = False
159

    
160
        if options.get('reject'):
161
            reject_reason = options.get('reject_reason', None)
162
            res = activation_backend.handle_moderation(
163
                user,
164
                accept=False,
165
                reject_reason=reject_reason)
166
            activation_backend.send_result_notifications(res, user)
167
            if res.is_error():
168
                print "Failed to reject.", res.message
169
            else:
170
                print "Account rejected"
171

    
172
        if options.get('accept'):
173
            res = activation_backend.handle_moderation(user, accept=True)
174
            activation_backend.send_result_notifications(res, user)
175
            if res.is_error():
176
                print "Failed to accept.", res.message
177
            else:
178
                print "Account accepted and activated"
179

    
180
        if options.get('active'):
181
            res = activation_backend.activate_user(user)
182
            if res.is_error():
183
                print "Failed to activate.", res.message
184
            else:
185
                print "Account %s activated" % user.username
186

    
187
        elif options.get('inactive'):
188
            res = activation_backend.deactivate_user(
189
                user,
190
                reason=options.get('inactive_reason', None))
191
            if res.is_error():
192
                print "Failed to deactivate,", res.message
193
            else:
194
                print "Account %s deactivated" % user.username
195

    
196
        invitations = options.get('invitations')
197
        if invitations is not None:
198
            user.invitations = int(invitations)
199

    
200
        groupname = options.get('add-group')
201
        if groupname is not None:
202
            try:
203
                group = Group.objects.get(name=groupname)
204
                user.groups.add(group)
205
            except Group.DoesNotExist, e:
206
                self.stdout.write(
207
                    "Group named %s does not exist\n" % groupname)
208

    
209
        groupname = options.get('delete-group')
210
        if groupname is not None:
211
            try:
212
                group = Group.objects.get(name=groupname)
213
                user.groups.remove(group)
214
            except Group.DoesNotExist, e:
215
                self.stdout.write(
216
                    "Group named %s does not exist\n" % groupname)
217

    
218
        pname = options.get('add-permission')
219
        if pname is not None:
220
            try:
221
                r, created = add_user_permission(user, pname)
222
                if created:
223
                    self.stdout.write(
224
                        'Permission: %s created successfully\n' % pname)
225
                if r > 0:
226
                    self.stdout.write(
227
                        'Permission: %s added successfully\n' % pname)
228
                elif r == 0:
229
                    self.stdout.write(
230
                        'User has already permission: %s\n' % pname)
231
            except Exception, e:
232
                raise CommandError(e)
233

    
234
        pname = options.get('delete-permission')
235
        if pname is not None and not user.has_perm(pname):
236
            try:
237
                r = remove_user_permission(user, pname)
238
                if r < 0:
239
                    self.stdout.write(
240
                        'Invalid permission codename: %s\n' % pname)
241
                elif r == 0:
242
                    self.stdout.write('User has not permission: %s\n' % pname)
243
                elif r > 0:
244
                    self.stdout.write(
245
                        'Permission: %s removed successfully\n' % pname)
246
            except Exception, e:
247
                raise CommandError(e)
248

    
249
        level = options.get('level')
250
        if level is not None:
251
            user.level = int(level)
252

    
253
        password = options.get('password')
254
        if password is not None:
255
            user.set_password(password)
256

    
257
        password = None
258
        if options['renew_password']:
259
            password = AstakosUser.objects.make_random_password()
260
            user.set_password(password)
261

    
262
        if options['renew_token']:
263
            user.renew_token()
264

    
265
        try:
266
            user.save()
267
        except ValidationError, e:
268
            raise CommandError(e)
269

    
270
        if password:
271
            self.stdout.write('User\'s new password: %s\n' % password)
272

    
273
        set_base_quota = options.get('set_base_quota')
274
        if set_base_quota is not None:
275
            resource, capacity = set_base_quota
276
            self.set_limit(user, resource, capacity, False)
277

    
278
    def set_limit(self, user, resource, capacity, force):
279
        if capacity != 'default':
280
            try:
281
                capacity = int(capacity)
282
            except ValueError:
283
                m = "Please specify capacity as a decimal integer or 'default'"
284
                raise CommandError(m)
285

    
286
        try:
287
            quota, default_capacity = user.get_resource_policy(resource)
288
        except Resource.DoesNotExist:
289
            raise CommandError("No such resource: %s" % resource)
290

    
291
        current = quota.capacity if quota is not None else 'default'
292

    
293
        if not force:
294
            self.stdout.write("user: %s (%s)\n" % (user.uuid, user.username))
295
            self.stdout.write("default capacity: %s\n" % default_capacity)
296
            self.stdout.write("current capacity: %s\n" % current)
297
            self.stdout.write("new capacity: %s\n" % capacity)
298
            self.stdout.write("Confirm? (y/n) ")
299
            response = raw_input()
300
            if string.lower(response) not in ['y', 'yes']:
301
                self.stdout.write("Aborted.\n")
302
                return
303

    
304
        if capacity == 'default':
305
            try:
306
                quotas.remove_base_quota(user, resource)
307
            except Exception as e:
308
                import traceback
309
                traceback.print_exc()
310
                raise CommandError("Failed to remove policy: %s" % e)
311
        else:
312
            try:
313
                quotas.add_base_quota(user, resource, capacity)
314
            except Exception as e:
315
                raise CommandError("Failed to add policy: %s" % e)