add forward auth header reading
All checks were successful
ci/woodpecker/push/build Pipeline was successful

This commit is contained in:
Jake Walker 2025-01-14 19:04:24 +00:00
parent b18572ee56
commit 4e89158d96
4 changed files with 99 additions and 13 deletions

View file

@ -12,7 +12,7 @@ from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, JSONResponse, RedirectResponse from fastapi.responses import FileResponse, JSONResponse, RedirectResponse
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from PIL import Image from PIL import Image
from sqlmodel import Session, and_, select from sqlmodel import Session, and_, or_, select
import models import models
from process import AudioProcessor from process import AudioProcessor
@ -30,7 +30,21 @@ def get_session() -> Generator[Session, Any, None]:
yield session yield session
def handle_user_auth(request: Request) -> tuple[str, str]:
if (
settings.forward_auth_name_header is None
or settings.forward_auth_uid_header is None
):
return ("default", "Admin")
return (
request.headers.get(settings.forward_auth_uid_header, "default"),
request.headers.get(settings.forward_auth_name_header, "Admin"),
)
SessionDep = Annotated[Session, Depends(get_session)] SessionDep = Annotated[Session, Depends(get_session)]
AuthDep = Annotated[tuple[str, str], Depends(handle_user_auth)]
log = structlog.get_logger() log = structlog.get_logger()
@ -46,13 +60,23 @@ audio_processor.start_processing()
@app.get("/admin") @app.get("/admin")
def admin_list_podcasts(session: SessionDep, request: Request): def admin_list_podcasts(session: SessionDep, request: Request, user: AuthDep):
podcasts = session.exec(select(models.Podcast)).all() podcasts = session.exec(
select(models.Podcast).where(
or_(
models.Podcast.owner_id == user[0],
models.Podcast.owner_id == None,
)
)
).all()
return templates.TemplateResponse( return templates.TemplateResponse(
request=request, request=request,
name="admin_feeds.html.j2", name="admin_feeds.html.j2",
context={"podcasts": podcasts}, context={
"podcasts": podcasts,
"user_name": user[1],
},
) )
@ -68,6 +92,7 @@ def admin_create_podcast(request: Request):
def admin_create_podcast_post( def admin_create_podcast_post(
session: SessionDep, session: SessionDep,
request: Request, request: Request,
user: AuthDep,
name: Annotated[str, Form()], name: Annotated[str, Form()],
): ):
if name.strip() == "": if name.strip() == "":
@ -81,7 +106,7 @@ def admin_create_podcast_post(
}, },
) )
podcast = models.Podcast(name=name, description=name) podcast = models.Podcast(name=name, description=name, owner_id=user[0])
session.add(podcast) session.add(podcast)
session.commit() session.commit()
@ -90,9 +115,19 @@ def admin_create_podcast_post(
@app.get("/admin/{podcast_id}") @app.get("/admin/{podcast_id}")
def admin_list_podcast(session: SessionDep, request: Request, podcast_id: str): def admin_list_podcast(
session: SessionDep, request: Request, podcast_id: str, user: AuthDep
):
podcast = session.exec( podcast = session.exec(
select(models.Podcast).where(models.Podcast.id == podcast_id) select(models.Podcast).where(
and_(
models.Podcast.id == podcast_id,
or_(
models.Podcast.owner_id == user[0],
models.Podcast.owner_id == None,
),
)
)
).first() ).first()
if podcast is None: if podcast is None:
@ -151,7 +186,11 @@ def finish_processing(
@app.post("/admin/{podcast_id}/upload") @app.post("/admin/{podcast_id}/upload")
async def admin_upload_episode( async def admin_upload_episode(
session: SessionDep, request: Request, podcast_id: str, file: UploadFile session: SessionDep,
request: Request,
podcast_id: str,
file: UploadFile,
user: AuthDep,
): ):
file_id = request.headers.get("uploader-file-id") file_id = request.headers.get("uploader-file-id")
chunks_total = int(request.headers.get("uploader-chunks-total")) chunks_total = int(request.headers.get("uploader-chunks-total"))
@ -164,7 +203,15 @@ async def admin_upload_episode(
file_id = "".join(c for c in file_id if c.isalnum()).strip() file_id = "".join(c for c in file_id if c.isalnum()).strip()
podcast = session.exec( podcast = session.exec(
select(models.Podcast).where(models.Podcast.id == podcast_id) select(models.Podcast).where(
and_(
models.Podcast.id == podcast_id,
or_(
models.Podcast.owner_id == user[0],
models.Podcast.owner_id == None,
),
)
)
).first() ).first()
if podcast is None: if podcast is None:
@ -216,12 +263,17 @@ def admin_delete_episode(
request: Request, request: Request,
podcast_id: str, podcast_id: str,
episode_id: str, episode_id: str,
user: AuthDep,
): ):
episode = session.exec( episode = session.exec(
select(models.PodcastEpisode).where( select(models.PodcastEpisode).where(
and_( and_(
models.PodcastEpisode.id == episode_id, models.PodcastEpisode.id == episode_id,
models.PodcastEpisode.podcast_id == podcast_id, models.PodcastEpisode.podcast_id == podcast_id,
or_(
models.Podcast.owner_id == user[0],
models.Podcast.owner_id == None,
),
) )
) )
).first() ).first()
@ -250,12 +302,17 @@ def admin_edit_episode(
request: Request, request: Request,
podcast_id: str, podcast_id: str,
episode_id: str, episode_id: str,
user: AuthDep,
): ):
episode = session.exec( episode = session.exec(
select(models.PodcastEpisode).where( select(models.PodcastEpisode).where(
and_( and_(
models.PodcastEpisode.id == episode_id, models.PodcastEpisode.id == episode_id,
models.PodcastEpisode.podcast_id == podcast_id, models.PodcastEpisode.podcast_id == podcast_id,
or_(
models.Podcast.owner_id == user[0],
models.Podcast.owner_id == None,
),
) )
) )
).first() ).first()
@ -284,6 +341,7 @@ def admin_edit_episode_post(
request: Request, request: Request,
podcast_id: str, podcast_id: str,
episode_id: str, episode_id: str,
user: AuthDep,
name: Annotated[str, Form()], name: Annotated[str, Form()],
description: Annotated[str, Form()], description: Annotated[str, Form()],
): ):
@ -292,6 +350,10 @@ def admin_edit_episode_post(
and_( and_(
models.PodcastEpisode.id == episode_id, models.PodcastEpisode.id == episode_id,
models.PodcastEpisode.podcast_id == podcast_id, models.PodcastEpisode.podcast_id == podcast_id,
or_(
models.Podcast.owner_id == user[0],
models.Podcast.owner_id == None,
),
) )
) )
).first() ).first()
@ -322,9 +384,19 @@ def admin_edit_episode_post(
@app.get("/admin/{podcast_id}/edit") @app.get("/admin/{podcast_id}/edit")
def admin_edit_podcast(session: SessionDep, request: Request, podcast_id: str): def admin_edit_podcast(
session: SessionDep, request: Request, user: AuthDep, podcast_id: str
):
podcast = session.exec( podcast = session.exec(
select(models.Podcast).where(models.Podcast.id == podcast_id) select(models.Podcast).where(
and_(
models.Podcast.id == podcast_id,
or_(
models.Podcast.owner_id == user[0],
models.Podcast.owner_id == None,
),
)
)
).first() ).first()
if podcast is None: if podcast is None:
@ -350,12 +422,21 @@ def admin_edit_podcast_post(
session: SessionDep, session: SessionDep,
request: Request, request: Request,
podcast_id: str, podcast_id: str,
user: AuthDep,
name: Annotated[str, Form()], name: Annotated[str, Form()],
description: Annotated[str, Form()], description: Annotated[str, Form()],
image: Optional[UploadFile] = None, image: Optional[UploadFile] = None,
): ):
podcast = session.exec( podcast = session.exec(
select(models.Podcast).where(models.Podcast.id == podcast_id) select(models.Podcast).where(
and_(
models.Podcast.id == podcast_id,
or_(
models.Podcast.owner_id == user[0],
models.Podcast.owner_id == None,
),
)
)
).first() ).first()
if podcast is None: if podcast is None:

