diff --git a/app/actions.ts b/app/actions.ts index db57980..09dfb76 100644 --- a/app/actions.ts +++ b/app/actions.ts @@ -165,6 +165,10 @@ export async function createOrUpdateListingAction(formData: FormData) { const descriptionRu = formData.get('descriptionRu') as string const address = formData.get('address') as string + + if (!slug || !categoryId || !neighborhoodId || !nameTr || !address) { + return { success: false, error: 'Lütfen zorunlu alanları (Slug, Kategori, Mahalle, İsim, Adres) doldurun.' } + } const phone = formData.get('phone') as string || null const whatsapp = formData.get('whatsapp') as string || null const website = formData.get('website') as string || null @@ -276,6 +280,10 @@ export async function createOrUpdateBlogPostAction(formData: FormData) { const contentEn = formData.get('contentEn') as string const contentRu = formData.get('contentRu') as string + if (!slug || !titleTr) { + return { success: false, error: 'Lütfen zorunlu alanları (Slug, Başlık) doldurun.' } + } + const tagsStr = formData.get('tags') as string || '' const tags = tagsStr.split(',').map(t => t.trim()).filter(Boolean) @@ -345,6 +353,10 @@ export async function createOrUpdateCollectionAction(formData: FormData) { const descriptionEn = formData.get('descriptionEn') as string const descriptionRu = formData.get('descriptionRu') as string + if (!slug || !titleTr) { + return { success: false, error: 'Lütfen zorunlu alanları (Slug, Başlık) doldurun.' } + } + const listingIdsStr = formData.get('listingIds') as string || '' const listingIds = listingIdsStr.split(',').map(i => i.trim()).filter(Boolean) @@ -409,6 +421,11 @@ export async function createOrUpdateEventAction(formData: FormData) { const startDateStr = formData.get('startDate') as string const endDateStr = formData.get('endDate') as string | null + + if (!slug || !titleTr || !startDateStr) { + return { success: false, error: 'Lütfen zorunlu alanları (Slug, Başlık, Başlangıç Tarihi) doldurun.' } + } + const isSponsored = formData.get('isSponsored') === 'true' const startDate = new Date(startDateStr) diff --git a/lib/openinary.ts b/lib/openinary.ts index c0e129c..0a2abd5 100644 --- a/lib/openinary.ts +++ b/lib/openinary.ts @@ -1,19 +1,46 @@ +import crypto from 'crypto' + export async function uploadToOpeninary(file: File, folder: string = "marmarislocal"): Promise { - const url = `${process.env.OPENINARY_API_URL}/upload`; + const baseUrl = process.env.OPENINARY_API_URL?.replace(/\/+$/, ''); + const url = `${baseUrl}/api/upload`; const key = process.env.OPENINARY_API_KEY; - if (!url || !key) { + if (!baseUrl || !key) { throw new Error("Openinary configuration (OPENINARY_API_URL or OPENINARY_API_KEY) is missing in environment variables."); } + // 1. ENAMETOOLONG Fix: Shorten very long folder parts (e.g. slugs) + const safeFolder = folder + .split('/') + .filter(Boolean) // Avoid double slashes in folder path + .map(part => { + if (part.length > 50) { + const hash = crypto.createHash('md5').update(part).digest('hex').substring(0, 8); + return `${part.substring(0, 40)}-${hash}`; + } + return part; + }) + .join('/'); + + // 2. ENAMETOOLONG Fix: Shorten very long filenames + const lastDotIndex = file.name.lastIndexOf('.'); + const ext = lastDotIndex !== -1 ? file.name.substring(lastDotIndex) : ''; + let nameWithoutExt = lastDotIndex !== -1 ? file.name.substring(0, lastDotIndex) : file.name; + + if (nameWithoutExt.length > 50) { + const hash = crypto.createHash('md5').update(nameWithoutExt).digest('hex').substring(0, 8); + nameWithoutExt = `${nameWithoutExt.substring(0, 40)}-${hash}`; + } + const safeFileName = `${nameWithoutExt}${ext}`; + const formData = new FormData(); - formData.append("files", file); - formData.append("folder", folder); + formData.append("files", file, safeFileName); + formData.append("folder", safeFolder); const response = await fetch(url, { method: "POST", headers: { - "x-api-key": key, + "Authorization": `Bearer ${key}`, }, body: formData, }); @@ -27,9 +54,11 @@ export async function uploadToOpeninary(file: File, folder: string = "marmarislo // Openinary standard response is usually an array: [{ url: "...", name: "..." }] if (Array.isArray(data) && data.length > 0) { - return data[0].url || data[0].secure_url; + const fileUrl = data[0].url || data[0].secure_url; + return fileUrl.startsWith('/') ? `${baseUrl}${fileUrl}` : fileUrl; } else if (data && typeof data === "object") { - return data.url || data.secure_url || (data.files && data.files[0]?.url); + const fileUrl = data.url || data.secure_url || (data.files && data.files[0]?.url); + return fileUrl.startsWith('/') ? `${baseUrl}${fileUrl}` : fileUrl; } throw new Error("Invalid response format from Openinary server.");