Skip to content
Snippets Groups Projects
highlight.py 4.22 KiB
from typing import TYPE_CHECKING

from fastapi import APIRouter, Depends
from sqlalchemy import select
from sqlalchemy import func as F

from server.data import db_engine
from server.api.errors import \
    NoDataForKeyError, \
    DataNotFoundWarning
from server.util.security import \
    UserPermissionChecker, \
    InsufficientPermissions

from nacsos_data.util.auth import UserPermissions
from nacsos_data.db.schemas.annotations import AssignmentScope
from nacsos_data.db.schemas.highlight import Highlighter
from nacsos_data.models.highlight import HighlighterModel

if TYPE_CHECKING:
    from sqlalchemy.ext.asyncio import AsyncSession  # noqa F401

router = APIRouter()


@router.get('/scope/{assignment_scope_id}', response_model=list[HighlighterModel] | None)
async def get_scope_highlighters(assignment_scope_id: str,
                                 permissions: UserPermissions = Depends(UserPermissionChecker('annotations_read'))) \
        -> list[HighlighterModel]:
    async with db_engine.session() as session:  # type: AsyncSession
        highlighter_ids = select(F.unnest(AssignmentScope.highlighter_ids).label('highlighter_id')) \
            .where(AssignmentScope.assignment_scope_id == assignment_scope_id) \
            .subquery()
        stmt = select(Highlighter) \
            .join(highlighter_ids, highlighter_ids.c.highlighter_id == Highlighter.highlighter_id) \
            .where(Highlighter.project_id == permissions.permissions.project_id)

        result = (await session.scalars(stmt)).all()
        if result is not None and len(result) > 0:
            return [HighlighterModel.model_validate(r.__dict__) for r in result]
        raise DataNotFoundWarning(f'No highlighter in project {permissions.permissions.project_id} '
                                  f'for scope with id {assignment_scope_id}!')


@router.get('/project', response_model=list[HighlighterModel])
async def get_project_highlighters(permissions: UserPermissions = Depends(UserPermissionChecker('annotations_read'))) \
        -> list[HighlighterModel]:
    async with db_engine.session() as session:  # type: AsyncSession
        stmt = select(Highlighter).where(Highlighter.project_id == permissions.permissions.project_id)
        results = (await session.scalars(stmt)).all()
        return [HighlighterModel.model_validate(r.__dict__) for r in results]


@router.put('/project', response_model=str)
async def upsert_highlighter(highlighter: HighlighterModel,
                             permissions: UserPermissions = Depends(UserPermissionChecker('annotations_edit'))) \
        -> str:
    if str(permissions.permissions.project_id) != str(highlighter.project_id):
        raise InsufficientPermissions('Project IDs don\'t match!')

    async with db_engine.session() as session:  # type: AsyncSession
        stmt = select(Highlighter).where(Highlighter.project_id == permissions.permissions.project_id,
                                         Highlighter.highlighter_id == highlighter.highlighter_id)
        result: Highlighter | None = (await session.scalars(stmt)).one_or_none()

        if result is not None:
            result.name = highlighter.name
            result.style = highlighter.style
            result.keywords = highlighter.keywords
        else:
            new_highlighter = Highlighter(**highlighter.model_dump())
            session.add(new_highlighter)

        await session.commit()

        return str(highlighter.highlighter_id)


@router.get('/{highlighter_id}', response_model=HighlighterModel | None)
async def get_highlighter(highlighter_id: str,
                          permissions: UserPermissions = Depends(UserPermissionChecker('annotations_read'))) \
        -> HighlighterModel:
    async with db_engine.session() as session:  # type: AsyncSession
        stmt = select(Highlighter).where(Highlighter.project_id == permissions.permissions.project_id,
                                         Highlighter.highlighter_id == highlighter_id)
        result = (await session.scalars(stmt)).one_or_none()
        if result is not None:
            return HighlighterModel.model_validate(result.__dict__)
        raise NoDataForKeyError(f'No highlighter in project {permissions.permissions.project_id} '
                                f'with id {highlighter_id}!')