All checks were successful
Deploy Development / deploy (push) Successful in 35s
Test Suite / pytest-backend (push) Successful in 24s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 6s
Test Suite / playwright-tests (push) Successful in 22s
- Enhanced exercise update functionality to support the promotion of attached media assets to 'official' status, requiring active visibility and copyright validation. - Updated backend API to handle new fields for promoting media and setting default copyright notices during exercise updates. - Improved frontend error handling to prompt users for confirmation when promoting media assets, including checks for copyright compliance. - Incremented version to 0.8.47, reflecting the latest changes in media management and governance.
108 lines
3.1 KiB
Python
108 lines
3.1 KiB
Python
"""§4.2: apply_official_exercise_media_rules — Lifecycle, Sichtbarkeit, Copyright."""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
from fastapi import HTTPException
|
|
|
|
os.environ.setdefault("SKIP_DB_MIGRATE", "1")
|
|
|
|
from routers.exercises import apply_official_exercise_media_rules
|
|
|
|
|
|
def _row(
|
|
aid: int,
|
|
*,
|
|
vis: str = "private",
|
|
lifecycle: str = "active",
|
|
copyright_notice: str | None = "",
|
|
name: str = "f.bin",
|
|
) -> dict:
|
|
return {
|
|
"id": aid,
|
|
"visibility": vis,
|
|
"club_id": 1,
|
|
"lifecycle_state": lifecycle,
|
|
"copyright_notice": copyright_notice,
|
|
"original_filename": name,
|
|
}
|
|
|
|
|
|
def test_non_official_visibility_noop() -> None:
|
|
cur = MagicMock()
|
|
apply_official_exercise_media_rules(
|
|
cur,
|
|
1,
|
|
"private",
|
|
promote_attached_media=False,
|
|
default_official_media_copyright=None,
|
|
)
|
|
cur.execute.assert_not_called()
|
|
|
|
|
|
def test_lifecycle_not_active_422() -> None:
|
|
cur = MagicMock()
|
|
cur.fetchall.return_value = [_row(1, lifecycle="trash_soft", copyright_notice="abc")]
|
|
with pytest.raises(HTTPException) as ei:
|
|
apply_official_exercise_media_rules(
|
|
cur,
|
|
1,
|
|
"official",
|
|
promote_attached_media=False,
|
|
default_official_media_copyright=None,
|
|
)
|
|
assert ei.value.status_code == 422
|
|
assert ei.value.detail["code"] == "OFFICIAL_MEDIA_LIFECYCLE"
|
|
|
|
|
|
def test_visibility_promotion_confirm_422() -> None:
|
|
cur = MagicMock()
|
|
cur.fetchall.return_value = [_row(1, vis="club", copyright_notice="halten")]
|
|
with pytest.raises(HTTPException) as ei:
|
|
apply_official_exercise_media_rules(
|
|
cur,
|
|
1,
|
|
"official",
|
|
promote_attached_media=False,
|
|
default_official_media_copyright=None,
|
|
)
|
|
assert ei.value.status_code == 422
|
|
assert ei.value.detail["code"] == "OFFICIAL_MEDIA_CONFIRM_REQUIRED"
|
|
assert ei.value.detail["assets_need_visibility_promotion"]
|
|
|
|
|
|
def test_copyright_required_422() -> None:
|
|
cur = MagicMock()
|
|
cur.fetchall.return_value = [_row(1, vis="official", copyright_notice="")]
|
|
with pytest.raises(HTTPException) as ei:
|
|
apply_official_exercise_media_rules(
|
|
cur,
|
|
1,
|
|
"official",
|
|
promote_attached_media=True,
|
|
default_official_media_copyright=None,
|
|
)
|
|
assert ei.value.status_code == 422
|
|
assert ei.value.detail["code"] == "OFFICIAL_MEDIA_CONFIRM_REQUIRED"
|
|
assert ei.value.detail["assets_missing_copyright"]
|
|
|
|
|
|
def test_promote_and_fill_copyright_updates() -> None:
|
|
cur = MagicMock()
|
|
cur.fetchall.return_value = [_row(1, vis="private", copyright_notice=" ")]
|
|
apply_official_exercise_media_rules(
|
|
cur,
|
|
42,
|
|
"official",
|
|
promote_attached_media=True,
|
|
default_official_media_copyright="© Test Holding",
|
|
)
|
|
assert cur.execute.call_count == 3
|
|
sql1 = cur.execute.call_args_list[1][0][0]
|
|
sql2 = cur.execute.call_args_list[2][0][0]
|
|
assert "visibility = 'official'" in sql1
|
|
assert "copyright_notice" in sql2
|
|
|