From a8998d36123d92f007aad8e216cddf73cef7e80d Mon Sep 17 00:00:00 2001
From: Qixiang Wan <qwan@redhat.com>
Date: Jul 10 2017 06:16:45 +0000
Subject: Add APIs for querying event types, build types and build states


---

diff --git a/freshmaker/api_utils.py b/freshmaker/api_utils.py
index 733c783..58278c0 100644
--- a/freshmaker/api_utils.py
+++ b/freshmaker/api_utils.py
@@ -19,7 +19,7 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # SOFTWARE.
 
-from flask import request, url_for
+from flask import request, url_for, jsonify
 
 from freshmaker import db
 from freshmaker.types import ArtifactType, ArtifactBuildState
@@ -131,3 +131,11 @@ def filter_events(flask_request):
     page = flask_request.args.get('page', 1, type=int)
     per_page = flask_request.args.get('per_page', 10, type=int)
     return query.paginate(page, per_page, False)
+
+
+def json_error(status, error, message):
+    response = jsonify({'status': status,
+                        'error': error,
+                        'message': message})
+    response.status_code = status
+    return response
diff --git a/freshmaker/views.py b/freshmaker/views.py
index bbb882d..17a5c24 100644
--- a/freshmaker/views.py
+++ b/freshmaker/views.py
@@ -21,14 +21,64 @@
 #
 # Written by Jan Kaluza <jkaluza@redhat.com>
 
+import six
 from flask import request, jsonify
 from flask.views import MethodView
 
 from freshmaker import app
+from freshmaker import types
 from freshmaker import models
