feat: allow updating custom menu slug with format validation, uniqueness checking and active cache sync
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type { FastifyPluginAsync } from "fastify";
|
||||
import { z } from "zod";
|
||||
import { requireAuth, requireRestaurantMember } from "../lib/auth.js";
|
||||
import { slugify } from "@menulio/shared";
|
||||
import { generateUniqueRestaurantSlug } from "../lib/slug.js";
|
||||
import { supabase } from "../lib/supabase.js";
|
||||
import { deleteCustomHostname, getCustomHostnameByHostname } from "../lib/cloudflare.js";
|
||||
@@ -12,7 +13,13 @@ const createRestaurantSchema = z.object({
|
||||
address: z.string().max(500).nullish(),
|
||||
});
|
||||
|
||||
const updateRestaurantSchema = createRestaurantSchema.partial();
|
||||
const updateRestaurantSchema = z.object({
|
||||
name: z.string().min(1).max(120).optional(),
|
||||
logoUrl: z.string().nullish(),
|
||||
phone: z.string().max(30).nullish(),
|
||||
address: z.string().max(500).nullish(),
|
||||
slug: z.string().min(2).max(100).optional(),
|
||||
});
|
||||
|
||||
export const restaurantsRoutes: FastifyPluginAsync = async (app) => {
|
||||
app.post("/restaurants", async (req, reply) => {
|
||||
@@ -101,7 +108,38 @@ export const restaurantsRoutes: FastifyPluginAsync = async (app) => {
|
||||
return reply.code(400).send({ message: "invalid body", issues: parsed.error.issues });
|
||||
}
|
||||
|
||||
const { name, logoUrl, phone, address } = parsed.data;
|
||||
const { name, logoUrl, phone, address, slug } = parsed.data;
|
||||
|
||||
let formattedSlug: string | undefined = undefined;
|
||||
if (slug !== undefined) {
|
||||
const cleanSlug = slugify(slug);
|
||||
if (!cleanSlug || cleanSlug.length < 2) {
|
||||
return reply.code(400).send({ message: "Geçersiz menü adresi formatı. Harf ve rakamlardan oluşmalıdır." });
|
||||
}
|
||||
|
||||
const RESERVED_SLUGS = new Set([
|
||||
"demo", "templates", "admin", "api", "privacy", "support",
|
||||
"login", "register", "app", "www", "auth", "account", "menu", "menus", "qr", "settings"
|
||||
]);
|
||||
|
||||
if (RESERVED_SLUGS.has(cleanSlug)) {
|
||||
return reply.code(400).send({ message: "Bu menü adresi sistem tarafından ayrılmıştır, kullanılamaz." });
|
||||
}
|
||||
|
||||
const { data: existing } = await supabase
|
||||
.from("restaurants")
|
||||
.select("id")
|
||||
.eq("slug", cleanSlug)
|
||||
.neq("id", id)
|
||||
.maybeSingle();
|
||||
|
||||
if (existing) {
|
||||
return reply.code(409).send({ message: "Bu özel menü adresi başka bir restoran tarafından kullanılıyor." });
|
||||
}
|
||||
|
||||
formattedSlug = cleanSlug;
|
||||
}
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from("restaurants")
|
||||
.update({
|
||||
@@ -109,6 +147,7 @@ export const restaurantsRoutes: FastifyPluginAsync = async (app) => {
|
||||
...(logoUrl !== undefined ? { logo_url: logoUrl } : {}),
|
||||
...(phone !== undefined ? { phone } : {}),
|
||||
...(address !== undefined ? { address } : {}),
|
||||
...(formattedSlug !== undefined ? { slug: formattedSlug } : {}),
|
||||
updated_at: new Date().toISOString(),
|
||||
})
|
||||
.eq("id", id)
|
||||
|
||||
Reference in New Issue
Block a user