2
# Copyright 2014 Canonical Ltd.
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License version 3, as
6
# published by the Free Software Foundation.
8
# This program is distributed in the hope that it will be useful, but
9
# WITHOUT ANY WARRANTY; without even the implied warranties of
10
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11
# PURPOSE. See the GNU Affero General Public License for more details.
13
# You should have received a copy of the GNU Affero General Public License
14
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
"""V1 of the REST API.
18
This file contains the views for the v1 API, as well as the URL routing table
22
from datetime import (
28
from pyramid.view import view_config
29
from pyramid.httpexceptions import HTTPBadRequest
31
from nfss import database
32
from nfss.auth import oauth_protected
35
UTC = timezone(timedelta(0))
38
def configure_routes(config):
39
"""Add url routes to 'config' object."""
40
config.add_route('v1.root', '/')
41
config.add_route('v1.project', '/{project}')
42
config.add_route('v1.test', '/{project}/{test}')
45
@view_config(route_name='v1.root', renderer='json', request_method='GET')
47
"""Return summary data about the projects and tests."""
48
data = database.get_details_for_all_projects(request.database())
52
'tests': json.loads(r[1]),
53
'last_updated': r[2].isoformat(),
54
'path': request.route_path('v1.project', project=r[0])
59
@view_config(route_name='v1.project', renderer='json', request_method='GET')
61
"""Return detailed information about this project's tests."""
62
project_name = request.matchdict['project']
63
project_data = database.get_details_for_project(
68
for test in project_data:
69
project_data[test]['path'] = request.route_path(
74
return dict(project_name=project_name, tests=project_data)
77
@view_config(route_name='v1.test', renderer='json', request_method='GET')
79
"""Return data points for this particular test.
81
Check the Range HTTP header, or return the last 30 days worth of data if
85
# import pudb; pudb.set_trace()
86
project_name = request.matchdict['project']
87
test_name = request.matchdict['test']
88
start = try_parse_date(request.params.get('start_date', None))
89
end = try_parse_date(request.params.get('end_date', None))
90
data, f, l, df, dl = database.get_details_for_test(
98
project_name=project_name,
100
first_data=f.isoformat(),
101
last_data=l.isoformat(),
102
data_range_first=df.isoformat(),
103
data_range_last=dl.isoformat(),
104
data=json.loads(data) if data else [],
108
def try_parse_date(date_param):
109
if date_param is not None:
111
return datetime.fromtimestamp(float(date_param), UTC)
117
@view_config(route_name='v1.test', renderer='json', request_method='POST')
119
def test_add(request, oauth_request):
120
"""Add data points to this test.
122
Return the created id of the data point added to the DB if it was
123
successful, or an error if it wasn't.
125
TODO: Secure this method somehow. Oauth2 token?
128
project_name = request.matchdict['project']
129
test_name = request.matchdict['test']
130
data = request.params['data']
131
except KeyError as e:
132
raise HTTPBadRequest("Missing data in POST request: %s" % e)
134
created_id = database.insert_test_data(
139
oauth_request.client_key
141
return dict(created_id=created_id)