-from freshmaker.api_utils import pagination_metadata, filter_artifact_builds, filter_events
+from freshmaker.api_utils import pagination_metadata
+from freshmaker.api_utils import filter_artifact_builds
+from freshmaker.api_utils import filter_events
+from freshmaker.api_utils import json_error
 
 api_v1 = {
+    'event_types': {
+        'event_types_list': {
+            'url': '/freshmaker/1/event-types/',
+            'options': {
+                'defaults': {'id': None},
+                'methods': ['GET'],
+            }
+        },
+        'event_type': {
+            'url': '/freshmaker/1/event-types/<int:id>',
+            'options': {
+                'methods': ['GET'],
+            }
+        },
+    },
+    'build_types': {
+        'build_types_list': {
+            'url': '/freshmaker/1/build-types/',
+            'options': {
+                'defaults': {'id': None},
+                'methods': ['GET'],
+            }
+        },
+        'build_type': {
+            'url': '/freshmaker/1/build-types/<int:id>',
+            'options': {
+                'methods': ['GET'],
+            }
+        },
+    },
+    'build_states': {
+        'build_states_list': {
+            'url': '/freshmaker/1/build-states/',
+            'options': {
+                'defaults': {'id': None},
+                'methods': ['GET'],
+            }
+        },
+        'build_state': {
+            'url': '/freshmaker/1/build-states/<int:id>',
+            'options': {
+                'methods': ['GET'],
+            }
+        },
+    },
     'events': {
         'events_list': {
             'url': '/freshmaker/1/events/',
@@ -62,8 +112,70 @@ api_v1 = {
 }
 
 
-class EventAPI(MethodView):
+class EventTypeAPI(MethodView):
+    def get(self, id):
+        event_types = []
+        for cls, val in six.iteritems(models.EVENT_TYPES):
+            event_types.append({'name': cls.__name__, 'id': val})
 
+        if id is None:
+            json_data = {}
+            json_data['items'] = event_types
+
+            return jsonify(json_data), 200
+
+        else:
+            event_type = [x for x in event_types if x['id'] == id]
+
+            if event_type:
+                return jsonify(event_type.pop()), 200
+            else:
+                return json_error(404, "Not Found", "No such event type found.")
+
+
+class BuildTypeAPI(MethodView):
+    def get(self, id):
+        build_types = []
+        for x in list(types.ArtifactType):
+            build_types.append({'name': x.name, 'id': x.value})
+
+        if id is None:
+            json_data = {}
+            json_data['items'] = build_types
+
+            return jsonify(json_data), 200
+
+        else:
+            build_type = [x for x in build_types if x['id'] == id]
+
+            if build_type:
+                return jsonify(build_type.pop()), 200
+            else:
+                return json_error(404, "Not Found", "No such build type found.")
+
+
+class BuildStateAPI(MethodView):
+    def get(self, id):
+        build_states = []
+        for x in list(types.ArtifactBuildState):
+            build_states.append({'name': x.name, 'id': x.value})
+
+        if id is None:
+            json_data = {}
+            json_data['items'] = build_states
+
+            return jsonify(json_data), 200
+
+        else:
+            build_state = [x for x in build_states if x['id'] == id]
+
+            if build_state:
+                return jsonify(build_state.pop()), 200
+            else:
+                return json_error(404, "Not Found", "No such build state found.")
+
+
+class EventAPI(MethodView):
     def get(self, id):
         if id is None:
             p_query = filter_events(request)
@@ -80,7 +192,7 @@ class EventAPI(MethodView):
             if event:
                 return jsonify(event.json()), 200
             else:
-                raise ValueError('No shuch event found.')
+                return json_error(404, "Not Found", "No such event found.")
 
 
 class BuildAPI(MethodView):
@@ -100,12 +212,15 @@ class BuildAPI(MethodView):
             if build:
                 return jsonify(build.json()), 200
             else:
-                raise ValueError('No such build found.')
+                return json_error(404, "Not Found", "No such build found.")
 
 
 API_V1_MAPPING = {
     'events': EventAPI,
     'builds': BuildAPI,
+    'event_types': EventTypeAPI,
+    'build_types': BuildTypeAPI,
+    'build_states': BuildStateAPI,
 }
 
 
diff --git a/tests/test_views.py b/tests/test_views.py
index 156f870..da3fa44 100644
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -21,6 +21,7 @@
 
 import unittest
 import json
+import six
 
 from freshmaker import app, db, events, models
 from freshmaker.types import ArtifactType, ArtifactBuildState
@@ -191,6 +192,63 @@ class TestViews(unittest.TestCase):
         self.assertEqual(len(evs), 1)
         self.assertEqual(evs[0]['search_key'], 'RHSA-2018-101')
 
+    def test_query_event_types(self):
+        resp = self.client.get('/freshmaker/1/event-types/')
+        event_types = json.loads(resp.data.decode('utf8'))['items']
+        self.assertEqual(len(event_types), len(models.EVENT_TYPES))
+
+    def test_query_event_type(self):
+        for cls, val in six.iteritems(models.EVENT_TYPES):
+            resp = self.client.get('/freshmaker/1/event-types/%s' % val)
+            event = json.loads(resp.data.decode('utf8'))
+            self.assertEqual(event['id'], val)
+            self.assertEqual(event['name'], cls.__name__)
+
+    def test_query_nonexist_event_type(self):
+        resp = self.client.get('/freshmaker/1/event-types/99999')
+        data = json.loads(resp.data.decode('utf8'))
+        self.assertEqual(data['status'], 404)
+        self.assertEqual(data['error'], 'Not Found')
+        self.assertEqual(data['message'], 'No such event type found.')
+
+    def test_query_build_types(self):
+        resp = self.client.get('/freshmaker/1/build-types/')
+        build_types = json.loads(resp.data.decode('utf8'))['items']
+        self.assertEqual(len(build_types), len(list(ArtifactType)))
+
+    def test_query_build_type(self):
+        for t in list(ArtifactType):
+            resp = self.client.get('/freshmaker/1/build-types/%s' % t.value)
+            build_type = json.loads(resp.data.decode('utf8'))
+            self.assertEqual(build_type['id'], t.value)
+            self.assertEqual(build_type['name'], t.name)
+
+    def test_query_nonexist_build_type(self):
+        resp = self.client.get('/freshmaker/1/build-types/99999')
+        data = json.loads(resp.data.decode('utf8'))
+        self.assertEqual(data['status'], 404)
+        self.assertEqual(data['error'], 'Not Found')
+        self.assertEqual(data['message'], 'No such build type found.')
+
+    def test_query_build_states(self):
+        resp = self.client.get('/freshmaker/1/build-states/')
+        build_types = json.loads(resp.data.decode('utf8'))['items']
+        self.assertEqual(len(build_types), len(list(ArtifactBuildState)))
+
+    def test_query_build_state(self):
+        for t in list(ArtifactBuildState):
+            resp = self.client.get('/freshmaker/1/build-states/%s' % t.value)
+            build_type = json.loads(resp.data.decode('utf8'))
+            self.assertEqual(build_type['id'], t.value)
+            self.assertEqual(build_type['name'], t.name)
+
+    def test_query_nonexist_build_state(self):
+        resp = self.client.get('/freshmaker/1/build-states/99999')
+        data = json.loads(resp.data.decode('utf8'))
+        self.assertEqual(data['status'], 404)
+        self.assertEqual(data['error'], 'Not Found')
+        self.assertEqual(data['message'], 'No such build state found.')
+
 
 if __name__ == '__main__':
     unittest.main()

