get_gages()   B
last analyzed

Complexity

Conditions 4

Size

Total Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 40
rs 8.5806
cc 4
1
"""
2
gages api imports api, app, db, auth, and models
3
4
Endpoints:
5
----------
6
7
- **/api/1.0/gages/** - **GET** List all gages
8
- **/api/1.0/gages/<id>** - **GET** Detailed information about gage number *id*
9
- **/api/1.0/gages/<id>/sample** - **POST** new sample data for gage *id*
10
11
"""
12
13
from flask import jsonify, request, url_for, current_app
14
from itsdangerous import JSONWebSignatureSerializer, BadSignature
15
16
from ..models import Gage
17
from .blueprint import api
18
from .errors import unauthorized
19
20
21
@api.route('/gages/')
22
def get_gages():
23
    """
24
    List all gages
25
26
    Example response: ::
27
28
        { "count": 5,
29
          "gages": [
30
            { "id": 2,
31
              "location": "Wild River near RT 2 in Gilead Maine",
32
              "name": "Wild River at Gilead",
33
              "url": "http://riverflo.ws/api/1.0/gages/2"
34
            },
35
            { "id": 3,
36
              "location": "Bear River near RT 2 in Newry Maine",
37
              "name": "Bear River at Newry",
38
              "url": "http://riverflo.ws/api/1.0/gages/3"
39
            }
40
          ],
41
          "next": "http://riverflo.ws/api/1.0/gages/?page=2",
42
          "prev": null
43
        }
44
    """
45
    page = request.args.get('page', 1, type=int)
46
    pagination = Gage.query.paginate(page,
47
                                     per_page=current_app.config['API_GAGES_PER_PAGE'],  # noqa
48
                                     error_out=False)
49
    gages = pagination.items
50
    prev = None
51
    if pagination.has_prev:
52
        prev = url_for('.get_gages', page=page-1, _external=True)
53
    next_p = None
54
    if pagination.has_next:
55
        next_p = url_for('.get_gages', page=page+1, _external=True)
56
    return jsonify({
57
        'gages': [gage.to_json() for gage in gages],
58
        'prev': prev,
59
        'next': next_p,
60
        'count': pagination.total
61
    })
62
63
64
@api.route('/gages/map/')
65
def get_gage_geojson():
66
    gages = Gage.query.all()
67
    geojson = {
68
        'type': 'FeatureCollection',
69
        'features': [gage.geojson() for gage in gages]
70
    }
71
    return jsonify(geojson)
72
73
74
@api.route('/gages/<int:gid>')
75
def get_gage(gid):
76
    """
77
    Detailed information about gage *id*
78
79
    Parameters:
80
        id (int): Primary id key of a gage
81
82
    Example response: ::
83
84
        { "html": "http://riverflo.ws/gage/androscoggin-rumford/",
85
          "id": 4,
86
          "location": null,
87
          "name": "Androscoggin River at Rumford",
88
          "regions": [
89
            { "html": "http://riverflo.ws/region/maine/",
90
              "id": 4,
91
              "name": "Maine",
92
              "url": "http://riverflo.ws/api/1.0/regions/4"
93
            }
94
          ],
95
          "sensors": [
96
            { "id": 10,
97
              "recent_sample": {
98
                "datetime": "Mon, 03 Nov 2014 18:15:00 GMT",
99
                "id": 5801,
100
                "url": "http://riverflo.ws/api/1.0/samples/5801",
101
                "value": 4.32
102
              },
103
              "type": "usgs-height",
104
              "url": "http://riverflo.ws/api/1.0/sensors/10"
105
            },
106
            { "id": 11,
107
              "recent_sample": {
108
                "datetime": "Mon, 03 Nov 2014 18:15:00 GMT",
109
                "id": 5866,
110
                "url": "http://riverflo.ws/api/1.0/samples/5866",
111
                "value": 3230.0
112
              },
113
              "type": "usgs-discharge",
114
              "url": "http://riverflo.ws/api/1.0/sensors/11"
115
            }
116
          ],
117
          "url": "http://riverflo.ws/api/1.0/gages/4"
118
        }
119
    """
120
    gage = Gage.query.get_or_404(gid)
