diff --git a/announcement_service_spec.yaml b/announcement_service_spec.yaml index 7411763..374b54c 100644 --- a/announcement_service_spec.yaml +++ b/announcement_service_spec.yaml @@ -16,8 +16,6 @@ paths: operationId: listPatchnotes parameters: - $ref: '#/components/parameters/SinceParam' - - $ref: '#/components/parameters/LimitParam' - - $ref: '#/components/parameters/OffsetParam' responses: "200": description: list of patch notes @@ -55,6 +53,23 @@ paths: "400": description: bad payload + /patchnotes/all: + get: + tags: [Patchnotes] + summary: Returns **all** patch notes (admin area) + operationId: listAllPatchnotes + responses: + "200": + description: list of all patch notes + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/patch_notes' + "404": + description: no Patch notes found + /patchnotes/{patchID}: parameters: - in: path @@ -119,25 +134,6 @@ components: schema: type: string format: date - LimitParam: - name: limit - in: query - description: Maximum number of items to return - required: false - schema: - type: integer - default: 20 - minimum: 1 - maximum: 100 - OffsetParam: - name: offset - in: query - description: Pagination offset - required: false - schema: - type: integer - default: 0 - minimum: 0 schemas: patch_notes: @@ -161,10 +157,10 @@ components: title: Patch note 1 changes: Fixed export bug version: 1.0.0 - patch_date: 2025-01-02 + patch_date: '2025-01-02' # ← als String in Quotes! patch_notes_input: - description: Schema for POST/PUT (server generates patchID & patch_date if omitted) + description: Schema for POST/PUT (server generates patchID if omitted) type: object properties: title: @@ -177,6 +173,11 @@ components: type: string format: date required: [title, changes, version, patch_date] + example: + title: Patch note 1 + changes: Fixed export bug + version: 1.0.0 + patch_date: '2025-01-02' # ← ebenfalls in Quotes responses: Error400: diff --git a/gen/openapi_server/__main__.py b/gen/openapi_server/__main__.py index 20a3a2f..2a1b759 100644 --- a/gen/openapi_server/__main__.py +++ b/gen/openapi_server/__main__.py @@ -6,13 +6,18 @@ from connexion.middleware import MiddlewarePosition from flask import Flask from openapi_server import encoder -from pymongo import MongoClient +from pymongo import MongoClient, ASCENDING from starlette.middleware.cors import CORSMiddleware import re client = MongoClient(host='mongodb://admin:admin@announcement-service-database-svc:27017/?authSource=admin') db = client["MainDB"] collection = db['patch_notes'] +last_login_collection = db["user_last_login"] + +last_login_collection.create_index( + [("user_id", ASCENDING)], unique=True, name="user_id_unique" +) app = connexion.FlaskApp(__name__, specification_dir='./openapi/') diff --git a/gen/openapi_server/controllers/patchnotes_controller.py b/gen/openapi_server/controllers/patchnotes_controller.py index 2ac1749..e626bc9 100644 --- a/gen/openapi_server/controllers/patchnotes_controller.py +++ b/gen/openapi_server/controllers/patchnotes_controller.py @@ -15,8 +15,9 @@ from connexion import ProblemException from flask import Response from __main__ import collection -from openapi_server.__main__ import collection +from openapi_server.__main__ import collection, last_login_collection from openapi_server.models.patch_notes import PatchNotes +from openapi_server.utils.auth import current_user_id def create_patchnote(body): # noqa: E501 @@ -119,36 +120,46 @@ def get_patchnote(patch_id): # noqa: E501 def list_patchnotes(since: str | None = None): - # 1) validate query param only if present + """GET /patchnotes – liefert neue Patchnotes und setzt last_login.""" + + user_id = current_user_id() # 1) aktueller Benutzer + + # 2) Wenn ?since fehlt, gespeichertes last_login holen + if since is None: + rec = last_login_collection.find_one({"user_id": user_id}) + since = rec["last_login"] if rec else None + + # 3) Datum validieren (nur wenn vorhanden) if since: try: datetime.strptime(since, "%Y-%m-%d") except ValueError: raise ProblemException( title="Bad Request", - detail="The date is invalid. Needs to be in this format YYYY-MM-DD", + detail="since must be YYYY-MM-DD", status=400, ) - query = {"patch_date": {"$gte": since}} + mongo_filter = {"patch_date": {"$gte": since}} else: - query = {} # no filter -> all notes + mongo_filter = {} # erster Login → alle Notes - # 2) fetch from Mongo - docs = list(collection.find(query).sort("patch_date", 1)) - - # 3) ensure every patch_date is *string* before serialising + # 4) Patchnotes abholen + docs = list(collection.find(mongo_filter).sort("patch_date", 1)) for d in docs: - if isinstance(d.get("patch_date"), (datetime, date)): - d["patch_date"] = d["patch_date"].strftime("%Y-%m-%d") - d.pop("_id", None) # optional: hide Mongo’s internal id + d.pop("_id", None) + if isinstance(d["patch_date"], (datetime, date)): + d["patch_date"] = d["patch_date"].isoformat() - # 4) serialise – default=str handles any remaining non-JSON types - return Response( - json_util.dumps(docs, default=str), - mimetype="application/json", - status=200, + # 5) Heutiges Datum als neuen last_login speichern + today = date.today().isoformat() + last_login_collection.update_one( + {"user_id": user_id}, + {"$set": {"last_login": today}}, + upsert=True, ) + return Response(json_util.dumps(docs), mimetype="application/json", status=200) + def update_patchnote(patch_id, body): # noqa: E501 """Updates one patch note (full replace) @@ -206,3 +217,5 @@ def update_patchnote(patch_id, body): # noqa: E501 mimetype="application/json", status=200, ) + + diff --git a/gen/openapi_server/utils/auth.py b/gen/openapi_server/utils/auth.py new file mode 100644 index 0000000..3f3fbc5 --- /dev/null +++ b/gen/openapi_server/utils/auth.py @@ -0,0 +1,15 @@ +import jwt +from connexion import ProblemException +from flask import request + +def current_user_id() -> str: + """Liest die User-UUID (sub) aus dem Bearer-JWT im Authorization-Header.""" + auth = request.headers.get("Authorization", "") + if not auth.startswith("Bearer "): + raise ProblemException(status=401, detail="Missing Bearer token") + + token = auth.split()[1] + + # ↓ Für Demo ohne Signaturprüfung – produktiv natürlich verifizieren! + payload = jwt.decode(token, options={"verify_signature": False}) + return payload["sub"] diff --git a/requirements.txt b/requirements.txt index 552ca0e..b5cdacb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,3 +15,6 @@ flask_cors >= 5.0.1 typing_extensions==4.12.2 Flask-Testing==0.8.1 starlette==0.46.1 + +typing_extensions==4.12.2 +PyJWT==2.10.1 \ No newline at end of file