diff --git a/server/api.go b/server/api.go index 96d2d4c..19e1a4e 100644 --- a/server/api.go +++ b/server/api.go @@ -150,7 +150,7 @@ func getSimulations(w http.ResponseWriter, r *http.Request) { func getSimulationDetails(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") if r.Method == "OPTIONS" { - w.Header().Set("Access-Control-Allow-Methods", "GET, PUT, POST, OPTIONS") + w.Header().Set("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS") w.WriteHeader(http.StatusOK) return } @@ -178,6 +178,11 @@ func getSimulationDetails(w http.ResponseWriter, r *http.Request) { return } + if r.Method == "DELETE" && len(pathParts) == 1 { + deleteSimulation(w, r, idStr) + return + } + if r.Method != "GET" { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return @@ -244,6 +249,44 @@ func updateSimulationTime(w http.ResponseWriter, r *http.Request, idStr string) json.NewEncoder(w).Encode(map[string]string{"status": "success"}) } +func deleteSimulation(w http.ResponseWriter, r *http.Request, idStr string) { + var name string + err := db.QueryRow("SELECT name FROM simulations WHERE id = ?", idStr).Scan(&name) + if err != nil { + if err == sql.ErrNoRows { + http.Error(w, "Simulation not found", http.StatusNotFound) + } else { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + return + } + + // Attempt dropping resource map hooks first + _, err = db.Exec("DELETE FROM resources WHERE simulation_id = ?", idStr) + if err != nil { + log.Println("Warning: Error deleting resources map from DB:", err) + } + + _, err = db.Exec("DELETE FROM simulations WHERE id = ?", idStr) + if err != nil { + log.Println("Error deleting simulation from DB:", err) + http.Error(w, "Failed to delete from database", http.StatusInternalServerError) + return + } + + // Physically destroy data payload mapped onto it + dirPath := filepath.Join("../results", name) + if _, statErr := os.Stat(dirPath); statErr == nil { + err = os.RemoveAll(dirPath) + if err != nil { + log.Println("Warning: Failed fully deleting physical directory items:", err) + } + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(map[string]string{"status": "success"}) +} + func renameSimulation(w http.ResponseWriter, r *http.Request, idStr string) { var reqBody struct { Name string `json:"name"` diff --git a/server/server b/server/server new file mode 100755 index 0000000..3ceaa5d Binary files /dev/null and b/server/server differ diff --git a/src/routes/simulation/[id]/+page.svelte b/src/routes/simulation/[id]/+page.svelte index da3d1e9..009d660 100644 --- a/src/routes/simulation/[id]/+page.svelte +++ b/src/routes/simulation/[id]/+page.svelte @@ -218,6 +218,27 @@ saveError = ""; uploadFiles = null; } + + async function handleDelete() { + if ( + !confirm( + "Are you sure you want to permanently delete this simulation and all its associated media files?", + ) + ) { + return; + } + const res = await fetch(`/api/simulations/${id}`, { + method: "DELETE", + }); + + if (res.ok) { + // Force client-side redirect back to cleanly wiped root + window.location.href = "/"; + } else { + const text = await res.text(); + alert("Failed to delete the simulation: " + text); + } + } << Back to Index @@ -233,6 +254,7 @@ + {:else}