Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / api / quotas.py @ c3d059f5

History | View | Annotate | Download (10.2 kB)

1 18f21257 Giorgos Korfiatis
# Copyright 2013 GRNET S.A. All rights reserved.
2 18f21257 Giorgos Korfiatis
#
3 18f21257 Giorgos Korfiatis
# Redistribution and use in source and binary forms, with or
4 18f21257 Giorgos Korfiatis
# without modification, are permitted provided that the following
5 18f21257 Giorgos Korfiatis
# conditions are met:
6 18f21257 Giorgos Korfiatis
#
7 18f21257 Giorgos Korfiatis
#   1. Redistributions of source code must retain the above
8 18f21257 Giorgos Korfiatis
#      copyright notice, this list of conditions and the following
9 18f21257 Giorgos Korfiatis
#      disclaimer.
10 18f21257 Giorgos Korfiatis
#
11 18f21257 Giorgos Korfiatis
#   2. Redistributions in binary form must reproduce the above
12 18f21257 Giorgos Korfiatis
#      copyright notice, this list of conditions and the following
13 18f21257 Giorgos Korfiatis
#      disclaimer in the documentation and/or other materials
14 18f21257 Giorgos Korfiatis
#      provided with the distribution.
15 18f21257 Giorgos Korfiatis
#
16 18f21257 Giorgos Korfiatis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 18f21257 Giorgos Korfiatis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 18f21257 Giorgos Korfiatis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 18f21257 Giorgos Korfiatis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 18f21257 Giorgos Korfiatis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 18f21257 Giorgos Korfiatis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 18f21257 Giorgos Korfiatis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 18f21257 Giorgos Korfiatis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 18f21257 Giorgos Korfiatis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 18f21257 Giorgos Korfiatis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 18f21257 Giorgos Korfiatis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 18f21257 Giorgos Korfiatis
# POSSIBILITY OF SUCH DAMAGE.
28 18f21257 Giorgos Korfiatis
#
29 18f21257 Giorgos Korfiatis
# The views and conclusions contained in the software and
30 18f21257 Giorgos Korfiatis
# documentation are those of the authors and should not be
31 18f21257 Giorgos Korfiatis
# interpreted as representing official policies, either expressed
32 18f21257 Giorgos Korfiatis
# or implied, of GRNET S.A.
33 18f21257 Giorgos Korfiatis
34 18f21257 Giorgos Korfiatis
from django.utils import simplejson as json
35 18f21257 Giorgos Korfiatis
from django.views.decorators.csrf import csrf_exempt
36 18f21257 Giorgos Korfiatis
from django.http import HttpResponse
37 a3e3917f Giorgos Korfiatis
from django.db import transaction
38 befa5997 Giorgos Korfiatis
39 befa5997 Giorgos Korfiatis
from snf_django.lib import api
40 ad730cc5 Giorgos Korfiatis
from snf_django.lib.api.faults import BadRequest, ItemNotFound
41 56bbece7 Giorgos Korfiatis
from django.core.cache import cache
42 befa5997 Giorgos Korfiatis
43 56bbece7 Giorgos Korfiatis
from astakos.im import settings
44 85ae5a4c Giorgos Korfiatis
from astakos.im import register
45 271d2c4c Giorgos Korfiatis
from astakos.im.quotas import get_user_quotas, service_get_quotas
46 18f21257 Giorgos Korfiatis
47 ec5e00aa Giorgos Korfiatis
import astakos.quotaholder_app.exception as qh_exception
48 ec5e00aa Giorgos Korfiatis
import astakos.quotaholder_app.callpoint as qh
49 18f21257 Giorgos Korfiatis
50 79b5d61b Sofia Papagiannaki
from .util import (json_response, is_integer, are_integer,
51 bea584e1 Giorgos Korfiatis
                   user_from_token, component_from_token)
