- backend/handlers/user/account.go: Wire DELETE /api/user/account to call anonymize_user() for registered users and delete_guest_user() for guests, with CardDAV contact cleanup - backend/handlers/user/profile_test.go: Add TestAccount_DeleteGuest and enhance TestAccount_Delete to verify anonymization results - backend/main.go: Add GET /api/health endpoint with DB ping and S3 status check; add HSTS and Referrer-Policy security headers; replace http.ListenAndServe with http.Server + graceful SIGTERM/SIGINT shutdown - frontend/routes/+layout.svelte: Replace alert() with toast notifications for email verification flow - frontend/routes/login/+page.svelte: Replace alert() with toast.info for social login prototype buttons - frontend/booking/BookingFlow.svelte: Remove 2 console.log debug calls; add cancellation policy note in Step 3; add timezone policy comment - frontend/ImageUpload.svelte: Comment out debug console.log - init-scripts/init-script.sql: Add delete_guest_user() SQL function - docs: Update README.md and Obsidian notes to reflect completed items
62 lines
1.5 KiB
Go
62 lines
1.5 KiB
Go
package user
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
|
|
"crussell/db"
|
|
"crussell/internal/dav"
|
|
"crussell/mw"
|
|
)
|
|
|
|
// DELETE /api/user/account
|
|
func DeleteAccountHandler(w http.ResponseWriter, r *http.Request) {
|
|
userID, ok := mw.GetUserID(r.Context())
|
|
if !ok {
|
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
var accountRole string
|
|
err := db.DB.QueryRow(r.Context(), `SELECT account_role FROM users WHERE id = $1`, userID).Scan(&accountRole)
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
http.Error(w, "user not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
log.Printf("Failed to fetch user role for deletion: %v", err)
|
|
http.Error(w, "server error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if accountRole == "guest" {
|
|
_, err = db.DB.Exec(r.Context(), `SELECT delete_guest_user($1)`, userID)
|
|
if err != nil {
|
|
log.Printf("Failed to delete guest user %s: %v", userID, err)
|
|
http.Error(w, "server error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
} else {
|
|
_, err = db.DB.Exec(r.Context(), `SELECT anonymize_user($1)`, userID)
|
|
if err != nil {
|
|
log.Printf("Failed to anonymize user %s: %v", userID, err)
|
|
http.Error(w, "server error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
// Delete CardDAV contact (non-blocking, best-effort)
|
|
if dav.Service != nil {
|
|
go func() {
|
|
uri := fmt.Sprintf("%s.vcf", userID)
|
|
if err := dav.Service.DeleteContact(1, uri); err != nil {
|
|
log.Printf("Warning: Failed to delete CardDAV contact for user %s: %v", userID, err)
|
|
}
|
|
}()
|
|
}
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|