20 Commits

Author SHA1 Message Date
Thomas Peetz d80aefe6b2 add publishing of kontor-model
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
2026-08-26 18:33:35 +02:00
Thomas Peetz 652378e7de update kontor-api
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-25 17:45:03 +02:00
tpeetz 57b942a9ca update Vaadin to 25.2.6 (#95)
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
Co-authored-by: Thomas Peetz <thomas.peetz@cimt-ag.de>
Reviewed-on: #95
2026-08-25 14:15:18 +00:00
Thomas Peetz bda453a92a change to version 0.4.0-SNAPSHOT
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-08-25 11:11:51 +02:00
Thomas Peetz a113f08ddc create release 0.3.0
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-08-25 09:43:49 +02:00
tpeetz cc631a14ed Merge pull request 'Vorbereitung Release 03.0' (#94) from develop/0.3.0 into main
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
Reviewed-on: #94
2026-08-25 06:01:17 +00:00
Thomas Peetz 9476d8853e add MediaLofiView
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-24 12:55:05 +02:00
tpeetz 8cc58aed5b implement routes for MediaFile, MediaVideo and MediaLofi
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-08-23 21:31:49 +02:00
tpeetz ec274a60d9 add build an git info
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-23 00:48:18 +02:00
tpeetz 5b7c41c829 add Routes and Processors
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-22 02:04:48 +02:00
Thomas Peetz f73ec33aeb add CheckLinkProcessor
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 7s
2026-08-21 19:46:56 +02:00
Thomas Peetz cdde57e033 remove deploy.gradle and use deploy--kontor.sh
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-08-19 16:42:16 +02:00
tpeetz 9d07ed9bfb add script to deploy Kontor from Nexus
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-19 14:39:46 +00:00
Thomas Peetz 59e705d012 using Gradle to deploy Kontor
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-08-19 15:57:53 +02:00
Thomas Peetz 3b50a94928 add monitoring of Spring Boot Camel routes
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-08-19 13:51:32 +02:00
Thomas Peetz fd5bb14e77 add Container build file to package precompiled binary
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-18 17:11:10 +02:00
tpeetz a786607608 fix build problems
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-08-16 23:01:14 +02:00
tpeetz 031d71406c change queue names
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
2026-08-14 22:45:34 +02:00
Thomas Peetz 48149b67cf extract SQLAlchemy model in separate python library 2026-08-14 16:39:46 +02:00
Thomas Peetz 9f0a0c1d1e Revert "Update Vaadin and Spring Boot version"
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 6s
This reverts commit 7555cfd51d.
2026-08-13 14:05:48 +02:00
399 changed files with 9824 additions and 134483 deletions
+1
View File
@@ -11,3 +11,4 @@ kontor-robyn.bak
kontor-robyn.bak2 kontor-robyn.bak2
kontor-data/.gradle kontor-data/.gradle
kontor-data/build/ kontor-data/build/
/kontor-api/kontor-api.code-workspace
+12
View File
@@ -0,0 +1,12 @@
# Posted by barth, modified by community. See post 'Timeline' for change history
# Retrieved 2026-08-19, License - CC BY-SA 4.0
NEXUS_URL=https://nexus.thpeetz.de
MAVEN_REPO=maven-snapshots
GROUP_ID=de.thpeetz
ARTIFACT_ID=kontor-spring
VERSION=0.4.0
FILE_EXTENSION=jar
download_url=$(curl -X GET "${NEXUS_URL}/service/rest/v1/search/assets?repository=${MAVEN_REPO}&maven.groupId=${GROUP_ID}&maven.artifactId=${ARTIFACT_ID}&maven.baseVersion=${VERSION}&maven.extension=${FILE_EXTENSION}" -H "accept: application/json" | jq -rc '.items | .[].downloadUrl' | sort | tail -n 1)
wget $download_url
-1
View File
@@ -14,7 +14,6 @@ ENV PATH="/root/.local/bin:${PATH}"
WORKDIR /app WORKDIR /app
COPY ./pyproject.toml . COPY ./pyproject.toml .
RUN uv sync RUN uv sync
# ------------------------------- Production Stage ------------------------------ ## # ------------------------------- Production Stage ------------------------------ ##
+13 -2
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "kontor-api" name = "kontor-api"
version = "0.1.0" version = "0.4.0"
description = "Add your description here" description = "Add your description here"
readme = "README.md" readme = "README.md"
requires-python = ">=3.13" requires-python = ">=3.13"
@@ -24,10 +24,21 @@ dependencies = [
"psycopg2-binary>=2.9.10", "psycopg2-binary>=2.9.10",
"pytest-cov>=6.1.1", "pytest-cov>=6.1.1",
"databases[sqlite]>=0.9.0", "databases[sqlite]>=0.9.0",
"pydantic[email]>=2.11.3",
"jinja2>=3.1.6", "jinja2>=3.1.6",
"asyncpg>=0.30.0", "asyncpg>=0.30.0",
"bcrypt>=4.3.0", "bcrypt>=4.3.0",
"fastapi-jwt-auth>=0.5.0", "fastapi-jwt-auth>=0.5.0",
"msgspec[toml,yaml]>=0.21.1", "msgspec[toml,yaml]>=0.21.1",
"kontor-model",
] ]
[[tool.uv.index]]
name = "nexus"
url = "https://nexus.thpeetz.de/repository/pypi-group/simple"
publish-url = "https://nexus.thpeetz.de/repository/pypi-internal/"
default = true
[[tool.uv.index]]
name = "nexus-proxy"
url = "https://nexus.thpeetz.de/repository/pypi-proxy/simple"
+7
View File
@@ -18,6 +18,7 @@ from src.apis.version1.comics import (
from src.apis.version1.media import ( from src.apis.version1.media import (
actor, actor,
file, file,
lofi,
mediaactorfile, mediaactorfile,
mediavideo, mediavideo,
mediaarticle, mediaarticle,
@@ -104,6 +105,12 @@ api_router.include_router(
tags=["media"], tags=["media"],
dependencies=[Depends(get_current_user_from_token)], dependencies=[Depends(get_current_user_from_token)],
) )
api_router.include_router(
lofi.router,
prefix="/media",
tags=["media"],
dependencies=[Depends(get_current_user_from_token)],
)
api_router.include_router( api_router.include_router(
mediaarticle.router, mediaarticle.router,
prefix="/media", prefix="/media",
+2 -2
View File
@@ -9,8 +9,8 @@ from src.core.security import (
authenticate_user_by_username, authenticate_user_by_username,
create_access_token, create_access_token,
) )
from src.schema.admin.login import LoginRequest from kontor_model.schema.admin.login import LoginRequest
from src.schema.admin.token import Token from kontor_model.schema.admin.token import Token
from src.webapps.auth.forms import LoginForm from src.webapps.auth.forms import LoginForm
login_router = APIRouter() login_router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.admin import MailAccount from kontor_model.db.models.admin import MailAccount
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.admin.mailaccount import MailAccountResponse, to_response from kontor_model.schema.admin.mailaccount import MailAccountResponse, to_response
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter from fastapi import APIRouter
from src.db.models.bookshelf import Article from kontor_model.db.models.bookshelf import Article
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.bookshelf.article import ArticleResponse, to_response from kontor_model.schema.bookshelf.article import ArticleResponse, to_response
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter from fastapi import APIRouter
from src.db.models.bookshelf import ArticleAuthor from kontor_model.db.models.bookshelf import ArticleAuthor
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.bookshelf.articleauthor import ArticleAuthorResponse, to_response from kontor_model.schema.bookshelf.articleauthor import ArticleAuthorResponse, to_response
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.bookshelf import Author from kontor_model.db.models.bookshelf import Author
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.bookshelf.author import AuthorResponse, to_response from kontor_model.schema.bookshelf.author import AuthorResponse, to_response
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter from fastapi import APIRouter
from src.db.models.bookshelf import Book from kontor_model.db.models.bookshelf import Book
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.bookshelf.book import BookResponse, to_response from kontor_model.schema.bookshelf.book import BookResponse, to_response
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter from fastapi import APIRouter
from src.db.models.bookshelf import BookAuthor from kontor_model.db.models.bookshelf import BookAuthor
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.bookshelf.bookauthor import BookAuthorResponse, to_response from kontor_model.schema.bookshelf.bookauthor import BookAuthorResponse, to_response
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter from fastapi import APIRouter
from src.db.models.bookshelf import BookshelfPublisher from kontor_model.db.models.bookshelf import BookshelfPublisher
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.bookshelf.publisher import PublisherResponse, to_response from kontor_model.schema.bookshelf.publisher import PublisherResponse, to_response
router = APIRouter() router = APIRouter()
@@ -2,11 +2,11 @@ from typing import List
from fastapi import APIRouter, HTTPException, status from fastapi import APIRouter, HTTPException, status
from src.db.models.comic import Artist from kontor_model.db.models.comic import Artist
from src.db.repository.comics.artist import get_artist_details from kontor_model.db.repository.comics.artist import get_artist_details
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.comics.artist import ArtistCreation, ArtistResponse, artist_to_response from kontor_model.schema.comics.artist import ArtistCreation, ArtistResponse, artist_to_response
from src.schema.comics.artist_details import ArtistDetailResponse from kontor_model.schema.comics.artist_details import ArtistDetailResponse
router = APIRouter() router = APIRouter()
+4 -4
View File
@@ -3,13 +3,13 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.core.log_conf import logger from src.core.log_conf import logger
from src.db.models.comic import Comic from kontor_model.db.models.comic import Comic
from src.db.repository.comics.comic import ( from kontor_model.db.repository.comics.comic import (
get_comic_details, get_comic_details,
) )
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.comics.comic import ComicResponse, comic_to_response from kontor_model.schema.comics.comic import ComicResponse, comic_to_response
from src.schema.comics.comic_details import ComicDetailsResponse from kontor_model.schema.comics.comic_details import ComicDetailsResponse
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.comic import ComicWork from kontor_model.db.models.comic import ComicWork
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.comics.comicwork import ComicWorkResponse, comicwork_to_response from kontor_model.schema.comics.comicwork import ComicWorkResponse, comicwork_to_response
router = APIRouter() router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.comic import Issue from kontor_model.db.models.comic import Issue
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.comics.issue import IssueResponse, issue_to_response from kontor_model.schema.comics.issue import IssueResponse, issue_to_response
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.comic import IssueWork from kontor_model.db.models.comic import IssueWork
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.comics.issuework import IssueWorkResponse, issuework_to_response from kontor_model.schema.comics.issuework import IssueWorkResponse, issuework_to_response
router = APIRouter() router = APIRouter()
@@ -2,11 +2,11 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.comic import Publisher from kontor_model.db.models.comic import Publisher
from src.db.repository.comics.publisher import get_publisher_details from kontor_model.db.repository.comics.publisher import get_publisher_details
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.comics.publisher import PublisherResponse, publisher_to_response from kontor_model.schema.comics.publisher import PublisherResponse, publisher_to_response
from src.schema.comics.publisher_details import PublisherDetailsResponse from kontor_model.schema.comics.publisher_details import PublisherDetailsResponse
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.comic import StoryArc from kontor_model.db.models.comic import StoryArc
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.comics.storyarc import StoryArcResponse, storyarc_to_response from kontor_model.schema.comics.storyarc import StoryArcResponse, storyarc_to_response
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.comic import Volume from kontor_model.db.models.comic import Volume
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.comics.volume import VolumeResponse, volume_to_response from kontor_model.schema.comics.volume import VolumeResponse, volume_to_response
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.comic import WorkType from kontor_model.db.models.comic import WorkType
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.comics.worktype import WorktypeResponse, worktype_to_response from kontor_model.schema.comics.worktype import WorktypeResponse, worktype_to_response
router = APIRouter() router = APIRouter()
+1 -1
View File
@@ -1,6 +1,6 @@
from fastapi import APIRouter, status from fastapi import APIRouter, status
from src.schema.admin.healthcheck import HealthCheck from kontor_model.schema.admin.healthcheck import HealthCheck
health_router = APIRouter() health_router = APIRouter()
+3 -3
View File
@@ -2,10 +2,10 @@ from typing import List
from fastapi import APIRouter, status, HTTPException from fastapi import APIRouter, status, HTTPException
from src.core.log_conf import logger from src.core.log_conf import logger
from src.db.repository.media.actor import delete_mediaactor, import_mediaactor from kontor_model.db.repository.media.actor import delete_mediaactor, import_mediaactor
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.media.actor import MediaActorModel, MediaActorResponse, actor_to_response from kontor_model.schema.media.actor import MediaActorModel, MediaActorResponse, actor_to_response
from src.db.models.media import MediaActor from kontor_model.db.models.media import MediaActor
router = APIRouter() router = APIRouter()
+6 -6
View File
@@ -2,21 +2,21 @@ from typing import List
from fastapi import APIRouter, status, HTTPException from fastapi import APIRouter, status, HTTPException
from src.core.log_conf import logger from src.core.log_conf import logger
from src.db.repository.media.actorfile import ( from kontor_model.db.repository.media.actorfile import (
create_new_mediaactorfile, create_new_mediaactorfile,
delete_mediaactorfile, delete_mediaactorfile,
) )
from src.db.repository.media.file import delete_mediafile, import_mediafile from kontor_model.db.repository.media.file import delete_mediafile, import_mediafile
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.media.actor import MediaActorResponse, actor_to_response from kontor_model.schema.media.actor import MediaActorResponse, actor_to_response
from src.schema.media.actorfile import MediaActorFileResponse, actorfile_to_response from kontor_model.schema.media.actorfile import MediaActorFileResponse, actorfile_to_response
from src.schema.media.file import ( from kontor_model.schema.media.file import (
MediaFileModel, MediaFileModel,
MediaFileResponse, MediaFileResponse,
file_to_response, file_to_response,
file_to_model, file_to_model,
) )
from src.db.models.media import MediaFile from kontor_model.db.models.media import MediaFile
router = APIRouter() router = APIRouter()
@@ -0,0 +1,91 @@
from typing import List
from fastapi import APIRouter, status, HTTPException
from kontor_model.db.models.media import MediaLofi
from src.db.session import SessionDep
from src.core.log_conf import logger
from kontor_model.schema.media.lofi import (
MediaLofiModel,
MediaLofiResponse,
lofi_to_response,
lofi_to_model
)
from kontor_model.db.repository.media.lofi import (
import_medialofi,
delete_medialofi
)
router = APIRouter()
@router.get("/lofi", response_model=List[MediaLofiResponse])
def get_all_lofis(
db: SessionDep, review: bool = False, download: bool = False
) -> List[MediaLofiResponse]:
"""
Get all MediaLofis.
"""
results: List[MediaLofiResponse] = []
lofis: List[MediaLofi]
if review:
lofis = db.query(MediaLofi).filter(MediaLofi.review.is_(True)).all()
elif download:
lofis = db.query(MediaLofi).filter(MediaLofi.should_download.is_(True)).all()
else:
lofis = db.query(MediaLofi).all()
for medialofi in lofis:
response = lofi_to_response(medialofi)
results.append(response)
return results
@router.get("/lofi/{lofi_id}", response_model=MediaLofiResponse)
def get_lofi(lofi_id: str, db: SessionDep) -> MediaLofiResponse:
"""
Get MediaLofi by id.
"""
lofi = db.get(MediaLofi, lofi_id)
if lofi is None:
raise HTTPException(status_code=404, detail="MediaLofi could not be found")
response = lofi_to_response(lofi)
return response
@router.delete("/lofi/{lofi_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_lofi(lofi_id: str, db: SessionDep):
"""
Delete MediaFile by given id.
"""
lofi = db.get(MediaLofi, lofi_id)
if not lofi:
raise HTTPException(status_code=404, detail="MediaLofi could not be found")
logger.info("delete MediaLofi: %s", lofi_id)
delete_medialofi(db=db, lofi_id=lofi.id)
@router.put("/lofi/{lofi_id}", response_model=MediaLofiResponse)
def update_lofi(lofi_id: str, db: SessionDep, info: MediaLofiResponse) -> MediaLofiResponse:
"""
Update MediaLofi with given id and data.
"""
media_lofi = db.get(MediaLofi, lofi_id)
if not media_lofi:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="MediaLofi could not be found")
lofi_to_model(info, media_lofi)
db.add(media_lofi)
db.commit()
media_lofi = db.get(MediaLofi, lofi_id)
if not media_lofi:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="MediaLofi could not be found")
response = lofi_to_response(media_lofi)
return response
@router.post("/lofi", status_code=status.HTTP_201_CREATED)
def add_lofi(new_lofi: MediaLofiModel, db: SessionDep) -> MediaLofiResponse:
logger.info("add medialofi %s", new_lofi)
try:
medialofi: MediaLofi = import_medialofi(db, new_lofi)
except:
raise HTTPException(status_code=409, detail="MediaLofi duplicate")
response = lofi_to_response(medialofi)
return response
@@ -1,10 +1,10 @@
from typing import List from typing import List
from fastapi import APIRouter, status, HTTPException from fastapi import APIRouter, status, HTTPException
from src.core.log_conf import logger from src.core.log_conf import logger
from src.db.models.media import MediaActorFile from kontor_model.db.models.media import MediaActorFile
from src.db.repository.media.actorfile import delete_mediaactorfile, import_mediaactorfile from kontor_model.db.repository.media.actorfile import delete_mediaactorfile, import_mediaactorfile
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.media.actorfile import MediaActorFileModel, MediaActorFileResponse, actorfile_to_response from kontor_model.schema.media.actorfile import MediaActorFileModel, MediaActorFileResponse, actorfile_to_response
router = APIRouter() router = APIRouter()
@@ -3,9 +3,9 @@ from typing import List
from fastapi import APIRouter from fastapi import APIRouter
from src.db.models.media import MediaArticle from kontor_model.db.models.media import MediaArticle
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.media.article import MediaArticleResponse, to_response from kontor_model.schema.media.article import MediaArticleResponse, to_response
router = APIRouter() router = APIRouter()
@@ -3,9 +3,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.media import MediaVideo from kontor_model.db.models.media import MediaVideo
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.media.video import MediaVideoResponse, video_to_response from kontor_model.schema.media.video import MediaVideoResponse, video_to_response
router = APIRouter() router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.tysc import Card from kontor_model.db.models.tysc import Card
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.tysc.card import CardResponse, to_response from kontor_model.schema.tysc.card import CardResponse, to_response
router = APIRouter() router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.tysc import CardSet from kontor_model.db.models.tysc import CardSet
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.tysc.cardset import CardSetResponse, to_response from kontor_model.schema.tysc.cardset import CardSetResponse, to_response
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.tysc import FieldPosition from kontor_model.db.models.tysc import FieldPosition
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.tysc.fieldposition import FieldPositionResponse, to_response from kontor_model.schema.tysc.fieldposition import FieldPositionResponse, to_response
router = APIRouter() router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.tysc import Player from kontor_model.db.models.tysc import Player
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.tysc.player import PlayerResponse, to_response from kontor_model.schema.tysc.player import PlayerResponse, to_response
router = APIRouter() router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.tysc import Rooster from kontor_model.db.models.tysc import Rooster
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.tysc.rooster import RoosterResponse, to_response from kontor_model.schema.tysc.rooster import RoosterResponse, to_response
router = APIRouter() router = APIRouter()
+2 -2
View File
@@ -3,8 +3,8 @@ from fastapi import APIRouter, HTTPException
from src.core.log_conf import logger from src.core.log_conf import logger
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.tysc.sport import SportResponse, to_response from kontor_model.schema.tysc.sport import SportResponse, to_response
from src.db.models.tysc import Sport from kontor_model.db.models.tysc import Sport
router = APIRouter() router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.tysc import Team from kontor_model.db.models.tysc import Team
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.tysc.team import TeamResponse, to_response from kontor_model.schema.tysc.team import TeamResponse, to_response
router = APIRouter() router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.tysc import Vendor from kontor_model.db.models.tysc import Vendor
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.tysc.vendor import VendorResponse, to_response from kontor_model.schema.tysc.vendor import VendorResponse, to_response
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.admin import Assignment from kontor_model.db.models.admin import Assignment
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.user.assignment import AssignmentResponse, to_response from kontor_model.schema.user.assignment import AssignmentResponse, to_response
router = APIRouter() router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from src.db.models.admin import Permission from kontor_model.db.models.admin import Permission
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.user.permission import PermissionResponse, to_response from kontor_model.schema.user.permission import PermissionResponse, to_response
router = APIRouter() router = APIRouter()
+2 -2
View File
@@ -4,10 +4,10 @@ from sqlalchemy import select
from src.core.log_conf import logger from src.core.log_conf import logger
from src.core.security import CurrentUser from src.core.security import CurrentUser
from src.db.models.admin import Profile from kontor_model.db.models.admin import Profile
from src.db.repository.user import create_new_profile from src.db.repository.user import create_new_profile
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.user.profile import ProfileResponse, ProfileModel, to_response from kontor_model.schema.user.profile import ProfileResponse, ProfileModel, to_response
router = APIRouter() router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
from fastapi import APIRouter from fastapi import APIRouter
from src.db.models.admin import Token from kontor_model.db.models.admin import Token
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.user.token import TokenResponse, to_response from kontor_model.schema.user.token import TokenResponse, to_response
router = APIRouter() router = APIRouter()
+9 -5
View File
@@ -9,17 +9,21 @@ load_dotenv(dotenv_path=env_path)
class Settings: class Settings:
PROJECT_NAME: str = "Kontor" PROJECT_NAME: str = "Kontor"
PROJECT_VERSION: str = "0.3.0" PROJECT_VERSION: str = "0.4.0"
DB_USER: str = os.getenv("DB_USER", "kontor") DB_USER: str = os.getenv("DB_USER", "kontor")
DB_PASSWORD: str = os.getenv("DB_PASSWORD", "kontor") DB_PASSWORD: str = os.getenv("DB_PASSWORD", "kontor")
DB_SERVER: str = os.getenv("DB_SERVER", "postgres") DB_SERVER: str = os.getenv("DB_SERVER", "postgres")
DB_PORT: int = int(os.getenv("DB_PORT", 5432)) DB_PORT: int = int(os.getenv("DB_PORT", 5432))
DB_DBNAME: str = os.getenv("DB_DBNAME", "kontor") DB_DBNAME: str = os.getenv("DB_DBNAME", "kontor")
DATABASE_URL: str = f"postgresql://{DB_USER}:{DB_PASSWORD}@{DB_SERVER}:{DB_PORT}/{DB_DBNAME}" DATABASE_URL: str = (
SECRET_KEY: str = os.getenv("SECRET_KEY", "J6GOtcwC2NJI1l0VkHu20PacPFGTxpirBxWwynoHjsc=") f"postgresql://{DB_USER}:{DB_PASSWORD}@{DB_SERVER}:{DB_PORT}/{DB_DBNAME}"
)
SECRET_KEY: str = os.getenv(
"SECRET_KEY", "J6GOtcwC2NJI1l0VkHu20PacPFGTxpirBxWwynoHjsc="
)
ALGORITHM = "HS256" ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 60*24*7 # one week in mins ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 7 # one week in mins
settings = Settings() settings = Settings()
+5 -5
View File
@@ -15,15 +15,15 @@ from pydantic import ValidationError
from src.core.config import settings from src.core.config import settings
from src.core.log_conf import logger from src.core.log_conf import logger
from src.db.models.admin import Profile from kontor_model.db.models.admin import Profile
from src.db.repository.admin import ( from kontor_model.db.repository.admin import (
get_profile_by_username, get_profile_by_username,
get_profile_by_email, get_profile_by_email,
is_database_empty, is_database_empty,
) )
from src.db.session import SessionLocal from src.db.session import SessionLocal
from src.schema.admin.token import TokenData from kontor_model.schema.admin.token import TokenData
from src.schema.user.profile import ProfileModel, to_model from kontor_model.schema.user.profile import ProfileModel, to_model
oauth2_scheme = OAuth2PasswordBearer( oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="/token", tokenUrl="/token",
@@ -163,7 +163,7 @@ async def get_current_user(
async def get_current_active_user( async def get_current_active_user(
current_user: Annotated[Profile, Security(get_current_user, scopes=["me"])], current_user: Annotated[Profile, Security(get_current_user, scopes=["me"])],
) -> ProfileModel: ) -> ProfileModel:
if not current_user.enabled: if not bool(current_user.enabled):
raise HTTPException(status_code=400, detail="Inactive user") raise HTTPException(status_code=400, detail="Inactive user")
user_model = to_model(current_user) user_model = to_model(current_user)
return user_model return user_model
-75
View File
@@ -1,75 +0,0 @@
from datetime import datetime
from typing import List
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship, mapped_column, Mapped
from src.db.models.base import Base, BaseMixin
class Profile(Base, BaseMixin):
__tablename__ = 'profile'
first_name: Mapped[str]
last_name: Mapped[str]
user_name: Mapped[str] = mapped_column(nullable=False)
email: Mapped[str]
password: Mapped[str]
enabled: Mapped[bool]
assignments: Mapped[List["Assignment"]] = relationship(back_populates="profile")
tokens: Mapped[List["Token"]] = relationship(back_populates="profile")
def get_full_name(self) -> str:
full_name: str = ""
if self.first_name is not None:
full_name += str(self.first_name)
if self.last_name is not None:
if len(full_name) > 0:
full_name += " "
full_name += str(self.last_name)
return full_name
def __str__(self):
return f"Profile({self.id} {self.user_name}, {self.email})"
class Token(Base, BaseMixin):
__tablename__ = "token"
token: Mapped[str] = mapped_column(nullable=False, unique=True)
name: Mapped[str]
last_used_date: Mapped[datetime]
enabled: Mapped[bool]
profile_id = mapped_column(ForeignKey("profile.id"), nullable=False)
profile: Mapped[Profile] = relationship(back_populates="tokens")
class Permission(Base, BaseMixin):
__tablename__ = "permission"
name: Mapped[str] = mapped_column(nullable=False)
assignments: Mapped[List["Assignment"]] = relationship(back_populates="permission")
class Assignment(Base, BaseMixin):
__tablename__ = "assignment"
profile_id = mapped_column(ForeignKey("profile.id"), nullable=False)
profile: Mapped[Profile] = relationship(back_populates="assignments")
permission_id = mapped_column(ForeignKey("permission.id"), nullable=False)
permission: Mapped[Permission] = relationship(back_populates="assignments")
class MailAccount(Base, BaseMixin):
__tablename__ = "mail_account"
host: Mapped[str]
port: Mapped[int]
protocol: Mapped[str]
user_name: Mapped[str]
password: Mapped[str]
start_tls: Mapped[bool]
class Mail(Base, BaseMixin):
__tablename__ = "mail"
folder: Mapped[str]
subject: Mapped[str]
body: Mapped[str]
sent_date: Mapped[datetime]
received_date: Mapped[datetime]
-27
View File
@@ -1,27 +0,0 @@
from typing import Optional
import uuid
from datetime import datetime
from sqlalchemy import func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class BaseMixin:
id: Mapped[str] = mapped_column(primary_key=True, default=str(uuid.uuid4()))
created_date: Mapped[datetime] = mapped_column(default=func.now())
last_modified_date: Mapped[datetime] = mapped_column(default=func.now())
version: Mapped[int] = mapped_column(default=0)
class BaseVideoMixin:
cloud_link: Mapped[Optional[str]]
file_name: Mapped[Optional[str]]
path: Mapped[str]
review: Mapped[bool]
title: Mapped[str]
url: Mapped[str]
should_download: Mapped[bool]
-52
View File
@@ -1,52 +0,0 @@
from typing import List
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import Mapped, mapped_column, relationship
from src.db.models.base import Base, BaseMixin
class Article(Base, BaseMixin):
__tablename__ = 'article'
title: Mapped[str] = mapped_column(unique=True)
article_authors = relationship("ArticleAuthor")
class Author(Base, BaseMixin):
__tablename__ = 'author'
first_name: Mapped[str]
last_name: Mapped[str]
article_authors: Mapped[List["ArticleAuthor"]] = relationship(back_populates="author")
book_authors: Mapped[List["BookAuthor"]] = relationship(back_populates="author")
class BookshelfPublisher(Base, BaseMixin):
__tablename__ = 'bookshelf_publisher'
name: Mapped[str] = mapped_column(unique=True)
books: Mapped[List["Book"]] = relationship(back_populates="publisher")
class Book(Base, BaseMixin):
__tablename__ = 'book'
isbn: Mapped[str] = mapped_column(unique=True)
title: Mapped[str]
year: Mapped[int] = mapped_column(nullable=False)
publisher_id: Mapped[str] = mapped_column(ForeignKey("bookshelf_publisher.id"), nullable=False)
publisher: Mapped[BookshelfPublisher] = relationship(back_populates="books")
book_authors: Mapped[List["BookAuthor"]] = relationship(back_populates="book")
class ArticleAuthor(Base, BaseMixin):
__tablename__ = 'article_author'
article_id: Mapped[str] = mapped_column(ForeignKey("article.id"), nullable=False)
article: Mapped[Article] = relationship(back_populates="article_authors")
author_id: Mapped[str] = mapped_column(ForeignKey("author.id"), nullable=False)
author: Mapped[Author] = relationship(back_populates="article_authors")
class BookAuthor(Base, BaseMixin):
__tablename__ = 'book_author'
author_id: Mapped[str] = mapped_column(ForeignKey("author.id"), nullable=False)
author: Mapped[Author] = relationship(back_populates="book_authors")
book_id: Mapped[str] = mapped_column(ForeignKey("book.id"), nullable=False)
book: Mapped[Book] = relationship(back_populates="book_authors")
-188
View File
@@ -1,188 +0,0 @@
import uuid
from datetime import datetime
from typing import Dict, List, Optional, Any
from natsort import natsorted
from sqlalchemy import ForeignKey, func
from sqlalchemy.orm import relationship, Mapped, mapped_column
from src.db.models.base import Base, BaseMixin
class Publisher(Base):
__tablename__ = "publisher"
id: Mapped[str] = mapped_column(primary_key=True, default=uuid.uuid4)
created_date: Mapped[datetime] = mapped_column(default=func.now())
last_modified_date: Mapped[datetime] = mapped_column(default=func.now())
version: Mapped[int] = mapped_column(default=0)
name: Mapped[str] = mapped_column(unique=True)
weblink: Mapped[Optional[str]]
parent_publisher_id: Mapped[Optional[str]] = mapped_column(ForeignKey('publisher.id'))
parent_publisher: Mapped[Optional['Publisher']] = relationship(back_populates="imprints", remote_side=[id])
imprints: Mapped[List['Publisher']] = relationship(back_populates="parent_publisher")
comics: Mapped[List["Comic"]] = relationship(back_populates="publisher")
def __repr__(self):
return f'Publisher({self.id} {self.name})'
def __str__(self):
return self.__repr__()
class Comic(Base, BaseMixin):
__tablename__ = 'comic'
title: Mapped[str] = mapped_column(unique=True)
publisher_id: Mapped[str] = mapped_column(ForeignKey('publisher.id'), nullable=False)
publisher: Mapped[Publisher] = relationship(back_populates="comics")
current_order: Mapped[bool]
completed: Mapped[bool]
weblink: Mapped[Optional[str]]
issues: Mapped[List["Issue"]] = relationship(back_populates="comic", order_by="Issue.issue_number")
story_arcs: Mapped[List["StoryArc"]] = relationship(back_populates="comic")
trade_paperbacks: Mapped[List["TradePaperback"]] = relationship(back_populates="comic")
volumes: Mapped[List["Volume"]] = relationship(back_populates="comic")
comic_works: Mapped[List["ComicWork"]] = relationship(back_populates="comic")
def __repr__(self):
return f'Comic({self.id} {self.version} {self.title} {self.publisher.name})'
def __str__(self):
return f'{self.title}({self.id})'
def get_artists(self) -> Dict[Any, List[Any]]:
works: Dict[Any, List[Any]] = {}
for work in self.comic_works:
work_type = work.work_type
artist = work.artist
if work_type in works:
works[work_type].append(artist)
else:
works[work_type] = [artist]
return works
def sorted_issues(self):
sorted_issues = natsorted(self.issues, key=lambda x: getattr(x, 'issue_number'))
return sorted_issues
class Volume(Base, BaseMixin):
__tablename__ = "volume"
name: Mapped[str] = mapped_column(nullable=False)
comic_id: Mapped[str] = mapped_column(ForeignKey("comic.id"), nullable=False)
comic: Mapped[Comic] = relationship(back_populates="volumes")
story_arcs: Mapped[List["StoryArc"]] = relationship(back_populates="volume")
issues: Mapped[List["Issue"]] = relationship(back_populates="volume")
class TradePaperback(Base, BaseMixin):
__tablename__ = "trade_paperback"
name: Mapped[str] = mapped_column(nullable=False)
issue_start: Mapped[int]
issue_end: Mapped[int]
comic_id: Mapped[str] = mapped_column(ForeignKey("comic.id"), nullable=False)
comic: Mapped[Comic] = relationship(back_populates="trade_paperbacks")
class StoryArc(Base, BaseMixin):
__tablename__ = "story_arc"
name: Mapped[str] = mapped_column(nullable=False)
comic_id: Mapped[str] = mapped_column(ForeignKey("comic.id"), nullable=False)
comic: Mapped[Comic] = relationship(back_populates="story_arcs")
volume_id: Mapped[str] = mapped_column(ForeignKey("volume.id"), nullable=True)
volume: Mapped[Volume] = relationship(back_populates="story_arcs")
issues: Mapped[List["Issue"]] = relationship(back_populates="story_arc")
class Issue(Base, BaseMixin):
__tablename__ = "issue"
issue_number: Mapped[str]
title: Mapped[Optional[str]]
published_on: Mapped[Optional[datetime]]
in_stock: Mapped[bool]
is_read: Mapped[bool]
comic_id: Mapped[str] = mapped_column(ForeignKey("comic.id"), nullable=False)
comic: Mapped[Comic] = relationship(back_populates="issues")
volume_id: Mapped[str] = mapped_column(ForeignKey("volume.id"), nullable=True)
volume: Mapped[Volume] = relationship(back_populates="issues")
story_arc_id: Mapped[str] = mapped_column(ForeignKey("story_arc.id"), nullable=True)
story_arc: Mapped[StoryArc] = relationship(back_populates="issues")
issue_works: Mapped[List["IssueWork"]] = relationship(back_populates="issue")
def get_full_title(self) -> str:
full_title: str = str(self.issue_number)
if self.title:
full_title += str(": " + self.title)
return full_title
def get_artists(self) -> Dict[Any, List[Any]]:
works: Dict[Any, List[Any]] = {}
for work in self.issue_works:
work_type = work.work_type
artist = work.artist
if work_type in works:
works[work_type].append(artist)
else:
works[work_type] = [artist]
return works
class Artist(Base, BaseMixin):
__tablename__ = "artist"
name: Mapped[str] = mapped_column(nullable=False)
weblink: Mapped[str] = mapped_column(nullable=True)
comic_works: Mapped[List["ComicWork"]] = relationship(back_populates="artist")
issue_works: Mapped[List["IssueWork"]] = relationship(back_populates="artist")
def get_comics(self) -> Dict[Any, List[Comic]]:
works: Dict[Any, List[Comic]] = {}
for work in self.comic_works:
work_type = work.work_type
comic = work.comic
if work_type in works:
works[work_type].append(comic)
else:
works[work_type] = [comic]
return works
class WorkType(Base, BaseMixin):
__tablename__ = "worktype"
name: Mapped[str] = mapped_column(nullable=False, unique=True)
comic_works: Mapped[List["ComicWork"]] = relationship(back_populates="work_type")
issue_works: Mapped[List["IssueWork"]] = relationship(back_populates="work_type")
def get_artists(self) -> Dict[str, List[Artist]]:
works: Dict[str, List[Artist]] = {}
for work in self.comic_works:
comic = work.comic.title
artist = work.artist
if comic in works:
works[comic].append(artist)
else:
works[comic] = [artist]
return works
def __repr__(self):
return f'Worktype({self.id} {self.version} {self.name} {len(self.comic_works)})'
def __str__(self):
return f'{self.name}({self.id})'
class ComicWork(Base, BaseMixin):
__tablename__ = "comic_work"
comic_id: Mapped[str] = mapped_column(ForeignKey("comic.id"), nullable=False)
comic: Mapped[Comic] = relationship(back_populates="comic_works")
artist_id: Mapped[str] = mapped_column(ForeignKey("artist.id"), nullable=False)
artist: Mapped[Artist] = relationship(back_populates="comic_works")
work_type_id: Mapped[str] = mapped_column(ForeignKey("worktype.id"), nullable=False)
work_type: Mapped[WorkType] = relationship(back_populates="comic_works")
class IssueWork(Base, BaseMixin):
__tablename__ = "issue_work"
issue_id: Mapped[str] = mapped_column(ForeignKey("issue.id"), nullable=False)
issue: Mapped[Issue] = relationship(back_populates="issue_works")
artist_id: Mapped[str] = mapped_column(ForeignKey("artist.id"), nullable=False)
artist: Mapped[Artist] = relationship(back_populates="issue_works")
work_type_id: Mapped[str] = mapped_column(ForeignKey("worktype.id"), nullable=False)
work_type: Mapped[WorkType] = relationship(back_populates="issue_works")
-97
View File
@@ -1,97 +0,0 @@
import logging
import re
import subprocess
from datetime import datetime
from pathlib import Path
from typing import List, Optional
import requests
from bs4 import BeautifulSoup
from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, relationship, mapped_column
from src.db.models.base import Base, BaseMixin, BaseVideoMixin
class MediaFile(Base, BaseMixin, BaseVideoMixin):
"""
MediaFile represents video link.
"""
__tablename__ = "media_file"
media_actor_files: Mapped[List["MediaActorFile"]] = relationship(
back_populates="media_file"
)
def __repr__(self):
return f"MediaFile({self.id} {self.title} {self.title})"
def __str__(self):
return f"{self.title}({self.id})"
def update_title(self):
"""
Update title from url.
"""
class MediaActor(Base, BaseMixin):
__tablename__ = "media_actor"
name: Mapped[str]
url: Mapped[Optional[str]] = mapped_column(unique=True)
media_actor_files = relationship("MediaActorFile")
def __repr__(self) -> str:
return f"MediaActor({self.id} {self.name} {self.url})"
def __str__(self) -> str:
return f"{self.url}({self.id})"
class MediaActorFile(Base, BaseMixin):
__tablename__ = "media_actor_file"
media_actor_id: Mapped[str] = mapped_column(
ForeignKey("media_actor.id"), nullable=False
)
media_actor: Mapped[MediaActor] = relationship(back_populates="media_actor_files")
media_file_id: Mapped[str] = mapped_column(
ForeignKey("media_file.id"), nullable=True
)
media_file: Mapped[MediaFile] = relationship(back_populates="media_actor_files")
def __repr__(self):
return f"MediaActorFile({self.id} {self.media_actor_id} {self.media_file_id})"
def __str__(self) -> str:
return f"{self.id} {self.media_actor_id} {self.media_file_id}"
class MediaArticle(Base, BaseMixin):
__tablename__ = "media_article"
review: Mapped[bool]
title: Mapped[str]
url: Mapped[str] = mapped_column(unique=True)
class MediaVideo(Base, BaseMixin):
"""
MediaFile represents video link.
"""
__tablename__ = "media_video"
cloud_link: Mapped[str]
file_name: Mapped[str]
path: Mapped[str]
review: Mapped[bool]
title: Mapped[str]
url: Mapped[str] = mapped_column(unique=True)
should_download: Mapped[bool]
def __repr__(self):
return f"MediaFile({self.id} {self.title} {self.url})"
def __str__(self):
if self.title is None:
return f"{self.url}({self.id})"
else:
return f"{self.title}({self.id})"
-100
View File
@@ -1,100 +0,0 @@
from typing import List
from sqlalchemy import ForeignKey, UniqueConstraint
from sqlalchemy.orm import relationship, mapped_column, Mapped
from src.db.models.base import Base, BaseMixin
class Sport(Base, BaseMixin):
__tablename__ = "sport"
__table_args__ = (
UniqueConstraint("name"),
)
name: Mapped[str] = mapped_column(nullable=False, index=True, unique=True)
teams: Mapped[List["Team"]] = relationship(back_populates="sport")
positions: Mapped[List["FieldPosition"]] = relationship(back_populates="sport")
class Team(Base, BaseMixin):
__tablename__ = "team"
name: Mapped[str] = mapped_column(nullable=False, index=True, unique=True)
short_name: Mapped[str] = mapped_column(nullable=False)
sport_id: Mapped[str] = mapped_column(ForeignKey("sport.id"), nullable=False)
sport: Mapped[Sport] = relationship(back_populates="teams")
roosters: Mapped[List["Rooster"]] = relationship(back_populates="team")
class FieldPosition(Base, BaseMixin):
__tablename__ = "field_position"
__table_args__ = (
UniqueConstraint("name", "sport_id"),
UniqueConstraint("short_name", "sport_id"),
)
name: Mapped[str] = mapped_column(nullable=False, index=True)
short_name: Mapped[str] = mapped_column(nullable=False)
sport_id: Mapped[str] = mapped_column(ForeignKey("sport.id"), nullable=False, index=True)
sport: Mapped[Sport] = relationship(back_populates="positions")
roosters: Mapped[List["Rooster"]] = relationship(back_populates="position")
class Player(Base, BaseMixin):
__tablename__ = "player"
__table_args__ = (
UniqueConstraint("first_name", "last_name"),
)
first_name: Mapped[str] = mapped_column(nullable=False, index=True)
last_name: Mapped[str] = mapped_column(nullable=False, index=True)
roosters: Mapped[List["Rooster"]] = relationship(back_populates="player")
def get_full_name(self) -> str:
return f"{self.last_name}, {self.first_name}"
class Rooster(Base, BaseMixin):
__tablename__ = "rooster"
__table_args__ = (
UniqueConstraint("year", "team_id", "player_id", "position_id"),
)
year: Mapped[int]
team_id: Mapped[str] = mapped_column(ForeignKey("team.id"), nullable=False, index=True)
team: Mapped[Team] = relationship(back_populates="roosters")
player_id: Mapped[str] = mapped_column(ForeignKey("player.id"), nullable=False, index=True)
player: Mapped[Player] = relationship(back_populates="roosters")
position_id: Mapped[str] = mapped_column(ForeignKey("field_position.id"), nullable=False, index=True)
position: Mapped[FieldPosition] = relationship(back_populates="roosters")
cards: Mapped[List["Card"]] = relationship(back_populates="rooster")
class Vendor(Base, BaseMixin):
__tablename__ = "vendor"
name: Mapped[str] = mapped_column(nullable=False, unique=True, index=True)
card_sets: Mapped[List["CardSet"]] = relationship(back_populates="vendor")
cards: Mapped[List["Card"]] = relationship(back_populates="vendor")
class CardSet(Base, BaseMixin):
__tablename__ = "card_set"
__table_args__ = (
UniqueConstraint("name", "vendor_id"),
)
name: Mapped[str] = mapped_column(index=True)
parallel_set: Mapped[bool]
insert_set: Mapped[bool]
vendor_id: Mapped[str] = mapped_column(ForeignKey("vendor.id"), nullable=False, index=True)
vendor: Mapped[Vendor] = relationship(back_populates="card_sets")
cards: Mapped[List["Card"]] = relationship(back_populates="card_set")
class Card(Base, BaseMixin):
__tablename__ = "card"
__table_args__ = (
UniqueConstraint("card_number", "year", "vendor_id", "card_set_id"),
)
card_number: Mapped[int] = mapped_column(index=True)
year: Mapped[int] = mapped_column(index=True)
card_set_id: Mapped[str] = mapped_column(ForeignKey("card_set.id"), nullable=False)
card_set: Mapped[CardSet] = relationship(back_populates="cards")
rooster_id: Mapped[str] = mapped_column(ForeignKey("rooster.id"), nullable=False)
rooster: Mapped[Rooster] = relationship(back_populates="cards")
vendor_id: Mapped[str] = mapped_column(ForeignKey("vendor.id"), nullable=False)
vendor: Mapped[Vendor] = relationship(back_populates="cards")
@@ -1,24 +0,0 @@
from typing import List
from src.db.models.comic import Publisher
from src.schema.comics.comic import ComicResponse
from src.schema.comics.publisher import PublisherResponse
from src.schema.comics.publisher_details import PublisherDetailsResponse
def get_publisher_details(publisher: Publisher) -> PublisherDetailsResponse:
imprints: List[PublisherResponse] = []
for imprint in publisher.imprints:
imprints.append(PublisherResponse(id=imprint.id, name=str(imprint.name)))
comics: List[ComicResponse] = []
for comic in publisher.comics:
comics.append(
ComicResponse(id=comic.id, title=comic.title, completed=comic.completed)
)
parent_publisher: PublisherResponse | None = None
if publisher.parent_publisher:
parent_publisher = PublisherResponse(id=publisher.parent_publisher.id, name=str(publisher.parent_publisher.name))
response: PublisherDetailsResponse = PublisherDetailsResponse(
id=publisher.id, name=str(publisher.name), parent_publisher=parent_publisher, imprints=imprints, comics=comics
)
return response
+2 -2
View File
@@ -2,10 +2,10 @@ from datetime import datetime
from typing import Optional from typing import Optional
import uuid import uuid
from src.core.log_conf import logger from src.core.log_conf import logger
from src.db.models.admin import Assignment, Profile from kontor_model.db.models.admin import Assignment, Profile
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from src.schema.user.profile import ProfileModel from kontor_model.schema.user.profile import ProfileModel
def create_new_profile(new_profile: ProfileModel, db: Session) -> Profile: def create_new_profile(new_profile: ProfileModel, db: Session) -> Profile:
+1 -1
View File
@@ -10,7 +10,7 @@ from src.apis.version1.admin.login import login_router
from src.core.config import settings from src.core.config import settings
from src.core.log_conf import logger from src.core.log_conf import logger
from src.core.middleware import RequestLoggingMiddleware from src.core.middleware import RequestLoggingMiddleware
from src.db.models.base import Base from kontor_model.db.models.base import Base
from src.db.session import engine from src.db.session import engine
from src.db.utils import check_db_connected, check_db_disconnected from src.db.utils import check_db_connected, check_db_disconnected
from src.webapps.base import api_router as web_app_router from src.webapps.base import api_router as web_app_router
@@ -0,0 +1,29 @@
{% extends "shared/base.html" %}
{% block title %}
<title>Add a Lofi Link</title>
{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="text-danger font-weight-bold">
{% for error in errors %}
<li>{{error}}</li>
{% endfor %}
</div>
</div>
<div class="row my-5">
<h3 class="text-center display-4">Add a Lofi Link</h3>
<form method="POST">
<div class="mb-3">
<input type="text" required class="form-control" name="url" value="{{url}}" placeholder="Lofi Link here">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
{% endblock %}
@@ -0,0 +1,51 @@
{% extends "shared/base.html" %}
{% block title %}
<title>MediaLofi Detail</title>
{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="col">
<h1 class="display-5">MediaLofi Detail</h1>
</div>
</div>
<div class="row">
<table class="table table-striped table-hover">
<tbody>
<tr>
<th scope="row">MediaLofi Title</th>
<td colspan="2">{{medialofi.title}}</td>
</tr>
<tr>
<th scope="row">MediaLofi URL</th>
<td colspan="2">{{medialofi.url}}</td>
</tr>
<tr>
<th scope="row">MediaLofi Download?</th>
<td colspan="2">{{medialofi.should_download}}</td>
</tr>
<tr>
<th scope="row">MediaLofi Review?</th>
<td colspan="2">{{medialofi.review}}</td>
</tr>
<tr>
<th scope="row">Data Created</th>
<td colspan="2">{{medialofi.created_date}}</td>
</tr>
<tr>
<th scope="row">Data Modified</th>
<td colspan="2">{{medialofi.last_modified_date}}</td>
</tr>
<tr>
<th scope="row">Data Version</th>
<td colspan="2">{{medialofi.version}}</td>
</tr>
</tbody>
</table>
</div>
</div>
{% endblock %}
@@ -0,0 +1,29 @@
{% extends "shared/base.html" %}
{% block title %}
<title>Lofi Links</title>
{% endblock %}
{% block content %}
{% with msg=msg %}
{% include "components/alerts.html" %}
{% endwith %}
<div class="container">
<table class="table table-hover">
<thead><tr>
<th scope="col">Titel</th>
<th scope="col">Review</th>
<th scope="col">Download</th>
</tr></thead>
<tbody>
{% for medialofi in medialofis %}
<tr>
<th scope="row"><a href="/media/lofi/{{medialofi.id}}">{{medialofi.title}}</a></th>
<td>{% with check=medialofi.review %}{% include "components/check.html" %}{% endwith %}</td>
<td>{% with check=medialofi.should_download %}{% include "components/check.html" %}{% endwith %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
@@ -2,4 +2,5 @@
<a href="/media/files/">MediaFiles</a> <a href="/media/files/">MediaFiles</a>
<a href="/media/actors/">MediaActors</a> <a href="/media/actors/">MediaActors</a>
<a href="/media/videos/">MediaVideos</a> <a href="/media/videos/">MediaVideos</a>
<a href="/media/lofi/">MediaLofi</a>
</div> </div>
+1 -1
View File
@@ -2,7 +2,7 @@ from typing import Optional
from fastapi import APIRouter, Request from fastapi import APIRouter, Request
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from src.db.models.admin import Permission, Profile from kontor_model.db.models.admin import Permission, Profile
from src.db.session import SessionDep from src.db.session import SessionDep
templates = Jinja2Templates(directory="src/templates") templates = Jinja2Templates(directory="src/templates")
+2 -1
View File
@@ -4,7 +4,7 @@ from fastapi.templating import Jinja2Templates
from src.webapps.admin import route_admin from src.webapps.admin import route_admin
from src.webapps.auth import route_login from src.webapps.auth import route_login
from src.webapps.comic import route_comics, route_worktype, route_artists from src.webapps.comic import route_comics, route_worktype, route_artists
from src.webapps.media import route_actors, route_media, route_videos from src.webapps.media import route_actors, route_lofi, route_media, route_videos
templates = Jinja2Templates(directory="src/templates") templates = Jinja2Templates(directory="src/templates")
@@ -15,6 +15,7 @@ api_router.include_router(route_worktype.router, tags=["webapp"])
api_router.include_router(route_media.router, tags=["webapp"]) api_router.include_router(route_media.router, tags=["webapp"])
api_router.include_router(route_actors.router, tags=["webapp"]) api_router.include_router(route_actors.router, tags=["webapp"])
api_router.include_router(route_videos.router, tags=["webapp"]) api_router.include_router(route_videos.router, tags=["webapp"])
api_router.include_router(route_lofi.router, tags=["webapp"])
api_router.include_router(route_login.router, tags=["webapp"]) api_router.include_router(route_login.router, tags=["webapp"])
api_router.include_router(route_admin.router, tags=["webapp"]) api_router.include_router(route_admin.router, tags=["webapp"])
@@ -2,14 +2,13 @@ from fastapi import APIRouter, Request, status, Form
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from src.db.models.comic import Artist from kontor_model.db.models.comic import Artist
from typing import AnyStr from typing import AnyStr
from src.db.repository.comics.artist import update_artist from kontor_model.db.repository.comics.artist import update_artist
from src.db.session import SessionDep from src.db.session import SessionDep
#from src.db.repository.comic import create_new_worktype, update_worktype #from src.db.repository.comic import create_new_worktype, update_worktype
from src.main import logger from kontor_model.schema.comics.artist import AddArtist
from src.schema.comics.artist import AddArtist
from src.webapps.comic.forms.artist import AddArtistForm from src.webapps.comic.forms.artist import AddArtistForm
#from src.schema.comics.worktype import AddWorkType #from src.schema.comics.worktype import AddWorkType
@@ -35,7 +34,7 @@ def edit_artist(db: SessionDep, request: Request, artist_id: str):
return templates.TemplateResponse("comic/artist_edit.html", {"request": request, "artist_name": artist.name, "artist_link": artist.weblink}) return templates.TemplateResponse("comic/artist_edit.html", {"request": request, "artist_name": artist.name, "artist_link": artist.weblink})
@router.post("/artist/edit/{artist_id}") @router.post("/artist/edit/{artist_id}")
async def edit_artist(request: Request, db: SessionDep, artist_id: str, action: str = Form(...), artist_name: str = Form(...), artist_link: str = Form(...)): async def edit_artist_post(request: Request, db: SessionDep, artist_id: str, action: str = Form(...), artist_name: str = Form(...), artist_link: str = Form(...)):
if action == "cancel": if action == "cancel":
return RedirectResponse(f"/comic/artists/{artist_id}", status_code=status.HTTP_303_SEE_OTHER) return RedirectResponse(f"/comic/artists/{artist_id}", status_code=status.HTTP_303_SEE_OTHER)
form = AddArtistForm(request, artist_id, artist_name, artist_link) form = AddArtistForm(request, artist_id, artist_name, artist_link)
+3 -3
View File
@@ -2,12 +2,12 @@ from fastapi import APIRouter, Form, Request, status
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from src.db.models.comic import Comic, Publisher, Issue from kontor_model.db.models.comic import Comic, Publisher, Issue
from typing import AnyStr from typing import AnyStr
from src.core.log_conf import logger from src.core.log_conf import logger
from src.db.repository.comics.comic import update_comic from kontor_model.db.repository.comics.comic import update_comic
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.comics.comic import ComicSchema from kontor_model.schema.comics.comic import ComicSchema
from src.webapps.comic.forms.comic import ValidateComicForm from src.webapps.comic.forms.comic import ValidateComicForm
templates = Jinja2Templates(directory="src/templates") templates = Jinja2Templates(directory="src/templates")
@@ -2,13 +2,13 @@ from fastapi import APIRouter, Request, status
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from src.db.models.comic import WorkType from kontor_model.db.models.comic import WorkType
from typing import AnyStr from typing import AnyStr
from src.db.repository.comics.worktype import create_new_worktype, update_worktype from kontor_model.db.repository.comics.worktype import create_new_worktype, update_worktype
from src.db.session import SessionDep from src.db.session import SessionDep
from src.main import logger from src.main import logger
from src.schema.comics.worktype import AddWorkType from kontor_model.schema.comics.worktype import AddWorkType
from src.webapps.comic.forms.worktype import AddWorktypeForm from src.webapps.comic.forms.worktype import AddWorktypeForm
templates = Jinja2Templates(directory="src/templates") templates = Jinja2Templates(directory="src/templates")
+1 -1
View File
@@ -2,7 +2,7 @@ from typing import AnyStr
from fastapi import APIRouter, Request from fastapi import APIRouter, Request
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from src.db.models.media import MediaActor from kontor_model.db.models.media import MediaActor
from src.db.session import SessionDep from src.db.session import SessionDep
templates = Jinja2Templates(directory="src/templates") templates = Jinja2Templates(directory="src/templates")
@@ -0,0 +1,51 @@
from typing import Optional
from fastapi import APIRouter, Request, status, responses
from fastapi.security.utils import get_authorization_scheme_param
from fastapi.templating import Jinja2Templates
from src.core.security import get_current_user_from_token
from kontor_model.db.models.media import MediaLofi
from kontor_model.db.models.admin import Profile
from kontor_model.db.repository.media.lofi import create_new_lofi
from src.db.session import SessionDep
from src.webapps.media.forms import AddLinkForm
templates = Jinja2Templates(directory="src/templates")
router = APIRouter(include_in_schema=False, prefix="/media")
@router.get("/lofi")
def get_medialofis(db: SessionDep, request: Request, msg: Optional[str] = None):
medialofis = db.query(MediaLofi).all()
try:
token = request.cookies.get("access_token")
_, param = get_authorization_scheme_param(token) # scheme will hold "Bearer" and param will hold actual token value
current_user: Profile = get_current_user_from_token(token=param)
return templates.TemplateResponse("media/lofi_list.html", {"request": request, "msg": msg, "user": current_user, "medialofis": medialofis})
except Exception as e:
print(e)
return templates.TemplateResponse("media/lofi_list.html", {"request": request, "msg": msg, "user": None, "medialofis": medialofis})
@router.get("/lofi/{lofi_id}")
def lofi_details(lofi_id: str, request: Request, db: SessionDep):
medialofi = db.get(MediaLofi, lofi_id)
return templates.TemplateResponse("media/lofi_detail.html", {"request": request, "medialofi":medialofi})
@router.get("/add-lofi")
def add_lofi_link(request: Request, db: SessionDep):
return templates.TemplateResponse("media/add_lofi_link.html", {"request": request})
@router.post("/add-lofi")
async def post_lofi_link(request: Request, db: SessionDep):
form = AddLinkForm(request)
await form.load_data()
if form.is_valid():
try:
#video = AddLink(**form.__dict__)
medialofi = create_new_lofi(url=str(form.url), db=db)
return responses.RedirectResponse(f"media/lofi/{medialofi.id}", status_code=status.HTTP_302_FOUND)
except Exception as e:
print(e)
form.__dict__.get("errors").append("Link already added")
return templates.TemplateResponse("media/add_lofi_link.html", form.__dict__)
return templates.TemplateResponse("media/add_lofi_link.html", form.__dict__)
+3 -3
View File
@@ -6,8 +6,8 @@ from fastapi.templating import Jinja2Templates
from sqlalchemy import or_ from sqlalchemy import or_
from src.core.security import get_current_user_from_token from src.core.security import get_current_user_from_token
from src.db.models.admin import Profile from kontor_model.db.models.admin import Profile
from src.db.models.media import MediaFile from kontor_model.db.models.media import MediaFile
from src.core.log_conf import logger from src.core.log_conf import logger
from src.db.session import SessionDep from src.db.session import SessionDep
@@ -37,7 +37,7 @@ def get_mediafiles(db: SessionDep, request: Request, msg: str | None = None):
try: try:
token = request.cookies.get("access_token") token = request.cookies.get("access_token")
scheme, param = get_authorization_scheme_param(token) # scheme will hold "Bearer" and param will hold actual token value scheme, param = get_authorization_scheme_param(token) # scheme will hold "Bearer" and param will hold actual token value
current_user: Profile = get_current_user_from_token(token=param) #current_user: Profile = get_current_user_from_token(token=param)
return templates.TemplateResponse("media/files.html", {"request": request, "msg": msg, "mediafiles": mediafiles}) return templates.TemplateResponse("media/files.html", {"request": request, "msg": msg, "mediafiles": mediafiles})
except Exception as e: except Exception as e:
print(e) print(e)
+8 -6
View File
@@ -1,11 +1,13 @@
from typing import Optional
from fastapi import APIRouter, Request, status, responses from fastapi import APIRouter, Request, status, responses
from fastapi.security.utils import get_authorization_scheme_param from fastapi.security.utils import get_authorization_scheme_param
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from src.core.security import get_current_user_from_token from src.core.security import get_current_user_from_token
from src.db.models.media import MediaVideo from kontor_model.db.models.media import MediaVideo
from src.db.models.admin import Profile from kontor_model.db.models.admin import Profile
from src.db.repository.media.video import create_new_video from kontor_model.db.repository.media.video import create_new_video
from src.db.session import SessionDep from src.db.session import SessionDep
from src.webapps.media.forms import AddLinkForm from src.webapps.media.forms import AddLinkForm
@@ -13,12 +15,12 @@ templates = Jinja2Templates(directory="src/templates")
router = APIRouter(include_in_schema=False, prefix="/media") router = APIRouter(include_in_schema=False, prefix="/media")
@router.get("/videos") @router.get("/videos")
def get_mediavideos(db: SessionDep, request: Request, msg: str = None): def get_mediavideos(db: SessionDep, request: Request, msg: Optional[str] = None):
mediavideos = db.query(MediaVideo).all() mediavideos = db.query(MediaVideo).all()
try: try:
token = request.cookies.get("access_token") token = request.cookies.get("access_token")
_, param = get_authorization_scheme_param(token) # scheme will hold "Bearer" and param will hold actual token value _, param = get_authorization_scheme_param(token) # scheme will hold "Bearer" and param will hold actual token value
current_user: Profile = get_current_user_from_token(token=param, db=db) current_user: Profile = get_current_user_from_token(token=param)
return templates.TemplateResponse("media/videos.html", {"request": request, "msg": msg, "user": current_user, "mediavideos": mediavideos}) return templates.TemplateResponse("media/videos.html", {"request": request, "msg": msg, "user": current_user, "mediavideos": mediavideos})
except Exception as e: except Exception as e:
print(e) print(e)
@@ -40,7 +42,7 @@ async def post_video_link(request: Request, db: SessionDep):
if form.is_valid(): if form.is_valid():
try: try:
#video = AddLink(**form.__dict__) #video = AddLink(**form.__dict__)
mediavideo = create_new_video(video=form, db=db) mediavideo = create_new_video(url=str(form.url), db=db)
return responses.RedirectResponse(f"media/videos/{mediavideo.id}", status_code=status.HTTP_302_FOUND) return responses.RedirectResponse(f"media/videos/{mediavideo.id}", status_code=status.HTTP_302_FOUND)
except Exception as e: except Exception as e:
print(e) print(e)
+1 -1
View File
@@ -11,7 +11,7 @@ from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker from sqlalchemy.orm import Session, sessionmaker
from src.apis.base import api_router from src.apis.base import api_router
from src.db.models.base import Base from kontor_model.db.models.base import Base
from src.db.session import get_db from src.db.session import get_db
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+1023 -560
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,7 +1,7 @@
# This file was generated by the Gradle 'init' task. # This file was generated by the Gradle 'init' task.
# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties # https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties
description='Kontor Documentation' description='Kontor Documentation'
version=0.3.0-SNAPSHOT version=0.4.0-SNAPSHOT
group=de.thpeetz group=de.thpeetz
org.gradle.configuration-cache=true org.gradle.configuration-cache=true
+1
View File
@@ -0,0 +1 @@
3.13
+29
View File
@@ -0,0 +1,29 @@
[project]
name = "kontor_model"
version = "0.4.0"
description = "Kontor Model"
readme = "README.md"
authors = [
{ name = "Thomas Peetz", email = "thomas.peetz@cimt-ag.de" }
]
requires-python = ">=3.13"
dependencies = [
"sqlalchemy>=2.0.52",
"msgspec[toml,yaml]>=0.21.1",
"pydantic[email]>=2.13.4",
]
[build-system]
requires = ["uv_build>=0.9.27,<0.10.0"]
build-backend = "uv_build"
[[tool.uv.index]]
name = "nexus"
url = "https://nexus.thpeetz.de/repository/pypi-group/simple"
publish-url = "https://nexus.thpeetz.de/repository/pypi-internal/"
default = true
[[tool.uv.index]]
name = "nexus-proxy"
url = "https://nexus.thpeetz.de/repository/pypi-proxy/simple"
@@ -0,0 +1,2 @@
def hello() -> str:
return "Hello from kontor-model!"
@@ -1,5 +1,5 @@
from typing import Any, Dict from typing import Any, Dict
from db.models.admin import ( from kontor_model.db.models.admin import (
Assignment, Assignment,
Token, Token,
Profile, Profile,
@@ -7,7 +7,7 @@ from db.models.admin import (
MailAccount, MailAccount,
Mail, Mail,
) )
from db.models.bookshelf import ( from kontor_model.db.models.bookshelf import (
ArticleAuthor, ArticleAuthor,
BookAuthor, BookAuthor,
BookshelfPublisher, BookshelfPublisher,
@@ -15,7 +15,7 @@ from db.models.bookshelf import (
Book, Book,
Author, Author,
) )
from db.models.comic import ( from kontor_model.db.models.comic import (
Issue, Issue,
StoryArc, StoryArc,
TradePaperback, TradePaperback,
@@ -27,14 +27,15 @@ from db.models.comic import (
Publisher, Publisher,
WorkType, WorkType,
) )
from db.models.media import ( from kontor_model.db.models.media import (
MediaFile, MediaFile,
MediaActor, MediaActor,
MediaActorFile, MediaActorFile,
MediaArticle, MediaArticle,
MediaVideo, MediaVideo,
MediaLofi,
) )
from db.models.tysc import ( from kontor_model.db.models.tysc import (
Card, Card,
CardSet, CardSet,
Rooster, Rooster,
@@ -72,6 +73,7 @@ registry: Dict[str, Any] = {
BookAuthor.__tablename__: BookAuthor, BookAuthor.__tablename__: BookAuthor,
MediaArticle.__tablename__: MediaArticle, MediaArticle.__tablename__: MediaArticle,
MediaVideo.__tablename__: MediaVideo, MediaVideo.__tablename__: MediaVideo,
MediaLofi.__tablename__: MediaLofi,
MediaFile.__tablename__: MediaFile, MediaFile.__tablename__: MediaFile,
MediaActor.__tablename__: MediaActor, MediaActor.__tablename__: MediaActor,
MediaActorFile.__tablename__: MediaActorFile, MediaActorFile.__tablename__: MediaActorFile,
@@ -4,7 +4,7 @@ from typing import Any, Dict
from sqlalchemy import Column, ForeignKey, Integer, String, Boolean from sqlalchemy import Column, ForeignKey, Integer, String, Boolean
from sqlalchemy.orm import relationship, mapped_column, Mapped from sqlalchemy.orm import relationship, mapped_column, Mapped
from db.models.base import Base, BaseMixin from kontor_model.db.models.base import Base, BaseMixin
class Profile(Base, BaseMixin): class Profile(Base, BaseMixin):
@@ -2,7 +2,7 @@ from typing import Any, Dict
from sqlalchemy import Column, ForeignKey, Integer, String from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from db.models.base import Base, BaseMixin from kontor_model.db.models.base import Base, BaseMixin
class Article(Base, BaseMixin): class Article(Base, BaseMixin):
@@ -56,7 +56,7 @@ class Author(Base, BaseMixin):
class BookshelfPublisher(Base, BaseMixin): class BookshelfPublisher(Base, BaseMixin):
__tablename__ = 'bookshelf_publisher' __tablename__ = 'bookshelf_publisher'
name = Column(String, unique=True) name = Column(String, unique=True)
books = relationship("Book") books = relationship("Book", back_populates="publisher")
def import_dict(self, import_data: Dict[str, Any]): def import_dict(self, import_data: Dict[str, Any]):
self.id = import_data['id'] self.id = import_data['id']
@@ -4,7 +4,7 @@ from typing import Dict, List, Optional, Any
from sqlalchemy import Column, ForeignKey, Integer, String, Boolean, func from sqlalchemy import Column, ForeignKey, Integer, String, Boolean, func
from sqlalchemy.orm import relationship, Mapped, mapped_column from sqlalchemy.orm import relationship, Mapped, mapped_column
from db.models.base import Base, BaseMixin from kontor_model.db.models.base import Base, BaseMixin
class Publisher(Base): class Publisher(Base):
@@ -1,14 +1,8 @@
import re
import subprocess
from datetime import datetime
from pathlib import Path
from typing import Any, Dict from typing import Any, Dict
import requests
from bs4 import BeautifulSoup
from sqlalchemy import Boolean, Column, String, ForeignKey from sqlalchemy import Boolean, Column, String, ForeignKey
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from db.models.base import Base, BaseMixin, BaseVideoMixin from kontor_model.db.models.base import Base, BaseMixin, BaseVideoMixin
class MediaFile(Base, BaseMixin, BaseVideoMixin): class MediaFile(Base, BaseMixin, BaseVideoMixin):
@@ -21,6 +15,9 @@ class MediaFile(Base, BaseMixin, BaseVideoMixin):
def __str__(self): def __str__(self):
return f'{self.title}({self.id})' return f'{self.title}({self.id})'
def update_title(self):
pass
def import_dict(self, import_data: Dict[str, Any]): def import_dict(self, import_data: Dict[str, Any]):
self.id = import_data['id'] self.id = import_data['id']
self.created_date = import_data['created_date'] self.created_date = import_data['created_date']
@@ -49,52 +46,6 @@ class MediaFile(Base, BaseMixin, BaseVideoMixin):
item['should_download'] = self.should_download item['should_download'] = self.should_download
return item return item
def update_title(self) -> None:
print(f"update title for {self.url}")
try:
r = requests.get(self.url)
soup = BeautifulSoup(r.content, "html.parser")
title_tag = soup.find('title')
if title_tag:
self.title = title_tag.get_text()
self.review = False
except:
self.title = None
self.review = True
self.last_modified_date = datetime.now()
def download_file(self, download_dir: str, dl_tool: str):
print(f"download file for {self.url} to {download_dir}")
result = subprocess.run([dl_tool, self.url], cwd=download_dir, capture_output=True, text=True)
if result.returncode == 0:
output = result.stdout
output = re.sub(' +', ' ', output)
lines_list = output.splitlines()
file_name = self.__parse_output__(lines_list)
if file_name is None:
self.review = True
self.should_download = True
self.file_name = None
else:
download_file = Path(file_name)
self.should_download = False
self.file_name = download_file.name
self.cloud_link = str(download_file.absolute())
self.last_modified_date = datetime.now()
def __parse_output__(self, lines_list):
self.file_name = None
for line in lines_list:
if 'has already been downloaded' in line:
end_len = len(' has already been downloaded')
self.file_name = line[11:-end_len]
if 'Destination' in line:
line_len = len(line)
start_len = len('[download] Destination: ')
file_len = line_len - start_len
self.file_name = line[-file_len:]
return self.file_name
class MediaActor(Base, BaseMixin): class MediaActor(Base, BaseMixin):
__tablename__ = 'media_actor' __tablename__ = 'media_actor'
@@ -222,3 +173,35 @@ class MediaVideo(Base, BaseMixin):
item['url'] = self.url item['url'] = self.url
item['should_download'] = self.should_download item['should_download'] = self.should_download
return item return item
class MediaLofi(Base, BaseMixin):
__tablename__ = 'media_lofi'
file_name = Column(String)
review = Column(Boolean)
should_download = Column(Boolean)
title = Column(String)
url = Column(String, unique=True)
def import_dict(self, import_data: Dict[str, Any]):
self.id = import_data['id']
self.created_date = import_data['created_date']
self.last_modified_date = import_data['last_modified_date']
self.version = import_data['version']
self.file_name = import_data['file_name']
self.review = import_data['review']
self.should_download = import_data['should_download']
self.title = import_data['title']
self.url = import_data['url']
def export_dict(self) -> Dict[str, Any]:
item: Dict[str, Any] = {}
item['id'] = self.id
item['created_date'] = str(self.created_date)
item['last_modified_date'] = str(self.last_modified_date)
item['version'] = self.version
item['file_name'] = self.file_name
item['review'] = self.review
item['should_download'] = self.should_download
item['title'] = self.title
item['url'] = self.url
return item
@@ -2,7 +2,7 @@ from typing import Dict, Any
from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Boolean from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Boolean
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from db.models.base import Base, BaseMixin from kontor_model.db.models.base import Base, BaseMixin
class Sport(Base, BaseMixin): class Sport(Base, BaseMixin):
@@ -2,7 +2,7 @@ from typing import Optional
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from src.db.models.admin import Profile from kontor_model.db.models.admin import Profile
def get_profile_by_username(username: str, db: Session) -> Optional[Profile]: def get_profile_by_username(username: str, db: Session) -> Optional[Profile]:
@@ -1,14 +1,12 @@
import uuid
from typing import List, Optional from typing import List, Optional
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from src.core.log_conf import logger from kontor_model.db.models.comic import Artist
from src.db.models.comic import Artist from kontor_model.schema.comics.artist import AddArtist
from src.schema.comics.artist import AddArtist from kontor_model.schema.comics.artist_details import ArtistDetailResponse, ArtistWorktypeComicResponse, ArtistWorktypeIssueResponse
from src.schema.comics.artist_details import ArtistDetailResponse, ArtistWorktypeComicResponse, ArtistWorktypeIssueResponse from kontor_model.schema.comics.comic import ComicResponse
from src.schema.comics.comic import ComicResponse from kontor_model.schema.comics.worktype import WorktypeResponse
from src.schema.comics.worktype import WorktypeResponse
def get_artist_details(artist: Artist) -> ArtistDetailResponse: def get_artist_details(artist: Artist) -> ArtistDetailResponse:
@@ -17,7 +15,17 @@ def get_artist_details(artist: Artist) -> ArtistDetailResponse:
for work in artist.comic_works: for work in artist.comic_works:
worktype_id = work.work_type.id worktype_id = work.work_type.id
if worktype_id in comic_works_map: if worktype_id in comic_works_map:
comic = ComicResponse(id=work.comic.id, title=work.comic.title, completed=work.comic.completed) comic = ComicResponse(
id=work.comic.id,
created_date=work.comic.created_date,
last_modified_date=work.comic.last_modified_date,
version=work.comic.version,
publisher_id=work.comic.publisher_id,
current_order=work.comic.current_order,
weblink=work.comic.weblink,
title=work.comic.title,
completed=work.comic.completed
)
comic_works_map[worktype_id].comics.append(comic) comic_works_map[worktype_id].comics.append(comic)
else: else:
comic_works_map[worktype_id] = ArtistWorktypeComicResponse( comic_works_map[worktype_id] = ArtistWorktypeComicResponse(
@@ -37,7 +45,6 @@ def get_artist_details(artist: Artist) -> ArtistDetailResponse:
return response return response
def update_artist(add_artist: AddArtist, artist_id: str, db: Session) -> Optional[Artist]: def update_artist(add_artist: AddArtist, artist_id: str, db: Session) -> Optional[Artist]:
logger.info("update artist")
artist: Optional[Artist] = db.get(Artist, artist_id) artist: Optional[Artist] = db.get(Artist, artist_id)
if artist is not None: if artist is not None:
artist.name = add_artist.name artist.name = add_artist.name
@@ -2,16 +2,15 @@ from typing import Dict, List, Optional
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from src.core.log_conf import logger from kontor_model.db.models.comic import Comic, Issue
from src.db.models.comic import Comic, Issue from kontor_model.schema.comics.artist import artist_to_response
from src.schema.comics.artist import artist_to_response from kontor_model.schema.comics.comic import ComicSchema, comic_to_response
from src.schema.comics.comic import ComicSchema, comic_to_response from kontor_model.schema.comics.comic_details import ComicDetailsResponse, ComicWorktypeArtistResponse
from src.schema.comics.comic_details import ComicDetailsResponse, ComicWorktypeArtistResponse from kontor_model.schema.comics.issue import IssueResponse, issue_to_response
from src.schema.comics.issue import IssueResponse, issue_to_response from kontor_model.schema.comics.issue_details import IssueDetailsResponse
from src.schema.comics.issue_details import IssueDetailsResponse from kontor_model.schema.comics.publisher import publisher_to_response
from src.schema.comics.publisher import publisher_to_response from kontor_model.schema.comics.volume import VolumeResponse, volume_to_response
from src.schema.comics.volume import VolumeResponse, volume_to_response from kontor_model.schema.comics.worktype import worktype_to_response
from src.schema.comics.worktype import worktype_to_response
def get_issue_details(issue: Issue) -> IssueDetailsResponse: def get_issue_details(issue: Issue) -> IssueDetailsResponse:
@@ -30,7 +29,6 @@ def get_issue_details(issue: Issue) -> IssueDetailsResponse:
def update_comic(new_comic: ComicSchema, comic_id: str, db: Session) -> Optional[Comic]: def update_comic(new_comic: ComicSchema, comic_id: str, db: Session) -> Optional[Comic]:
logger.info(f"update_comic: {new_comic} with {comic_id}")
comic: Optional[Comic] = db.get(Comic, comic_id) comic: Optional[Comic] = db.get(Comic, comic_id)
return comic return comic
@@ -48,7 +46,6 @@ def get_comic_details(comic: Comic) -> ComicDetailsResponse:
if worktype_id in works_map: if worktype_id in works_map:
artist = artist_to_response(work.artist) artist = artist_to_response(work.artist)
works_map[worktype_id].artists.append(artist) works_map[worktype_id].artists.append(artist)
logger.info(f"add artist to response map: {artist} -> {works_map}")
print(f"add artist to response map: {artist} -> {works_map}") print(f"add artist to response map: {artist} -> {works_map}")
else: else:
works_map[worktype_id] = ComicWorktypeArtistResponse( works_map[worktype_id] = ComicWorktypeArtistResponse(
@@ -0,0 +1,52 @@
from typing import List
from kontor_model.db.models.comic import Publisher
from kontor_model.schema.comics.comic import ComicResponse
from kontor_model.schema.comics.publisher import PublisherResponse
from kontor_model.schema.comics.publisher_details import PublisherDetailsResponse
def get_publisher_details(publisher: Publisher) -> PublisherDetailsResponse:
imprints: List[PublisherResponse] = []
for imprint in publisher.imprints:
imprints.append(
PublisherResponse(
id=imprint.id,
created_date=imprint.created_date,
last_modified_date=imprint.last_modified_date,
version=imprint.version,
weblink=str(imprint.weblink),
parent_publisher_id=imprint.parent_publisher_id,
name=str(imprint.name)
)
)
comics: List[ComicResponse] = []
for comic in publisher.comics:
comics.append(
ComicResponse(
id=comic.id,
created_date=comic.created_date,
last_modified_date=comic.last_modified_date,
version=comic.version,
publisher_id=comic.publisher_id,
current_order=comic.current_order,
weblink=comic.weblink,
title=comic.title,
completed=comic.completed
)
)
parent_publisher: PublisherResponse | None = None
if publisher.parent_publisher:
parent_publisher = PublisherResponse(
id=publisher.parent_publisher.id,
created_date=publisher.parent_publisher.created_date,
last_modified_date=publisher.parent_publisher.last_modified_date,
version=publisher.parent_publisher.version,#
weblink=str(publisher.parent_publisher.weblink),
parent_publisher_id=publisher.parent_publisher.parent_publisher_id,
name=str(publisher.parent_publisher.name)
)
response: PublisherDetailsResponse = PublisherDetailsResponse(
id=publisher.id, name=str(publisher.name), parent_publisher=parent_publisher, imprints=imprints, comics=comics
)
return response
@@ -4,9 +4,8 @@ from typing import AnyStr, Optional
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from src.core.log_conf import logger from kontor_model.db.models.comic import WorkType
from src.db.models.comic import WorkType from kontor_model.schema.comics.worktype import AddWorkType
from src.schema.comics.worktype import AddWorkType
def create_new_worktype(work: AddWorkType, db: Session) -> WorkType: def create_new_worktype(work: AddWorkType, db: Session) -> WorkType:
@@ -18,12 +17,10 @@ def create_new_worktype(work: AddWorkType, db: Session) -> WorkType:
db.add(worktype) db.add(worktype)
db.commit() db.commit()
db.refresh(worktype) db.refresh(worktype)
logger.info(f"create_new_worktype: {worktype}")
return worktype return worktype
def update_worktype(work: AddWorkType, worktype_id: AnyStr, db: Session) -> Optional[WorkType]: def update_worktype(work: AddWorkType, worktype_id: AnyStr, db: Session) -> Optional[WorkType]:
logger.info("update worktype")
worktype: Optional[WorkType] = db.get(WorkType, worktype_id) worktype: Optional[WorkType] = db.get(WorkType, worktype_id)
if worktype is not None: if worktype is not None:
worktype.name = work.worktype worktype.name = work.worktype
@@ -3,14 +3,13 @@ import uuid
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from src.core.log_conf import logger from kontor_model.db.models.media import MediaActor
from src.db.models.media import MediaActor from kontor_model.db.repository.media.actorfile import delete_mediaactorfile
from src.db.repository.media.actorfile import delete_mediaactorfile from kontor_model.schema.media.actor import MediaActorModel
from src.schema.media.actor import MediaActorModel
def create_new_mediaactor(new_actor: MediaActorModel, db: Session) -> MediaActor: def create_new_mediaactor(new_actor: MediaActorModel, db: Session) -> MediaActor:
logger.info(f"create MediaActor with url {new_actor.url}") print(f"create MediaActor with url {new_actor.url}")
media_actor: MediaActor = MediaActor() media_actor: MediaActor = MediaActor()
media_actor.id = str(uuid.uuid4()) media_actor.id = str(uuid.uuid4())
if new_actor.name is not None: if new_actor.name is not None:
@@ -22,11 +21,11 @@ def create_new_mediaactor(new_actor: MediaActorModel, db: Session) -> MediaActor
db.add(media_actor) db.add(media_actor)
db.commit() db.commit()
db.refresh(media_actor) db.refresh(media_actor)
logger.info(f"created {media_actor}") print(f"created {media_actor}")
return media_actor return media_actor
def delete_mediaactor(db: Session, actor_id: str): def delete_mediaactor(db: Session, actor_id: str):
logger.info(f"delete MediaActor with id {actor_id}") print(f"delete MediaActor with id {actor_id}")
media_actor = db.get(MediaActor, actor_id) media_actor = db.get(MediaActor, actor_id)
if media_actor is not None: if media_actor is not None:
actor_files = media_actor.media_actor_files actor_files = media_actor.media_actor_files
@@ -40,7 +39,7 @@ def import_mediaactor(db: Session, new_actor: MediaActorModel) -> MediaActor:
""" """
import MediaFile and set missing values with default ones. import MediaFile and set missing values with default ones.
""" """
logger.info("import MediaActor with %s", new_actor) print("import MediaActor with %s", new_actor)
media_actor: MediaActor = MediaActor() media_actor: MediaActor = MediaActor()
media_actor.id = new_actor.id media_actor.id = new_actor.id
if new_actor.created_date: if new_actor.created_date:
@@ -3,9 +3,8 @@ import uuid
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from src.core.log_conf import logger from kontor_model.db.models.media import MediaActorFile
from src.db.models.media import MediaActorFile from kontor_model.schema.media.actorfile import MediaActorFileModel
from src.schema.media.actorfile import MediaActorFileModel
def create_new_mediaactorfile( def create_new_mediaactorfile(
@@ -14,7 +13,7 @@ def create_new_mediaactorfile(
""" """
Create relation for MediaFile and MediaActor Create relation for MediaFile and MediaActor
""" """
logger.info("create MediaActorFile with actor %s and file %s", actor_id, file_id) print("create MediaActorFile with actor %s and file %s", actor_id, file_id)
media_actor_file: MediaActorFile = MediaActorFile() media_actor_file: MediaActorFile = MediaActorFile()
media_actor_file.id = str(uuid.uuid4()) media_actor_file.id = str(uuid.uuid4())
media_actor_file.created_date = datetime.now() media_actor_file.created_date = datetime.now()
@@ -32,7 +31,7 @@ def delete_mediaactorfile(db: Session, actorfile_id: str):
""" """
Delete relation between MediaFile and MediaActor. Delete relation between MediaFile and MediaActor.
""" """
logger.info("delete MediaActorFile with id %s", actorfile_id) print("delete MediaActorFile with id %s", actorfile_id)
media_actorfile = db.get(MediaActorFile, actorfile_id) media_actorfile = db.get(MediaActorFile, actorfile_id)
db.delete(media_actorfile) db.delete(media_actorfile)
db.commit() db.commit()
@@ -44,7 +43,7 @@ def import_mediaactorfile(
""" """
Import MediaFile and set missing values with default ones. Import MediaFile and set missing values with default ones.
""" """
logger.info("import MediaActorFile with %s", new_actorfile) print("import MediaActorFile with %s", new_actorfile)
media_actor_file: MediaActorFile = MediaActorFile() media_actor_file: MediaActorFile = MediaActorFile()
media_actor_file.id = new_actorfile.id media_actor_file.id = new_actorfile.id
if new_actorfile.created_date: if new_actorfile.created_date:
@@ -3,16 +3,15 @@ import uuid
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from src.core.log_conf import logger from kontor_model.db.models.media import MediaFile
from src.db.models.media import MediaFile from kontor_model.schema.media.file import MediaFileModel
from src.schema.media.file import MediaFileModel
def create_new_mediafile(link: str, db: Session) -> MediaFile: def create_new_mediafile(link: str, db: Session) -> MediaFile:
""" """
Create MediaFile with gievne URL. Create MediaFile with gievne URL.
""" """
logger.info("create MediaFile with url {link}") print("create MediaFile with url {link}")
media_file: MediaFile = MediaFile() media_file: MediaFile = MediaFile()
media_file.id = str(uuid.uuid4()) media_file.id = str(uuid.uuid4())
media_file.url = link media_file.url = link
@@ -24,7 +23,7 @@ def create_new_mediafile(link: str, db: Session) -> MediaFile:
db.add(media_file) db.add(media_file)
db.commit() db.commit()
db.refresh(media_file) db.refresh(media_file)
logger.info("created %s", media_file) print("created %s", media_file)
return media_file return media_file
@@ -32,7 +31,7 @@ def delete_mediafile(db: Session, media_file_id: str):
""" """
Delete MediaFile with given ID from db. Delete MediaFile with given ID from db.
""" """
logger.info("delete MediaFile with id %s", media_file_id) print("delete MediaFile with id %s", media_file_id)
media_file = db.get(MediaFile, media_file_id) media_file = db.get(MediaFile, media_file_id)
db.delete(media_file) db.delete(media_file)
db.commit() db.commit()
@@ -42,7 +41,7 @@ def import_mediafile(db: Session, new_file: MediaFileModel) -> MediaFile:
""" """
import MediaActor and set missing values with defautl ones. import MediaActor and set missing values with defautl ones.
""" """
logger.info("import MediaFile with %s", new_file) print("import MediaFile with %s", new_file)
media_file: MediaFile = MediaFile() media_file: MediaFile = MediaFile()
media_file.id = new_file.id media_file.id = new_file.id
if new_file.created_date: if new_file.created_date:
@@ -0,0 +1,69 @@
from datetime import datetime
import uuid
from sqlalchemy.orm import Session
from kontor_model.db.models.media import MediaLofi
from kontor_model.schema.media.lofi import MediaLofiModel
def create_new_lofi(url: str, db: Session) -> MediaLofi:
"""
Create MediaLofi with given URL.
"""
print("create MediaLofi with url %s", url)
media_lofi = MediaLofi()
media_lofi.id = str(uuid.uuid4())
media_lofi.url = url
media_lofi.created_date = datetime.now()
media_lofi.last_modified_date = datetime.now()
media_lofi.review = True
media_lofi.should_download = False
db.add(media_lofi)
db.commit()
db.refresh(media_lofi)
print(media_lofi)
return media_lofi
def import_medialofi(db: Session, new_lofi: MediaLofiModel) -> MediaLofi:
"""
import MediaLofi and set missing values with default ones.
"""
print("import MediaLofi with %s", new_lofi)
media_lofi: MediaLofi = MediaLofi()
media_lofi.id = new_lofi.id
if new_lofi.created_date:
media_lofi.created_date = new_lofi.created_date
else:
media_lofi.created_date = datetime.now()
if new_lofi.last_modified_date:
media_lofi.last_modified_date = new_lofi.last_modified_date
else:
media_lofi.last_modified_date = datetime.now()
media_lofi.version = new_lofi.version
if new_lofi.title:
media_lofi.title = new_lofi.title
else:
media_lofi.title = ""
if new_lofi.url:
media_lofi.url = new_lofi.url
else:
# TODO shoud exeception be raised when url is missing?
media_lofi.url = ""
media_lofi.review = new_lofi.review
media_lofi.should_download = new_lofi.should_download
db.add(media_lofi)
db.commit()
db.refresh(media_lofi)
return media_lofi
def delete_medialofi(db: Session, lofi_id: str):
"""
Delete MediaLofi with given ID from db.
"""
print("delete MediaLofi with id %s", lofi_id)
lofi = db.get(MediaLofi, lofi_id)
db.delete(lofi)
db.commit()
@@ -3,15 +3,14 @@ import uuid
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from src.db.models.media import MediaVideo from kontor_model.db.models.media import MediaVideo
from src.webapps.media.forms import AddLinkForm
def create_new_video(video: AddLinkForm, db: Session) -> MediaVideo: def create_new_video(url: str, db: Session) -> MediaVideo:
print(video.url) print(url)
media_video = MediaVideo() media_video = MediaVideo()
media_video.id = str(uuid.uuid4()) media_video.id = str(uuid.uuid4())
media_video.url = str(video.url) media_video.url = url
media_video.created_date = datetime.now() media_video.created_date = datetime.now()
media_video.last_modified_date = datetime.now() media_video.last_modified_date = datetime.now()
media_video.review = True media_video.review = True
@@ -0,0 +1,41 @@
from datetime import datetime
from typing import Optional
import uuid
from kontor_model.db.models.admin import Assignment, Profile
from sqlalchemy.orm import Session
from kontor_model.schema.user.profile import ProfileModel
def create_new_profile(new_profile: ProfileModel, db: Session) -> Profile:
print(f"create Profile with username {new_profile.username}")
profile: Profile = Profile()
profile.id = str(uuid.uuid4())
profile.user_name = new_profile.username
profile.first_name = new_profile.first_name
profile.last_name = new_profile.last_name
profile.created_date = datetime.now()
profile.last_modified_date = datetime.now()
profile.version = 0
db.add(profile)
db.commit()
db.refresh(profile)
print(f"created {profile}")
return profile
def delete_profile(db: Session, profile_id: str):
print(f"delete Profile with id {profile_id}")
profile: Optional[Profile] = db.get(Profile, profile_id)
if profile is not None:
assignments = profile.assignments
for assignment in assignments:
delete_assignment(db, assignment.id)
db.delete(profile)
db.commit()
def delete_assignment(db: Session, assignment_id: str) -> None:
print(f"delete Assignment with id {assignment_id}")
assignment: Optional[Assignment] = db.get(Assignment, assignment_id)
if assignment is not None:
db.delete(assignment)
db.commit()
@@ -2,7 +2,7 @@ from datetime import datetime
from pydantic import BaseModel from pydantic import BaseModel
from src.db.models.admin import MailAccount from kontor_model.db.models.admin import MailAccount
class MailAccountResponse(BaseModel): class MailAccountResponse(BaseModel):
@@ -24,11 +24,11 @@ def to_response(account: MailAccount) -> MailAccountResponse:
created_date=account.created_date, created_date=account.created_date,
last_modified_date=account.last_modified_date, last_modified_date=account.last_modified_date,
version=account.version, version=account.version,
host=account.host, host=str(account.host),
port=account.port, port=account.port,
protocol=account.protocol, protocol=str(account.protocol),
user_name=account.user_name, user_name=str(account.user_name),
password=account.password, password=str(account.password),
start_tls=account.start_tls, start_tls=bool(account.start_tls),
) )
return response return response
@@ -2,7 +2,7 @@ from datetime import datetime
from pydantic import BaseModel from pydantic import BaseModel
from src.db.models.bookshelf import Article from kontor_model.db.models.bookshelf import Article
class ArticleResponse(BaseModel): class ArticleResponse(BaseModel):
@@ -18,6 +18,6 @@ def to_response(article: Article) -> ArticleResponse:
created_date=article.created_date, created_date=article.created_date,
last_modified_date=article.last_modified_date, last_modified_date=article.last_modified_date,
version=article.version, version=article.version,
title=article.title title=str(article.title)
) )
return response return response

Some files were not shown because too many files have changed in this diff Show More