diff --git a/app/admin_web.py b/app/admin_web.py index 0ad45e2..f44cdf7 100644 --- a/app/admin_web.py +++ b/app/admin_web.py @@ -220,8 +220,32 @@ def _websites_form_body( ) -> str: error_html = f'
{escape(error)}
' if error else "" success_html = f'
{escape(success)}
' if success else "" - rows = [[website.id, website.site_name, website.site_url] for website in websites] - websites_table = _table(["ID", "Name", "URL"], rows) + body_rows = [] + for website in websites: + actions = f""" +
+ Edit +
+ +
+
+ """ + body_rows.append( + "" + f"{website.id}" + f"{escape(website.site_name)}" + f"{escape(website.site_url)}" + f"{actions}" + "" + ) + if body_rows: + websites_table = ( + "" + + "".join(body_rows) + + "
IDNameURLActions
" + ) + else: + websites_table = _table(["ID", "Name", "URL", "Actions"], []) return f"""

Register websites here so imports and tryout references can be tied to a known source site.

{success_html} @@ -239,6 +263,34 @@ def _websites_form_body( """ +def _website_edit_form_body( + website: Website, + error: str | None = None, + success: str | None = None, + site_name: str | None = None, + site_url: str | None = None, +) -> str: + error_html = f'
{escape(error)}
' if error else "" + success_html = f'
{escape(success)}
' if success else "" + display_name = website.site_name if site_name is None else site_name + display_url = website.site_url if site_url is None else site_url + return f""" +

Website ID: {website.id}

+ {success_html} + {error_html} +
+ + + + +
+ + Back +
+
+ """ + + async def _basis_items_for_playground(db: AsyncSession, limit: int = 20) -> list[Item]: result = await db.execute( select(Item) @@ -562,6 +614,119 @@ async def websites_submit( return _render_admin_page("Websites", "Websites", body) +@router.get("/websites/{website_id}/edit", include_in_schema=False) +async def website_edit_view( + website_id: int, + request: Request, + db: AsyncSession = Depends(get_db), +): + admin = await _current_admin(request) + if not admin: + return _login_redirect() + + website = await db.get(Website, website_id) + if website is None: + result = await db.execute(select(Website).order_by(Website.id.asc())) + websites = list(result.scalars().all()) + body = _websites_form_body(websites, error=f"Website not found: {website_id}") + return _render_admin_page("Websites", "Websites", body) + + body = _website_edit_form_body(website) + return _render_admin_page("Edit Website", "Edit Website", body) + + +@router.post("/websites/{website_id}/edit", include_in_schema=False) +async def website_edit_submit( + website_id: int, + request: Request, + db: AsyncSession = Depends(get_db), + site_name: str = Form(...), + site_url: str = Form(...), +): + admin = await _current_admin(request) + if not admin: + return _login_redirect() + + website = await db.get(Website, website_id) + if website is None: + result = await db.execute(select(Website).order_by(Website.id.asc())) + websites = list(result.scalars().all()) + body = _websites_form_body(websites, error=f"Website not found: {website_id}") + return _render_admin_page("Websites", "Websites", body) + + normalized_name = site_name.strip() + normalized_url = site_url.strip().rstrip("/") + + if not normalized_name: + body = _website_edit_form_body( + website, + error="Website name is required.", + site_name=site_name, + site_url=site_url, + ) + return _render_admin_page("Edit Website", "Edit Website", body) + + if not normalized_url.startswith(("http://", "https://")): + body = _website_edit_form_body( + website, + error="Website URL must start with http:// or https://.", + site_name=site_name, + site_url=site_url, + ) + return _render_admin_page("Edit Website", "Edit Website", body) + + website.site_name = normalized_name + website.site_url = normalized_url + try: + await db.commit() + except IntegrityError: + await db.rollback() + body = _website_edit_form_body( + website, + error="Website URL already exists.", + site_name=site_name, + site_url=site_url, + ) + return _render_admin_page("Edit Website", "Edit Website", body) + + await db.refresh(website) + body = _website_edit_form_body( + website, + success=f"Website #{website.id} updated successfully.", + ) + return _render_admin_page("Edit Website", "Edit Website", body) + + +@router.post("/websites/{website_id}/delete", include_in_schema=False) +async def website_delete_submit( + website_id: int, + request: Request, + db: AsyncSession = Depends(get_db), +): + admin = await _current_admin(request) + if not admin: + return _login_redirect() + + website = await db.get(Website, website_id) + if website is None: + result = await db.execute(select(Website).order_by(Website.id.asc())) + websites = list(result.scalars().all()) + body = _websites_form_body(websites, error=f"Website not found: {website_id}") + return _render_admin_page("Websites", "Websites", body) + + deleted_label = f"{website.site_name} ({website.site_url})" + await db.delete(website) + await db.commit() + + result = await db.execute(select(Website).order_by(Website.id.asc())) + websites = list(result.scalars().all()) + body = _websites_form_body( + websites, + success=f"Website deleted successfully: {deleted_label}", + ) + return _render_admin_page("Websites", "Websites", body) + + @router.get("/calibration-status", include_in_schema=False) async def calibration_status_view(request: Request, db: AsyncSession = Depends(get_db)): admin = await _current_admin(request)