Remove obsolete endpoints #89

Merged
tpeetz merged 1 commits from feature/88-remove-obsolete-endpoints into develop/0.3.0 2026-05-19 17:52:31 +00:00
40 changed files with 589 additions and 152 deletions
Showing only changes of commit 4aa9cf8263 - Show all commits
+13 -5
View File
@@ -3,20 +3,25 @@ add router for different parts (like comics, tysc, media)
"""
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.admin import mailaccount
from src.apis.version1.comics import artist, comic, issue, worktype, volume, storyarc
from src.apis.version1.media import mediaactor, mediaactorfile, mediafile, mediavideo, mediaarticle
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.user import profile
from src.apis.version1.user import assignment, permission, profile, token
from src.apis.version1.bookshelf import article
api_router = APIRouter(prefix="/api")
api_router.include_router(comic.router, prefix="/comics", tags=["comics"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(artist.router, prefix="/comics", tags=["comics"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(issue.router, prefix="/comics", tags=["comics"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(worktype.router, prefix="/comics", tags=["comics"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(volume.router, prefix="/comics", tags=["comics"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(storyarc.router, prefix="/comics", tags=["comics"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(mediafile.router, prefix="/media", tags=["media"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(mediavideo.router, prefix="/media", tags=["media"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(mediaarticle.router, prefix="/media", tags=["media"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(mediaactor.router, prefix="/media", tags=["media"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(mediaactorfile.router, prefix="/media", tags=["media"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(sport.router, prefix="/tysc", tags=["tysc"], dependencies=[Depends(get_current_user_from_token)])
@@ -28,5 +33,8 @@ api_router.include_router(vendor.router, prefix="/tysc", tags=["tysc"], dependen
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)])
api_router.include_router(token.router, prefix="/user", tags=["user"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(permission.router, prefix="/user", tags=["user"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(assignment.router, prefix="/user", tags=["user"], dependencies=[Depends(get_current_user_from_token)])
api_router.include_router(mailaccount.router, prefix="/admin", tags=["admin"], dependencies=[Depends(get_current_user_from_token)])
+22 -12
View File
@@ -1,8 +1,7 @@
from datetime import timedelta
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi import APIRouter, Depends, HTTPException, Response, status
from fastapi.security import OAuth2PasswordRequestForm
from pydantic import BaseModel
from typing import Annotated
from src.core.config import settings
from src.core.log_conf import logger
@@ -11,16 +10,12 @@ from src.core.security import (
authenticate_user_by_username,
create_access_token,
)
from src.schema.admin import Token
from src.schema.admin.login import LoginRequest
from src.schema.admin.token import Token
from src.webapps.auth.forms import LoginForm
login_router = APIRouter()
class LoginRequest(BaseModel):
email: str | None = None
password: str | None = None
@login_router.post(
"/login",
tags=["login"],
@@ -47,9 +42,8 @@ def login(request: LoginRequest) -> Token:
@login_router.post("/token", tags=["login"], summary="Login for access token")
async def login_for_access_token(
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
) -> Token:
#async def login_for_access_token(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]) -> Token:
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()) -> Token:
user = authenticate_user_by_username(form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=400, detail="Incorrect username or password")
@@ -59,3 +53,19 @@ async def login_for_access_token(
expires_delta=access_token_expires,
)
return Token(access_token=access_token, token_type="bearer")
def login_for_token_cookie(response: Response, form_data: LoginForm = Depends()):
user = authenticate_user_by_email(str(form_data.username), str(form_data.password))
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
)
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user.email}, expires_delta=access_token_expires
)
response.set_cookie(
key="access_token", value=f"Bearer {access_token}", httponly=True
)
return {"access_token": access_token, "token_type": "bearer"}
@@ -4,7 +4,7 @@ from fastapi import APIRouter
from src.db.models.admin import MailAccount
from src.db.session import SessionDep
from src.schema.admin import MailAccountResponse, to_response
from src.schema.admin.mailaccount import MailAccountResponse, to_response
router = APIRouter()
@@ -1,54 +0,0 @@
from datetime import timedelta
from typing import Annotated
from fastapi import APIRouter, Body, HTTPException, status, Depends, Response
from fastapi.security import OAuth2PasswordRequestForm
from src.core.config import settings
from src.core.log_conf import logger
from src.core.security import create_access_token, authenticate_user_by_email, authenticate_user_by_username, get_current_active_user
from src.db.models.admin import Profile
from src.schema.admin import Token, ProfileModel
from src.webapps.auth.forms import LoginForm
router = APIRouter()
@router.post("/token")
def login_for_access_token(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]) -> Token:
user = authenticate_user_by_username(form_data.username, form_data.password)
logger.info(f"Request /token: login with {form_data.username}")
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user.email, "scope": " ".join(form_data.scopes)}, expires_delta=access_token_expires
)
return Token(access_token=access_token, token_type="bearer")
# @router.post("/token-cookie", response_model=Token)
def login_for_token_cookie(response: Response, form_data: LoginForm = Depends()):
user = authenticate_user_by_email(form_data.username, form_data.password) # type: ignore
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
)
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user.email}, expires_delta=access_token_expires
)
response.set_cookie(
key="access_token", value=f"Bearer {access_token}", httponly=True
)
return {"access_token": access_token, "token_type": "bearer"}
@router.get("/profile", response_model=ProfileModel)
async def read_profile(current_user: Annotated[Profile, Depends(get_current_active_user)]):
return current_user
+6 -6
View File
@@ -3,17 +3,17 @@ 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
from src.schema.comics.issue import IssueResponse, to_response
router = APIRouter()
@router.get("/issues", response_model=List[IssueDetailsResponse])
def get_issues(db: SessionDep) -> List[IssueDetailsResponse]:
results: List[IssueDetailsResponse] = []
@router.get("/issues", response_model=List[IssueResponse])
def get_issues(db: SessionDep) -> List[IssueResponse]:
results: List[IssueResponse] = []
issues = db.query(Issue).all()
for issue in issues:
results.append(get_issue_details(issue))
response = to_response(issue)
results.append(response)
return results
@@ -0,0 +1,18 @@
from typing import List
from fastapi import APIRouter
from src.db.models.comic import StoryArc
from src.db.session import SessionDep
from src.schema.comics.storyarc import StoryArcResponse, to_response
router = APIRouter()
@router.get("/storyarcs", response_model=List[StoryArcResponse])
def get_issues(db: SessionDep) -> List[StoryArcResponse]:
results: List[StoryArcResponse] = []
storyarcs = db.query(StoryArc).all()
for storyarc in storyarcs:
response = to_response(storyarc)
results.append(response)
return results
@@ -0,0 +1,18 @@
from typing import List
from fastapi import APIRouter
from src.db.models.comic import Volume
from src.db.session import SessionDep
from src.schema.comics.volume import VolumeResponse, to_response
router = APIRouter()
@router.get("/volumes", response_model=List[VolumeResponse])
def get_issues(db: SessionDep) -> List[VolumeResponse]:
results: List[VolumeResponse] = []
worktypes = db.query(Volume).all()
for worktype in worktypes:
response = to_response(worktype)
results.append(response)
return results
@@ -0,0 +1,19 @@
from typing import List
from fastapi import APIRouter
from src.db.models.comic import WorkType
from src.db.session import SessionDep
from src.schema.comics.worktype import WorktypeResponse, to_response
router = APIRouter()
@router.get("/worktypes", response_model=List[WorktypeResponse])
def get_issues(db: SessionDep) -> List[WorktypeResponse]:
results: List[WorktypeResponse] = []
worktypes = db.query(WorkType).all()
for worktype in worktypes:
response = to_response(worktype)
results.append(response)
return results
+1 -1
View File
@@ -1,6 +1,6 @@
from fastapi import APIRouter, status
from src.schema.admin import HealthCheck
from src.schema.admin.healthcheck import HealthCheck
health_router = APIRouter()
@@ -0,0 +1,25 @@
from typing import List
from fastapi import APIRouter
from src.db.models.media import MediaArticle
from src.db.session import SessionDep
from src.schema.media.article import MediaArticleResponse, to_response
router = APIRouter()
@router.get("/articles", response_model=List[MediaArticleResponse])
def get_all_files(
db: SessionDep, review: bool = False, download: bool = False
) -> List[MediaArticleResponse]:
"""
Get all MediaVideos.
"""
results: List[MediaArticleResponse] = []
articles: List[MediaArticle]
articles = db.query(MediaArticle).all()
for article in articles:
response = to_response(article)
results.append(response)
return results
@@ -0,0 +1,31 @@
from typing import List
from fastapi import APIRouter
from src.db.models.media import MediaVideo
from src.db.session import SessionDep
from src.schema.media.video import MediaVideoResponse, to_response
router = APIRouter()
@router.get("/videos", response_model=List[MediaVideoResponse])
def get_all_files(
db: SessionDep, review: bool = False, download: bool = False
) -> List[MediaVideoResponse]:
"""
Get all MediaVideos.
"""
results: List[MediaVideoResponse] = []
files: List[MediaVideo]
if review:
files = db.query(MediaVideo).filter(MediaVideo.review.is_(True)).all()
elif download:
files = db.query(MediaVideo).filter(MediaVideo.should_download.is_(True)).all()
else:
files = db.query(MediaVideo).all()
for mediafile in files:
response = to_response(mediafile)
results.append(response)
return results
@@ -0,0 +1,20 @@
from typing import List
from fastapi import APIRouter
from src.db.models.admin import Assignment
from src.db.session import SessionDep
from src.schema.user.assignment import AssignmentResponse, to_response
router = APIRouter()
@router.get("/assignments", response_model=List[AssignmentResponse])
def get_all_profiles(db: SessionDep) -> List[AssignmentResponse]:
results: List[AssignmentResponse] = []
profiles = db.query(Assignment).all()
for profile in profiles:
response = to_response(profile)
results.append(response)
return results
@@ -0,0 +1,19 @@
from typing import List
from fastapi import APIRouter
from src.db.models.admin import Permission
from src.db.session import SessionDep
from src.schema.user.permission import PermissionResponse, to_response
router = APIRouter()
@router.get("/permissions", response_model=List[PermissionResponse])
def get_all_profiles(db: SessionDep) -> List[PermissionResponse]:
results: List[PermissionResponse] = []
permissions = db.query(Permission).all()
for permission in permissions:
response = to_response(permission)
results.append(response)
return results
+10 -4
View File
@@ -3,6 +3,7 @@ from fastapi import APIRouter, HTTPException, status
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 src.db.repository.user import create_new_profile, get_profile_details
from src.db.session import SessionDep
@@ -11,8 +12,13 @@ from src.schema.user.profile import ProfileResponse, ProfileModel
router = APIRouter()
@router.get("/profile", response_model=ProfileModel)
async def read_profile(current_user: CurrentUser):
return current_user
@router.get("/profiles", response_model=List[ProfileResponse])
def get_all_profiles(db: SessionDep) -> List[ProfileResponse]: # type: ignore
def get_all_profiles(db: SessionDep) -> List[ProfileResponse]:
results: List[ProfileResponse] = []
profiles = db.scalars(select(Profile)).all()
for profile in profiles:
@@ -21,7 +27,7 @@ def get_all_profiles(db: SessionDep) -> List[ProfileResponse]: # type: ignore
return results
@router.get("/profiles/{profile_id}", response_model=ProfileResponse)
def get_profile(profile_id: str, db: SessionDep) -> ProfileResponse: # type: ignore
def get_profile(profile_id: str, db: SessionDep) -> ProfileResponse:
profile = db.get(Profile, profile_id)
if not profile:
raise HTTPException(status_code=404, detail="MediaActor could not be found")
@@ -37,8 +43,8 @@ def delete_profile(profile_id: str, db: SessionDep): # type: ignore
delete_profile(profile_id=profile_id, db=db)
@router.post("/profiles", status_code=status.HTTP_201_CREATED)
def add_profile(new_profile: ProfileModel, db: SessionDep) -> ProfileResponse: # type: ignore
logger.info(f"add profile {new_profile.user_name}")
def add_profile(new_profile: ProfileModel, db: SessionDep) -> ProfileResponse:
logger.info(f"add profile {new_profile.username}")
try:
profile: Profile = create_new_profile(new_profile, db)
except:
@@ -0,0 +1,19 @@
from typing import List
from fastapi import APIRouter
from src.db.models.admin import Token
from src.db.session import SessionDep
from src.schema.user.token import TokenResponse, to_response
router = APIRouter()
@router.get("/tokens", response_model=List[TokenResponse])
def get_all_profiles(db: SessionDep) -> List[TokenResponse]:
results: List[TokenResponse] = []
tokens = db.query(Token).all()
for token in tokens:
response = to_response(token)
results.append(response)
return results
+35
View File
@@ -0,0 +1,35 @@
import json
import time
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from src.core.log_conf import logger
class RequestLoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next) -> Response:
start_time = time.time()
path = request.url.path
if path != "/health":
# Log request info
request_info ={
"method": request.method,
"path": path,
"client_ip": request.client.host if request.client else "unknown"
}
logger.info("Incoming: %s", json.dumps(request_info))
# Process request
response = await call_next(request)
if path != "/health":
# Log response info
duration_ms = (time.time()- start_time)*1000
response_info = {
"status_code": response.status_code,
"duration_ms": round(duration_ms, 2)
}
logger.info("completed: %s", json.dumps(response_info))
return response
+18 -16
View File
@@ -1,12 +1,15 @@
import logging
from datetime import datetime, timedelta, timezone
from typing import Annotated, Dict, List, Optional
from typing import Annotated, List, Optional
import bcrypt
from fastapi import Depends, HTTPException, Request, Security, status
from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel
from fastapi.security import OAuth2, OAuth2PasswordBearer, SecurityScopes
from fastapi.security.utils import get_authorization_scheme_param
from fastapi import Depends, HTTPException, Security, status
#from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel
from fastapi.security import (
#OAuth2,
OAuth2PasswordBearer,
SecurityScopes
)
#from fastapi.security.utils import get_authorization_scheme_param
from jose import JWTError, jwt
from pydantic import ValidationError
@@ -19,7 +22,8 @@ from src.db.repository.admin import (
is_database_empty,
)
from src.db.session import SessionLocal
from src.schema.admin import ProfileModel, TokenData
from src.schema.admin.token import TokenData
from src.schema.user.profile import ProfileModel, to_model
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="/token",
@@ -161,13 +165,7 @@ async def get_current_active_user(
) -> ProfileModel:
if not current_user.enabled:
raise HTTPException(status_code=400, detail="Inactive user")
user_model = ProfileModel(
username=current_user.user_name,
email=current_user.email, # type: ignore
first_name=current_user.first_name,
last_name=current_user.last_name, # type: ignore
active=current_user.enabled,
) # type: ignore
user_model = to_model(current_user)
return user_model
@@ -181,7 +179,7 @@ def get_current_user_from_token(token: str = Depends(oauth2_scheme)):
payload = jwt.decode(
token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]
)
username: str = payload.get("sub") # type: ignore
username: Optional[str] = payload.get("sub")
logger.info("username/email extracted is %s", username)
if username is None:
raise credentials_exception
@@ -190,8 +188,12 @@ def get_current_user_from_token(token: str = Depends(oauth2_scheme)):
with SessionLocal() as db:
user = get_profile_by_email(email=username, db=db)
if user is None:
raise credentials_exception
user = get_profile_by_username(username=username, db=db)
if user is None:
raise credentials_exception
return user
UserDep = Annotated[Profile, Depends(get_current_user_from_token)]
CurrentUser = Annotated[Profile, Depends(get_current_active_user)]
+1 -1
View File
@@ -38,7 +38,7 @@ def delete_profile(db: Session, profile_id: str):
def get_profile_details(profile: Profile) -> ProfileResponse:
reponse: ProfileResponse = ProfileResponse(
id=profile.id,
user_name=str(profile.user_name)
username=str(profile.user_name)
)
return reponse
+6 -4
View File
@@ -9,6 +9,7 @@ from src.apis.version1.healthcheck import health_router
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 src.db.session import engine
from src.db.utils import check_db_connected, check_db_disconnected
@@ -23,10 +24,10 @@ async def lifespan(app: FastAPI):
def include_router(app: FastAPI):
app.include_router(api_router)
app.include_router(web_app_router)
app.include_router(health_router)
app.include_router(login_router)
app.include_router(api_router, tags=["api"])
app.include_router(web_app_router, tags=["webapp"])
app.include_router(health_router, tags=["admin"])
app.include_router(login_router, tags=["webapp"])
def configure_static(app: FastAPI):
@@ -41,6 +42,7 @@ def add_middle_ware(app: FastAPI):
allow_methods=["*"],
allow_headers=["*"],
)
app.add_middleware(RequestLoggingMiddleware)
def create_tables():
@@ -0,0 +1,9 @@
from pydantic import BaseModel
class HealthCheck(BaseModel):
"""
Health check model
"""
status: str = "ok"
+8
View File
@@ -0,0 +1,8 @@
from typing import Optional
from pydantic import BaseModel
class LoginRequest(BaseModel):
email: Optional[str] = None
password: Optional[str] = None
@@ -1,37 +1,10 @@
from datetime import datetime
from typing import Optional, List
from pydantic import BaseModel
from src.db.models.admin import MailAccount
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
username: Optional[str] = None
scopes: List[str] = []
class ProfileModel(BaseModel):
username: str
email: str
first_name: str
last_name: str
active: bool
class HealthCheck(BaseModel):
"""
Health check model
"""
status: str = "ok"
class MailAccountResponse(BaseModel):
id: str
created_date: datetime
+13
View File
@@ -0,0 +1,13 @@
from typing import List, Optional
from pydantic import BaseModel
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
username: Optional[str] = None
scopes: List[str] = []
+30
View File
@@ -1,8 +1,38 @@
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
from src.db.models.comic import Issue
class IssueResponse(BaseModel):
id: str
created_date: datetime
last_modified_date: datetime
version: int
issue_number: str
title: Optional[str]
published_on: Optional[datetime]
in_stock: bool
is_read: bool
comic_id: str
volume_id: Optional[str]
story_arc_id: Optional[str]
def to_response(issue: Issue) -> IssueResponse:
response: IssueResponse = IssueResponse(
id=issue.id,
created_date=issue.created_date,
last_modified_date=issue.last_modified_date,
version=issue.version,
issue_number=issue.issue_number,
title=issue.title,
published_on=issue.published_on,
in_stock=issue.in_stock,
is_read=issue.is_read,
comic_id=issue.comic_id,
volume_id=issue.volume_id,
story_arc_id=issue.story_arc_id
)
return response
@@ -11,3 +11,4 @@ class IssueDetailsResponse(BaseModel):
is_read: bool
comic: ComicResponse
volume: VolumeResponse | None
+30
View File
@@ -0,0 +1,30 @@
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
from src.db.models.comic import StoryArc
class StoryArcResponse(BaseModel):
id: str
created_date: datetime
last_modified_date: datetime
version: int
name: str
comic_id: str
volume_id: Optional[str]
class AddLink(BaseModel):
url: str
def to_response(storyarc: StoryArc) -> StoryArcResponse:
response: StoryArcResponse = StoryArcResponse(
id=storyarc.id,
created_date=storyarc.created_date,
last_modified_date=storyarc.last_modified_date,
version=storyarc.version,
name=storyarc.name,
comic_id=storyarc.comic_id,
volume_id=storyarc.volume_id
)
return response
+19
View File
@@ -1,6 +1,25 @@
from datetime import datetime
from pydantic import BaseModel
from src.db.models.comic import Volume
class VolumeResponse(BaseModel):
id: str
created_date: datetime
last_modified_date: datetime
version: int
name: str
comic_id: str
def to_response(volume: Volume) -> VolumeResponse:
response: VolumeResponse = VolumeResponse(
id=volume.id,
created_date=volume.created_date,
last_modified_date=volume.last_modified_date,
version=volume.version,
name=volume.name,
comic_id=volume.comic_id
)
return response
+17
View File
@@ -1,9 +1,26 @@
from datetime import datetime
from pydantic import BaseModel
from src.db.models.comic import WorkType
class AddWorkType(BaseModel):
worktype: str
class WorktypeResponse(BaseModel):
id: str
created_date: datetime
last_modified_date: datetime
version: int
name: str
def to_response(worktype: WorkType) -> WorktypeResponse:
response: WorktypeResponse = WorktypeResponse(
id=worktype.id,
created_date=worktype.created_date,
last_modified_date=worktype.last_modified_date,
version=worktype.version,
name=worktype.name
)
return response
+30
View File
@@ -0,0 +1,30 @@
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
from src.db.models.media import MediaArticle
class MediaArticleResponse(BaseModel):
id: str
created_date: datetime
last_modified_date: datetime
version: int
review: bool = False
title: Optional[str] = None
url: Optional[str] = None
class AddLink(BaseModel):
url: str
def to_response(video: MediaArticle) -> MediaArticleResponse:
response: MediaArticleResponse = MediaArticleResponse(
id=video.id,
created_date=video.created_date,
last_modified_date=video.last_modified_date,
version=video.version,
review=video.review,
title=video.title,
url=video.url,
)
return response
+33
View File
@@ -1,5 +1,38 @@
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
from src.db.models.media import MediaVideo
class MediaVideoResponse(BaseModel):
id: str
created_date: datetime
last_modified_date: datetime
version: int
cloud_link: Optional[str] = None
file_name: Optional[str] = None
path: Optional[str] = None
review: bool = False
title: Optional[str] = None
url: Optional[str] = None
should_download: bool = False
class AddLink(BaseModel):
url: str
def to_response(video: MediaVideo) -> MediaVideoResponse:
response: MediaVideoResponse = MediaVideoResponse(
id=video.id,
created_date=video.created_date,
last_modified_date=video.last_modified_date,
version=video.version,
cloud_link=video.cloud_link,
file_name=video.file_name,
path=video.path,
review=video.review,
title=video.title,
url=video.url,
should_download=video.should_download
)
return response
+26
View File
@@ -0,0 +1,26 @@
from datetime import datetime
from pydantic import BaseModel
from src.db.models.admin import Assignment
class AssignmentResponse(BaseModel):
id: str
created_date: datetime
last_modified_date: datetime
version: int
profile_id: str
permission_id: str
def to_response(assignment: Assignment) -> AssignmentResponse:
response: AssignmentResponse = AssignmentResponse(
id=assignment.id,
created_date=assignment.created_date,
last_modified_date=assignment.last_modified_date,
version=assignment.version,
profile_id=assignment.profile_id,
permission_id=assignment.permission_id
)
return response
+24
View File
@@ -0,0 +1,24 @@
from datetime import datetime
from pydantic import BaseModel
from src.db.models.admin import Permission
class PermissionResponse(BaseModel):
id: str
created_date: datetime
last_modified_date: datetime
version: int
name: str
def to_response(permission: Permission) -> PermissionResponse:
response: PermissionResponse = PermissionResponse(
id=permission.id,
created_date=permission.created_date,
last_modified_date=permission.last_modified_date,
version=permission.version,
name=permission.name
)
return response
+16 -2
View File
@@ -1,12 +1,26 @@
from pydantic import BaseModel
from src.db.models.admin import Profile
class ProfileResponse(BaseModel):
id: str
user_name: str
username: str
class ProfileModel(BaseModel):
user_name: str
username: str
email: str
first_name: str
last_name: str
active: bool
def to_model(profile: Profile) -> ProfileModel:
model: ProfileModel = ProfileModel(
username=profile.user_name,
email=profile.email,
first_name=profile.first_name,
last_name=profile.last_name,
active=profile.enabled,
)
return model
+32
View File
@@ -0,0 +1,32 @@
from datetime import datetime
from pydantic import BaseModel
from src.db.models.admin import Token
class TokenResponse(BaseModel):
id: str
created_date: datetime
last_modified_date: datetime
version: int
token: str
name: str
last_used_date: datetime
enabled: bool
profile_id: str
def to_response(token: Token) -> TokenResponse:
response: TokenResponse = TokenResponse(
id=token.id,
created_date=token.created_date,
last_modified_date=token.last_modified_date,
version=token.version,
token=token.token,
name=token.name,
last_used_date=token.last_used_date,
enabled=token.enabled,
profile_id=token.profile_id
)
return response
+2 -2
View File
@@ -1,5 +1,5 @@
from src.apis.version1.admin.token import login_for_token_cookie
from fastapi import APIRouter, Depends
from src.apis.version1.admin.login import login_for_token_cookie
from fastapi import APIRouter
from fastapi import HTTPException
from fastapi import Request
from fastapi.templating import Jinja2Templates
+9 -9
View File
@@ -9,15 +9,15 @@ from src.webapps.media import route_actors, route_media, route_videos
templates = Jinja2Templates(directory="src/templates")
api_router = APIRouter()
api_router.include_router(route_comics.router)
api_router.include_router(route_artists.router)
api_router.include_router(route_worktype.router)
api_router.include_router(route_media.router)
api_router.include_router(route_actors.router)
api_router.include_router(route_videos.router)
api_router.include_router(route_login.router)
api_router.include_router(route_admin.router)
api_router.include_router(route_comics.router, tags=["webapp"])
api_router.include_router(route_artists.router, tags=["webapp"])
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_login.router, tags=["webapp"])
api_router.include_router(route_admin.router, tags=["webapp"])
@api_router.get("/")
@api_router.get("/", tags=["webapp"])
def home(request: Request, msg: str | None = None):
return templates.TemplateResponse("index.html", {"request": request, "msg": msg})
+2 -2
View File
@@ -11,7 +11,7 @@ from src.schema.comics.comic import ComicSchema
from src.webapps.comic.forms.comic import ValidateComicForm
templates = Jinja2Templates(directory="src/templates")
router = APIRouter(include_in_schema=False, prefix="/comic")
router = APIRouter(include_in_schema=True, prefix="/comic")
@router.get("/comics")
def get_comics(db: SessionDep, request: Request, msg: str | None = None):
@@ -58,7 +58,7 @@ async def validate_comic(request: Request, db: SessionDep, comic_id: str, action
if form.is_valid():
try:
comic = ComicSchema(**form.__dict__)
comic = update_comic(comic=comic, comic_id=comic_id, db=db)
comic = update_comic(new_comic=comic, comic_id=comic_id, db=db)
return RedirectResponse(f"/comic/comics/{comic.id}", status_code=status.HTTP_303_SEE_OTHER)
except Exception as e:
print(e)
+3 -3
View File
@@ -8,7 +8,7 @@ import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import Session, sessionmaker
from src.apis.base import api_router
from src.db.models.base import Base
@@ -45,7 +45,7 @@ def app() -> Generator[FastAPI, Any, None]:
@pytest.fixture(scope="module")
def db_session(app: FastAPI) -> Generator[SessionTesting, Any, None]:
def db_session(app: FastAPI) -> Generator[Session, Any, None]:
connection = engine.connect()
transaction = connection.begin()
session = SessionTesting(bind=connection)
@@ -57,7 +57,7 @@ def db_session(app: FastAPI) -> Generator[SessionTesting, Any, None]:
@pytest.fixture(scope="module")
def client(
app: FastAPI, db_session: SessionTesting
app: FastAPI, db_session: Session
) -> Generator[TestClient, Any, None]:
"""
Create a new FastAPI TestClient that uses the `db_session` fixture to override
+1 -1
View File
@@ -43,7 +43,7 @@ MAPPING: Dict[str, str] = {
"permission": "api/user/permissions",
"assignment": "api/user/assignments",
"token": "api/user/tokens",
"mail_account": "api/admin/mailaccount",
"mail_account": "api/admin/mailaccounts",
}
class EndPointNotAvailableException(Exception):
+2 -2
View File
@@ -28,8 +28,8 @@ if __name__== "__main__":
try:
data = server.request(logger, table=table)
logger.info("%s: %s", table, len(data))
if len(data) == 1:
logger.info("show data: %s", data)
#if len(data) == 1:
# logger.info("show data: %s", data)
except EndPointNotAvailableException:
logger.info("Endpoint not implemented")
logger.info("kontor.sync finished")