← back to Dear Bubbe Nextjs
app/api/moderation/route.ts
188 lines
import { NextRequest, NextResponse } from 'next/server'
import { readFileSync, writeFileSync, existsSync } from 'fs'
import { join } from 'path'
// Forbidden topics that trigger strikes
const FORBIDDEN_TOPICS = [
// Political topics
'palestine', 'gaza', 'west bank', 'settlements', 'occupation',
'netanyahu', 'bibi', 'hamas', 'hezbollah', 'intifada',
'apartheid', 'zionist', 'zionism', 'idf war crimes',
'bds', 'boycott israel', 'free palestine',
// Keep politics out
'israeli politics', 'knesset', 'likud', 'labor party',
// Sensitive current events
'october 7', 'oct 7', 'hostages', 'gaza war'
]
// File to store strikes
const STRIKES_FILE = join(process.cwd(), 'data', 'user_strikes.json')
interface UserStrikes {
[userId: string]: {
strikes: number
violations: Array<{
timestamp: string
message: string
topic: string
}>
banned: boolean
}
}
function loadStrikes(): UserStrikes {
if (!existsSync(STRIKES_FILE)) {
// Create data directory if it doesn't exist
const dataDir = join(process.cwd(), 'data')
if (!existsSync(dataDir)) {
require('fs').mkdirSync(dataDir, { recursive: true })
}
writeFileSync(STRIKES_FILE, JSON.stringify({}))
return {}
}
return JSON.parse(readFileSync(STRIKES_FILE, 'utf-8'))
}
function saveStrikes(strikes: UserStrikes) {
writeFileSync(STRIKES_FILE, JSON.stringify(strikes, null, 2))
}
export async function POST(request: NextRequest) {
try {
const { message, userId } = await request.json()
if (!message || !userId) {
return NextResponse.json(
{ error: 'Message and userId required' },
{ status: 400 }
)
}
const lowerMessage = message.toLowerCase()
// Check for forbidden topics
const foundTopic = FORBIDDEN_TOPICS.find(topic =>
lowerMessage.includes(topic.toLowerCase())
)
if (foundTopic) {
const strikes = loadStrikes()
// Initialize user if not exists
if (!strikes[userId]) {
strikes[userId] = {
strikes: 0,
violations: [],
banned: false
}
}
// Check if already banned
if (strikes[userId].banned) {
return NextResponse.json({
violation: true,
banned: true,
message: "Your account has been suspended for repeated violations. Contact support if you believe this is an error."
})
}
// Add strike
strikes[userId].strikes += 1
strikes[userId].violations.push({
timestamp: new Date().toISOString(),
message: message.substring(0, 100), // Store first 100 chars
topic: foundTopic
})
const userStrikes = strikes[userId].strikes
// Ban if 3 strikes
if (userStrikes >= 3) {
strikes[userId].banned = true
saveStrikes(strikes)
// Notify admin (this would normally send to admin agent)
console.log(`[MODERATION] User ${userId} BANNED after 3 strikes`)
// Here we would notify the Bubbe Admin Agent
// For now, log to a file
const adminLog = join(process.cwd(), 'data', 'admin_notifications.log')
const logEntry = `${new Date().toISOString()} - User ${userId} banned for political content violations\n`
require('fs').appendFileSync(adminLog, logEntry)
return NextResponse.json({
violation: true,
banned: true,
strikes: userStrikes,
message: "You have been banned after 3 strikes for discussing forbidden political topics. Your account is now suspended."
})
}
saveStrikes(strikes)
// Return warning message
const warningMessages = {
1: `⚠️ WARNING - Strike 1 of 3: Please don't discuss political topics like ${foundTopic}. I'm here to be your Bubbe, not debate politics! Let's talk about your life, your family, your dating life - things that really matter!`,
2: `⚠️⚠️ SERIOUS WARNING - Strike 2 of 3: This is your second violation for discussing ${foundTopic}. One more strike and your account will be suspended. Please, bubbeleh, let's keep politics out of this. Tell me about YOUR life instead!`
}
return NextResponse.json({
violation: true,
strikes: userStrikes,
topic: foundTopic,
warning: warningMessages[userStrikes as keyof typeof warningMessages] || warningMessages[1],
deflection: "So enough of that mishigas - tell me about YOU! Are you dating anyone? How's work? When did you last eat a proper meal?"
})
}
// No violation found
return NextResponse.json({
violation: false,
message: "Message approved"
})
} catch (error) {
console.error('[MODERATION] Error:', error)
return NextResponse.json(
{ error: 'Moderation check failed' },
{ status: 500 }
)
}
}
// GET endpoint to check user status
export async function GET(request: NextRequest) {
try {
const userId = request.nextUrl.searchParams.get('userId')
if (!userId) {
return NextResponse.json(
{ error: 'userId required' },
{ status: 400 }
)
}
const strikes = loadStrikes()
const userRecord = strikes[userId]
if (!userRecord) {
return NextResponse.json({
strikes: 0,
banned: false
})
}
return NextResponse.json({
strikes: userRecord.strikes,
banned: userRecord.banned,
violations: userRecord.violations
})
} catch (error) {
console.error('[MODERATION] Error checking status:', error)
return NextResponse.json(
{ error: 'Status check failed' },
{ status: 500 }
)
}
}