#57 Add APIs for querying event types, build types and build states
Merged 7 years ago by qwan. Opened 7 years ago by qwan.
qwan/freshmaker query-types-api  into  master

file modified
+9 -1
@@ -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 @@ 

      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

file modified
+119 -4
@@ -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 @@ 

  }

  

  

- 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 @@ 

              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 @@ 

              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,

  }

  

  

file modified
+58
@@ -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 @@ 

          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()

no initial comment

rebased

7 years ago

Will this return the "No such event type found." to the user with a 500 error?

Seems like a 404 would be most appropriate.

In general, looks good. :+1: to merge, although I'd advise reconsidering the exception handling if it is throwing 500 errors back to the user.

Same above. 404 would be good.

Same above. 404 would be good.

LGTM.

It would be good to raise 404 if id is None, if freshmaker does not do that now.

rebased

7 years ago

updated to return 404 for 'Not Found' errors and rebase to latest master.

Pull-Request has been merged by qwan

7 years ago