feat(admin): consentement aux annonces et désabonnement sans connexion
Les comptes déjà créés ne sont pas inscrits. Le choix est facultatif à l’inscription et dans les paramètres. Un lien public demande confirmation avant d’arrêter les actualités, sans toucher aux messages de compte.
This commit is contained in:
53
memento-note/app/api/marketing/unsubscribe/route.ts
Normal file
53
memento-note/app/api/marketing/unsubscribe/route.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { unsubscribeByUserId } from '@/lib/marketing/preference'
|
||||
import { publicAppOrigin, verifyUnsubscribeToken } from '@/lib/marketing/unsubscribe-token'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
function tokenFromRequest(request: NextRequest, bodyToken?: string | null): string | null {
|
||||
return (
|
||||
request.nextUrl.searchParams.get('token') ||
|
||||
bodyToken ||
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
async function applyUnsubscribe(request: NextRequest, token: string | null) {
|
||||
const payload = token ? verifyUnsubscribeToken(token) : null
|
||||
if (!payload) {
|
||||
return NextResponse.json({ ok: false }, { status: 400 })
|
||||
}
|
||||
const forwarded = request.headers.get('x-forwarded-for')
|
||||
const ip = forwarded?.split(',')[0]?.trim() || request.headers.get('x-real-ip')
|
||||
await unsubscribeByUserId({
|
||||
userId: payload.userId,
|
||||
source: 'unsubscribe-one-click',
|
||||
meta: { ip, userAgent: request.headers.get('user-agent') },
|
||||
})
|
||||
return new NextResponse('OK', { status: 200 })
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
let bodyToken: string | null = null
|
||||
const contentType = request.headers.get('content-type') || ''
|
||||
try {
|
||||
if (contentType.includes('application/x-www-form-urlencoded')) {
|
||||
const form = await request.formData()
|
||||
bodyToken = String(form.get('token') || '')
|
||||
} else if (contentType.includes('application/json')) {
|
||||
const json = await request.json().catch(() => null)
|
||||
bodyToken = json?.token ? String(json.token) : null
|
||||
}
|
||||
} catch {
|
||||
bodyToken = null
|
||||
}
|
||||
return applyUnsubscribe(request, tokenFromRequest(request, bodyToken))
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const token = request.nextUrl.searchParams.get('token') || ''
|
||||
const origin = publicAppOrigin() || request.nextUrl.origin
|
||||
const url = new URL('/unsubscribe', origin)
|
||||
if (token) url.searchParams.set('token', token)
|
||||
return NextResponse.redirect(url, 303)
|
||||
}
|
||||
Reference in New Issue
Block a user