diff options
Diffstat (limited to 'Biz')
| -rw-r--r-- | Biz/PodcastItLater/Core.py | 10 | ||||
| -rw-r--r-- | Biz/PodcastItLater/Web.py | 52 | ||||
| -rw-r--r-- | Biz/PodcastItLater/Worker.py | 3 |
3 files changed, 31 insertions, 34 deletions
diff --git a/Biz/PodcastItLater/Core.py b/Biz/PodcastItLater/Core.py index a2c1b3b..4a017cc 100644 --- a/Biz/PodcastItLater/Core.py +++ b/Biz/PodcastItLater/Core.py @@ -373,7 +373,10 @@ class Database: # noqa: PLR0904 SELECT id, url, email, status, created_at, error_message, title, author FROM queue - WHERE status IN ('pending', 'processing', 'error') + WHERE status IN ( + 'pending', 'processing', 'extracting', + 'synthesizing', 'uploading', 'error' + ) ORDER BY created_at DESC LIMIT 20 """) @@ -888,7 +891,10 @@ class Database: # noqa: PLR0904 title, author FROM queue WHERE user_id = ? AND - status IN ('pending', 'processing', 'error') + status IN ( + 'pending', 'processing', 'extracting', + 'synthesizing', 'uploading', 'error' + ) ORDER BY created_at DESC LIMIT 20 """, diff --git a/Biz/PodcastItLater/Web.py b/Biz/PodcastItLater/Web.py index 30ebf53..0f095d3 100644 --- a/Biz/PodcastItLater/Web.py +++ b/Biz/PodcastItLater/Web.py @@ -36,7 +36,6 @@ import re import sys import tempfile import typing -from unittest.mock import patch import urllib.parse import uvicorn from datetime import datetime @@ -55,6 +54,7 @@ from starlette.middleware.sessions import SessionMiddleware from starlette.responses import RedirectResponse from starlette.testclient import TestClient from typing import override +from unittest.mock import patch logger = logging.getLogger(__name__) Log.setup(logger) @@ -363,6 +363,9 @@ class QueueStatus(Component[AnyChildren, QueueStatusAttrs]): status_classes = { "pending": "bg-warning text-dark", "processing": "bg-primary", + "extracting": "bg-info text-dark", + "synthesizing": "bg-primary", + "uploading": "bg-success", "error": "bg-danger", "cancelled": "bg-secondary", } @@ -370,6 +373,9 @@ class QueueStatus(Component[AnyChildren, QueueStatusAttrs]): status_icons = { "pending": "bi-clock", "processing": "bi-arrow-repeat", + "extracting": "bi-file-text", + "synthesizing": "bi-mic", + "uploading": "bi-cloud-arrow-up", "error": "bi-exclamation-triangle", "cancelled": "bi-x-circle", } @@ -437,7 +443,9 @@ class QueueStatus(Component[AnyChildren, QueueStatusAttrs]): ), # Display queue position if available html.small( - html.i(classes=["bi", "bi-hourglass-split", "me-1"]), + html.i( + classes=["bi", "bi-hourglass-split", "me-1"], + ), f"Position in queue: #{queue_pos}", classes=["text-info", "d-block", "mt-1"], ) @@ -472,7 +480,13 @@ class QueueStatus(Component[AnyChildren, QueueStatusAttrs]): html.div( # Retry button for error items html.button( - html.i(classes=["bi", "bi-arrow-clockwise", "me-1"]), + html.i( + classes=[ + "bi", + "bi-arrow-clockwise", + "me-1", + ], + ), "Retry", hx_post=f"/queue/{item['id']}/retry", hx_trigger="click", @@ -1247,11 +1261,11 @@ def account_page(request: Request) -> UI.AccountPage | RedirectResponse: # Get usage stats period_start, period_end = Billing.get_period_boundaries(user) usage = Billing.get_usage(user["id"], period_start, period_end) - + # Get limits tier = user.get("plan_tier", "free") limits = Billing.TIER_LIMITS.get(tier, Billing.TIER_LIMITS["free"]) - + return UI.AccountPage( user=user, usage=usage, @@ -1260,17 +1274,6 @@ def account_page(request: Request) -> UI.AccountPage | RedirectResponse: ) -@app.get("/logout") -def logout(request: Request) -> Response: - """Handle logout.""" - request.session.clear() - return Response( - "", - status_code=302, - headers={"Location": "/"}, - ) - - @app.post("/submit") def submit_article( # noqa: PLR0911, PLR0914 request: Request, @@ -1645,21 +1648,6 @@ def billing_checkout(request: Request, data: FormData) -> Response: return Response(f"Error: {e!s}", status_code=400) -@app.post("/billing/portal") -def billing_portal(request: Request) -> Response | RedirectResponse: - """Create Stripe Billing Portal session.""" - user_id = request.session.get("user_id") - if not user_id: - return Response("Unauthorized", status_code=401) - - try: - portal_url = Billing.create_portal_session(user_id, BASE_URL) - return RedirectResponse(url=portal_url, status_code=303) - except Exception: - logger.exception("Portal error - ensure Stripe portal is configured") - return Response("Portal not configured", status_code=500) - - @app.post("/stripe/webhook") async def stripe_webhook(request: Request) -> Response: """Handle Stripe webhook events.""" @@ -3132,7 +3120,7 @@ class TestAccountPage(BaseWebTest): Core.Database.add_episode_to_user(self.user_id, ep_id) response = self.client.get("/account") - + self.assertEqual(response.status_code, 200) self.assertIn("My Account", response.text) self.assertIn("test@example.com", response.text) diff --git a/Biz/PodcastItLater/Worker.py b/Biz/PodcastItLater/Worker.py index 5203490..94db30e 100644 --- a/Biz/PodcastItLater/Worker.py +++ b/Biz/PodcastItLater/Worker.py @@ -620,6 +620,7 @@ class ArticleProcessor: return # Step 1: Extract article content + Core.Database.update_job_status(job_id, "extracting") title, content, author, pub_date = ( ArticleProcessor.extract_article_content(url) ) @@ -630,6 +631,7 @@ class ArticleProcessor: return # Step 2: Generate audio with metadata + Core.Database.update_job_status(job_id, "synthesizing") audio_data = self.text_to_speech(content, title, author, pub_date) if self.shutdown_handler.is_shutdown_requested(): @@ -638,6 +640,7 @@ class ArticleProcessor: return # Step 3: Upload to S3 + Core.Database.update_job_status(job_id, "uploading") filename = ArticleProcessor.generate_filename(job_id, title) audio_url = self.upload_to_s3(audio_data, filename) |
