Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / api / backends / lib / django / __init__.py @ 29b87e7c

History | View | Annotate | Download (10.2 kB)

1
# Copyright 2011-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
from django.db import IntegrityError, transaction
35
from django.core.exceptions import ObjectDoesNotExist
36

    
37
from functools import wraps
38
from smtplib import SMTPException
39

    
40
from astakos.im.models import (
41
    AstakosUser, AstakosGroup, GroupKind, Resource, Service, RESOURCE_SEPARATOR
42
)
43
from astakos.im.api.backends.base import BaseBackend, SuccessResult, FailureResult
44
from astakos.im.api.backends.errors import (
45
    ItemNotExists, ItemExists, MissingIdentifier, MultipleItemsExist
46
)
47
from astakos.im.util import reserved_email, model_to_dict
48
from astakos.im.endpoints.quotaholder import get_quota
49

    
50
import logging
51

    
52
logger = logging.getLogger(__name__)
53

    
54
DEFAULT_CONTENT_TYPE = None
55

    
56

    
57
def safe(func):
58
    """Decorator function for views that implement an API method."""
59
    @transaction.commit_manually
60
    @wraps(func)
61
    def wrapper(self, *args, **kwargs):
62
        logger.debug('%s %s %s' % (func, args, kwargs))
63
        try:
64
            data = func(self, *args, **kwargs) or ()
65
        except Exception, e:
66
            logger.exception(e)
67
            transaction.rollback()
68
            return FailureResult(e)
69
        else:
70
            transaction.commit()
71
            return SuccessResult(data)
72
    return wrapper
73

    
74

    
75
class DjangoBackend(BaseBackend):
76
    def _lookup_object(self, model, **kwargs):
77
        """
78
        Returns an object of the specific model matching the given lookup
79
        parameters.
80
        """
81
        if not kwargs:
82
            raise MissingIdentifier
83
        try:
84
            return model.objects.get(**kwargs)
85
        except model.DoesNotExist:
86
            raise ItemNotExists(model._meta.verbose_name, **kwargs)
87
        except model.MultipleObjectsReturned:
88
            raise MultipleItemsExist(model._meta.verbose_name, **kwargs)
89

    
90
    def _lookup_user(self, id):
91
        """
92
        Returns an AstakosUser having this id.
93
        """
94
        if not isinstance(id, int):
95
            raise TypeError('User id should be of type int')
96
        return self._lookup_object(AstakosUser, id=id)
97

    
98
    def _lookup_service(self, id):
99
        """
100
        Returns an Service having this id.
101
        """
102
        if not isinstance(id, int):
103
            raise TypeError('Service id should be of type int')
104
        return self._lookup_object(Service, id=id)
105

    
106
    def _list(self, model, filter=()):
107
        q = model.objects.all()
108
        if filter:
109
            q = q.filter(id__in=filter)
110
        return map(lambda o: model_to_dict(o, exclude=[]), q)
111

    
112
    def _create_object(self, model, **kwargs):
113
        o = model.objects.create(**kwargs)
114
        o.save()
115
        return o
116

    
117
    def _update_object(self, model, id, save=True, **kwargs):
118
        o = self._lookup_object(model, id=id)
119
        if kwargs:
120
            o.__dict__.update(kwargs)
121
        if save:
122
            o.save()
123
        return o
124

    
125
    @safe
126
    def update_user(self, user_id, renew_token=False, **kwargs):
127
        user = self._update_object(AstakosUser, user_id, save=False, **kwargs)
128
        if renew_token:
129
            user.renew_token()
130
        if kwargs or renew_token:
131
            user.save()
132

    
133
    @safe
134
    def create_user(self, **kwargs):
135
        policies = kwargs.pop('policies', ())
136
        permissions = kwargs.pop('permissions', ())
137
        groups = kwargs.pop('groups', ())
138
        password = kwargs.pop('password', None)
139

    
140
        u = self._create_object(AstakosUser, **kwargs)
141

    
142
        if password:
143
            u.set_password(password)
144
        u.permissions = permissions
145
        u.policies = policies
146
        u.extended_groups = groups
147
        return self._list(AstakosUser, filter=(u.id,))
148

    
149
    @safe
150
    def add_policies(self, user_id, update=False, policies=()):
151
        user = self._lookup_user(user_id)
152
        rejected = []
153
        append = rejected.append
154
        for p in policies:
155
            service = p.get('service')
156
            resource = p.get('resource')
157
            uplimit = p.get('uplimit')
158
            try:
159
                user.add_policy(service, resource, uplimit, update)
160
            except (ObjectDoesNotExist, IntegrityError), e:
161
                append((service, resource, e))
162
        return rejected
163
    
164
    @safe