52 18f21257 Giorgos Korfiatis
53 8fb8d0cf Giorgos Korfiatis
54 56bbece7 Giorgos Korfiatis
def get_visible_resources():
55 56bbece7 Giorgos Korfiatis
    key = "resources"
56 56bbece7 Giorgos Korfiatis
    result = cache.get(key)
57 56bbece7 Giorgos Korfiatis
    if result is None:
58 9b10cb20 Kostas Papadimitriou
        result = register.get_api_visible_resources()
59 9b10cb20 Kostas Papadimitriou
        cache.set(key, result, settings.RESOURCE_CACHE_TIMEOUT)
60 56bbece7 Giorgos Korfiatis
    return result
61 56bbece7 Giorgos Korfiatis
62 56bbece7 Giorgos Korfiatis
63 befa5997 Giorgos Korfiatis
@api.api_method(http_method='GET', token_required=True, user_required=False)
64 befa5997 Giorgos Korfiatis
@user_from_token
65 78c3a39c Sofia Papagiannaki
def quotas(request):
66 56bbece7 Giorgos Korfiatis
    visible_resources = get_visible_resources()
67 85ae5a4c Giorgos Korfiatis
    resource_names = [r.name for r in visible_resources]
68 85ae5a4c Giorgos Korfiatis
    result = get_user_quotas(request.user, resources=resource_names)
69 18f21257 Giorgos Korfiatis
    return json_response(result)
70 18f21257 Giorgos Korfiatis
71 18f21257 Giorgos Korfiatis
72 bb005bc2 Giorgos Korfiatis
@api.api_method(http_method='GET', token_required=True, user_required=False)
73 bea584e1 Giorgos Korfiatis
@component_from_token
74 bb005bc2 Giorgos Korfiatis
def service_quotas(request):
75 5afce44d Giorgos Korfiatis
    user = request.GET.get('user')
76 5afce44d Giorgos Korfiatis
    users = [user] if user is not None else None
77 bea584e1 Giorgos Korfiatis
    result = service_get_quotas(request.component_instance, users=users)
78 ad730cc5 Giorgos Korfiatis
79 ad730cc5 Giorgos Korfiatis
    if user is not None and result == {}:
80 ad730cc5 Giorgos Korfiatis
        raise ItemNotFound("No such user '%s'" % user)
81 ad730cc5 Giorgos Korfiatis
82 bb005bc2 Giorgos Korfiatis
    return json_response(result)
83 bb005bc2 Giorgos Korfiatis
84 bb005bc2 Giorgos Korfiatis
85 befa5997 Giorgos Korfiatis
@api.api_method(http_method='GET', token_required=False, user_required=False)
86 1028e568 Giorgos Korfiatis
def resources(request):
87 56bbece7 Giorgos Korfiatis
    resources = get_visible_resources()
88 85ae5a4c Giorgos Korfiatis
    result = register.resources_to_dict(resources)
89 1028e568 Giorgos Korfiatis
    return json_response(result)
90 1028e568 Giorgos Korfiatis
91 1028e568 Giorgos Korfiatis
92 18f21257 Giorgos Korfiatis
@csrf_exempt
93 18f21257 Giorgos Korfiatis
def commissions(request):
94 18f21257 Giorgos Korfiatis
    method = request.method
95 18f21257 Giorgos Korfiatis
    if method == 'GET':
96 18f21257 Giorgos Korfiatis
        return get_pending_commissions(request)
97 18f21257 Giorgos Korfiatis
    elif method == 'POST':
98 18f21257 Giorgos Korfiatis
        return issue_commission(request)
99 2aba7764 Sofia Papagiannaki
    return api.api_method_not_allowed(request, allowed_methods=['GET', 'POST'])
100 18f21257 Giorgos Korfiatis
101 18f21257 Giorgos Korfiatis
102 befa5997 Giorgos Korfiatis
@api.api_method(http_method='GET', token_required=True, user_required=False)
103 bea584e1 Giorgos Korfiatis
@component_from_token
104 18f21257 Giorgos Korfiatis
def get_pending_commissions(request):
105 bea584e1 Giorgos Korfiatis
    client_key = str(request.component_instance)
