fix admin delete to wipe originals/edits/geojson; rename button to Reset data
The old DELETE /api/admin/users/{handle}/activities only removed *.json
files and _merged/, leaving originals/ (Strava FIT files) and edits/
untouched — causing the 968 MB disk usage after a delete.
_wipe_user_activities() now removes activities/, edits/, originals/,
_merged/, index.json, athlete.json, and .bincio_cache.json. Admin page
button renamed to "Reset data" with updated confirmation text.
This commit is contained in:
+37
-18
@@ -517,38 +517,57 @@ async def admin_rebuild(
|
|||||||
return JSONResponse({"ok": True})
|
return JSONResponse({"ok": True})
|
||||||
|
|
||||||
|
|
||||||
|
def _wipe_user_activities(user_dir: Path) -> int:
|
||||||
|
"""Delete all extracted activity files and caches for a user.
|
||||||
|
|
||||||
|
Removes activities/ (JSON + GeoJSON + timeseries), edits/, originals/,
|
||||||
|
_merged/, index.json, athlete.json, and the dedup cache.
|
||||||
|
Leaves the user directory itself intact (account remains in the DB).
|
||||||
|
Returns the number of files deleted.
|
||||||
|
"""
|
||||||
|
import shutil
|
||||||
|
deleted = 0
|
||||||
|
|
||||||
|
for subdir in ("activities", "edits", "originals"):
|
||||||
|
d = user_dir / subdir
|
||||||
|
if d.exists():
|
||||||
|
for f in d.rglob("*"):
|
||||||
|
if f.is_file():
|
||||||
|
deleted += 1
|
||||||
|
shutil.rmtree(d)
|
||||||
|
|
||||||
|
for name in ("_merged", ):
|
||||||
|
d = user_dir / name
|
||||||
|
if d.exists():
|
||||||
|
shutil.rmtree(d)
|
||||||
|
|
||||||
|
for name in ("index.json", "athlete.json", ".bincio_cache.json"):
|
||||||
|
f = user_dir / name
|
||||||
|
if f.exists():
|
||||||
|
f.unlink()
|
||||||
|
deleted += 1
|
||||||
|
|
||||||
|
return deleted
|
||||||
|
|
||||||
|
|
||||||
@app.delete("/api/admin/users/{handle}/activities")
|
@app.delete("/api/admin/users/{handle}/activities")
|
||||||
async def admin_delete_activities(
|
async def admin_delete_activities(
|
||||||
handle: str,
|
handle: str,
|
||||||
bincio_session: Optional[str] = Cookie(default=None),
|
bincio_session: Optional[str] = Cookie(default=None),
|
||||||
) -> JSONResponse:
|
) -> JSONResponse:
|
||||||
"""Delete all activity JSON files for a user and wipe the merged cache."""
|
"""Delete all activity data for a user and wipe the merged cache."""
|
||||||
_require_admin(bincio_session)
|
_require_admin(bincio_session)
|
||||||
user_dir = _get_data_dir() / handle
|
user_dir = _get_data_dir() / handle
|
||||||
if not user_dir.is_dir():
|
if not user_dir.is_dir():
|
||||||
raise HTTPException(404, f"No data directory for user '{handle}'")
|
raise HTTPException(404, f"No data directory for user '{handle}'")
|
||||||
|
|
||||||
deleted = 0
|
deleted = _wipe_user_activities(user_dir)
|
||||||
activities_dir = user_dir / "activities"
|
|
||||||
if activities_dir.is_dir():
|
|
||||||
for f in activities_dir.glob("*.json"):
|
|
||||||
f.unlink()
|
|
||||||
deleted += 1
|
|
||||||
|
|
||||||
# Wipe merged cache, top-level index, and dedup cache so re-uploads aren't blocked
|
|
||||||
import shutil
|
|
||||||
merged_dir = user_dir / "_merged"
|
|
||||||
if merged_dir.exists():
|
|
||||||
shutil.rmtree(merged_dir)
|
|
||||||
for name in ("index.json", ".bincio_cache.json"):
|
|
||||||
f = user_dir / name
|
|
||||||
if f.exists():
|
|
||||||
f.unlink()
|
|
||||||
|
|
||||||
_trigger_rebuild(handle)
|
_trigger_rebuild(handle)
|
||||||
return JSONResponse({"ok": True, "deleted": deleted})
|
return JSONResponse({"ok": True, "deleted": deleted})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ── Write API (ported from bincio edit, auth-gated) ───────────────────────────
|
# ── Write API (ported from bincio edit, auth-gated) ───────────────────────────
|
||||||
|
|
||||||
def _user_data_dir(handle: str) -> Path:
|
def _user_data_dir(handle: str) -> Path:
|
||||||
|
|||||||
@@ -33,10 +33,11 @@ import Base from '../../layouts/Base.astro';
|
|||||||
|
|
||||||
<!-- Confirmation dialog -->
|
<!-- Confirmation dialog -->
|
||||||
<dialog id="confirm-dialog" class="rounded-xl bg-zinc-900 border border-zinc-700 p-6 text-white max-w-sm w-full backdrop:bg-black/60">
|
<dialog id="confirm-dialog" class="rounded-xl bg-zinc-900 border border-zinc-700 p-6 text-white max-w-sm w-full backdrop:bg-black/60">
|
||||||
<p class="text-sm text-zinc-300 mb-5">Delete all activities for <strong id="confirm-handle" class="text-white"></strong>? This cannot be undone.</p>
|
<p class="text-sm text-zinc-300 mb-1">Reset all data for <strong id="confirm-handle" class="text-white"></strong>?</p>
|
||||||
|
<p class="text-xs text-zinc-500 mb-5">Removes all activities, originals, edits, and images. The account is kept. This cannot be undone.</p>
|
||||||
<div class="flex gap-3 justify-end">
|
<div class="flex gap-3 justify-end">
|
||||||
<button id="confirm-cancel" class="px-4 py-2 rounded-lg text-sm bg-zinc-800 hover:bg-zinc-700 text-zinc-300 transition-colors">Cancel</button>
|
<button id="confirm-cancel" class="px-4 py-2 rounded-lg text-sm bg-zinc-800 hover:bg-zinc-700 text-zinc-300 transition-colors">Cancel</button>
|
||||||
<button id="confirm-ok" class="px-4 py-2 rounded-lg text-sm bg-red-700 hover:bg-red-600 text-white font-medium transition-colors">Delete</button>
|
<button id="confirm-ok" class="px-4 py-2 rounded-lg text-sm bg-red-700 hover:bg-red-600 text-white font-medium transition-colors">Reset</button>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -124,7 +125,8 @@ import Base from '../../layouts/Base.astro';
|
|||||||
<button
|
<button
|
||||||
class="delete-btn text-xs px-3 py-1.5 rounded-lg bg-zinc-800 hover:bg-red-900 hover:text-red-300 text-zinc-400 transition-colors"
|
class="delete-btn text-xs px-3 py-1.5 rounded-lg bg-zinc-800 hover:bg-red-900 hover:text-red-300 text-zinc-400 transition-colors"
|
||||||
data-handle="${u.handle}"
|
data-handle="${u.handle}"
|
||||||
>Delete activities</button>
|
title="Wipe all activities, originals, edits and images — account is kept"
|
||||||
|
>Reset data</button>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
Reference in New Issue
Block a user