View file

@ -15,6 +15,7 @@ class Podcast(SQLModel, table=True):
description: str description: str
explicit: bool = Field(default=True) explicit: bool = Field(default=True)
image_filename: Optional[str] = Field(default=None) image_filename: Optional[str] = Field(default=None)
owner_id: Optional[str] = Field(default=None)
episodes: list["PodcastEpisode"] = Relationship(back_populates="podcast") episodes: list["PodcastEpisode"] = Relationship(back_populates="podcast")

View file

@ -1,4 +1,5 @@
from pathlib import Path from pathlib import Path
from typing import Optional
from pydantic import Field from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic_settings import BaseSettings, SettingsConfigDict
@ -7,6 +8,8 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings): class Settings(BaseSettings):
directory: Path = Field(default=Path.cwd() / "data") directory: Path = Field(default=Path.cwd() / "data")
uploads_directory: Path = Field(default=Path.cwd() / "uploads") uploads_directory: Path = Field(default=Path.cwd() / "uploads")
forward_auth_name_header: Optional[str] = Field(default=None)
forward_auth_uid_header: Optional[str] = Field(default=None)
model_config = SettingsConfigDict(env_nested_delimiter="__", env_prefix="PG_") model_config = SettingsConfigDict(env_nested_delimiter="__", env_prefix="PG_")

View file

@ -1,7 +1,8 @@
{% extends 'admin_layout.html.j2' %} {% extends 'admin_layout.html.j2' %}
{% block content %} {% block content %}
{{ super() }} {{ super() }}
<h1>Podcasts</h1> <h1>Hello {{ user_name }}!</h1>
<h2>My Podcasts</h2>
<p> <p>
<b>Actions:</b> <a href="/admin/new">Create</a> <b>Actions:</b> <a href="/admin/new">Create</a>
</p> </p>