Statistics
| Branch: | Tag: | Revision:

root / snf-django-lib / snf_django / lib / api / utils.py @ a96e84cf

History | View | Annotate | Download (4.5 kB)

1 72bf812d Christos Stavrakakis
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2 72bf812d Christos Stavrakakis
#
3 72bf812d Christos Stavrakakis
# Redistribution and use in source and binary forms, with or
4 72bf812d Christos Stavrakakis
# without modification, are permitted provided that the following
5 72bf812d Christos Stavrakakis
# conditions are met:
6 72bf812d Christos Stavrakakis
#
7 72bf812d Christos Stavrakakis
#   1. Redistributions of source code must retain the above
8 72bf812d Christos Stavrakakis
#      copyright notice, this list of conditions and the following
9 72bf812d Christos Stavrakakis
#      disclaimer.
10 72bf812d Christos Stavrakakis
#
11 72bf812d Christos Stavrakakis
#   2. Redistributions in binary form must reproduce the above
12 72bf812d Christos Stavrakakis
#      copyright notice, this list of conditions and the following
13 72bf812d Christos Stavrakakis
#      disclaimer in the documentation and/or other materials
14 72bf812d Christos Stavrakakis
#      provided with the distribution.
15 72bf812d Christos Stavrakakis
#
16 72bf812d Christos Stavrakakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 72bf812d Christos Stavrakakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 72bf812d Christos Stavrakakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 72bf812d Christos Stavrakakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 72bf812d Christos Stavrakakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 72bf812d Christos Stavrakakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 72bf812d Christos Stavrakakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 72bf812d Christos Stavrakakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 72bf812d Christos Stavrakakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 72bf812d Christos Stavrakakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 72bf812d Christos Stavrakakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 72bf812d Christos Stavrakakis
# POSSIBILITY OF SUCH DAMAGE.
28 72bf812d Christos Stavrakakis
#
29 72bf812d Christos Stavrakakis
# The views and conclusions contained in the software and
30 72bf812d Christos Stavrakakis
# documentation are those of the authors and should not be
31 72bf812d Christos Stavrakakis
# interpreted as representing official policies, either expressed
32 72bf812d Christos Stavrakakis
# or implied, of GRNET S.A.
33 72bf812d Christos Stavrakakis
34 72bf812d Christos Stavrakakis
import datetime
35 72bf812d Christos Stavrakakis
from dateutil.parser import parse as date_parse
36 72bf812d Christos Stavrakakis
from django.utils import simplejson as json
37 72bf812d Christos Stavrakakis
38 72bf812d Christos Stavrakakis
from django.conf import settings
39 72bf812d Christos Stavrakakis
from snf_django.lib.api import faults
40 72bf812d Christos Stavrakakis
41 72bf812d Christos Stavrakakis
42 72bf812d Christos Stavrakakis
class UTC(datetime.tzinfo):
43 72bf812d Christos Stavrakakis
    """
44 72bf812d Christos Stavrakakis
    Helper UTC time information object.
45 72bf812d Christos Stavrakakis
    """
46 72bf812d Christos Stavrakakis
47 72bf812d Christos Stavrakakis
    def utcoffset(self, dt):
48 72bf812d Christos Stavrakakis
        return datetime.timedelta(0)
49 72bf812d Christos Stavrakakis
50 72bf812d Christos Stavrakakis
    def tzname(self, dt):
51 72bf812d Christos Stavrakakis
        return 'UTC'
52 72bf812d Christos Stavrakakis
53 72bf812d Christos Stavrakakis
    def dst(self, dt):
54 72bf812d Christos Stavrakakis
        return datetime.timedelta(0)
55 72bf812d Christos Stavrakakis
56 72bf812d Christos Stavrakakis
57 72bf812d Christos Stavrakakis
def isoformat(d):
58 72bf812d Christos Stavrakakis
    """Return an ISO8601 date string that includes a timezone.
59 72bf812d Christos Stavrakakis

60 72bf812d Christos Stavrakakis
    >>> from datetime import datetime
61 72bf812d Christos Stavrakakis
    >>> d = datetime(2012, 8, 10, 00, 59, 59)
62 72bf812d Christos Stavrakakis
    >>> isoformat(d)
63 72bf812d Christos Stavrakakis
    '2012-08-10T00:59:59+00:00'
64 72bf812d Christos Stavrakakis
    """
65 72bf812d Christos Stavrakakis
66 72bf812d Christos Stavrakakis
    return d.replace(tzinfo=UTC()).isoformat()
67 72bf812d Christos Stavrakakis
68 72bf812d Christos Stavrakakis
69 72bf812d Christos Stavrakakis
def isoparse(s):
70 72bf812d Christos Stavrakakis
    """Parse an ISO8601 date string into a datetime object."""
71 72bf812d Christos Stavrakakis
72 72bf812d Christos Stavrakakis
    if not s:
73 72bf812d Christos Stavrakakis
        return None
74 72bf812d Christos Stavrakakis
75 72bf812d Christos Stavrakakis
    try:
76 72bf812d Christos Stavrakakis
        since = date_parse(s)
