add missing endpoints
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s

This commit is contained in:
Thomas Peetz
2026-05-18 16:45:56 +02:00
parent 6dd8e12218
commit 71724ac800
32 changed files with 347 additions and 138 deletions
+25 -25
View File
@@ -2,31 +2,31 @@
add router for different parts (like comics, tysc, media) add router for different parts (like comics, tysc, media)
""" """
from fastapi import APIRouter from fastapi import APIRouter, Depends
from src.apis.version1.admin import token
from src.apis.version1.comics import artist, comic, issue
from src.apis.version1.media import mediaactor, mediaactorfile, mediafile
from src.apis.version1.tysc import card, cardset, fieldposition, player, rooster, sport, team, vendor
from src.core.security import get_current_user_from_token
from src.apis.version1 import ( from src.apis.version1.user import profile
comic, from src.apis.version1.bookshelf import article
mediaactor,
mediafile,
mediaactorfile,
sport,
player,
team,
fieldposition,
vendor,
admin,
user,
)
api_router = APIRouter(prefix="/api") api_router = APIRouter(prefix="/api")
api_router.include_router(comic.router, prefix="/comics", tags=["comics"]) api_router.include_router(comic.router, prefix="/comics", tags=["comics"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(mediafile.router, prefix="/media", tags=["media"]) api_router.include_router(artist.router, prefix="/comics", tags=["comics"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(mediaactor.router, prefix="/media", tags=["media"]) api_router.include_router(issue.router, prefix="/comics", tags=["comics"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(mediaactorfile.router, prefix="/media", tags=["media"]) api_router.include_router(mediafile.router, prefix="/media", tags=["media"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(sport.router, prefix="/tysc", tags=["tysc"]) api_router.include_router(mediaactor.router, prefix="/media", tags=["media"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(player.router, prefix="/tysc", tags=["tysc"]) api_router.include_router(mediaactorfile.router, prefix="/media", tags=["media"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(team.router, prefix="/tysc", tags=["tysc"]) api_router.include_router(sport.router, prefix="/tysc", tags=["tysc"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(fieldposition.router, prefix="/tysc", tags=["tysc"]) api_router.include_router(player.router, prefix="/tysc", tags=["tysc"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(vendor.router, prefix="/tysc", tags=["tysc"]) api_router.include_router(team.router, prefix="/tysc", tags=["tysc"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(admin.router, prefix="/login", tags=["login"]) api_router.include_router(fieldposition.router, prefix="/tysc", tags=["tysc"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(user.router, prefix="/user", tags=["user"]) api_router.include_router(rooster.router, prefix="/tysc", tags=["tysc"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(vendor.router, prefix="/tysc", tags=["tysc"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(cardset.router, prefix="/tysc", tags=["tysc"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(card.router, prefix="/tysc", tags=["tysc"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(article.router, prefix="/bookshelf", tags=["bookshelf"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(token.router, prefix="/login", tags=["login"])
api_router.include_router(profile.router, prefix="/user", tags=["user"], dependencies=[Depends(get_current_user_from_token)])
@@ -26,7 +26,7 @@ class LoginRequest(BaseModel):
) )
def login(request: LoginRequest) -> Token: def login(request: LoginRequest) -> Token:
logger.info(f"login with {request.email}") logger.info(f"login with {request.email}")
user = authenticate_user_by_email(request.email, request.password) user = authenticate_user_by_email(str(request.email), str(request.password))
scopes = ["admin", "read"] scopes = ["admin", "read"]
if not user: if not user:
raise HTTPException( raise HTTPException(
@@ -0,0 +1,20 @@
from typing import List
from fastapi import APIRouter
from src.db.models.bookshelf import Article
from src.db.session import SessionDep
from src.schema.bookshelf.article import ArticleResponse, to_response
router = APIRouter()
@router.get("/articles", response_model=List[ArticleResponse])
def get_all_artists(db: SessionDep) -> List[ArticleResponse]:
results: List[ArticleResponse] = []
articles = db.query(Article).all()
for article in articles:
response = to_response(article)
results.append(response)
return results
@@ -0,0 +1,43 @@
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 src.db.session import SessionDep
from src.schema.comics.artist import ArtistCreation, ArtistResponse
from src.schema.comics.artist_details import ArtistDetailResponse
router = APIRouter()
@router.get("/artists", response_model=List[ArtistResponse])
def get_all_artists(db: SessionDep) -> List[ArtistResponse]:
results: List[ArtistResponse] = []
artists = db.query(Artist).all()
for artist in artists:
results.append(ArtistResponse(id=artist.id, name=str(artist.name)))
return results
@router.get("/artists/{artist_id}", response_model=ArtistDetailResponse)
def get_artist(artist_id: str, db: SessionDep) -> ArtistDetailResponse:
artist = db.get(Artist, artist_id)
if artist is None:
raise HTTPException(status_code=404, detail="Artist could not be found")
response: ArtistDetailResponse = get_artist_details(artist)
return response
@router.post("/artists", status_code=status.HTTP_201_CREATED)
def add_artist(db: SessionDep, artist_creation: ArtistCreation) -> ArtistResponse:
artist: Artist = Artist()
setattr(artist, "name", artist_creation.name)
try:
db.add(artist)
db.commit()
except:
raise HTTPException(status_code=409, detail="Artist already added")
response = ArtistResponse(id=artist.id, name=str(artist.name))
return response
@@ -1,9 +1,9 @@
from typing import List from typing import List
from fastapi import APIRouter, HTTPException, status 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 Artist, Comic, Issue, Publisher from src.db.models.comic import Comic, Publisher
from src.db.repository.comics.artist import get_artist_details from src.db.repository.comics.artist import get_artist_details
from src.db.repository.comics.comic import ( from src.db.repository.comics.comic import (
get_comic_details, get_comic_details,
@@ -13,11 +13,8 @@ from src.db.repository.comics.comic import (
) )
from src.db.repository.comics.publisher import get_publisher_details from src.db.repository.comics.publisher import get_publisher_details
from src.db.session import SessionDep from src.db.session import SessionDep
from src.schema.comics.artist import ArtistCreation, ArtistResponse
from src.schema.comics.artist_details import ArtistDetailResponse
from src.schema.comics.comic import ComicResponse from src.schema.comics.comic import ComicResponse
from src.schema.comics.comic_details import ComicDetailsResponse from src.schema.comics.comic_details import ComicDetailsResponse
from src.schema.comics.issue_details import IssueDetailsResponse
from src.schema.comics.publisher import PublisherResponse from src.schema.comics.publisher import PublisherResponse
from src.schema.comics.publisher_details import PublisherDetailsResponse from src.schema.comics.publisher_details import PublisherDetailsResponse
@@ -25,7 +22,7 @@ router = APIRouter()
@router.get("/comics") @router.get("/comics")
def get_all_comics(db: SessionDep) -> List[ComicResponse]: # type: ignore def get_all_comics(db: SessionDep) -> List[ComicResponse]:
results: List[ComicResponse] = [] results: List[ComicResponse] = []
comics = list_comics(db) comics = list_comics(db)
for comic in comics: for comic in comics:
@@ -35,7 +32,7 @@ def get_all_comics(db: SessionDep) -> List[ComicResponse]: # type: ignore
@router.get("/comics/{comic_id}", response_model=ComicDetailsResponse) @router.get("/comics/{comic_id}", response_model=ComicDetailsResponse)
def get_comic(comic_id: str, db: SessionDep) -> ComicDetailsResponse: # type: ignore def get_comic(comic_id: str, db: SessionDep) -> ComicDetailsResponse:
comic = db.get(Comic, comic_id) comic = db.get(Comic, comic_id)
if comic is None: if comic is None:
raise HTTPException(status_code=404, detail="Comic could not be found") raise HTTPException(status_code=404, detail="Comic could not be found")
@@ -45,39 +42,10 @@ def get_comic(comic_id: str, db: SessionDep) -> ComicDetailsResponse: # type: ig
return response return response
@router.get("/artists", response_model=List[ArtistResponse])
def get_all_artists(db: SessionDep) -> List[ArtistResponse]: # type: ignore
results: List[ArtistResponse] = []
artists = db.query(Artist).all()
for artist in artists:
results.append(ArtistResponse(id=artist.id, name=str(artist.name))) # type: ignore
return results
@router.get("/artists/{artist_id}", response_model=ArtistDetailResponse)
def get_artist(artist_id: str, db: SessionDep) -> ArtistDetailResponse: # type: ignore
artist = db.get(Artist, artist_id)
if artist is None:
raise HTTPException(status_code=404, detail="Artist could not be found")
response: ArtistDetailResponse = get_artist_details(artist)
return response
@router.post("/artists", status_code=status.HTTP_201_CREATED)
def add_artist(db: SessionDep, artist_creation: ArtistCreation) -> ArtistResponse: # type: ignore
artist: Artist = Artist()
setattr(artist, "name", artist_creation.name)
try:
db.add(artist)
db.commit()
except:
raise HTTPException(status_code=409, detail="Artist already added")
response = ArtistResponse(id=artist.id, name=str(artist.name))
return response
@router.get("/publishers", response_model=List[PublisherResponse]) @router.get("/publishers", response_model=List[PublisherResponse])
def get_all_publishers(db: SessionDep) -> List[PublisherResponse]: # type: ignore def get_all_publishers(db: SessionDep) -> List[PublisherResponse]:
results: List[PublisherResponse] = [] results: List[PublisherResponse] = []
publishers = db.query(Publisher).all() publishers = db.query(Publisher).all()
for publisher in publishers: for publisher in publishers:
@@ -86,18 +54,10 @@ def get_all_publishers(db: SessionDep) -> List[PublisherResponse]: # type: ignor
@router.get("/publishers/{publisher_id}", response_model=PublisherDetailsResponse) @router.get("/publishers/{publisher_id}", response_model=PublisherDetailsResponse)
def get_publisher(publisher_id: str, db: SessionDep) -> PublisherDetailsResponse: # type: ignore def get_publisher(publisher_id: str, db: SessionDep) -> PublisherDetailsResponse:
publisher = db.get(Publisher, publisher_id) publisher = db.get(Publisher, publisher_id)
if publisher is None: if publisher is None:
raise HTTPException(status_code=404, detail="Publisher could not be found") raise HTTPException(status_code=404, detail="Publisher could not be found")
response: PublisherDetailsResponse = get_publisher_details(publisher) response: PublisherDetailsResponse = get_publisher_details(publisher)
return response return response
@router.get("/issues", response_model=List[IssueDetailsResponse])
def get_issues(db: SessionDep) -> List[IssueDetailsResponse]: # type: ignore
results: List[IssueDetailsResponse] = []
issues = db.query(Issue).all()
for issue in issues:
results.append(get_issue_details(issue))
return results
@@ -0,0 +1,19 @@
from typing import List
from fastapi import APIRouter
from src.db.models.comic import Issue
from src.db.repository.comics.comic import get_issue_details
from src.db.session import SessionDep
from src.schema.comics.issue_details import IssueDetailsResponse
router = APIRouter()
@router.get("/issues", response_model=List[IssueDetailsResponse])
def get_issues(db: SessionDep) -> List[IssueDetailsResponse]:
results: List[IssueDetailsResponse] = []
issues = db.query(Issue).all()
for issue in issues:
results.append(get_issue_details(issue))
return results
@@ -1,9 +1,8 @@
from typing import List from typing import List
from fastapi import APIRouter, status, HTTPException, Depends from fastapi import APIRouter, status, HTTPException
from sqlalchemy import select, Sequence from sqlalchemy import select
from src.core.log_conf import logger from src.core.log_conf import logger
from src.core.security import UserDep, get_current_user_from_token
from src.db.repository.media import ( from src.db.repository.media import (
create_new_mediaactorfile, create_new_mediaactorfile,
create_new_mediafile, create_new_mediafile,
@@ -34,11 +33,7 @@ def update_titles(db: SessionDep) -> list[MediaFileResponse]:
return results return results
@router.get( @router.get("/files", response_model=list[MediaFileResponse])
"/files",
response_model=list[MediaFileResponse],
dependencies=[Depends(get_current_user_from_token)],
)
def get_all_files( def get_all_files(
db: SessionDep, review: bool = False, download: bool = False db: SessionDep, review: bool = False, download: bool = False
) -> List[MediaFileResponse]: ) -> List[MediaFileResponse]:
@@ -59,11 +54,7 @@ def get_all_files(
return results return results
@router.get( @router.get("/files/{file_id}", response_model=MediaFileResponse)
"/files/{file_id}",
response_model=MediaFileResponse,
dependencies=[Depends(get_current_user_from_token)],
)
def get_file(file_id: str, db: SessionDep) -> MediaFileResponse: def get_file(file_id: str, db: SessionDep) -> MediaFileResponse:
""" """
Get MediaFile with given id or return HTTPException. Get MediaFile with given id or return HTTPException.
+19
View File
@@ -0,0 +1,19 @@
from typing import List
from fastapi import APIRouter
from src.db.models.tysc import Card
from src.db.session import SessionDep
from src.schema.tysc.card import CardResponse, to_response
router = APIRouter()
@router.get("/cards")
def get_all_players(db: SessionDep) -> List[CardResponse]:
results: List[CardResponse] = []
cards = db.query(Card).all()
for card in cards:
response = to_response(card)
results.append(response)
return results
@@ -0,0 +1,19 @@
from typing import List
from fastapi import APIRouter
from src.db.models.tysc import CardSet
from src.db.session import SessionDep
from src.schema.tysc.cardset import CardSetResponse, to_response
router = APIRouter()
@router.get("/cardsets")
def get_all_players(db: SessionDep) -> List[CardSetResponse]:
results: List[CardSetResponse] = []
cardsets = db.query(CardSet).all()
for cardset in cardsets:
response = to_response(cardset)
results.append(response)
return results
@@ -0,0 +1,19 @@
from typing import List
from fastapi import APIRouter
from src.db.models.tysc import Rooster
from src.db.session import SessionDep
from src.schema.tysc.rooster import RoosterResponse, to_response
router = APIRouter()
@router.get("/roosters")
def get_all_sports(db: SessionDep) -> List[RoosterResponse]:
results: list[RoosterResponse] = []
roosters = db.query(Rooster).all()
for rooster in roosters:
response = to_response(rooster)
results.append(response)
return results
+1 -1
View File
@@ -142,7 +142,7 @@ async def get_current_user(
logger.info("Exception raised", exc_info=True) logger.info("Exception raised", exc_info=True)
raise credentials_exception raise credentials_exception
with SessionLocal() as db: with SessionLocal() as db:
user = get_profile_by_username(username=token_data.username, db=db) user = get_profile_by_username(username=str(token_data.username), db=db)
if user is None: if user is None:
logger.info("user not found") logger.info("user not found")
raise credentials_exception raise credentials_exception
+24 -22
View File
@@ -1,50 +1,52 @@
from typing import List
from sqlalchemy import Column, ForeignKey, Integer, String from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship from sqlalchemy.orm import Mapped, mapped_column, relationship
from src.db.models.base import Base, BaseMixin from src.db.models.base import Base, BaseMixin
class Article(Base, BaseMixin): class Article(Base, BaseMixin):
__tablename__ = 'article' __tablename__ = 'article'
title = Column(String, unique=True) title: Mapped[str] = mapped_column(unique=True)
article_authors = relationship("ArticleAuthor") article_authors = relationship("ArticleAuthor")
class Author(Base, BaseMixin): class Author(Base, BaseMixin):
__tablename__ = 'author' __tablename__ = 'author'
first_name = Column(String) first_name: Mapped[str]
last_name = Column(String) last_name: Mapped[str]
article_authors = relationship("ArticleAuthor") article_authors: Mapped[List["ArticleAuthor"]] = relationship(back_populates="author")
book_authors = relationship("BookAuthor") book_authors: Mapped[List["BookAuthor"]] = relationship(back_populates="author")
class BookshelfPublisher(Base, BaseMixin): class BookshelfPublisher(Base, BaseMixin):
__tablename__ = 'bookshelf_publisher' __tablename__ = 'bookshelf_publisher'
name = Column(String, unique=True) name: Mapped[str] = mapped_column(unique=True)
books = relationship("Book") books: Mapped[List["Book"]] = relationship(back_populates="publisher")
class Book(Base, BaseMixin): class Book(Base, BaseMixin):
__tablename__ = 'book' __tablename__ = 'book'
isbn = Column(String, unique=True) isbn: Mapped[str] = mapped_column(unique=True)
title = Column(String) title: Mapped[str]
year = Column(Integer, nullable=False) year: Mapped[int] = mapped_column(nullable=False)
publisher_id = Column(String, ForeignKey('bookshelf_publisher.id'), nullable=False) publisher_id: Mapped[str] = mapped_column(ForeignKey("bookshelf_publisher.id"), nullable=False)
publisher = relationship('BookshelfPublisher', back_populates="books") publisher: Mapped[BookshelfPublisher] = relationship(back_populates="books")
book_authors = relationship("BookAuthor") book_authors: Mapped[List["BookAuthor"]] = relationship(back_populates="book")
class ArticleAuthor(Base, BaseMixin): class ArticleAuthor(Base, BaseMixin):
__tablename__ = 'article_author' __tablename__ = 'article_author'
article_id = Column(String, ForeignKey('article.id'), nullable=False) article_id: Mapped[str] = mapped_column(ForeignKey("article.id"), nullable=False)
article = relationship('Article', back_populates="article_authors") article: Mapped[Article] = relationship(back_populates="article_authors")
author_id = Column(String, ForeignKey('author.id'), nullable=False) author_id: Mapped[str] = mapped_column(ForeignKey("author.id"), nullable=False)
author = relationship('Author', back_populates="article_authors") author: Mapped[Author] = relationship(back_populates="article_authors")
class BookAuthor(Base, BaseMixin): class BookAuthor(Base, BaseMixin):
__tablename__ = 'book_author' __tablename__ = 'book_author'
author_id = Column(String, ForeignKey('author.id'), nullable=False) author_id: Mapped[str] = mapped_column(ForeignKey("author.id"), nullable=False)
author = relationship('Author', back_populates="book_authors") author: Mapped[Author] = relationship(back_populates="book_authors")
book_id = Column(String, ForeignKey('book.id'), nullable=False) book_id: Mapped[str] = mapped_column(ForeignKey("book.id"), nullable=False)
book = relationship('Book', back_populates="book_authors") book: Mapped[Book] = relationship(back_populates="book_authors")
+4 -1
View File
@@ -20,13 +20,16 @@ def list_comics(db: Session) -> List[Comic]:
def get_issue_details(issue: Issue) -> IssueDetailsResponse: def get_issue_details(issue: Issue) -> IssueDetailsResponse:
volume = None
if issue.volume:
volume = VolumeResponse(id=issue.volume.id, name=issue.volume.name)
response = IssueDetailsResponse( response = IssueDetailsResponse(
id=issue.id, id=issue.id,
issue_number=str(issue.issue_number), issue_number=str(issue.issue_number),
in_stock=bool(issue.in_stock), in_stock=bool(issue.in_stock),
is_read=bool(issue.is_read), is_read=bool(issue.is_read),
comic=ComicResponse(id=issue.comic.id, title=issue.comic.title, completed=issue.comic.completed), comic=ComicResponse(id=issue.comic.id, title=issue.comic.title, completed=issue.comic.completed),
volume=VolumeResponse(id=issue.volume.id, name=issue.volume.name) volume=volume
) )
return response return response
+1 -1
View File
@@ -6,7 +6,7 @@ from fastapi.staticfiles import StaticFiles
from src.apis.base import api_router from src.apis.base import api_router
from src.apis.version1.healthcheck import health_router from src.apis.version1.healthcheck import health_router
from src.apis.version1.login import login_router 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.db.models.base import Base from src.db.models.base import Base
@@ -0,0 +1,23 @@
from datetime import datetime
from pydantic import BaseModel
from src.db.models.bookshelf import Article
class ArticleResponse(BaseModel):
id: str
created_date: datetime
last_modified_date: datetime
version: int
title: str
def to_response(article: Article) -> ArticleResponse:
response: ArticleResponse = ArticleResponse(
id=article.id,
created_date=article.created_date,
last_modified_date=article.last_modified_date,
version=article.version,
title=article.title
)
return response
+31
View File
@@ -0,0 +1,31 @@
from datetime import datetime
from pydantic import BaseModel
from src.db.models.tysc import Card
class CardResponse(BaseModel):
id: str
created_date: datetime
last_modified_date: datetime
version: int
card_number: int
year: int
card_set_id: str
rooster_id: str
vendor_id: str
def to_response(card: Card) -> CardResponse:
response: CardResponse = CardResponse(
id=card.id,
created_date=card.created_date,
last_modified_date=card.last_modified_date,
version=card.version,
card_number=card.card_number,
year=card.year,
card_set_id=card.card_set_id,
rooster_id=card.rooster_id,
vendor_id=card.vendor_id
)
return response
+30
View File
@@ -0,0 +1,30 @@
from datetime import datetime
from pydantic import BaseModel
from src.db.models.tysc import CardSet
class CardSetResponse(BaseModel):
id: str
created_date: datetime
last_modified_date: datetime
version: int
name: str
parallel_set: bool
insert_set: bool
vendor_id: str
def to_response(cardset: CardSet) -> CardSetResponse:
response: CardSetResponse = CardSetResponse(
id=cardset.id,
created_date=cardset.created_date,
last_modified_date=cardset.last_modified_date,
version=cardset.version,
name=cardset.name,
parallel_set=cardset.parallel_set,
insert_set=cardset.insert_set,
vendor_id=cardset.vendor_id
)
return response
+1 -1
View File
@@ -2,7 +2,7 @@ from datetime import datetime
from pydantic import BaseModel from pydantic import BaseModel
from src.db.models.tysc import FieldPosition, Team from src.db.models.tysc import FieldPosition
class FieldPositionResponse(BaseModel): class FieldPositionResponse(BaseModel):
+1 -1
View File
@@ -19,7 +19,7 @@ class RoosterResponse(BaseModel):
position_id: str position_id: str
def to_reponse(rooster: Rooster) -> RoosterResponse: def to_response(rooster: Rooster) -> RoosterResponse:
""" """
convert database object to response object (Pydantic). convert database object to response object (Pydantic).
""" """
+5 -7
View File
@@ -1,8 +1,4 @@
# from src.apis.version1.admin import login_for_access_token from src.apis.version1.admin.token import login_for_token_cookie
from fastapi.security import OAuth2PasswordRequestForm
from src.apis.version1.admin import login_for_token_cookie
from src.db.session import SessionDep
from fastapi import APIRouter, Depends from fastapi import APIRouter, Depends
from fastapi import HTTPException from fastapi import HTTPException
from fastapi import Request from fastapi import Request
@@ -20,7 +16,7 @@ def login(request: Request):
@router.post("/login/") @router.post("/login/")
async def login(request: Request): async def validate_login(request: Request):
form = LoginForm(request) form = LoginForm(request)
await form.load_data() await form.load_data()
if await form.is_valid(): if await form.is_valid():
@@ -31,6 +27,8 @@ async def login(request: Request):
return response return response
except HTTPException: except HTTPException:
form.__dict__.update(msg="") form.__dict__.update(msg="")
form.__dict__.get("errors").append("Incorrect Email or Password") errors = form.__dict__.get("errors")
if errors:
errors.append("Incorrect Email or Password")
return templates.TemplateResponse("auth/login.html", form.__dict__) return templates.TemplateResponse("auth/login.html", form.__dict__)
return templates.TemplateResponse("auth/login.html", form.__dict__) return templates.TemplateResponse("auth/login.html", form.__dict__)
+31 -13
View File
@@ -28,24 +28,30 @@ MAPPING: Dict[str, str] = {
"story_arc": "api/comics/storyarcs", "story_arc": "api/comics/storyarcs",
"issue": "api/comics/issues", "issue": "api/comics/issues",
"issue_work": "api/comics/issueworks", "issue_work": "api/comics/issueworks",
"article": "", "article": "api/bookshelf/articles",
"bookshelf_publisher": "", "bookshelf_publisher": "api/bookshelf/publishers",
"book": "", "book": "api/bookshelf/books",
"author": "", "author": "api/bookshelf/authors",
"article_author": "", "article_author": "api/bookshelf/articleauthors",
"book_author": "", "book_author": "api/bookshelf/bookauthors",
"media_article": "", "media_article": "api/media/articles",
"media_video": "api/media/videos", "media_video": "api/media/videos",
"media_file": "api/media/files", "media_file": "api/media/files",
"media_actor": "api/media/actors", "media_actor": "api/media/actors",
"media_actor_file": "api/media/actorfiles", "media_actor_file": "api/media/actorfiles",
"profile": "", "profile": "api/user/profiles",
"permission": "", "permission": "api/user/permissions",
"assignment": "", "assignment": "api/user/assignments",
"token": "", "token": "api/user/tokens",
"mail_account": "", "mail_account": "api/admin/mailaccount",
} }
class EndPointNotAvailableException(Exception):
"""
Raised when calling an not existing endpoint.
"""
pass
@dataclass @dataclass
class Login: class Login:
@@ -99,7 +105,9 @@ class Server:
url: str = f"{self.url}/{MAPPING[table]}?{param}" url: str = f"{self.url}/{MAPPING[table]}?{param}"
headers: Dict[str, str] = {"Authorization": f"Bearer {self.token}"} headers: Dict[str, str] = {"Authorization": f"Bearer {self.token}"}
response = requests.get(url, headers=headers, timeout=self.timeout) response = requests.get(url, headers=headers, timeout=self.timeout)
log.info(f"Status: {response.status_code}") log.debug(f"Status: {response.status_code}")
if response.status_code==404:
raise EndPointNotAvailableException
data = response.json() data = response.json()
return data return data
@@ -121,6 +129,16 @@ class ApiConfig:
login: Login login: Login
server: List[Server] server: List[Server]
def get_server(self, server_name: str) -> Optional[Server]:
"""
"""
found_server = None
for server in self.server:
if server.name == server_name:
found_server = server
return found_server
def get_logger(level, config: str): def get_logger(level, config: str):
+1 -1
View File
@@ -1,4 +1,4 @@
from typing import Any, AnyStr, Dict 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
+19 -5
View File
@@ -1,12 +1,13 @@
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
from dataclasses import dataclass from typing import List
from api import get_logger, get_api_config from api import MAPPING, EndPointNotAvailableException, Server, get_logger, get_api_config
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument("--verbose", "-v", action="count", default=0) parser.add_argument("--verbose", "-v", action="count", default=0)
parser.add_argument("--config", "-c", default="kontor-api") parser.add_argument("--config", "-c", default="kontor-api")
parser.add_argument("--dry-run", "-m", action="store_true") parser.add_argument("--dry-run", "-m", action="store_true")
parser.add_argument("--server", "-s")
parser.add_argument("--cleanup", "-d", action="store_true") parser.add_argument("--cleanup", "-d", action="store_true")
args = parser.parse_args() args = parser.parse_args()
@@ -15,7 +16,20 @@ if __name__== "__main__":
logger = get_logger(args.verbose, "kontor") logger = get_logger(args.verbose, "kontor")
logger.info("kontor.sync started") logger.info("kontor.sync started")
apiConfig = get_api_config(logger, args.config) apiConfig = get_api_config(logger, args.config)
for server in apiConfig.server: server_list: List[Server] = []
data = server.request(logger, "media_file") if args.server:
logger.info(len(data)) server = apiConfig.get_server(args.server)
if server:
server_list.append(server)
else:
server_list.extend(apiConfig.server)
for server in server_list:
for table, path in MAPPING.items():
try:
data = server.request(logger, table=table)
logger.info("%s: %s", table, len(data))
if len(data) == 1:
logger.info("show data: %s", data)
except EndPointNotAvailableException:
logger.info("Endpoint not implemented")
logger.info("kontor.sync finished") logger.info("kontor.sync finished")