165
    def remove_policies(self, user_id, policies=()):
166
        user = self._lookup_user(user_id)
167
        if not user:
168
            return user_id
169
        rejected = []
170
        append = rejected.append
171
        for p in policies:
172
            service = p.get('service')
173
            resource = p.get('resource')
174
            try:
175
                user.delete_policy(service, resource)
176
            except ObjectDoesNotExist, e:
177
                append((service, resource, e))
178
        return rejected
179
    @safe
180
    def add_permissions(self, user_id, permissions=()):
181
        user = self._lookup_user(user_id)
182
        rejected = []
183
        append = rejected.append
184
        for p in permissions:
185
            try:
186
                user.add_permission(p)
187
            except IntegrityError, e:
188
                append((p, e))
189
        return rejected
190
    
191
    @safe
192
    def remove_permissions(self, user_id, permissions=()):
193
        user = self._lookup_user(user_id)
194
        rejected = []
195
        append = rejected.append
196
        for p in permissions:
197
            try:
198
                user.remove_permission(p)
199
            except (ObjectDoesNotExist, IntegrityError), e:
200
                append((p, e))
201
        return rejected
202
    
203
    @safe
204
    def invite_users(self, senderid, recipients=()):
205
        user = self._lookup_user(senderid)
206
        rejected = []
207
        append = rejected.append
208
        for r in recipients:
209
            try:
210
                user.invite(r.get('email'), r.get('realname'))
211
            except (IntegrityError, SMTPException), e:
212
                append((email, e))
213
        return rejected
214
    
215
    @safe
216
    def list_users(self, filter=()):
217
        return self._list(AstakosUser, filter=filter)
218

    
219
    @safe
220
    def get_resource_usage(self, user_id):
221
        user = self._lookup_user(user_id)
222
        r = get_quota((user,))
223
        print '>>>', r 
224
        c, data = r 
225
        resources = []
226
        append = resources.append
227
        for t in data:
228
            t = (i if i else 0 for i in t)
229
            (entity, name, quantity, capacity, importLimit, exportLimit,
230
             imported, exported, returned, released, flags) = t
231
            service, sep, resource = name.partition(RESOURCE_SEPARATOR)
232
            resource = Resource.objects.select_related().get(
233
                service__name=service, name=resource)
234
            d = dict(name=name,
235
                     description=resource.desc,
236
                     unit=resource.unit or '',
237
                     maxValue=quantity + capacity,
238
                     currValue=quantity + imported - released - exported + returned)
239
            append(d)
240
        return resources
241

    
242
    @safe
243
    def list_resources(self, filter=()):
244
        return self._list(Resource, filter=filter)
245

    
246
    @safe
247
    def create_service(self, **kwargs):
248
        resources = kwargs.pop('resources', ())
249
        s = self._create_object(Service, **kwargs)
250
        s.resources = resources
251
        return self._list(Service, filter=(s.id,))
252

    
253
    @safe
254
    def remove_services(self, ids=()):
255
        # TODO return information for unknown ids
256
        q = Service.objects.filter(id__in=ids)
257
        q.delete()
258
    
259
    @safe
260
    def update_service(self, service_id, renew_token=False, **kwargs):
261
        s = self._update_object(Service, service_id, save=False, **kwargs)
262
        if renew_token:
263
            s.renew_token()
264

    
265
        if kwargs or renew_token:
266
            s.save()
267

    
268
    @safe
269
    def add_resources(self, service_id, update=False, resources=()):
270
        s = self._lookup_service(service_id)
271
        rejected = []
272
        append = rejected.append
273
        for r in resources:
274
            try:
275
                rr = r.copy()
276
                resource_id = rr.pop('id', None)
277
                if update:
278
                    if not resource_id:
279
                        raise MissingIdentifier
280
                    resource = self._update_object(Resource, resource_id, **rr)
281
                else:
282
                    resource = self._create_object(Resource, service=s, **rr)
283
            except Exception, e:
284
                append((r, e))
285
        return rejected
286
    
287
    @safe
288
    def remove_resources(self, service_id, ids=()):
289
        # TODO return information for unknown ids
290
        q = Resource.objects.filter(service__id=service_id,
291
                                id__in=ids)
292
        q.delete()
293
    
294
    @safe
295
    def create_group(self, **kwargs):
296
        policies = kwargs.pop('policies', ())
297
        permissions = kwargs.pop('permissions', ())
298
        members = kwargs.pop('members', ())
299
        owners = kwargs.pop('owners', ())
300

    
301
        g = self._create_object(AstakosGroup, **kwargs)
302

    
303
        g.permissions = permissions
304
        g.policies = policies
305
#         g.members = members
306
        g.owners = owners
307
        return self._list(AstakosGroup, filter=(g.id,))