Postgres
This commit is contained in:
@@ -39,9 +39,32 @@ function getModel(provider: LlmProvider): string {
|
||||
return process.env.OPENAI_MODEL || 'gpt-4o-mini'
|
||||
}
|
||||
|
||||
function hasApiKey(provider: LlmProvider): boolean {
|
||||
if (provider === 'openrouter') return !!process.env.OPENROUTER_API_KEY
|
||||
return !!process.env.OPENAI_API_KEY
|
||||
}
|
||||
|
||||
function buildFallbackLandingContent(orgName: string, context: string) {
|
||||
const cleanOrg = orgName.trim()
|
||||
const cleanContext = context.trim().replace(/\s+/g, ' ')
|
||||
const shortContext = cleanContext.slice(0, 180)
|
||||
const detailSentence = shortContext
|
||||
? `Dabei stehen insbesondere ${shortContext}.`
|
||||
: 'Dabei stehen regionale Vernetzung, starke Ausbildung und praxisnahe Unterstützung im Mittelpunkt.'
|
||||
|
||||
return {
|
||||
title: `${cleanOrg} - Stark im Handwerk`,
|
||||
text: `${cleanOrg} verbindet Betriebe, stärkt die Gemeinschaft und setzt sich für die Interessen des Handwerks vor Ort ein. ${detailSentence}`,
|
||||
fallbackUsed: true,
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(req: Request) {
|
||||
let parsedBody: any = null
|
||||
|
||||
try {
|
||||
const body = await req.json()
|
||||
parsedBody = body
|
||||
const { orgName, context } = body
|
||||
|
||||
if (!orgName || !context) {
|
||||
@@ -49,9 +72,14 @@ export async function POST(req: Request) {
|
||||
}
|
||||
|
||||
const provider = getProvider()
|
||||
const client = createClient(provider)
|
||||
const model = getModel(provider)
|
||||
|
||||
if (!hasApiKey(provider)) {
|
||||
return NextResponse.json(buildFallbackLandingContent(orgName, context))
|
||||
}
|
||||
|
||||
const client = createClient(provider)
|
||||
|
||||
const systemMessage = `Sie sind ein professioneller Copywriter für eine moderne deutsche Innung oder Kreishandwerkerschaft.
|
||||
Erstellen Sie eine moderne, ansprechende Überschrift (Heading) und einen Einleitungstext für eine Landingpage.
|
||||
|
||||
@@ -89,6 +117,10 @@ WICHTIG: Geben Sie AUSSCHLIESSLICH ein valides JSON-Objekt zurück, komplett ohn
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('Error generating AI landing page content:', error)
|
||||
if (parsedBody?.orgName && parsedBody?.context) {
|
||||
return NextResponse.json(buildFallbackLandingContent(parsedBody.orgName, parsedBody.context))
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: error?.message || 'Failed to generate content' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { auth } from '@/lib/auth'
|
||||
import { auth, getSanitizedHeaders } from '@/lib/auth'
|
||||
import { prisma } from '@innungsapp/shared'
|
||||
import { headers } from 'next/headers'
|
||||
|
||||
export async function POST() {
|
||||
const session = await auth.api.getSession({ headers: await headers() })
|
||||
const session = await auth.api.getSession({ headers: await getSanitizedHeaders() })
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Nicht eingeloggt' }, { status: 401 })
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { auth } from '@/lib/auth'
|
||||
import { auth, getSanitizedHeaders } from '@/lib/auth'
|
||||
import { prisma } from '@innungsapp/shared'
|
||||
import { headers } from 'next/headers'
|
||||
// @ts-ignore
|
||||
import { hashPassword } from 'better-auth/crypto'
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await auth.api.getSession({ headers: await headers() })
|
||||
const session = await auth.api.getSession({ headers: await getSanitizedHeaders() })
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Nicht eingeloggt' }, { status: 401 })
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { NextRequest } from 'next/server'
|
||||
import { auth } from '@/lib/auth'
|
||||
import { auth, getSanitizedHeaders } from '@/lib/auth'
|
||||
import { prisma } from '@innungsapp/shared'
|
||||
|
||||
export async function GET(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await auth.api.getSession({ headers: req.headers })
|
||||
const session = await auth.api.getSession({ headers: await getSanitizedHeaders(req.headers) })
|
||||
if (!session?.user) {
|
||||
return new Response('Unauthorized', { status: 401 })
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { auth } from '@/lib/auth'
|
||||
import { auth, getSanitizedHeaders } from '@/lib/auth'
|
||||
import { prisma } from '@innungsapp/shared'
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await auth.api.getSession({ headers: req.headers })
|
||||
const session = await auth.api.getSession({ headers: await getSanitizedHeaders(req.headers) })
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* DEV-ONLY: Sets a password for the demo admin user via better-auth.
|
||||
* Call once after seeding: GET http://localhost:3032/api/setup
|
||||
* Call once after seeding: GET http://localhost:3010/api/setup
|
||||
* Remove this file before going to production.
|
||||
*/
|
||||
import { NextResponse } from 'next/server'
|
||||
|
||||
@@ -2,14 +2,21 @@ import { NextRequest, NextResponse } from 'next/server'
|
||||
import { writeFile, mkdir } from 'fs/promises'
|
||||
import path from 'path'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { auth } from '@/lib/auth'
|
||||
import { auth, getSanitizedHeaders } from '@/lib/auth'
|
||||
|
||||
const UPLOAD_DIR = process.env.UPLOAD_DIR ?? './uploads'
|
||||
const UPLOAD_DIR = process.env.UPLOAD_DIR ?? (process.env.NODE_ENV === 'production' ? '/app/uploads' : './uploads')
|
||||
const MAX_SIZE_BYTES = Number(process.env.UPLOAD_MAX_SIZE_MB ?? 10) * 1024 * 1024
|
||||
|
||||
function getUploadRoot() {
|
||||
if (path.isAbsolute(UPLOAD_DIR)) {
|
||||
return UPLOAD_DIR
|
||||
}
|
||||
return path.resolve(process.cwd(), UPLOAD_DIR)
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
// Auth check
|
||||
const session = await auth.api.getSession({ headers: req.headers })
|
||||
const session = await auth.api.getSession({ headers: await getSanitizedHeaders(req.headers) })
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
@@ -39,7 +46,7 @@ export async function POST(req: NextRequest) {
|
||||
|
||||
const ext = path.extname(file.name)
|
||||
const fileName = `${randomUUID()}${ext}`
|
||||
const uploadPath = path.join(process.cwd(), UPLOAD_DIR)
|
||||
const uploadPath = getUploadRoot()
|
||||
|
||||
await mkdir(uploadPath, { recursive: true })
|
||||
const buffer = Buffer.from(await file.arrayBuffer())
|
||||
|
||||
@@ -2,21 +2,28 @@ import { NextRequest, NextResponse } from 'next/server'
|
||||
import { readFile } from 'fs/promises'
|
||||
import path from 'path'
|
||||
|
||||
const UPLOAD_DIR = process.env.UPLOAD_DIR ?? './uploads'
|
||||
// Added comment to force recompile after ENOSPC
|
||||
const UPLOAD_DIR = process.env.UPLOAD_DIR ?? (process.env.NODE_ENV === 'production' ? '/app/uploads' : './uploads')
|
||||
|
||||
function getUploadRoot() {
|
||||
if (path.isAbsolute(UPLOAD_DIR)) {
|
||||
return UPLOAD_DIR
|
||||
}
|
||||
return path.resolve(process.cwd(), UPLOAD_DIR)
|
||||
}
|
||||
|
||||
export async function GET(
|
||||
req: NextRequest,
|
||||
{ params }: { params: Promise<{ path: string[] }> }
|
||||
) {
|
||||
try {
|
||||
const { path: filePathParams } = await params;
|
||||
const filePath = path.join(process.cwd(), UPLOAD_DIR, ...filePathParams)
|
||||
const { path: filePathParams } = await params
|
||||
const uploadRoot = getUploadRoot()
|
||||
const filePath = path.join(uploadRoot, ...filePathParams)
|
||||
|
||||
// Security: prevent path traversal
|
||||
const resolved = path.resolve(filePath)
|
||||
const uploadDir = path.resolve(path.join(process.cwd(), UPLOAD_DIR))
|
||||
if (!resolved.startsWith(uploadDir)) {
|
||||
const uploadDir = path.resolve(uploadRoot)
|
||||
if (!resolved.startsWith(uploadDir + path.sep) && resolved !== uploadDir) {
|
||||
return new NextResponse('Forbidden', { status: 403 })
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user