Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Integration tests

on:
push:
pull_request:

jobs:
integration-tests:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Cache pip dependencies
id: cache
uses: actions/cache@v4
with:
path: functions/venv
key: ${{ runner.os }}-pip-${{ hashFiles('functions/requirements.txt', 'functions/requirements_dev.txt') }}
restore-keys: |
${{ runner.os }}-pip-

- name: Create venv and install dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: |
python -m venv functions/venv
functions/venv/bin/pip install --upgrade pip
functions/venv/bin/pip install -r functions/requirements.txt -r functions/requirements_dev.txt

- name: Run integration tests with coverage
run: |
functions/venv/bin/pytest --cov=functions --cov-report=term --cov-fail-under=75
34 changes: 33 additions & 1 deletion functions/api/categories.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from database import Database
from exceptions import DataNotFoundError
from flask import Blueprint, Response, jsonify
from models import CategoryInput
from models import CategoryInput, CategoryPatch
from request_models import CategoriesQueryParams

categories_bp = Blueprint("categories", __name__)
Expand All @@ -28,6 +28,21 @@ def get_categories(validated_params: CategoriesQueryParams, application: str) ->
return jsonify([cat.model_dump() for cat in categories]), 200


@categories_bp.route("/<string:category_id>", methods=["GET"], strict_slashes=False)
@require_application
def get_category_by_id(category_id: str, application: str) -> tuple[Response, int]:
with Database() as db:
if not db.application.exists(application):
raise DataNotFoundError(f"Application '{application}' not found")

category = db.category.get(
category_id=category_id,
application=application
)

return jsonify(category.model_dump()), 200


@categories_bp.route("", methods=["POST"], strict_slashes=False)
@require_application
@validate_json(CategoryInput)
Expand All @@ -39,3 +54,20 @@ def create_category(validated_data: CategoryInput, application: str) -> tuple[Re
category_id = db.category.create(validated_data, application=application)

return jsonify({"id": category_id}), 201


@categories_bp.route("/<string:category_id>", methods=["PATCH"], strict_slashes=False)
@require_application
@validate_json(CategoryPatch)
def update_category(
category_id: str, validated_data: CategoryPatch, application: str
) -> tuple[Response, int]:
with Database() as db:
if not db.application.exists(application):
raise DataNotFoundError(f"Application '{application}' not found")

updated_category = db.category.update(
category_id, validated_data, application=application
)

return jsonify(updated_category.model_dump()), 200
99 changes: 99 additions & 0 deletions functions/api/schema/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2076,6 +2076,105 @@ paths:
"500":
$ref: "#/components/responses/ServerError"

/v2/categories/{category_id}:
get:
summary: Get a category by ID
description: Retrieve a single category by its ID. Application context is provided via X-Application header.
tags:
- Categories
parameters:
- name: X-Application
in: header
required: true
schema:
type: string
description: Application context for the category
example: "webuddhist"
- name: category_id
in: path
required: true
schema:
type: string
description: The ID of the category to retrieve
responses:
"200":
description: Category retrieved successfully
content:
application/json:
schema:
$ref: "#/components/schemas/CategoryOutput"
example:
id: "CAT12345678"
parent_id: null
title:
en: "Literature"
bo: "རྩོམ་རིག"
children: []
"400":
$ref: "#/components/responses/InvalidRequest"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/ServerError"
patch:
summary: Update a category
description: Partially update a category. Only provided fields (title, description, parent_id) will be updated; omitted fields retain their current values.
tags:
- Categories
parameters:
- name: X-Application
in: header
required: true
schema:
type: string
description: Application context for the category
example: "webuddhist"
- name: category_id
in: path
required: true
schema:
type: string
description: The ID of the category to update
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CategoryInput"
examples:
update_title:
summary: Update title
value:
title:
en: "Updated Title"
bo: "གསར་བསྒྱུར་མིང་།"
update_with_description:
summary: Update with description
value:
title:
en: "Category Title"
description:
en: "Updated description"
update_parent_id:
summary: Update parent ID
value:
parent_id: "parent_id_here"
responses:
"200":
description: Category updated successfully
content:
application/json:
schema:
$ref: "#/components/schemas/CategoryOutput"
"400":
$ref: "#/components/responses/InvalidRequest"
"404":
$ref: "#/components/responses/NotFound"
"422":
$ref: "#/components/responses/ValidationError"
"500":
$ref: "#/components/responses/ServerError"

/v2/applications:
post:
summary: Create a new application
Expand Down
Loading