From c69d13d1f33a96e02e2300d68c4503390423745d Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Thu, 2 Mar 2023 09:22:37 +0100 Subject: [PATCH] Open API 3.0 - Added first draft of yaml file - Added Python stubs generated by postman export tool --- misc/index.yaml | 396 ++++++++++++++++++++++++ src/server/BreCal/__init__.py | 29 ++ src/server/BreCal/api/notifications.py | 17 + src/server/BreCal/api/participant.py | 16 + src/server/BreCal/api/shipcalls.py | 36 +++ src/server/BreCal/api/times.py | 45 +++ src/server/BreCal/api/verify.py | 13 + src/server/BreCal/impl/__init__.py | 5 + src/server/BreCal/impl/notifications.py | 25 ++ src/server/BreCal/impl/participant.py | 23 ++ src/server/BreCal/impl/shipcalls.py | 45 +++ src/server/BreCal/impl/times.py | 63 ++++ src/server/BreCal/impl/verify.py | 15 + src/server/BreCal/schemas/model.py | 69 +++++ src/server/README.md | 14 + src/server/requirements.txt | 8 + src/server/setup.py | 12 + 17 files changed, 831 insertions(+) create mode 100644 misc/index.yaml create mode 100644 src/server/BreCal/__init__.py create mode 100644 src/server/BreCal/api/notifications.py create mode 100644 src/server/BreCal/api/participant.py create mode 100644 src/server/BreCal/api/shipcalls.py create mode 100644 src/server/BreCal/api/times.py create mode 100644 src/server/BreCal/api/verify.py create mode 100644 src/server/BreCal/impl/__init__.py create mode 100644 src/server/BreCal/impl/notifications.py create mode 100644 src/server/BreCal/impl/participant.py create mode 100644 src/server/BreCal/impl/shipcalls.py create mode 100644 src/server/BreCal/impl/times.py create mode 100644 src/server/BreCal/impl/verify.py create mode 100644 src/server/BreCal/schemas/model.py create mode 100644 src/server/README.md create mode 100644 src/server/requirements.txt create mode 100644 src/server/setup.py diff --git a/misc/index.yaml b/misc/index.yaml new file mode 100644 index 0000000..67a6825 --- /dev/null +++ b/misc/index.yaml @@ -0,0 +1,396 @@ +openapi: '3.0.0' +info: + version: '1.0.0' + title: 'Bremen calling API' + description: Administer DEBRE ship calls, times and notifications + termsOfService: "https://www.bsmd.de/" # url to terms page + contact: + name: "Bremen calling API" + url: "https://www.textbausteine.net" + email: "info@textbausteine.net" + license: + name: "Use at your own risk" + url: "https://www.bsmd.de/license" + +servers: + # tutorial: https://idratherbewriting.com/learnapidoc/pubapis_openapi_step3_servers_object.html + - url : "https://puls200.dyn-dns.org:8088/brecal/api" + description: "Test server self-hosted by yours truly" + +paths: + # tutorial: https://idratherbewriting.com/learnapidoc/pubapis_openapi_step4_paths_object.html + /verify: + get: + summary: Get the user id if successful + responses: + 200: + description: Successful response + content: + application/json: + schema: + title: Verify user token + type: integer + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 500: + $ref: '#/components/responses/500' + 503: + $ref: '#/components/responses/503' + + /shipcalls: + get: + summary: Gets a list of ship calls + parameters: + - name: participant_id + in: query + required: true + description: "**Id of participant**. *Example: 2*. Id of participant entity requesting ship calls" + schema: + type: integer + responses: + 200: + description: ship call list + content: + application/json: + schema: + $ref: '#/components/schemas/shipcalls' + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 500: + $ref: '#/components/responses/500' + 503: + $ref: '#/components/responses/503' + post: + summary: Create a new ship call + requestBody: + description: Creates a new ship call. **Do not** provide id parameter. + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/shipcall' + responses: + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 500: + $ref: '#/components/responses/500' + 503: + $ref: '#/components/responses/503' + + put: + summary: Updates a ship call + requestBody: + description: Creates a new ship call. The id parameter is **required**. + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/shipcall' + responses: + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 500: + $ref: '#/components/responses/500' + 503: + $ref: '#/components/responses/503' + + /participant: + get: + summary: gets a particular participant entry corresponding to user id + parameters: + - name: user_id + in: query + required: true + description: "**Id of user**. *Example: 2*. User id returned by verify call." + schema: + type: integer + responses: + 200: + description: ship call list + content: + application/json: + schema: + $ref: '#/components/schemas/participant' + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 500: + $ref: '#/components/responses/500' + 503: + $ref: '#/components/responses/503' + + /times: + get: + summary: Get all recorded times for a a ship call + parameters: + - name: shipcall_id + in: query + description: "**Id**. *Example: 42*. Id of referenced ship call." + schema: + type: integer + responses: + 200: + description: list of recorded times + content: + application/json: + schema: + $ref: '#/components/schemas/times_list' + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 500: + $ref: '#/components/responses/500' + 503: + $ref: '#/components/responses/503' + + post: + summary: Create a new times entry for a ship call + requestBody: + description: Times entry that will be added to the ship call. **Do not** provide id parameter. + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/times' + responses: + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 500: + $ref: '#/components/responses/500' + 503: + $ref: '#/components/responses/503' + + put: + summary: Update a times entry for a ship call + requestBody: + description: Times entry that will be added to the ship call. The id parameter is **required**. + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/times' + responses: + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 500: + $ref: '#/components/responses/500' + 503: + $ref: '#/components/responses/503' + + delete: + summary: Delete a times entry for a ship call. + parameters: + - name: id + in: query + required: true + schema: + $ref: '#/components/schemas/timesId' + responses: + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 500: + $ref: '#/components/responses/500' + 503: + $ref: '#/components/responses/503' + + /notifications: + get: + summary: Gets a list of notifications pursuant to a specified participant and ship call + parameters: + - name: participant_id + in: query + required: true + description: "**Id of participant**. *Example: 2*. Id returned through loading of participant" + schema: + type: integer + - name: shipcall_id + in: query + required: true + description: "**Id of ship call**. *Example: 52*. Id given in ship call list" + schema: + $ref: '#/components/schemas/shipcallId' + responses: + 200: + description: notification list + content: + application/json: + schema: + $ref: '#/components/schemas/notification' + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 500: + $ref: '#/components/responses/500' + 503: + $ref: '#/components/responses/503' + +components: + schemas: + timesId: + description: The unique identifier for a times entry + type: integer + shipcallId: + description: The unique identifier of a ship call + type: integer + shipcall: + type: object + required: + - id + - ship_id + - type + - eta + - voyage + - etd + properties: + id: + $ref: '#/components/schemas/shipcallId' + + type: + type: string + enum: + - incoming + - outgoing + - shifting + + description: + type: string + + shipcalls: + type: array + items: + $ref: '#/components/schemas/shipcall' + + times: + type: object + description: the id parameter needs to be missing on POST and to be present on PUT (Update) calls, otherwise a 400 response will be generated + required: + - shipcall_id + - participant_id + properties: + id: + type: integer + start_planned: + type: string + format: date-time + end_planned: + type: string + format: date-time + duration_planned: + type: integer + start_actual: + type: string + format: date-time + end_actual: + type: string + format: date-time + shipcall_id: + type: integer + participant_id: + type: integer + + times_list: + type: array + items: + $ref: '#/components/schemas/times' + + notification: + type: object + description: a notification created by the engine if a times entry violates a rule + properties: + id: + type: integer + times_id: + type: integer + participant_id: + type: integer + notification_type: + type: string + enum: [undefined, email, push] + timestamp: + type: string + format: date-time + acknowledged: + type: boolean + + notification_list: + type: array + items: + $ref: '#/components/schemas/notification' + + participant: + type: object + description: A organisational entity that participates in Bremen Calling + properties: + id: + type: integer + name: + type: string + street: + type: string + postal code: + type: string + city: + type: string + + Error: + type: object + required: + - message + properties: + message: + description: A human readable error message + type: string + + securitySchemes: + ApiKey: + type: apiKey + in: header + name: X-Api-Key + responses: + 400: + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + 401: + description: Not authorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + 500: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + 503: + description: Not available + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +security: + - ApiKey: [] +externalDocs: + url: http://textbausteine.net/ + description: Extra documentation and conditions for Bremen Calling diff --git a/src/server/BreCal/__init__.py b/src/server/BreCal/__init__.py new file mode 100644 index 0000000..5a358da --- /dev/null +++ b/src/server/BreCal/__init__.py @@ -0,0 +1,29 @@ +from flask import Flask + +import os + +from .api import shipcalls +from .api import verify + + +def create_app(test_config=None): + app = Flask(__name__, instance_relative_config=True) + app.config.from_mapping( + SECRET_KEY='dev' + ) + if test_config is None: + app.config.from_pyfile('config.py', silent=True) + else: + app.config.from_mapping(test_config) + + try: + print(f'Instance path = {app.instance_path}') + os.makedirs(app.instance_path) + except OSError: + pass + + # Add blueprints + app.register_blueprint(shipcalls.bp) + app.register_blueprint(verify.bp) + + return app diff --git a/src/server/BreCal/api/notifications.py b/src/server/BreCal/api/notifications.py new file mode 100644 index 0000000..7244730 --- /dev/null +++ b/src/server/BreCal/api/notifications.py @@ -0,0 +1,17 @@ +from flask import Blueprint, request +from webargs.flaskparser import parser +from marshmallow import Schema, fields +from ..schemas import model +from .. import impl + +bp = Blueprint('notifications', __name__) + + +@bp.route('/notifications', methods=['get']) +def GetNotifications(): + + options = {} + options["participant_id"] = request.args.get("participant_id") + options["shipcall_id"] = request.args.get("shipcall_id") + + return impl.notifications.GetNotifications(options) diff --git a/src/server/BreCal/api/participant.py b/src/server/BreCal/api/participant.py new file mode 100644 index 0000000..85c0810 --- /dev/null +++ b/src/server/BreCal/api/participant.py @@ -0,0 +1,16 @@ +from flask import Blueprint, request +from webargs.flaskparser import parser +from marshmallow import Schema, fields +from ..schemas import model +from .. import impl + +bp = Blueprint('participant', __name__) + + +@bp.route('/participant', methods=['get']) +def GetParticipant(): + + options = {} + options["user_id"] = request.args.get("user_id") + + return impl.participant.GetParticipant(options) diff --git a/src/server/BreCal/api/shipcalls.py b/src/server/BreCal/api/shipcalls.py new file mode 100644 index 0000000..7f9e865 --- /dev/null +++ b/src/server/BreCal/api/shipcalls.py @@ -0,0 +1,36 @@ +from flask import Blueprint, request +from webargs.flaskparser import parser +from marshmallow import Schema, fields +from ..schemas import model +from .. import impl + +bp = Blueprint('shipcalls', __name__) + + +@bp.route('/shipcalls', methods=['get']) +def GetShipcalls(): + + options = {} + options["participant_id"] = request.args.get("participant_id") + + return impl.shipcalls.GetShipcalls(options) + + +@bp.route('/shipcalls', methods=['post']) +def PostShipcalls(): + + schema = model.Shipcall() + + body = parser.parse(schema, request, location='json') + + return impl.shipcalls.PostShipcalls(body) + + +@bp.route('/shipcalls', methods=['put']) +def PutShipcalls(): + + schema = model.Shipcall() + + body = parser.parse(schema, request, location='json') + + return impl.shipcalls.PutShipcalls(body) diff --git a/src/server/BreCal/api/times.py b/src/server/BreCal/api/times.py new file mode 100644 index 0000000..dac468a --- /dev/null +++ b/src/server/BreCal/api/times.py @@ -0,0 +1,45 @@ +from flask import Blueprint, request +from webargs.flaskparser import parser +from marshmallow import Schema, fields +from ..schemas import model +from .. import impl + +bp = Blueprint('times', __name__) + + +@bp.route('/times', methods=['get']) +def GetTimes(): + + options = {} + options["shipcall_id"] = request.args.get("shipcall_id") + + return impl.times.GetTimes(options) + + +@bp.route('/times', methods=['post']) +def PostTimes(): + + schema = model.Times() + + body = parser.parse(schema, request, location='json') + + return impl.times.PostTimes(body) + + +@bp.route('/times', methods=['put']) +def PutTimes(): + + schema = model.Times() + + body = parser.parse(schema, request, location='json') + + return impl.times.PutTimes(body) + + +@bp.route('/times', methods=['delete']) +def DeleteTimes(): + + options = {} + options["id"] = request.args.get("id") + + return impl.times.DeleteTimes(options) diff --git a/src/server/BreCal/api/verify.py b/src/server/BreCal/api/verify.py new file mode 100644 index 0000000..893415f --- /dev/null +++ b/src/server/BreCal/api/verify.py @@ -0,0 +1,13 @@ +from flask import Blueprint, request +from webargs.flaskparser import parser +from marshmallow import Schema, fields +from ..schemas import model +from .. import impl + +bp = Blueprint('verify', __name__) + + +@bp.route('/verify', methods=['get']) +def GetVerify(): + + return impl.verify.GetVerify() diff --git a/src/server/BreCal/impl/__init__.py b/src/server/BreCal/impl/__init__.py new file mode 100644 index 0000000..a3b69d6 --- /dev/null +++ b/src/server/BreCal/impl/__init__.py @@ -0,0 +1,5 @@ +from . import notifications +from . import participant +from . import shipcalls +from . import times +from . import verify diff --git a/src/server/BreCal/impl/notifications.py b/src/server/BreCal/impl/notifications.py new file mode 100644 index 0000000..920591d --- /dev/null +++ b/src/server/BreCal/impl/notifications.py @@ -0,0 +1,25 @@ +import json + + +def GetNotifications(options): + """ + :param options: A dictionary containing all the paramters for the Operations + options["participant_id"]: **Id of participant**. *Example: 2*. Id returned through loading of participant + options["shipcall_id"]: **Id of ship call**. *Example: 52*. Id given in ship call list + + """ + + # Implement your business logic here + # All the parameters are present in the options argument + + return json.dumps({ + "acknowledged": "", + "id": "", + "notification_type": "", + "participant_id": "", + "times_id": "", + "timestamp": "", + }), 200 + + + diff --git a/src/server/BreCal/impl/participant.py b/src/server/BreCal/impl/participant.py new file mode 100644 index 0000000..69f956f --- /dev/null +++ b/src/server/BreCal/impl/participant.py @@ -0,0 +1,23 @@ +import json + + +def GetParticipant(options): + """ + :param options: A dictionary containing all the paramters for the Operations + options["user_id"]: **Id of user**. *Example: 2*. User id returned by verify call. + + """ + + # Implement your business logic here + # All the parameters are present in the options argument + + return json.dumps({ + "city": "", + "id": "", + "name": "", + "postal code": "", + "street": "", + }), 200 + + + diff --git a/src/server/BreCal/impl/shipcalls.py b/src/server/BreCal/impl/shipcalls.py new file mode 100644 index 0000000..f1d9869 --- /dev/null +++ b/src/server/BreCal/impl/shipcalls.py @@ -0,0 +1,45 @@ +import json + + +def GetShipcalls(options): + """ + :param options: A dictionary containing all the paramters for the Operations + options["participant_id"]: **Id of participant**. *Example: 2*. Id of participant entity requesting ship calls + + """ + + # Implement your business logic here + # All the parameters are present in the options argument + + return json.dumps([{ + "description": "", + "id": "", + "type": "", + }]), 200 + + +def PostShipcalls(body): + """ + + :param body: The parsed body of the request + """ + + # Implement your business logic here + # All the parameters are present in the options argument + + return 400 + + +def PutShipcalls(body): + """ + + :param body: The parsed body of the request + """ + + # Implement your business logic here + # All the parameters are present in the options argument + + return 400 + + + diff --git a/src/server/BreCal/impl/times.py b/src/server/BreCal/impl/times.py new file mode 100644 index 0000000..e98bf44 --- /dev/null +++ b/src/server/BreCal/impl/times.py @@ -0,0 +1,63 @@ +import json + + +def GetTimes(options): + """ + :param options: A dictionary containing all the paramters for the Operations + options["shipcall_id"]: **Id**. *Example: 42*. Id of referenced ship call. + + """ + + # Implement your business logic here + # All the parameters are present in the options argument + + return json.dumps([{ + "duration_planned": "", + "end_actual": "", + "end_planned": "", + "id": "", + "participant_id": "", + "shipcall_id": "", + "start_actual": "", + "start_planned": "", + }]), 200 + + +def PostTimes(body): + """ + + :param body: The parsed body of the request + """ + + # Implement your business logic here + # All the parameters are present in the options argument + + return 400 + + +def PutTimes(body): + """ + + :param body: The parsed body of the request + """ + + # Implement your business logic here + # All the parameters are present in the options argument + + return 400 + + +def DeleteTimes(options): + """ + :param options: A dictionary containing all the paramters for the Operations + options["id"] + + """ + + # Implement your business logic here + # All the parameters are present in the options argument + + return 400 + + + diff --git a/src/server/BreCal/impl/verify.py b/src/server/BreCal/impl/verify.py new file mode 100644 index 0000000..5366764 --- /dev/null +++ b/src/server/BreCal/impl/verify.py @@ -0,0 +1,15 @@ +import json + + +def GetVerify(): + """ + + """ + + # Implement your business logic here + # All the parameters are present in the options argument + + return json.dumps(""), 200 + + + diff --git a/src/server/BreCal/schemas/model.py b/src/server/BreCal/schemas/model.py new file mode 100644 index 0000000..1f582e8 --- /dev/null +++ b/src/server/BreCal/schemas/model.py @@ -0,0 +1,69 @@ +from marshmallow import Schema, fields + + +class Error(Schema): + message = fields.String(required=True,) + + +class GetVerifyInlineResp(Schema): + pass + + +class Notification(Schema): + acknowledged = fields.Boolean() + id = fields.Int() + notification_type = fields.String() + participant_id = fields.Int() + times_id = fields.Int() + timestamp = fields.DateTime() + + + +class Participant(Schema): + city = fields.String() + id = fields.Int() + name = fields.String() + postal_code = fields.String(data_key="postal code",) + street = fields.String() + + +class Shipcall(Schema): + description = fields.String() + id = fields.Raw(required=True,) + + type = fields.String(required=True,) + + +class ShipcallId(Schema): + pass + + +class Times(Schema): + duration_planned = fields.Int() + end_actual = fields.DateTime() + + end_planned = fields.DateTime() + + id = fields.Int() + participant_id = fields.Int(required=True,) + shipcall_id = fields.Int(required=True,) + start_actual = fields.DateTime() + + start_planned = fields.DateTime() + + + +class TimesId(Schema): + pass + + +class NotificationList(Notification): + pass + + +class Shipcalls(Shipcall): + pass + + +class TimesList(Times): + pass diff --git a/src/server/README.md b/src/server/README.md new file mode 100644 index 0000000..64c3cbc --- /dev/null +++ b/src/server/README.md @@ -0,0 +1,14 @@ +# BreCal + +## OpenAPI 3.0 Generated Flask project + +All the routes are defined in 'project/api' folder. +Each route parses the request and calls the corresponding function in the 'project/impl' directory passing all the parameters and request body as function arguments. + +To run this project: +``` +pip install -r requirements.txt +export FLASK_APP='BreCal' +export FLASK_ENV=development +flask run +``` \ No newline at end of file diff --git a/src/server/requirements.txt b/src/server/requirements.txt new file mode 100644 index 0000000..df28546 --- /dev/null +++ b/src/server/requirements.txt @@ -0,0 +1,8 @@ +click==7.1.2 +Flask==1.1.2 +itsdangerous==1.1.0 +Jinja2==2.11.2 +MarkupSafe==1.1.1 +marshmallow==3.9.1 +webargs==6.1.1 +Werkzeug==1.0.1 \ No newline at end of file diff --git a/src/server/setup.py b/src/server/setup.py new file mode 100644 index 0000000..54a2a09 --- /dev/null +++ b/src/server/setup.py @@ -0,0 +1,12 @@ +from setuptools import find_packages, setup + +setup( + name='BreCal', + version='1.0.0', + packages=find_packages(), + include_package_data=True, + zip_safe=False, + install_requires=[ + 'flask' + ] +)