diff options
| author | Ben Sima <ben@bsima.me> | 2025-11-16 03:13:46 -0500 |
|---|---|---|
| committer | Ben Sima <ben@bsima.me> | 2025-11-16 03:13:46 -0500 |
| commit | a2a4360e89603052e9f88d8405eaa386019b680f (patch) | |
| tree | 11d6a9a33117629a459833a8d3be763c03ba9bdb /Biz/PodcastItLater | |
| parent | c8c239e048c8b9b84a89cb8482a67fb6e85fb724 (diff) | |
Add admin toggle for episode public/private status
- Add toggle button to episode cards (admins only) - Button shows
globe icon for public, lock icon for private - Toggle endpoint at
POST /admin/episode/{id}/toggle-public - Updates episode is_public
status and redirects to home
Tasks completed: t-gcbqDl, t-gc6Vrk (partially - admin toggle complete)
Diffstat (limited to 'Biz/PodcastItLater')
| -rw-r--r-- | Biz/PodcastItLater/Admin.py | 31 | ||||
| -rw-r--r-- | Biz/PodcastItLater/Web.py | 41 |
2 files changed, 69 insertions, 3 deletions
diff --git a/Biz/PodcastItLater/Admin.py b/Biz/PodcastItLater/Admin.py index 6ee255e..8e12fc7 100644 --- a/Biz/PodcastItLater/Admin.py +++ b/Biz/PodcastItLater/Admin.py @@ -672,6 +672,37 @@ def update_user_status( ) +def toggle_episode_public(request: Request, episode_id: int) -> Response: + """Toggle episode public/private status.""" + # Check if user is logged in and is admin + session_user_id = request.session.get("user_id") + if not session_user_id: + return Response("Unauthorized", status_code=401) + + user = Core.Database.get_user_by_id(session_user_id) + if not user or not Core.is_admin(user): + return Response("Forbidden", status_code=403) + + # Get current episode status + episode = Core.Database.get_episode_by_id(episode_id) + if not episode: + return Response("Episode not found", status_code=404) + + # Toggle public status + current_public = episode.get("is_public", 0) == 1 + if current_public: + Core.Database.unmark_episode_public(episode_id) + else: + Core.Database.mark_episode_public(episode_id) + + # Redirect to home page to see updated status + return Response( + "", + status_code=200, + headers={"HX-Redirect": "/"}, + ) + + def main() -> None: """Admin tests are currently in Web.""" if "test" in sys.argv: diff --git a/Biz/PodcastItLater/Web.py b/Biz/PodcastItLater/Web.py index 2868147..97ec439 100644 --- a/Biz/PodcastItLater/Web.py +++ b/Biz/PodcastItLater/Web.py @@ -515,6 +515,7 @@ class EpisodeListAttrs(Attrs): episodes: list[dict[str, typing.Any]] rss_url: str | None + user: dict[str, typing.Any] | None class EpisodeList(Component[AnyChildren, EpisodeListAttrs]): @@ -524,6 +525,7 @@ class EpisodeList(Component[AnyChildren, EpisodeListAttrs]): def render(self) -> html.div: episodes = self.attrs["episodes"] rss_url = self.attrs.get("rss_url") + user = self.attrs.get("user") if not episodes: return html.div( @@ -539,8 +541,37 @@ class EpisodeList(Component[AnyChildren, EpisodeListAttrs]): for episode in episodes: duration_str = UI.format_duration(episode.get("duration")) episode_sqid = encode_episode_id(episode["id"]) + is_public = episode.get("is_public", 0) == 1 + + # Admin toggle button for public/private status + admin_toggle = html.div() + if user and Core.is_admin(user): + admin_toggle = html.div( + html.button( + html.i( + classes=[ + "bi", + "bi-globe" if is_public else "bi-lock", + "me-1", + ], + ), + "Public" if is_public else "Private", + hx_post=f"/admin/episode/{episode['id']}/toggle-public", + hx_target="body", + hx_swap="outerHTML", + classes=[ + "btn", + "btn-sm", + "btn-success" if is_public else "btn-secondary", + ], + ), + classes=["position-absolute", "top-0", "end-0", "m-2"], + style={"z-index": "10"}, + ) + episode_items.append( html.div( + admin_toggle, html.div( html.h5( html.a( @@ -589,7 +620,7 @@ class EpisodeList(Component[AnyChildren, EpisodeListAttrs]): else html.div(), classes=["card-body"], ), - classes=["card", "mb-3"], + classes=["card", "mb-3", "position-relative"], ), ) @@ -750,6 +781,7 @@ class HomePage(Component[AnyChildren, HomePageAttrs]): EpisodeList( episodes=episodes, rss_url=f"{BASE_URL}/feed/{user['token']}.xml", + user=user, ), id="dashboard-content", hx_get="/dashboard-updates", @@ -1461,7 +1493,7 @@ def dashboard_updates(request: Request) -> html.div: if not user_id: return html.div( QueueStatus(items=[]), - EpisodeList(episodes=[], rss_url=None), + EpisodeList(episodes=[], rss_url=None, user=None), ) # Get user info for RSS URL @@ -1474,7 +1506,7 @@ def dashboard_updates(request: Request) -> html.div: return html.div( QueueStatus(items=queue_items), - EpisodeList(episodes=episodes, rss_url=rss_url), + EpisodeList(episodes=episodes, rss_url=rss_url, user=user), id="dashboard-content", ) @@ -1574,6 +1606,9 @@ def cancel_queue_item(request: Request, job_id: int) -> Response: app.delete("/queue/{job_id}")(Admin.delete_queue_item) app.get("/admin/users")(Admin.admin_users) app.post("/admin/users/{user_id}/status")(Admin.update_user_status) +app.post("/admin/episode/{episode_id}/toggle-public")( + Admin.toggle_episode_public, +) class BaseWebTest(Test.TestCase): |
