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:
|
) -> str:
|
||||||
error_html = f'<div class="error">{escape(error)}</div>' if error else ""
|
error_html = f'<div class="error">{escape(error)}</div>' if error else ""
|
||||||
success_html = f'<div class="success">{escape(success)}</div>' if success 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]
|
body_rows = []
|
||||||
websites_table = _table(["ID", "Name", "URL"], 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"""
|
return f"""
|
||||||
<p class="muted">Register websites here so imports and tryout references can be tied to a known source site.</p>
|
<p class="muted">Register websites here so imports and tryout references can be tied to a known source site.</p>
|
||||||
{success_html}
|
{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]:
|
async def _basis_items_for_playground(db: AsyncSession, limit: int = 20) -> list[Item]:
|
||||||
result = await db.execute(
|
result = await db.execute(
|
||||||
select(Item)
|
select(Item)
|
||||||
@@ -562,6 +614,119 @@ async def websites_submit(
|
|||||||
return _render_admin_page("Websites", "Websites", body)
|
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)
|
@router.get("/calibration-status", include_in_schema=False)
|
||||||
async def calibration_status_view(request: Request, db: AsyncSession = Depends(get_db)):
|
async def calibration_status_view(request: Request, db: AsyncSession = Depends(get_db)):
|
||||||
admin = await _current_admin(request)
|
admin = await _current_admin(request)
|
||||||
|
|||||||
Reference in New Issue
Block a user