121
    return jsonify(gage.to_long_json())
122
123
124
@api.route('/gages/<int:gid>/sample', methods=['POST'])
125
def gage_new_samples(gid):
126
    """
127
    Submit new samples to gage *id*
128
129
    Parameters:
130
        id (int): Primary id key number of a gage
131
132
    Samples are formatted in body of request as a JSON Web Signature using the
133
    ``Gage.key``
134
135
    Example sample submitter: ::
136
137
        from itsdangerous import JSONWebSignatureSerializer
138
        import requests
139
140
        payload = {'samples':[
141
            {'type':'level',
142
             'value':16.7,
143
             'datetime': str(datetime.datetime.now())
144
             },
145
            {'type':'amps',
146
             'value':367.3,
147
             'datetime': str(datetime.datetime.now())
148
             },
149
            {'type':'voltage',
150
             'value':14.3,
151
             'datetime': str(datetime.datetime.now())
152
             },
153
            {'type':'discharge',
154
             'value':480,
155
             'datetime': str(datetime.datetime.now())
156
            }
157
            ],
158
            'gage':{
159
            'id':5
160
            }}
161
162
        s = JSONWebSignatureSerializer('<gage.key>')
163
164
        def submit(payload):
165
            data = s.dumps(payload)
166
            url = "http://riverflo.ws/api/1.0/gages/<gage.id>/sample"
167
            r = requests.post(url, data=data)
168
            if r.status_code is 200:
169
                return True
170
            else:
171
                return False
172
173
    If the key matches the stored key for the gage id in the url, \
174
    the server will iterate over the samples and add them to the database \
175
    creating new sensors for the gage if a new sample type is found. \
176
    Then the server will return JSON with a status code of 200.
177
178
    Example response: ::
179
180
        { 'gage': {u'id': 5,
181
            'location': 'Androscoggin River downstream of I-95 in Auburn ME',
182
            'name': 'Androscoggin River at Auburn',
183
            'url': 'http://riverflo.ws/api/1.0/gages/5'},
184
         'result': 'created',
185
         'samples': [{'datetime': 'Tue, 04 Nov 2014 20:43:39 GMT',
186
           'id': 10781,
187
           'url': 'http://riverflo.ws/api/1.0/samples/10781',
188
           'value': 16.7},
189
          {'datetime': 'Tue, 04 Nov 2014 20:43:39 GMT',
190
           'id': 10782,
191
           'url': 'http://riverflo.ws/api/1.0/samples/10782',
192
           'value': 367.3},
193
          {'datetime': 'Tue, 04 Nov 2014 20:43:39 GMT',
194
           'id': 10783,
195
           'url': 'http://riverflo.ws/api/1.0/samples/10783',
196
           'value': 14.3},
197
          {'datetime': 'Tue, 04 Nov 2014 20:43:39 GMT',
198
           'id': 10784,
199
           'url': 'http://riverflo.ws/api/1.0/samples/10784',
200
           'value': 480.0}]}
201
202
    If the signature does not match, the server will return JSON \
203
    with a status code of 401 - Unauthorized: ::
204
205
        {'error': 'unauthorized', 'message': 'bad signature'}
206
207
    """
208
    gage = Gage.query.get_or_404(gid)
209
    s = JSONWebSignatureSerializer(gage.key)
210
    try:
211
        req_json = s.loads(request.data)
212
    except BadSignature:  # If the signature doesn't match
213
        return unauthorized('bad signature')
214
    except TypeError:  # Return unauthorized if no key defined for gage
215
        return unauthorized('bad signature')
216
    else:
217
        samples = req_json['samples']
218
        output = []
219
        print(samples)
220
        for sample in samples:
221
            result = gage.new_sample(stype=sample['type'].lower(),
222
                                     value=sample['value'],
223
                                     sdatetime=sample['datetime'])
224
            result_json = result.to_sensor_json()
225
            print(result_json)
226
            result_json['sender_id'] = sample['sender_id']
227
            print(result_json)
228
            output.append(result_json)
229
        return jsonify({
230
            'gage': gage.to_json(),
231
            'samples': output,
232
            'result': 'created'
233
        })
234