← 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 }
    )
  }
}