77 72bf812d Christos Stavrakakis
        utc_since = since.astimezone(UTC()).replace(tzinfo=None)
78 72bf812d Christos Stavrakakis
    except ValueError:
79 72bf812d Christos Stavrakakis
        raise faults.BadRequest('Invalid changes-since parameter.')
80 72bf812d Christos Stavrakakis
81 72bf812d Christos Stavrakakis
    now = datetime.datetime.now()
82 72bf812d Christos Stavrakakis
    if utc_since > now:
83 72bf812d Christos Stavrakakis
        raise faults.BadRequest('changes-since value set in the future.')
84 72bf812d Christos Stavrakakis
85 72bf812d Christos Stavrakakis
    if now - utc_since > datetime.timedelta(seconds=settings.POLL_LIMIT):
86 72bf812d Christos Stavrakakis
        raise faults.BadRequest('Too old changes-since value.')
87 72bf812d Christos Stavrakakis
88 72bf812d Christos Stavrakakis
    return utc_since
89 72bf812d Christos Stavrakakis
90 72bf812d Christos Stavrakakis
91 72bf812d Christos Stavrakakis
def get_request_dict(request):
92 72bf812d Christos Stavrakakis
    """Return data sent by the client as python dictionary.
93 72bf812d Christos Stavrakakis

94 72bf812d Christos Stavrakakis
    Only JSON format is supported
95 72bf812d Christos Stavrakakis

96 72bf812d Christos Stavrakakis
    """
97 b694875c Christos Stavrakakis
    data = request.body
98 72bf812d Christos Stavrakakis
    content_type = request.META.get("CONTENT_TYPE")
99 87dd67af Christos Stavrakakis
    if content_type is None:
100 12c730d9 Georgios D. Tsoukalas
        raise faults.BadRequest("Missing Content-Type header field")
101 72bf812d Christos Stavrakakis
    if content_type.startswith("application/json"):
102 72bf812d Christos Stavrakakis
        try:
103 72bf812d Christos Stavrakakis
            return json.loads(data)
104 72bf812d Christos Stavrakakis
        except ValueError:
105 72bf812d Christos Stavrakakis
            raise faults.BadRequest("Invalid JSON data")
106 72bf812d Christos Stavrakakis
    else:
107 32e4e343 Christos Stavrakakis
        raise faults.BadRequest("Unsupported Content-type: '%s'" %
108 32e4e343 Christos Stavrakakis
                                content_type)
109 e3ff6830 Georgios D. Tsoukalas
110 e3ff6830 Georgios D. Tsoukalas
111 347b2ba1 Giorgos Korfiatis
def prefix_pattern(prefix, append_slash=True):
112 e3ff6830 Georgios D. Tsoukalas
    """Return a reliable urls.py pattern from a prefix"""
113 e3ff6830 Georgios D. Tsoukalas
    prefix = prefix.strip('/')
114 347b2ba1 Giorgos Korfiatis
    if prefix and append_slash:
115 e3ff6830 Georgios D. Tsoukalas
        prefix += '/'
116 e3ff6830 Georgios D. Tsoukalas
    pattern = '^' + prefix
117 e3ff6830 Georgios D. Tsoukalas
    return pattern
118 b6bc4afa Christos Stavrakakis
119 b6bc4afa Christos Stavrakakis
120 b6bc4afa Christos Stavrakakis
def filter_modified_since(request, objects):
121 b6bc4afa Christos Stavrakakis
    """Filter DB objects based on 'changes-since' request parameter.
122 b6bc4afa Christos Stavrakakis

123 b6bc4afa Christos Stavrakakis
    Parse request for 'changes-since' parameter and get only the DB objects
124 b6bc4afa Christos Stavrakakis
    that have been updated after that time. Otherwise, return the non-deleted
125 b6bc4afa Christos Stavrakakis
    objects.
126 b6bc4afa Christos Stavrakakis

127 b6bc4afa Christos Stavrakakis
    """
128 b6bc4afa Christos Stavrakakis
    since = isoparse(request.GET.get("changes-since"))
129 b6bc4afa Christos Stavrakakis
    if since:
130 b6bc4afa Christos Stavrakakis
        modified_objs = objects.filter(updated__gte=since)
131 b6bc4afa Christos Stavrakakis
        if not modified_objs:
132 1a60832d Christos Stavrakakis
            raise faults.NotModified()
133 b6bc4afa Christos Stavrakakis
        return modified_objs
134 b6bc4afa Christos Stavrakakis
    else:
135 b6bc4afa Christos Stavrakakis
        return objects.filter(deleted=False)
136 a96e84cf Christos Stavrakakis
137 a96e84cf Christos Stavrakakis
138 a96e84cf Christos Stavrakakis
def get_attribute(request, attribute, required=True):
139 a96e84cf Christos Stavrakakis
    value = request.get(attribute, None)
140 a96e84cf Christos Stavrakakis
    if required and value is None:
141 a96e84cf Christos Stavrakakis
        raise faults.BadRequest("Malformed request. Missing attribute '%s'." %
142 a96e84cf Christos Stavrakakis
                                attribute)
143 a96e84cf Christos Stavrakakis
    return value