40 Commits

Author SHA1 Message Date
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
Thomas Peetz 7555cfd51d Update Vaadin and Spring Boot version
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 6s
2026-08-13 14:04:30 +02:00
Thomas Peetz ea038ec70c refactor package layout
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 7s
2026-08-12 19:05:06 +02:00
Thomas Peetz ecfa0eb6d8 remove subprojects integration and kontor-data
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-12 15:19:04 +02:00
Thomas Peetz fe63a80b23 update vaadin and lombok versionsand disable asciidoctor
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-12 13:28:41 +02:00
tpeetz 567e254840 add kontor-data to extract data model
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 10s
2026-08-10 22:49:46 +02:00
Thomas Peetz a4975928ae add integration subproject for Camel routes
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 52s
2026-08-10 15:23:32 +02:00
Thomas Peetz 1dcf342736 add queues and processing
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-05 15:46:39 +02:00
tpeetz 6abbe2e585 Add reading queue media.link.add
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-04 23:22:26 +02:00
tpeetz 8eecd47399 setup basic project with Python Robyn
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
2026-08-02 17:39:41 +02:00
tpeetz 9d01925097 add kontor-robyn
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
2026-07-31 22:46:46 +02:00
Thomas Peetz bd721a8e64 add msgspec to Python projects
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-07-31 18:28:23 +02:00
Thomas Peetz c4932a4665 use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-07-31 04:07:07 +02:00
Thomas Peetz def3f7ea11 use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-07-31 04:06:35 +02:00
Thomas Peetz bef7b0bd59 use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-07-31 04:06:02 +02:00
Thomas Peetz 5655bc5322 use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-07-31 04:05:23 +02:00
Thomas Peetz 375438a8fa use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 2s
2026-07-31 04:02:25 +02:00
Thomas Peetz 90b1e8def3 use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-07-31 04:01:54 +02:00
Thomas Peetz 816165579c use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
2026-07-31 04:00:04 +02:00
Thomas Peetz fbcdbb3e1a use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 7s
2026-07-31 03:59:26 +02:00
Thomas Peetz e46ab25920 use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
2026-07-31 03:57:45 +02:00
Thomas Peetz 1fa64bf5ce use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-07-31 02:40:12 +02:00
Thomas Peetz fdb9da358a use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-07-31 00:59:26 +02:00
Thomas Peetz 235f64aa08 use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-07-31 00:57:12 +02:00
Thomas Peetz 9f17823922 use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-07-30 22:37:35 +02:00
Thomas Peetz 0c6b26b79e use msgspec to parse message
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-07-30 22:35:25 +02:00
Thomas Peetz c7a322f29d add msgspec to Python projects
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 9s
2026-07-30 17:37:17 +02:00
tpeetz 32dcd43fe5 add message sending with stomp protocol
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-07-26 22:08:49 +02:00
tpeetz 5edb929b0f fix generating Container image build
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 11s
2026-07-26 19:59:56 +02:00
tpeetz f0cf98d36e remove asciidoctor from kontor-spring
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-07-23 05:12:03 +02:00
tpeetz 19e7eba250 add check for short filenames
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-07-22 23:20:51 +02:00
tpeetz 81d6018e0f add Nexus config
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-07-22 22:54:36 +02:00
tpeetz c685e9aca5 fix SNAPSHOT Version
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-07-22 17:09:36 +00:00
tpeetz d39c14cd9a change creation of MediaFile
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-07-22 19:00:39 +02:00
tpeetz 2ce6bbc083 fix messageobject
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-07-21 20:51:20 +00:00
tpeetz 3a351ac5b7 fix json conversion
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2026-07-21 18:55:42 +00:00
tpeetz 31c01c3033 adding dry-run option
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 9s
2026-07-11 17:38:24 +02:00
tpeetz 0d5ee0dd63 implement REST API for adding MediaFileActors
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 11s
2026-06-14 01:58:57 +02:00
436 changed files with 4392 additions and 3466 deletions
+5
View File
@@ -6,3 +6,8 @@ node_modules/
.editorconfig
db-password.txt
couchdb-password.txt
kontor-robyn/kontor.db
kontor-robyn.bak
kontor-robyn.bak2
kontor-data/.gradle
kontor-data/build/
+1 -1
View File
@@ -14,7 +14,7 @@ ENV PATH="/root/.local/bin:${PATH}"
WORKDIR /app
COPY ./pyproject.toml .
RUN --mount=type=bind,source=/home/tpeetz/projects/kontor/kontor-model,target=/container/kontor-model uv add /container/kontor-model
RUN uv sync
# ------------------------------- Production Stage ------------------------------ ##
+5 -1
View File
@@ -24,9 +24,13 @@ dependencies = [
"psycopg2-binary>=2.9.10",
"pytest-cov>=6.1.1",
"databases[sqlite]>=0.9.0",
"pydantic[email]>=2.11.3",
"jinja2>=3.1.6",
"asyncpg>=0.30.0",
"bcrypt>=4.3.0",
"fastapi-jwt-auth>=0.5.0",
"msgspec[toml,yaml]>=0.21.1",
"kontor-model",
]
[tool.uv.sources]
kontor-model = { path = "../kontor-model", editable = true }
+7
View File
@@ -18,6 +18,7 @@ from src.apis.version1.comics import (
from src.apis.version1.media import (
actor,
file,
lofi,
mediaactorfile,
mediavideo,
mediaarticle,
@@ -104,6 +105,12 @@ api_router.include_router(
tags=["media"],
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(
mediaarticle.router,
prefix="/media",
+2 -2
View File
@@ -9,8 +9,8 @@ from src.core.security import (
authenticate_user_by_username,
create_access_token,
)
from src.schema.admin.login import LoginRequest
from src.schema.admin.token import Token
from kontor_model.schema.admin.login import LoginRequest
from kontor_model.schema.admin.token import Token
from src.webapps.auth.forms import LoginForm
login_router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.admin.mailaccount import MailAccountResponse, to_response
from kontor_model.schema.admin.mailaccount import MailAccountResponse, to_response
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.bookshelf.article import ArticleResponse, to_response
from kontor_model.schema.bookshelf.article import ArticleResponse, to_response
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.bookshelf.articleauthor import ArticleAuthorResponse, to_response
from kontor_model.schema.bookshelf.articleauthor import ArticleAuthorResponse, to_response
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.bookshelf.author import AuthorResponse, to_response
from kontor_model.schema.bookshelf.author import AuthorResponse, to_response
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.bookshelf.book import BookResponse, to_response
from kontor_model.schema.bookshelf.book import BookResponse, to_response
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.bookshelf.bookauthor import BookAuthorResponse, to_response
from kontor_model.schema.bookshelf.bookauthor import BookAuthorResponse, to_response
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.bookshelf.publisher import PublisherResponse, to_response
from kontor_model.schema.bookshelf.publisher import PublisherResponse, to_response
router = APIRouter()
@@ -2,11 +2,11 @@ from typing import List
from fastapi import APIRouter, HTTPException, status
from src.db.models.comic import Artist
from src.db.repository.comics.artist import get_artist_details
from kontor_model.db.models.comic import Artist
from kontor_model.db.repository.comics.artist import get_artist_details
from src.db.session import SessionDep
from src.schema.comics.artist import ArtistCreation, ArtistResponse, artist_to_response
from src.schema.comics.artist_details import ArtistDetailResponse
from kontor_model.schema.comics.artist import ArtistCreation, ArtistResponse, artist_to_response
from kontor_model.schema.comics.artist_details import ArtistDetailResponse
router = APIRouter()
+4 -4
View File
@@ -3,13 +3,13 @@ from typing import List
from fastapi import APIRouter, HTTPException
from src.core.log_conf import logger
from src.db.models.comic import Comic
from src.db.repository.comics.comic import (
from kontor_model.db.models.comic import Comic
from kontor_model.db.repository.comics.comic import (
get_comic_details,
)
from src.db.session import SessionDep
from src.schema.comics.comic import ComicResponse, comic_to_response
from src.schema.comics.comic_details import ComicDetailsResponse
from kontor_model.schema.comics.comic import ComicResponse, comic_to_response
from kontor_model.schema.comics.comic_details import ComicDetailsResponse
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.comics.comicwork import ComicWorkResponse, comicwork_to_response
from kontor_model.schema.comics.comicwork import ComicWorkResponse, comicwork_to_response
router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
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.schema.comics.issue import IssueResponse, issue_to_response
from kontor_model.schema.comics.issue import IssueResponse, issue_to_response
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.comics.issuework import IssueWorkResponse, issuework_to_response
from kontor_model.schema.comics.issuework import IssueWorkResponse, issuework_to_response
router = APIRouter()
@@ -2,11 +2,11 @@ from typing import List
from fastapi import APIRouter, HTTPException
from src.db.models.comic import Publisher
from src.db.repository.comics.publisher import get_publisher_details
from kontor_model.db.models.comic import Publisher
from kontor_model.db.repository.comics.publisher import get_publisher_details
from src.db.session import SessionDep
from src.schema.comics.publisher import PublisherResponse, publisher_to_response
from src.schema.comics.publisher_details import PublisherDetailsResponse
from kontor_model.schema.comics.publisher import PublisherResponse, publisher_to_response
from kontor_model.schema.comics.publisher_details import PublisherDetailsResponse
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.comics.storyarc import StoryArcResponse, storyarc_to_response
from kontor_model.schema.comics.storyarc import StoryArcResponse, storyarc_to_response
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.comics.volume import VolumeResponse, volume_to_response
from kontor_model.schema.comics.volume import VolumeResponse, volume_to_response
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.comics.worktype import WorktypeResponse, worktype_to_response
from kontor_model.schema.comics.worktype import WorktypeResponse, worktype_to_response
router = APIRouter()
+1 -1
View File
@@ -1,6 +1,6 @@
from fastapi import APIRouter, status
from src.schema.admin.healthcheck import HealthCheck
from kontor_model.schema.admin.healthcheck import HealthCheck
health_router = APIRouter()
+3 -3
View File
@@ -2,10 +2,10 @@ from typing import List
from fastapi import APIRouter, status, HTTPException
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.schema.media.actor import MediaActorModel, MediaActorResponse, actor_to_response
from src.db.models.media import MediaActor
from kontor_model.schema.media.actor import MediaActorModel, MediaActorResponse, actor_to_response
from kontor_model.db.models.media import MediaActor
router = APIRouter()
+6 -6
View File
@@ -2,21 +2,21 @@ from typing import List
from fastapi import APIRouter, status, HTTPException
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,
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.schema.media.actor import MediaActorResponse, actor_to_response
from src.schema.media.actorfile import MediaActorFileResponse, actorfile_to_response
from src.schema.media.file import (
from kontor_model.schema.media.actor import MediaActorResponse, actor_to_response
from kontor_model.schema.media.actorfile import MediaActorFileResponse, actorfile_to_response
from kontor_model.schema.media.file import (
MediaFileModel,
MediaFileResponse,
file_to_response,
file_to_model,
)
from src.db.models.media import MediaFile
from kontor_model.db.models.media import MediaFile
router = APIRouter()
@@ -0,0 +1,42 @@
from typing import List
from fastapi import APIRouter, HTTPException
from kontor_model.db.models.media import MediaLofi
from src.db.session import SessionDep
from kontor_model.schema.media.lofi import MediaLofiResponse, lofi_to_response
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
@@ -1,9 +1,10 @@
from typing import List
from fastapi import APIRouter, status, HTTPException
from src.db.models.media import MediaActorFile
from src.db.repository.media.actorfile import delete_mediaactorfile
from src.core.log_conf import logger
from kontor_model.db.models.media import MediaActorFile
from kontor_model.db.repository.media.actorfile import delete_mediaactorfile, import_mediaactorfile
from src.db.session import SessionDep
from src.schema.media.actorfile import MediaActorFileResponse, actorfile_to_response
from kontor_model.schema.media.actorfile import MediaActorFileModel, MediaActorFileResponse, actorfile_to_response
router = APIRouter()
@@ -30,3 +31,13 @@ def delete_actorfile(actorfile_id: str, db: SessionDep):
if not media_actorfile:
raise HTTPException(status_code=404, detail="MediaActor could not be found")
delete_mediaactorfile(db, media_actorfile.id)
@router.post("/actorfiles", status_code=status.HTTP_201_CREATED)
def add_actorfile(new_actorfile: MediaActorFileModel, db: SessionDep) -> MediaActorFileResponse:
logger.info("add actorfile %s - %s", new_actorfile.media_actor_id, new_actorfile.media_file_id)
try:
mediaActorFile: MediaActorFile = import_mediaactorfile(db, new_actorfile)
except Exception as exception:
raise HTTPException(status_code=409, detail=f"Link duplicate: {exception}")
response = actorfile_to_response(mediaActorFile)
return response
@@ -3,9 +3,9 @@ from typing import List
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.schema.media.article import MediaArticleResponse, to_response
from kontor_model.schema.media.article import MediaArticleResponse, to_response
router = APIRouter()
@@ -3,9 +3,9 @@ from typing import List
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.schema.media.video import MediaVideoResponse, video_to_response
from kontor_model.schema.media.video import MediaVideoResponse, video_to_response
router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
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.schema.tysc.card import CardResponse, to_response
from kontor_model.schema.tysc.card import CardResponse, to_response
router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
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.schema.tysc.cardset import CardSetResponse, to_response
from kontor_model.schema.tysc.cardset import CardSetResponse, to_response
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.tysc.fieldposition import FieldPositionResponse, to_response
from kontor_model.schema.tysc.fieldposition import FieldPositionResponse, to_response
router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
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.schema.tysc.player import PlayerResponse, to_response
from kontor_model.schema.tysc.player import PlayerResponse, to_response
router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
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.schema.tysc.rooster import RoosterResponse, to_response
from kontor_model.schema.tysc.rooster import RoosterResponse, to_response
router = APIRouter()
+2 -2
View File
@@ -3,8 +3,8 @@ from fastapi import APIRouter, HTTPException
from src.core.log_conf import logger
from src.db.session import SessionDep
from src.schema.tysc.sport import SportResponse, to_response
from src.db.models.tysc import Sport
from kontor_model.schema.tysc.sport import SportResponse, to_response
from kontor_model.db.models.tysc import Sport
router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
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.schema.tysc.team import TeamResponse, to_response
from kontor_model.schema.tysc.team import TeamResponse, to_response
router = APIRouter()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
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.schema.tysc.vendor import VendorResponse, to_response
from kontor_model.schema.tysc.vendor import VendorResponse, to_response
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.user.assignment import AssignmentResponse, to_response
from kontor_model.schema.user.assignment import AssignmentResponse, to_response
router = APIRouter()
@@ -2,9 +2,9 @@ from typing import List
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.schema.user.permission import PermissionResponse, to_response
from kontor_model.schema.user.permission import PermissionResponse, to_response
router = APIRouter()
+2 -2
View File
@@ -4,10 +4,10 @@ from sqlalchemy import select
from src.core.log_conf import logger
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.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()
+2 -2
View File
@@ -2,9 +2,9 @@ from typing import List
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.schema.user.token import TokenResponse, to_response
from kontor_model.schema.user.token import TokenResponse, to_response
router = APIRouter()
+5 -5
View File
@@ -15,15 +15,15 @@ from pydantic import ValidationError
from src.core.config import settings
from src.core.log_conf import logger
from src.db.models.admin import Profile
from src.db.repository.admin import (
from kontor_model.db.models.admin import Profile
from kontor_model.db.repository.admin import (
get_profile_by_username,
get_profile_by_email,
is_database_empty,
)
from src.db.session import SessionLocal
from src.schema.admin.token import TokenData
from src.schema.user.profile import ProfileModel, to_model
from kontor_model.schema.admin.token import TokenData
from kontor_model.schema.user.profile import ProfileModel, to_model
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="/token",
@@ -163,7 +163,7 @@ async def get_current_user(
async def get_current_active_user(
current_user: Annotated[Profile, Security(get_current_user, scopes=["me"])],
) -> ProfileModel:
if not current_user.enabled:
if not bool(current_user.enabled):
raise HTTPException(status_code=400, detail="Inactive user")
user_model = to_model(current_user)
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]
-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")
-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
import uuid
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 src.schema.user.profile import ProfileModel
from kontor_model.schema.user.profile import ProfileModel
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.log_conf import logger
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.utils import check_db_connected, check_db_disconnected
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/actors/">MediaActors</a>
<a href="/media/videos/">MediaVideos</a>
<a href="/media/lofi/">MediaLofi</a>
</div>
+1 -1
View File
@@ -2,7 +2,7 @@ from typing import Optional
from fastapi import APIRouter, Request
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
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.auth import route_login
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")
@@ -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_actors.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_admin.router, tags=["webapp"])
@@ -2,14 +2,13 @@ from fastapi import APIRouter, Request, status, Form
from fastapi.templating import Jinja2Templates
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 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.repository.comic import create_new_worktype, update_worktype
from src.main import logger
from src.schema.comics.artist import AddArtist
from kontor_model.schema.comics.artist import AddArtist
from src.webapps.comic.forms.artist import AddArtistForm
#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})
@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":
return RedirectResponse(f"/comic/artists/{artist_id}", status_code=status.HTTP_303_SEE_OTHER)
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.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 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.schema.comics.comic import ComicSchema
from kontor_model.schema.comics.comic import ComicSchema
from src.webapps.comic.forms.comic import ValidateComicForm
templates = Jinja2Templates(directory="src/templates")
@@ -2,13 +2,13 @@ from fastapi import APIRouter, Request, status
from fastapi.templating import Jinja2Templates
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 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.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
templates = Jinja2Templates(directory="src/templates")
+1 -1
View File
@@ -2,7 +2,7 @@ from typing import AnyStr
from fastapi import APIRouter, Request
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
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 src.core.security import get_current_user_from_token
from src.db.models.admin import Profile
from src.db.models.media import MediaFile
from kontor_model.db.models.admin import Profile
from kontor_model.db.models.media import MediaFile
from src.core.log_conf import logger
from src.db.session import SessionDep
@@ -37,7 +37,7 @@ def get_mediafiles(db: SessionDep, request: Request, msg: str | None = None):
try:
token = request.cookies.get("access_token")
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})
except Exception as e:
print(e)
+8 -6
View File
@@ -1,11 +1,13 @@
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 src.db.models.media import MediaVideo
from src.db.models.admin import Profile
from src.db.repository.media.video import create_new_video
from kontor_model.db.models.media import MediaVideo
from kontor_model.db.models.admin import Profile
from kontor_model.db.repository.media.video import create_new_video
from src.db.session import SessionDep
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.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()
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, 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})
except Exception as e:
print(e)
@@ -40,7 +42,7 @@ async def post_video_link(request: Request, db: SessionDep):
if form.is_valid():
try:
#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)
except Exception as e:
print(e)
+1 -1
View File
@@ -11,7 +11,7 @@ from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
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
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+514 -413
View File
File diff suppressed because it is too large Load Diff
+34 -6
View File
@@ -1,11 +1,6 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This is a general purpose Gradle build.
* Learn more about Gradle by exploring our Samples at https://docs.gradle.org/9.4.1/samples
*/
plugins {
id("base")
id("maven-publish")
id("de.infolektuell.typst") version "0.8.0"
}
@@ -16,6 +11,39 @@ typst.sourceSets {
val main by registering {
// The files to compile (without .typ extension) in src/main/typst
documents = listOf("kontor") // src/main/typst/document.typst
inputs.put("version", version.toString())
}
}
tasks.withType<AbstractPublishToMaven>().configureEach {
dependsOn(tasks.named("compileTypst"))
}
publishing {
publications {
create<MavenPublication>("maven") {
artifactId = "kontor"
artifact(file("build/typst/main/pdf/kontor.pdf")) {
classifier = "docs"
extension = "pdf"
}
}
}
repositories {
maven {
// Determine URL based on version
url = uri(
if (version.toString().endsWith("SNAPSHOT")) {
"https://nexus.thpeetz.de/repository/maven-snapshots/"
} else {
"https://nexus.thpeetz.de/repository/maven-releases/"
}
)
// Credentials
credentials {
username = project.findProperty("nexusUsername") as String? ?: System.getenv("NEXUS_USERNAME")
password = project.findProperty("nexusPassword") as String? ?: System.getenv("NEXUS_PASSWORD")
}
}
}
}
+3 -1
View File
@@ -1,5 +1,7 @@
# This file was generated by the Gradle 'init' task.
# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties
description='Kontor Documentation'
version=0.3.0-SNAPSHOT
group=de.thpeetz
org.gradle.configuration-cache=true
+5 -6
View File
@@ -1,5 +1,6 @@
#let version = sys.inputs.at("version", default: "0.0.1")
//#set page("a4")
#import "@preview/basic-report:0.4.0": *
#import "@preview/basic-report:0.5.0": *
#import "@preview/in-dexter:0.7.2": *
#import "@preview/pintorita:0.1.4"
@@ -8,14 +9,12 @@
#show: it => basic-report(
doc-category: "Entwicklungs- und Projekthandbuch",
doc-title: "Projekt kontor",
doc-title: "Projekt kontor\nVersion " + version,
author: "Thomas Peetz",
//affiliation: "MouseTec, Entenhausen",
//logo: image("assets/aerospace-engineering.png", width: 2cm),
// <a href="https://www.flaticon.com/free-icons/aerospace" title="aerospace icons">Aerospace icons created by gravisio - Flaticon</a>
language: "de",
compact-mode: false,
it
show-outline: true,
it,
)
= Allgemeines
+1
View File
@@ -0,0 +1 @@
3.13
+18
View File
@@ -0,0 +1,18 @@
[project]
name = "kontor_model"
version = "0.3.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"
@@ -0,0 +1,2 @@
def hello() -> str:
return "Hello from kontor-model!"
@@ -1,5 +1,5 @@
from typing import Any, Dict
from db.models.admin import (
from kontor_model.db.models.admin import (
Assignment,
Token,
Profile,
@@ -7,7 +7,7 @@ from db.models.admin import (
MailAccount,
Mail,
)
from db.models.bookshelf import (
from kontor_model.db.models.bookshelf import (
ArticleAuthor,
BookAuthor,
BookshelfPublisher,
@@ -15,7 +15,7 @@ from db.models.bookshelf import (
Book,
Author,
)
from db.models.comic import (
from kontor_model.db.models.comic import (
Issue,
StoryArc,
TradePaperback,
@@ -27,14 +27,15 @@ from db.models.comic import (
Publisher,
WorkType,
)
from db.models.media import (
from kontor_model.db.models.media import (
MediaFile,
MediaActor,
MediaActorFile,
MediaArticle,
MediaVideo,
MediaLofi,
)
from db.models.tysc import (
from kontor_model.db.models.tysc import (
Card,
CardSet,
Rooster,
@@ -72,6 +73,7 @@ registry: Dict[str, Any] = {
BookAuthor.__tablename__: BookAuthor,
MediaArticle.__tablename__: MediaArticle,
MediaVideo.__tablename__: MediaVideo,
MediaLofi.__tablename__: MediaLofi,
MediaFile.__tablename__: MediaFile,
MediaActor.__tablename__: MediaActor,
MediaActorFile.__tablename__: MediaActorFile,
@@ -4,7 +4,7 @@ from typing import Any, Dict
from sqlalchemy import Column, ForeignKey, Integer, String, Boolean
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):
@@ -2,7 +2,7 @@ from typing import Any, Dict
from sqlalchemy import Column, ForeignKey, Integer, String
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):
@@ -56,7 +56,7 @@ class Author(Base, BaseMixin):
class BookshelfPublisher(Base, BaseMixin):
__tablename__ = 'bookshelf_publisher'
name = Column(String, unique=True)
books = relationship("Book")
books = relationship("Book", back_populates="publisher")
def import_dict(self, import_data: Dict[str, Any]):
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.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):
@@ -1,14 +1,8 @@
import re
import subprocess
from datetime import datetime
from pathlib import Path
from typing import Any, Dict
import requests
from bs4 import BeautifulSoup
from sqlalchemy import Boolean, Column, String, ForeignKey
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):
@@ -21,6 +15,9 @@ class MediaFile(Base, BaseMixin, BaseVideoMixin):
def __str__(self):
return f'{self.title}({self.id})'
def update_title(self):
pass
def import_dict(self, import_data: Dict[str, Any]):
self.id = import_data['id']
self.created_date = import_data['created_date']
@@ -49,52 +46,6 @@ class MediaFile(Base, BaseMixin, BaseVideoMixin):
item['should_download'] = self.should_download
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):
__tablename__ = 'media_actor'
@@ -222,3 +173,35 @@ class MediaVideo(Base, BaseMixin):
item['url'] = self.url
item['should_download'] = self.should_download
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.orm import relationship
from db.models.base import Base, BaseMixin
from kontor_model.db.models.base import Base, BaseMixin
class Sport(Base, BaseMixin):
@@ -2,7 +2,7 @@ from typing import Optional
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]:
@@ -1,14 +1,12 @@
import uuid
from typing import List, Optional
from sqlalchemy.orm import Session
from src.core.log_conf import logger
from src.db.models.comic import Artist
from src.schema.comics.artist import AddArtist
from src.schema.comics.artist_details import ArtistDetailResponse, ArtistWorktypeComicResponse, ArtistWorktypeIssueResponse
from src.schema.comics.comic import ComicResponse
from src.schema.comics.worktype import WorktypeResponse
from kontor_model.db.models.comic import Artist
from kontor_model.schema.comics.artist import AddArtist
from kontor_model.schema.comics.artist_details import ArtistDetailResponse, ArtistWorktypeComicResponse, ArtistWorktypeIssueResponse
from kontor_model.schema.comics.comic import ComicResponse
from kontor_model.schema.comics.worktype import WorktypeResponse
def get_artist_details(artist: Artist) -> ArtistDetailResponse:
@@ -17,7 +15,17 @@ def get_artist_details(artist: Artist) -> ArtistDetailResponse:
for work in artist.comic_works:
worktype_id = work.work_type.id
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)
else:
comic_works_map[worktype_id] = ArtistWorktypeComicResponse(
@@ -37,7 +45,6 @@ def get_artist_details(artist: Artist) -> ArtistDetailResponse:
return response
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)
if artist is not None:
artist.name = add_artist.name
@@ -2,16 +2,15 @@ from typing import Dict, List, Optional
from sqlalchemy.orm import Session
from src.core.log_conf import logger
from src.db.models.comic import Comic, Issue
from src.schema.comics.artist import artist_to_response
from src.schema.comics.comic import ComicSchema, comic_to_response
from src.schema.comics.comic_details import ComicDetailsResponse, ComicWorktypeArtistResponse
from src.schema.comics.issue import IssueResponse, issue_to_response
from src.schema.comics.issue_details import IssueDetailsResponse
from src.schema.comics.publisher import publisher_to_response
from src.schema.comics.volume import VolumeResponse, volume_to_response
from src.schema.comics.worktype import worktype_to_response
from kontor_model.db.models.comic import Comic, Issue
from kontor_model.schema.comics.artist import artist_to_response
from kontor_model.schema.comics.comic import ComicSchema, comic_to_response
from kontor_model.schema.comics.comic_details import ComicDetailsResponse, ComicWorktypeArtistResponse
from kontor_model.schema.comics.issue import IssueResponse, issue_to_response
from kontor_model.schema.comics.issue_details import IssueDetailsResponse
from kontor_model.schema.comics.publisher import publisher_to_response
from kontor_model.schema.comics.volume import VolumeResponse, volume_to_response
from kontor_model.schema.comics.worktype import worktype_to_response
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]:
logger.info(f"update_comic: {new_comic} with {comic_id}")
comic: Optional[Comic] = db.get(Comic, comic_id)
return comic
@@ -48,7 +46,6 @@ def get_comic_details(comic: Comic) -> ComicDetailsResponse:
if worktype_id in works_map:
artist = artist_to_response(work.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}")
else:
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 src.core.log_conf import logger
from src.db.models.comic import WorkType
from src.schema.comics.worktype import AddWorkType
from kontor_model.db.models.comic import WorkType
from kontor_model.schema.comics.worktype import AddWorkType
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.commit()
db.refresh(worktype)
logger.info(f"create_new_worktype: {worktype}")
return 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)
if worktype is not None:
worktype.name = work.worktype
@@ -3,14 +3,13 @@ import uuid
from sqlalchemy.orm import Session
from src.core.log_conf import logger
from src.db.models.media import MediaActor
from src.db.repository.media.actorfile import delete_mediaactorfile
from src.schema.media.actor import MediaActorModel
from kontor_model.db.models.media import MediaActor
from kontor_model.db.repository.media.actorfile import delete_mediaactorfile
from kontor_model.schema.media.actor import MediaActorModel
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.id = str(uuid.uuid4())
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.commit()
db.refresh(media_actor)
logger.info(f"created {media_actor}")
print(f"created {media_actor}")
return media_actor
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)
if media_actor is not None:
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.
"""
logger.info("import MediaActor with %s", new_actor)
print("import MediaActor with %s", new_actor)
media_actor: MediaActor = MediaActor()
media_actor.id = new_actor.id
if new_actor.created_date:
@@ -3,9 +3,8 @@ import uuid
from sqlalchemy.orm import Session
from src.core.log_conf import logger
from src.db.models.media import MediaActorFile
from src.schema.media.actorfile import MediaActorFileModel
from kontor_model.db.models.media import MediaActorFile
from kontor_model.schema.media.actorfile import MediaActorFileModel
def create_new_mediaactorfile(
@@ -14,7 +13,7 @@ def create_new_mediaactorfile(
"""
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.id = str(uuid.uuid4())
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.
"""
logger.info("delete MediaActorFile with id %s", actorfile_id)
print("delete MediaActorFile with id %s", actorfile_id)
media_actorfile = db.get(MediaActorFile, actorfile_id)
db.delete(media_actorfile)
db.commit()
@@ -44,6 +43,21 @@ def import_mediaactorfile(
"""
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.id = new_actorfile.id
if new_actorfile.created_date:
media_actor_file.created_date = new_actorfile.created_date
else:
media_actor_file.created_date = datetime.now()
if new_actorfile.last_modified_date:
media_actor_file.last_modified_date = new_actorfile.last_modified_date
else:
media_actor_file.last_modified_date = datetime.now()
media_actor_file.version = new_actorfile.version
media_actor_file.media_actor_id = new_actorfile.media_actor_id
media_actor_file.media_file_id = new_actorfile.media_file_id
db.add(media_actor_file)
db.commit()
db.refresh(media_actor_file)
return media_actor_file
@@ -3,16 +3,15 @@ import uuid
from sqlalchemy.orm import Session
from src.core.log_conf import logger
from src.db.models.media import MediaFile
from src.schema.media.file import MediaFileModel
from kontor_model.db.models.media import MediaFile
from kontor_model.schema.media.file import MediaFileModel
def create_new_mediafile(link: str, db: Session) -> MediaFile:
"""
Create MediaFile with gievne URL.
"""
logger.info("create MediaFile with url {link}")
print("create MediaFile with url {link}")
media_file: MediaFile = MediaFile()
media_file.id = str(uuid.uuid4())
media_file.url = link
@@ -24,7 +23,7 @@ def create_new_mediafile(link: str, db: Session) -> MediaFile:
db.add(media_file)
db.commit()
db.refresh(media_file)
logger.info("created %s", media_file)
print("created %s", 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.
"""
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)
db.delete(media_file)
db.commit()
@@ -42,7 +41,7 @@ def import_mediafile(db: Session, new_file: MediaFileModel) -> MediaFile:
"""
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.id = new_file.id
if new_file.created_date:
@@ -0,0 +1,22 @@
from datetime import datetime
import uuid
from sqlalchemy.orm import Session
from kontor_model.db.models.media import MediaLofi
def create_new_lofi(url: str, db: Session) -> MediaLofi:
print(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
@@ -3,15 +3,14 @@ import uuid
from sqlalchemy.orm import Session
from src.db.models.media import MediaVideo
from src.webapps.media.forms import AddLinkForm
from kontor_model.db.models.media import MediaVideo
def create_new_video(video: AddLinkForm, db: Session) -> MediaVideo:
print(video.url)
def create_new_video(url: str, db: Session) -> MediaVideo:
print(url)
media_video = MediaVideo()
media_video.id = str(uuid.uuid4())
media_video.url = str(video.url)
media_video.url = url
media_video.created_date = datetime.now()
media_video.last_modified_date = datetime.now()
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 src.db.models.admin import MailAccount
from kontor_model.db.models.admin import MailAccount
class MailAccountResponse(BaseModel):
@@ -24,11 +24,11 @@ def to_response(account: MailAccount) -> MailAccountResponse:
created_date=account.created_date,
last_modified_date=account.last_modified_date,
version=account.version,
host=account.host,
host=str(account.host),
port=account.port,
protocol=account.protocol,
user_name=account.user_name,
password=account.password,
start_tls=account.start_tls,
protocol=str(account.protocol),
user_name=str(account.user_name),
password=str(account.password),
start_tls=bool(account.start_tls),
)
return response
@@ -2,7 +2,7 @@ from datetime import datetime
from pydantic import BaseModel
from src.db.models.bookshelf import Article
from kontor_model.db.models.bookshelf import Article
class ArticleResponse(BaseModel):
@@ -18,6 +18,6 @@ def to_response(article: Article) -> ArticleResponse:
created_date=article.created_date,
last_modified_date=article.last_modified_date,
version=article.version,
title=article.title
title=str(article.title)
)
return response
@@ -2,7 +2,7 @@ from datetime import datetime
from pydantic import BaseModel
from src.db.models.bookshelf import ArticleAuthor
from kontor_model.db.models.bookshelf import ArticleAuthor
class ArticleAuthorResponse(BaseModel):
@@ -19,7 +19,7 @@ def to_response(articleauthor: ArticleAuthor) -> ArticleAuthorResponse:
created_date=articleauthor.created_date,
last_modified_date=articleauthor.last_modified_date,
version=articleauthor.version,
article_id=articleauthor.article_id,
author_id=articleauthor.author_id
article_id=str(articleauthor.article_id),
author_id=str(articleauthor.author_id)
)
return response
@@ -2,7 +2,7 @@ from datetime import datetime
from pydantic import BaseModel
from src.db.models.bookshelf import Author
from kontor_model.db.models.bookshelf import Author
class AuthorResponse(BaseModel):
@@ -19,7 +19,7 @@ def to_response(author: Author) -> AuthorResponse:
created_date=author.created_date,
last_modified_date=author.last_modified_date,
version=author.version,
first_name=author.first_name,
last_name=author.last_name
first_name=str(author.first_name),
last_name=str(author.last_name)
)
return response

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