106 18f21257 Giorgos Korfiatis
107 18f21257 Giorgos Korfiatis
    result = qh.get_pending_commissions(clientkey=client_key)
108 18f21257 Giorgos Korfiatis
    return json_response(result)
109 18f21257 Giorgos Korfiatis
110 18f21257 Giorgos Korfiatis
111 bbf79074 Giorgos Korfiatis
def _provisions_to_list(provisions):
112 bbf79074 Giorgos Korfiatis
    lst = []
113 bbf79074 Giorgos Korfiatis
    for provision in provisions:
114 bbf79074 Giorgos Korfiatis
        try:
115 bbf79074 Giorgos Korfiatis
            holder = provision['holder']
116 bbf79074 Giorgos Korfiatis
            source = provision['source']
117 bbf79074 Giorgos Korfiatis
            resource = provision['resource']
118 bbf79074 Giorgos Korfiatis
            quantity = provision['quantity']
119 bbf79074 Giorgos Korfiatis
            key = (holder, source, resource)
120 bbf79074 Giorgos Korfiatis
            lst.append((key, quantity))
121 ad730cc5 Giorgos Korfiatis
            if not is_integer(quantity):
122 ad730cc5 Giorgos Korfiatis
                raise ValueError()
123 4df49ee7 Giorgos Korfiatis
        except (TypeError, KeyError, ValueError):
124 ad730cc5 Giorgos Korfiatis
            raise BadRequest("Malformed provision %s" % str(provision))
125 bbf79074 Giorgos Korfiatis
    return lst
126 bbf79074 Giorgos Korfiatis
127 bbf79074 Giorgos Korfiatis
128 18f21257 Giorgos Korfiatis
@csrf_exempt
129 befa5997 Giorgos Korfiatis
@api.api_method(http_method='POST', token_required=True, user_required=False)
130 bea584e1 Giorgos Korfiatis
@component_from_token
131 18f21257 Giorgos Korfiatis
def issue_commission(request):
132 b694875c Christos Stavrakakis
    data = request.body
133 4df49ee7 Giorgos Korfiatis
    try:
134 4df49ee7 Giorgos Korfiatis
        input_data = json.loads(data)
135 4df49ee7 Giorgos Korfiatis
    except json.JSONDecodeError:
136 4df49ee7 Giorgos Korfiatis
        raise BadRequest("POST data should be in json format.")
137 18f21257 Giorgos Korfiatis
138 bea584e1 Giorgos Korfiatis
    client_key = str(request.component_instance)
139 ad730cc5 Giorgos Korfiatis
    provisions = input_data.get('provisions')
140 ad730cc5 Giorgos Korfiatis
    if provisions is None:
141 ad730cc5 Giorgos Korfiatis
        raise BadRequest("Provisions are missing.")
142 3a1bed03 Giorgos Korfiatis
    if not isinstance(provisions, list):
143 4df49ee7 Giorgos Korfiatis
        raise BadRequest("Provisions should be a list.")
144 4df49ee7 Giorgos Korfiatis
145 bbf79074 Giorgos Korfiatis
    provisions = _provisions_to_list(provisions)
146 18f21257 Giorgos Korfiatis
    force = input_data.get('force', False)
147 3a1bed03 Giorgos Korfiatis
    if not isinstance(force, bool):
148 3a1bed03 Giorgos Korfiatis
        raise BadRequest('"force" option should be a boolean.')
149 3a1bed03 Giorgos Korfiatis
150 18f21257 Giorgos Korfiatis
    auto_accept = input_data.get('auto_accept', False)
151 3a1bed03 Giorgos Korfiatis
    if not isinstance(auto_accept, bool):
152 3a1bed03 Giorgos Korfiatis
        raise BadRequest('"auto_accept" option should be a boolean.')
