blob: fa4a21e573755beb6574c8ad25cd384803a1fd88 [file] [log] [blame]
# Copyright 2012 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import httplib
import json
import urlparse
from google.appengine.ext import webapp
from model import client as client_db
from model import metric as metric_db
from model import product as product_db
class MetricHandler(webapp.RequestHandler):
"""A class to handle creating, reading, updating and deleting metrics.
Handles GET, POST, PUT and DELETE requests for /metrics/<product>/<client>/
and /metrics/<product>/<client>/<metric>. All functions have the same
signature, even though they may not use all parameters, so that a single route
can be used for the handler.
"""
def get(self, product_id, client_id, metric_id):
"""Responds with information about all metrics or a specific metric.
/metrics/<product>/<client>
Responds with a JSON encoded object that contains a list of metric IDs for
the given product and client
/metrics/<product>/<client>/<metric>
Responds with a JSON encoded object of the product ID, client ID, metric
ID, description and units for the given product, client and metric.
Args:
product_id: The product ID.
client_id: The client ID.
metric_id: The metric ID. May be empty.
"""
product = product_db.Product.get_by_key_name(product_id)
if not product:
self.error(httplib.NOT_FOUND)
return
client = client_db.Client.get_by_key_name(client_id, product)
if not client:
self.error(httplib.NOT_FOUND)
return
if not metric_id:
metrics = metric_db.Metric.all()
metrics.ancestor(client)
metrics_result = []
for metric in metrics:
metrics_result.append({'metric_id': metric.key().name(),
'description': metric.description,
'units': metric.units})
result = {'product_id': product.key().name(),
'client_id': client.key().name(),
'metrics': metrics_result}
else:
metric = metric_db.Metric.get_by_key_name(metric_id, client)
if not metric:
self.error(httplib.NOT_FOUND)
return
result = {'product_id': product.key().name(),
'client_id': client.key().name(),
'metric_id': metric.key().name(),
'description': metric.description,
'units': metric.units}
self.response.headers['Content-Type'] = 'application/json'
json.dump(result, self.response.out)
def post(self, product_id, client_id, metric_id):
"""Creates a new metric.
/metrics/<product>/<client>
Creates a new metric. The metric ID, description and units should be
specified in the body of the request.
/metrics/<product>/<client>/<metric>
Unused.
Args:
product_id: The product ID.
client_id: The client ID.
metric_id: The metric ID. Must be empty.
"""
# Validate input.
if metric_id:
self.error(httplib.BAD_REQUEST)
return
metric_id = self.request.get('metric_id', None)
description = self.request.get('description', None)
units = self.request.get('units', None)
if not metric_id or not description or not units:
self.error(httplib.BAD_REQUEST)
return
# Perform DB lookups.
product = product_db.Product.get_by_key_name(product_id)
if not product:
self.error(httplib.NOT_FOUND)
return
client = client_db.Client.get_by_key_name(client_id, product)
if not client:
self.error(httplib.NOT_FOUND)
return
# Make sure that this metric ID doesn't already exist.
metric = metric_db.Metric.get_by_key_name(metric_id, client)
if metric:
self.error(httplib.BAD_REQUEST)
return
# Creates a new metric.
metric = metric_db.Metric(key_name=metric_id, parent=client,
description=description, units=units)
metric.put()
self.response.set_status(httplib.CREATED, message='MetricCreated')
def put(self, product_id, client_id, metric_id):
"""Updates a metric.
/metrics/<product>/<client>
Unused.
/metrics/<product>/<client>/<metric>
Updates a metric. The description and units should be specified in the
body of the request.
Args:
product_id: The product ID.
client_id: The client ID.
metric_id: The metric ID. Must not be empty.
"""
# Validate input.
if not metric_id:
self.error(httplib.BAD_REQUEST)
return
# Appengine bug: parameters in body aren't parsed for PUT requests.
# http://code.google.com/p/googleappengine/issues/detail?id=170
params = urlparse.parse_qs(self.request.body)
description = params.get('description', [None])[0]
units = params.get('units', [None])[0]
if not description or not units:
self.error(httplib.BAD_REQUEST)
return
# Perform DB lookups.
product = product_db.Product.get_by_key_name(product_id)
if not product:
self.error(httplib.NOT_FOUND)
return
client = client_db.Client.get_by_key_name(client_id, product)
if not client:
self.error(httplib.NOT_FOUND)
return
metric = metric_db.Metric.get_by_key_name(metric_id, client)
if not metric:
self.error(httplib.NOT_FOUND)
return
# Update the metric.
metric.description = description
metric.units = units
metric.put()
def delete(self, product_id, client_id, metric_id):
"""Deletes a metric.
/metrics/<product>/<client>
Unused.
/metrics/<product>/<client>/<metric>
Deletes the specified metric.
Args:
product_id: The product ID.
client_id: The client ID.
metric_id: The metric ID. Must not be empty.
"""
# Validate input.
if not metric_id:
self.error(httplib.BAD_REQUEST)
return
# Perform DB lookups.
product = product_db.Product.get_by_key_name(product_id)
if not product:
self.error(httplib.NOT_FOUND)
return
client = client_db.Client.get_by_key_name(client_id, product)
if not client:
self.error(httplib.NOT_FOUND)
return
metric = metric_db.Metric.get_by_key_name(metric_id, client)
if not metric:
self.error(httplib.NOT_FOUND)
return
# Delete the metric.
metric.delete()