Add website edit and delete actions
This commit is contained in:
169
app/admin_web.py
169
app/admin_web.py
@@ -220,8 +220,32 @@ def _websites_form_body(
|
||||
) -> str:
|
||||
error_html = f'<div class="error">{escape(error)}</div>' if error else ""
|
||||
success_html = f'<div class="success">{escape(success)}</div>' 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"""
|
||||
<div class="actions" style="margin-top:0">
|
||||
<a href="/admin/websites/{website.id}/edit" style="display:inline-block;padding:8px 12px;border-radius:8px;background:#0f172a;color:#fff;text-decoration:none;">Edit</a>
|
||||
<form method="post" action="/admin/websites/{website.id}/delete" onsubmit="return confirm('Delete website {escape(website.site_name)} and all related tryouts, items, sessions, and snapshots?');" style="margin:0">
|
||||
<button type="submit" style="background:#991b1b;">Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
"""
|
||||
body_rows.append(
|
||||
"<tr>"
|
||||
f"<td>{website.id}</td>"
|
||||
f"<td>{escape(website.site_name)}</td>"
|
||||
f"<td>{escape(website.site_url)}</td>"
|
||||
f"<td>{actions}</td>"
|
||||
"</tr>"
|
||||
)
|
||||
if body_rows:
|
||||
websites_table = (
|
||||
"<table><thead><tr><th>ID</th><th>Name</th><th>URL</th><th>Actions</th></tr></thead><tbody>"
|
||||
+ "".join(body_rows)
|
||||
+ "</tbody></table>"
|
||||
)
|
||||
else:
|
||||
websites_table = _table(["ID", "Name", "URL", "Actions"], [])
|
||||
return f"""
|
||||
<p class="muted">Register websites here so imports and tryout references can be tied to a known source site.</p>
|
||||
{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'<div class="error">{escape(error)}</div>' if error else ""
|
||||
success_html = f'<div class="success">{escape(success)}</div>' 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"""
|
||||
<p class="muted">Website ID: <strong>{website.id}</strong></p>
|
||||
{success_html}
|
||||
{error_html}
|
||||
<form method="post" action="/admin/websites/{website.id}/edit" autocomplete="off">
|
||||
<label for="site_name">Website Name</label>
|
||||
<input id="site_name" name="site_name" type="text" value="{escape(display_name)}">
|
||||
<label for="site_url">Website URL</label>
|
||||
<input id="site_url" name="site_url" type="url" value="{escape(display_url)}">
|
||||
<div class="actions">
|
||||
<button type="submit">Save Changes</button>
|
||||
<a href="/admin/websites" style="display:inline-block;padding:12px 14px;border-radius:10px;background:#e2e8f0;color:#0f172a;text-decoration:none;font-size:15px;font-weight:600;">Back</a>
|
||||
</div>
|
||||
</form>
|
||||
"""
|
||||
|
||||
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user