153 3a1bed03 Giorgos Korfiatis
154 3a1bed03 Giorgos Korfiatis
    name = input_data.get('name', "")
155 2931c601 Kostas Papadimitriou
    if not isinstance(name, basestring):
156 3a1bed03 Giorgos Korfiatis
        raise BadRequest("Commission name should be a string.")
157 18f21257 Giorgos Korfiatis
158 18f21257 Giorgos Korfiatis
    try:
159 18f21257 Giorgos Korfiatis
        result = _issue_commission(clientkey=client_key,
160 18f21257 Giorgos Korfiatis
                                   provisions=provisions,
161 3a1bed03 Giorgos Korfiatis
                                   name=name,
162 18f21257 Giorgos Korfiatis
                                   force=force,
163 18f21257 Giorgos Korfiatis
                                   accept=auto_accept)
164 18f21257 Giorgos Korfiatis
        data = {"serial": result}
165 18f21257 Giorgos Korfiatis
        status_code = 201
166 18f21257 Giorgos Korfiatis
    except (qh_exception.NoCapacityError,
167 18f21257 Giorgos Korfiatis
            qh_exception.NoQuantityError) as e:
168 18f21257 Giorgos Korfiatis
        status_code = 413
169 18f21257 Giorgos Korfiatis
        body = {"message": e.message,
170 18f21257 Giorgos Korfiatis
                "code": status_code,
171 18f21257 Giorgos Korfiatis
                "data": e.data,
172 18f21257 Giorgos Korfiatis
                }
173 18f21257 Giorgos Korfiatis
        data = {"overLimit": body}
174 18f21257 Giorgos Korfiatis
    except qh_exception.NoHoldingError as e:
175 18f21257 Giorgos Korfiatis
        status_code = 404
176 18f21257 Giorgos Korfiatis
        body = {"message": e.message,
177 18f21257 Giorgos Korfiatis
                "code": status_code,
178 18f21257 Giorgos Korfiatis
                "data": e.data,
179 18f21257 Giorgos Korfiatis
                }
180 18f21257 Giorgos Korfiatis
        data = {"itemNotFound": body}
181 18f21257 Giorgos Korfiatis
    except qh_exception.InvalidDataError as e:
182 18f21257 Giorgos Korfiatis
        status_code = 400
183 18f21257 Giorgos Korfiatis
        body = {"message": e.message,
184 18f21257 Giorgos Korfiatis
                "code": status_code,
185 18f21257 Giorgos Korfiatis
                }
186 18f21257 Giorgos Korfiatis
        data = {"badRequest": body}
187 18f21257 Giorgos Korfiatis
188 18f21257 Giorgos Korfiatis
    return json_response(data, status_code=status_code)
189 18f21257 Giorgos Korfiatis
190 18f21257 Giorgos Korfiatis
191 a3e3917f Giorgos Korfiatis
@transaction.commit_on_success
192 3a1bed03 Giorgos Korfiatis
def _issue_commission(clientkey, provisions, name, force, accept):
193 18f21257 Giorgos Korfiatis
    serial = qh.issue_commission(clientkey=clientkey,
194 18f21257 Giorgos Korfiatis
                                 provisions=provisions,
195 3a1bed03 Giorgos Korfiatis
                                 name=name,
196 18f21257 Giorgos Korfiatis
                                 force=force)
197 18f21257 Giorgos Korfiatis
    if accept:
198 51db2da2 Giorgos Korfiatis
        qh.resolve_pending_commission(clientkey=clientkey, serial=serial)
199 18f21257 Giorgos Korfiatis
200 18f21257 Giorgos Korfiatis
    return serial
201 18f21257 Giorgos Korfiatis
202 18f21257 Giorgos Korfiatis
203 6c0f4562 Giorgos Korfiatis
def notFoundCF(serial):
204 6c0f4562 Giorgos Korfiatis
    body = {"code": 404,
205 6c0f4562 Giorgos Korfiatis
            "message": "serial %s does not exist" % serial,
206 6c0f4562 Giorgos Korfiatis
            }
