def test_extensions_restapi_doc_responses_build(self): # when statuses are None or not a list|tuple # 200 and 500 statuses are defaults for status_codes in [None, 'bad']: doc_rsps = build_responses(status_codes) assert 200 in doc_rsps assert 500 in doc_rsps assert 404 not in doc_rsps assert doc_rsps == { 200: {'description': 'successful operation'}, 500: {'description': 'internal server error'}, } # statuses can be a list or a tuple of integers for status_codes in [[404, 500], (404, 500,)]: doc_rsps = build_responses(status_codes) assert 200 not in doc_rsps assert 404 in doc_rsps assert 500 in doc_rsps assert doc_rsps == { 404: {'description': 'item not found', 'schema': ErrorSchema}, 500: {'description': 'internal server error'}, } # status code can be a string (at least parsable to int) doc_rsps = build_responses(['200']) assert doc_rsps == {200: {'description': 'successful operation'}} # status code can also not be in default responses (a.k.a. _RESPONSES) doc_rsps = build_responses([300]) assert doc_rsps == {300: {'description': ''}} doc_rsps = build_responses(['bad']) assert doc_rsps == {}
class EventsById(MethodView): @auth_required(roles=['building_manager', 'module_data_processor']) @api.doc( summary='Get event by ID', description='''A specific entrypoint to retrieve events according to the the ID associated. Useful for testing purpose to ensure the event is stored and available as desired.''', responses=build_responses([200, 404, 422, 500])) @api.response(EventSchema) def get(self, event_id): """Return an item from its ID""" item = db.session.query(Event).get_or_404(event_id) # permissions checks verify_scope(sites=[item.site_id]) return item @auth_required(roles=['module_data_processor']) @api.doc( summary='Update existing event', description='Update an event from its ID and return the updated event.', responses=build_responses([200, 404, 422, 500])) @api.arguments(EventSchema) @api.response(EventSchema) def put(self, update_data, event_id): """Update an item from its ID and return updated item""" item = db.session.query(Event).get_or_404(event_id) # permissions checks verify_scope(sites=[item.site_id]) check_etag(item, etag_schema=EventSchema) EventSchema().update_obj(item, update_data) db.session.add(item) db.session.commit() return item @auth_required(roles=['module_data_processor']) @api.doc(summary='Delete event', description='''Delete an event. Requires to have its ID.''', responses=build_responses([200, 404, 422, 500])) @api.response(code=204) def delete(self, event_id): """Delete an item from its ID""" item = db.session.query(Event).get_or_404(event_id) # permissions checks verify_scope(sites=[item.site_id]) check_etag(item, etag_schema=EventSchema) db.session.delete(item) db.session.commit()
def test_extensions_restapi_doc_responses_build_schemas(self): class DataSchema(ma.Schema): data = ma.fields.String() doc_rsps = build_responses([200, 204], schemas={200: DataSchema}) assert 200 in doc_rsps assert 'schema' in doc_rsps[200] assert doc_rsps[200]['schema'] == DataSchema assert 204 in doc_rsps assert 'schema' not in doc_rsps[204]
class Events(MethodView): @auth_required(roles=['building_manager', 'module_data_processor']) @api.doc( summary='List events', description='''This endpoint allows one to retrieve events by any service plugged to the BEMServer running instance. Because the set of generated events can be big, the use of filters is recommended. Typical filters can be: + localization: through the use of site_id, building_id, floor_id. + criticity level. + category or sub-category. Also, ensure you correctly use the `page_size` and `page` parameters in your calls to get the full list of generated events.''') @api.arguments(EventQueryArgsSchema, location='query') @api.response(EventSchema(many=True)) @api.paginate(SQLCursorPage) def get(self, args): """Return event list""" sort = args.pop('sort', ()) sensor_id = args.pop('sensor_id', None) min_start_time = args.pop('min_start_time', None) max_start_time = args.pop('max_start_time', None) min_end_time = args.pop('min_end_time', None) max_end_time = args.pop('max_end_time', None) items = db.session.query(Event).filter_by(**args) # permissions filter uacc = get_user_account() if uacc is not None and '*' not in uacc.sites: items = items.filter(Event.site_id.in_(uacc.sites)) if sensor_id is not None: items = items.filter( Event.sensor_ids.contains('"{}"'.format(sensor_id))) if min_start_time is not None: items = items.filter(Event.start_time >= min_start_time) if max_start_time is not None: items = items.filter(Event.start_time < max_start_time) if min_end_time is not None: items = items.filter(Event.end_time >= min_end_time) if max_end_time is not None: items = items.filter(Event.end_time < max_end_time) # TODO: factorize sort logic (in Schema?) for name, direc in sort: criterion = getattr(getattr(Event, name), 'desc' if direc < 0 else 'asc')() items = items.order_by(criterion) return items @auth_required(roles=['module_data_processor']) @api.doc( summary='Add a new event', description='''Endpoint to be called by services when they output some event to BEMServer.<br>**Ensure you use the service_id of your service, after registering to the `/services` API!**<br>Additionally, the more information/fields are set, the easiest it is for other services to use the events you generate.''', responses=build_responses([201, 422, 500])) @api.arguments(EventSchema) @api.response(EventSchema, code=201) def post(self, new_data): """Create a new event""" item = EventSchema().make_obj(new_data) # permissions checks verify_scope(sites=[item.site_id]) db.session.add(item) db.session.commit() return item