feat: implement DELETE /restaurants/:id endpoint and mobile UI danger zone for restaurant deletion
This commit is contained in:
@@ -3,6 +3,7 @@ import { z } from "zod";
|
||||
import { requireAuth, requireRestaurantMember } from "../lib/auth.js";
|
||||
import { generateUniqueRestaurantSlug } from "../lib/slug.js";
|
||||
import { supabase } from "../lib/supabase.js";
|
||||
import { deleteCustomHostname, getCustomHostnameByHostname } from "../lib/cloudflare.js";
|
||||
|
||||
const createRestaurantSchema = z.object({
|
||||
name: z.string().min(1).max(120),
|
||||
@@ -206,4 +207,59 @@ export const restaurantsRoutes: FastifyPluginAsync = async (app) => {
|
||||
|
||||
return reply.send({ success: true, themeKey });
|
||||
});
|
||||
|
||||
app.delete("/restaurants/:id", async (req, reply) => {
|
||||
const userId = await requireAuth(req, reply);
|
||||
if (!userId || !supabase) return;
|
||||
|
||||
const { id } = req.params as { id: string };
|
||||
const isMember = await requireRestaurantMember(userId, id);
|
||||
if (!isMember) return reply.code(403).send({ message: "forbidden" });
|
||||
|
||||
// Delete custom hostnames from Cloudflare if any custom domains exist
|
||||
const { data: domains } = await supabase.from("domains").select("id, hostname").eq("restaurant_id", id);
|
||||
if (domains && domains.length > 0) {
|
||||
for (const dom of domains) {
|
||||
try {
|
||||
const cfHostname = await getCustomHostnameByHostname(dom.hostname);
|
||||
if (cfHostname?.id) {
|
||||
await deleteCustomHostname(cfHostname.id);
|
||||
}
|
||||
} catch (err) {
|
||||
req.log.warn({ err, hostname: dom.hostname }, "Cloudflare hostname delete failed during restaurant deletion");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete associated database records
|
||||
await supabase.from("domains").delete().eq("restaurant_id", id);
|
||||
await supabase.from("restaurant_themes").delete().eq("restaurant_id", id);
|
||||
await supabase.from("restaurant_members").delete().eq("restaurant_id", id);
|
||||
|
||||
// Delete locations, menus, categories, items
|
||||
const { data: locations } = await supabase.from("locations").select("id").eq("restaurant_id", id);
|
||||
if (locations && locations.length > 0) {
|
||||
const locIds = locations.map((l) => l.id);
|
||||
const { data: menus } = await supabase.from("menus").select("id").in("location_id", locIds);
|
||||
if (menus && menus.length > 0) {
|
||||
const menuIds = menus.map((m) => m.id);
|
||||
const { data: categories } = await supabase.from("menu_categories").select("id").in("menu_id", menuIds);
|
||||
if (categories && categories.length > 0) {
|
||||
const catIds = categories.map((c) => c.id);
|
||||
await supabase.from("menu_items").delete().in("category_id", catIds);
|
||||
await supabase.from("menu_categories").delete().in("menu_id", menuIds);
|
||||
}
|
||||
await supabase.from("menus").delete().in("location_id", locIds);
|
||||
}
|
||||
await supabase.from("locations").delete().eq("restaurant_id", id);
|
||||
}
|
||||
|
||||
const { error } = await supabase.from("restaurants").delete().eq("id", id);
|
||||
if (error) {
|
||||
req.log.error(error);
|
||||
return reply.code(500).send({ message: "failed to delete restaurant" });
|
||||
}
|
||||
|
||||
return reply.send({ success: true, message: "Restoran başarıyla silindi." });
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user