207 6c0f4562 Giorgos Korfiatis
    return {"itemNotFound": body}
208 6c0f4562 Giorgos Korfiatis
209 6c0f4562 Giorgos Korfiatis
210 6c0f4562 Giorgos Korfiatis
def conflictingCF(serial):
211 6c0f4562 Giorgos Korfiatis
    body = {"code": 400,
212 6c0f4562 Giorgos Korfiatis
            "message": "cannot both accept and reject serial %s" % serial,
213 6c0f4562 Giorgos Korfiatis
            }
214 6c0f4562 Giorgos Korfiatis
    return {"badRequest": body}
215 18f21257 Giorgos Korfiatis
216 18f21257 Giorgos Korfiatis
217 18f21257 Giorgos Korfiatis
@csrf_exempt
218 befa5997 Giorgos Korfiatis
@api.api_method(http_method='POST', token_required=True, user_required=False)
219 bea584e1 Giorgos Korfiatis
@component_from_token
220 a3e3917f Giorgos Korfiatis
@transaction.commit_on_success
221 18f21257 Giorgos Korfiatis
def resolve_pending_commissions(request):
222 b694875c Christos Stavrakakis
    data = request.body
223 4df49ee7 Giorgos Korfiatis
    try:
224 4df49ee7 Giorgos Korfiatis
        input_data = json.loads(data)
225 4df49ee7 Giorgos Korfiatis
    except json.JSONDecodeError:
226 4df49ee7 Giorgos Korfiatis
        raise BadRequest("POST data should be in json format.")
227 18f21257 Giorgos Korfiatis
228 bea584e1 Giorgos Korfiatis
    client_key = str(request.component_instance)
229 18f21257 Giorgos Korfiatis
    accept = input_data.get('accept', [])
230 18f21257 Giorgos Korfiatis
    reject = input_data.get('reject', [])
231 18f21257 Giorgos Korfiatis
232 4df49ee7 Giorgos Korfiatis
    if not isinstance(accept, list) or not isinstance(reject, list):
233 4df49ee7 Giorgos Korfiatis
        m = '"accept" and "reject" should reference lists of serials.'
234 4df49ee7 Giorgos Korfiatis
        raise BadRequest(m)
235 4df49ee7 Giorgos Korfiatis
236 ad730cc5 Giorgos Korfiatis
    if not are_integer(accept) or not are_integer(reject):
237 ad730cc5 Giorgos Korfiatis
        raise BadRequest("Serials should be integer.")
238 ad730cc5 Giorgos Korfiatis
239 18f21257 Giorgos Korfiatis
    result = qh.resolve_pending_commissions(clientkey=client_key,
240 18f21257 Giorgos Korfiatis
                                            accept_set=accept,
241 18f21257 Giorgos Korfiatis
                                            reject_set=reject)
242 6c0f4562 Giorgos Korfiatis
    accepted, rejected, notFound, conflicting = result
243 6c0f4562 Giorgos Korfiatis
    notFound = [(serial, notFoundCF(serial)) for serial in notFound]
244 6c0f4562 Giorgos Korfiatis
    conflicting = [(serial, conflictingCF(serial)) for serial in conflicting]
245 6c0f4562 Giorgos Korfiatis
    cloudfaults = notFound + conflicting
246 18f21257 Giorgos Korfiatis
    data = {'accepted': accepted,
247 18f21257 Giorgos Korfiatis
            'rejected': rejected,
248 18f21257 Giorgos Korfiatis
            'failed': cloudfaults
249 18f21257 Giorgos Korfiatis
            }
250 18f21257 Giorgos Korfiatis
251 18f21257 Giorgos Korfiatis
    return json_response(data)
252 18f21257 Giorgos Korfiatis
253 18f21257 Giorgos Korfiatis
254 befa5997 Giorgos Korfiatis
@api.api_method(http_method='GET', token_required=True, user_required=False)
255 bea584e1 Giorgos Korfiatis
@component_from_token
256 18f21257 Giorgos Korfiatis
def get_commission(request, serial):
257 18f21257 Giorgos Korfiatis
    data = request.GET
258 bea584e1 Giorgos Korfiatis
    client_key = str(request.component_instance)
259 ad730cc5 Giorgos Korfiatis
    try:
260 ad730cc5 Giorgos Korfiatis
        serial = int(serial)
261 ad730cc5 Giorgos Korfiatis
    except ValueError:
262 ad730cc5 Giorgos Korfiatis
        raise BadRequest("Serial should be an integer.")
263 18f21257 Giorgos Korfiatis
264 18f21257 Giorgos Korfiatis
    try:
265 18f21257 Giorgos Korfiatis
        data = qh.get_commission(clientkey=client_key,
266 18f21257 Giorgos Korfiatis
                                 serial=serial)
267 18f21257 Giorgos Korfiatis
        status_code = 200
268 18f21257 Giorgos Korfiatis
        return json_response(data, status_code)
269 51db2da2 Giorgos Korfiatis
    except qh_exception.NoCommissionError:
270 18f21257 Giorgos Korfiatis
        return HttpResponse(status=404)
271 18f21257 Giorgos Korfiatis
272 18f21257 Giorgos Korfiatis
273 18f21257 Giorgos Korfiatis
@csrf_exempt
274 befa5997 Giorgos Korfiatis
@api.api_method(http_method='POST', token_required=True, user_required=False)
275 bea584e1 Giorgos Korfiatis
@component_from_token
276 a3e3917f Giorgos Korfiatis
@transaction.commit_on_success
277 18f21257 Giorgos Korfiatis
def serial_action(request, serial):
278 b694875c Christos Stavrakakis
    data = request.body
279 4df49ee7 Giorgos Korfiatis
    try:
280 4df49ee7 Giorgos Korfiatis
        input_data = json.loads(data)
281 4df49ee7 Giorgos Korfiatis
    except json.JSONDecodeError:
282 4df49ee7 Giorgos Korfiatis
        raise BadRequest("POST data should be in json format.")
283 4df49ee7 Giorgos Korfiatis
284 ad730cc5 Giorgos Korfiatis
    try:
285 ad730cc5 Giorgos Korfiatis
        serial = int(serial)
286 ad730cc5 Giorgos Korfiatis
    except ValueError:
287 ad730cc5 Giorgos Korfiatis
        raise BadRequest("Serial should be an integer.")
288 18f21257 Giorgos Korfiatis
289 bea584e1 Giorgos Korfiatis
    client_key = str(request.component_instance)
290 18f21257 Giorgos Korfiatis
291 18f21257 Giorgos Korfiatis
    accept = 'accept' in input_data
292 18f21257 Giorgos Korfiatis
    reject = 'reject' in input_data
293 18f21257 Giorgos Korfiatis
294 18f21257 Giorgos Korfiatis
    if accept == reject:
295 18f21257 Giorgos Korfiatis
        raise BadRequest('Specify either accept or reject action.')
296 18f21257 Giorgos Korfiatis
297 6c0f4562 Giorgos Korfiatis
    result = qh.resolve_pending_commission(clientkey=client_key,
298 6c0f4562 Giorgos Korfiatis
                                           serial=serial,
299 6c0f4562 Giorgos Korfiatis
                                           accept=accept)
300 18f21257 Giorgos Korfiatis
    response = HttpResponse()
301 18f21257 Giorgos Korfiatis
    if not result:
302 18f21257 Giorgos Korfiatis
        response.status_code = 404
303 18f21257 Giorgos Korfiatis
304 18f21257 Giorgos Korfiatis
    return response