Initial commit

This commit is contained in:
2025-06-22 00:01:22 +03:00
parent fd70166cf6
commit 033b80bfad
153 changed files with 26874 additions and 1 deletions

View File

@@ -0,0 +1,58 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
import { hashPassword } from "@/lib/auth"
import { type UserRole, DEPARTMENTS, TEAMS, FIELDS } from "@/types/user"
export async function POST(request: NextRequest) {
try {
const { name, isAdmin, field, department, team, role } = await request.json()
// Input validation
if (!name || !field || !department || !team) {
return NextResponse.json({ error: "נתונים חסרים" }, { status: 400 })
}
// Validate department, team, and field
if (!FIELDS.includes(field as any)) {
return NextResponse.json({ error: "תחום לא תקין" }, { status: 400 })
}
if (!DEPARTMENTS.includes(department as any)) {
return NextResponse.json({ error: "מסגרת לא תקינה" }, { status: 400 })
}
if (!TEAMS.includes(team as any)) {
return NextResponse.json({ error: "צוות לא תקין" }, { status: 400 })
}
const validRoles: UserRole[] = ["user", "team_admin", "department_admin", "field_admin", "global_admin"]
// Set role based on isAdmin flag or explicit role
const userRole: UserRole = (role as UserRole) || (isAdmin ? "global_admin" : "user")
if (!validRoles.includes(userRole)) {
return NextResponse.json({ error: "תפקיד לא תקין" }, { status: 400 })
}
// Generate unique Login ID
const { generateUniqueIsraeliID } = await import("@/lib/auth")
const nationalId = await generateUniqueIsraeliID()
// Hash default password "password123"
const hashedPassword = await hashPassword("password123")
await safeQuery(
"INSERT INTO users (national_id, password, name, is_admin, role, must_change_password, field, department, team) VALUES (?, ?, ?, ?, ?, TRUE, ?, ?, ?)",
[nationalId, hashedPassword, name, isAdmin, userRole, field, department, team],
)
return NextResponse.json({
success: true,
nationalId: nationalId,
message: `משתמש ${name} נוסף בהצלחה עם מזהה: ${nationalId}`,
})
} catch (error) {
console.error("Add user error:", error)
return NextResponse.json({ error: "שגיאה בהוספת משתמש" }, { status: 500 })
}
}

View File

@@ -0,0 +1,76 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
import { type UserRole, ROLE_HIERARCHY, ROLE_NAMES } from "@/types/user"
export async function POST(request: NextRequest) {
try {
const { adminId, targetUserId, newRole } = await request.json()
if (!adminId || !targetUserId || !newRole) {
return NextResponse.json({ error: "נתונים חסרים" }, { status: 400 })
}
// Get admin data
const adminData = (await safeQuery("SELECT role, field, department, team FROM users WHERE national_id = ?", [
adminId,
])) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const admin = adminData[0]
const adminLevel = ROLE_HIERARCHY[admin.role as UserRole] || 0
// Get target user data
const targetData = (await safeQuery("SELECT role, field, department, team, name FROM users WHERE national_id = ?", [
targetUserId,
])) as any[]
if (targetData.length === 0) {
return NextResponse.json({ error: "משתמש לא נמצא" }, { status: 404 })
}
const target = targetData[0]
const newRoleLevel = ROLE_HIERARCHY[newRole as UserRole] || 0
// Check if admin has permission to change this role
if (adminLevel <= newRoleLevel) {
return NextResponse.json({ error: "אין הרשאה לתת תפקיד זה" }, { status: 403 })
}
// Check if admin can manage this user based on hierarchy
let canManage = false
if (admin.role === "global_admin") {
canManage = true
} else if (admin.role === "field_admin" && admin.field === target.field) {
canManage = true
} else if (admin.role === "department_admin" && admin.department === target.department) {
canManage = true
} else if (admin.role === "team_admin" && admin.team === target.team) {
canManage = true
}
if (!canManage) {
return NextResponse.json({ error: "אין הרשאה לנהל משתמש זה" }, { status: 403 })
}
// Update user role
await safeQuery("UPDATE users SET role = ? WHERE national_id = ?", [newRole, targetUserId])
// Log the action
await safeQuery(
'INSERT INTO admin_actions (admin_id, action_type, target_user_id, target_role) VALUES (?, "role_change", ?, ?)',
[adminId, targetUserId, newRole],
)
return NextResponse.json({
success: true,
message: `תפקיד ${target.name} שונה ל${ROLE_NAMES[newRole as UserRole]}`,
})
} catch (error) {
console.error("Change role error:", error)
return NextResponse.json({ error: "שגיאה בשינוי תפקיד" }, { status: 500 })
}
}

View File

@@ -0,0 +1,54 @@
import { NextResponse } from "next/server"
import { healthCheck, getPoolStats } from "@/lib/database"
export async function GET() {
try {
const health = await healthCheck()
const poolStats = getPoolStats()
return NextResponse.json({
...health,
poolStats,
recommendations: generateRecommendations(poolStats),
})
} catch (error) {
console.error("Database health check error:", error)
return NextResponse.json(
{
status: "error",
error: error instanceof Error ? error.message : "Unknown error",
timestamp: new Date().toISOString(),
},
{ status: 500 },
)
}
}
function generateRecommendations(stats: any) {
const recommendations = []
if (!stats) {
recommendations.push("Unable to get pool statistics")
return recommendations
}
const utilizationRate = (stats.totalConnections - stats.freeConnections) / stats.connectionLimit
if (utilizationRate > 0.8) {
recommendations.push("High connection utilization - consider increasing connection limit")
}
if (stats.acquiringConnections > 5) {
recommendations.push("Many connections waiting - possible connection leak or high load")
}
if (stats.freeConnections === 0) {
recommendations.push("No free connections available - increase pool size or check for connection leaks")
}
if (recommendations.length === 0) {
recommendations.push("Database pool is healthy")
}
return recommendations
}

View File

@@ -0,0 +1,79 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
export async function POST(request: NextRequest) {
try {
const { adminId } = await request.json()
if (!adminId) {
return NextResponse.json({ error: "מזהה מנהל חסר" }, { status: 400 })
}
// Get admin's field and department
const adminData = (await safeQuery(
"SELECT field, department FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
[adminId],
)) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const { field: adminField, department: adminDepartment } = adminData[0]
if (!adminField || !adminDepartment) {
return NextResponse.json({ error: "למנהל לא הוגדרו תחום ומסגרת" }, { status: 400 })
}
// Check cooldown for department resets
const lastReset = (await safeQuery(
'SELECT timestamp FROM admin_actions WHERE action_type = "reset_department" AND admin_id = ? ORDER BY timestamp DESC LIMIT 1',
[adminId],
)) as any[]
if (lastReset.length > 0) {
const lastResetTime = new Date(lastReset[0].timestamp).getTime()
const now = new Date().getTime()
const cooldownMs = 90 * 10 // 1.5 minutes for department resets
if (now - lastResetTime < cooldownMs) {
return NextResponse.json({ error: "יש להמתין 90 שניות בין איפוסי מסגרת" }, { status: 429 })
}
}
// Reset department users' statuses with field and department context, but exclude locked users
await safeQuery(
"UPDATE users SET in_shelter = NULL, last_updated = NULL WHERE field = ? AND department = ? AND lock_status = FALSE",
[adminField, adminDepartment],
)
// Get count of locked users that were skipped
const lockedUsers = (await safeQuery(
"SELECT COUNT(*) as count FROM users WHERE field = ? AND department = ? AND lock_status = TRUE",
[adminField, adminDepartment],
)) as any[]
const lockedCount = lockedUsers[0]?.count || 0
// Log the action
await safeQuery(
'INSERT INTO admin_actions (admin_id, action_type, target_user_id) VALUES (?, "reset_department", NULL)',
[adminId],
)
let message = `כל הסטטוסים של מסגרת ${adminDepartment} בתחום ${adminField} אופסו בהצלחה`
if (lockedCount > 0) {
message += ` (${lockedCount} משתמשים נעולים לא אופסו)`
}
return NextResponse.json({
success: true,
field: adminField,
department: adminDepartment,
message,
lockedCount,
})
} catch (error) {
console.error("Department reset error:", error)
return NextResponse.json({ error: "שגיאה באיפוס המסגרת" }, { status: 500 })
}
}

View File

@@ -0,0 +1,52 @@
import { NextResponse } from "next/server"
import { executeQuery } from "@/lib/database"
export async function POST(request: Request) {
try {
const { adminId } = await request.json()
if (!adminId) {
return NextResponse.json({ error: "מזהה מנהל חסר" }, { status: 400 })
}
// Get admin's field and department
const adminData = (await executeQuery(
"SELECT field, department FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
[adminId],
)) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const { field: adminField, department: adminDepartment } = adminData[0]
if (!adminField || !adminDepartment) {
return NextResponse.json({ error: "למנהל לא הוגדרו תחום ומסגרת" }, { status: 400 })
}
// Get department stats with field and department context
const results = (await executeQuery(
`
SELECT
SUM(CASE WHEN in_shelter IS NULL THEN 1 ELSE 0 END) as no_report,
SUM(CASE WHEN in_shelter = 'yes' THEN 1 ELSE 0 END) as in_shelter,
SUM(CASE WHEN in_shelter = 'no' THEN 1 ELSE 0 END) as not_in_shelter,
SUM(CASE WHEN in_shelter = 'no_alarm' THEN 1 ELSE 0 END) as no_alarm,
SUM(CASE WHEN in_shelter = 'safe_after_exit' THEN 1 ELSE 0 END) as safe_after_exit
FROM users
WHERE field = ? AND department = ?
`,
[adminField, adminDepartment],
)) as any[]
return NextResponse.json({
...results[0],
field: adminField,
department: adminDepartment,
})
} catch (error) {
console.error("Department stats error:", error)
return NextResponse.json({ error: "שגיאה בטעינת סטטיסטיקות המסגרת" }, { status: 500 })
}
}

View File

@@ -0,0 +1,62 @@
import { type NextRequest, NextResponse } from "next/server"
import { executeQuery } from "@/lib/database"
export async function POST(request: NextRequest) {
try {
const { adminId, category } = await request.json()
if (!adminId || !category) {
return NextResponse.json({ error: "נתונים חסרים" }, { status: 400 })
}
// Get admin's field and department
const adminData = (await executeQuery(
"SELECT field, department FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
[adminId],
)) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const { field: adminField, department: adminDepartment } = adminData[0]
if (!adminField || !adminDepartment) {
return NextResponse.json({ error: "למנהל לא הוגדרו תחום ומסגרת" }, { status: 400 })
}
let query = ""
const params: any[] = [adminField, adminDepartment]
switch (category) {
case "no_report":
query =
"SELECT national_id, name, team FROM users WHERE field = ? AND department = ? AND in_shelter IS NULL ORDER BY team, name"
break
case "in_shelter":
query =
"SELECT national_id, name, team FROM users WHERE field = ? AND department = ? AND in_shelter = 'yes' ORDER BY team, name"
break
case "not_in_shelter":
query =
"SELECT national_id, name, team FROM users WHERE field = ? AND department = ? AND in_shelter = 'no' ORDER BY team, name"
break
case "no_alarm":
query =
"SELECT national_id, name, team FROM users WHERE field = ? AND department = ? AND in_shelter = 'no_alarm' ORDER BY team, name"
break
case "safe_after_exit":
query =
"SELECT national_id, name , team FROM users WHERE field = ? AND department = ? AND in_shelter = 'safe_after_exit' ORDER BY name"
break
default:
return NextResponse.json({ error: "קטגוריה לא תקינה" }, { status: 400 })
}
const users = (await executeQuery(query, params)) as any[]
return NextResponse.json(users)
} catch (error) {
console.error("Get department users by category error:", error)
return NextResponse.json({ error: "שגיאה בטעינת משתמשי המסגרת" }, { status: 500 })
}
}

View File

@@ -0,0 +1,58 @@
import { NextResponse } from "next/server"
import { executeQuery } from "@/lib/database"
export async function POST(request: Request) {
try {
const { adminId } = await request.json()
if (!adminId) {
return NextResponse.json({ error: "מזהה מנהל חסר" }, { status: 400 })
}
// Get admin's field and department
const adminData = (await executeQuery(
"SELECT field, department FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
[adminId],
)) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const { field: adminField, department: adminDepartment } = adminData[0]
if (!adminField || !adminDepartment) {
return NextResponse.json({ error: "למנהל לא הוגדרו תחום ומסגרת" }, { status: 400 })
}
// Get department users with field and department context
const users = (await executeQuery(
`
SELECT
national_id,
name,
in_shelter,
last_updated,
is_admin,
must_change_password,
field,
department,
team,
lock_status
FROM users
WHERE field = ? AND department = ?
ORDER BY team, name
`,
[adminField, adminDepartment],
)) as any[]
return NextResponse.json({
users,
field: adminField,
department: adminDepartment,
})
} catch (error) {
console.error("Department users error:", error)
return NextResponse.json({ error: "שגיאה בטעינת משתמשי המסגרת" }, { status: 500 })
}
}

View File

@@ -0,0 +1,61 @@
export const dynamic = 'force-dynamic';
import type { NextRequest } from "next/server"
// Store active connections
const connections = new Set<ReadableStreamDefaultController>()
export async function GET(request: NextRequest) {
const stream = new ReadableStream({
start(controller) {
connections.add(controller)
// Send initial connection message
controller.enqueue(`data: ${JSON.stringify({ type: "connected", timestamp: new Date().toISOString() })}\n\n`)
// Keep connection alive with periodic pings
const pingInterval = setInterval(() => {
try {
controller.enqueue(`data: ${JSON.stringify({ type: "ping", timestamp: new Date().toISOString() })}\n\n`)
} catch (err) {
clearInterval(pingInterval)
connections.delete(controller)
}
}, 30000)
// Clean up on close
request.signal.addEventListener("abort", () => {
clearInterval(pingInterval)
connections.delete(controller)
try {
controller.close()
} catch (err) {
// Connection already closed
}
})
},
})
return new Response(stream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Cache-Control",
},
})
}
// Function to broadcast updates to all connected clients
export function broadcastUpdate(data: any) {
const message = `data: ${JSON.stringify({ type: "update", data, timestamp: new Date().toISOString() })}\n\n`
connections.forEach((controller) => {
try {
controller.enqueue(message)
} catch (err) {
connections.delete(controller)
}
})
}

View File

@@ -0,0 +1,70 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
export async function POST(request: NextRequest) {
try {
const { adminId } = await request.json()
if (!adminId) {
return NextResponse.json({ error: "מזהה מנהל חסר" }, { status: 400 })
}
// Get admin's field
const adminData = (await safeQuery("SELECT field FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'", [
adminId,
])) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const adminField = adminData[0].field
if (!adminField) {
return NextResponse.json({ error: "למנהל לא הוגדר תחום" }, { status: 400 })
}
// Check cooldown for field resets
const lastReset = (await safeQuery(
'SELECT timestamp FROM admin_actions WHERE action_type = "reset_field" AND admin_id = ? ORDER BY timestamp DESC LIMIT 1',
[adminId],
)) as any[]
if (lastReset.length > 0) {
const lastResetTime = new Date(lastReset[0].timestamp).getTime()
const now = new Date().getTime()
const cooldownMs = 2 * 60 * 10 // 2 minutes for field resets
if (now - lastResetTime < cooldownMs) {
return NextResponse.json({ error: "יש להמתין 2 דקות בין איפוסי תחום" }, { status: 429 })
}
}
// Reset field users' statuses, but exclude locked users
await safeQuery("UPDATE users SET in_shelter = NULL, last_updated = NULL WHERE field = ? AND lock_status = FALSE", [
adminField,
])
// Get count of locked users that were skipped
const lockedUsers = (await safeQuery("SELECT COUNT(*) as count FROM users WHERE field = ? AND lock_status = TRUE", [
adminField,
])) as any[]
const lockedCount = lockedUsers[0]?.count || 0
// Log the action
await safeQuery(
'INSERT INTO admin_actions (admin_id, action_type, target_user_id) VALUES (?, "reset_field", NULL)',
[adminId],
)
let message = `כל הסטטוסים של תחום ${adminField} אופסו בהצלחה`
if (lockedCount > 0) {
message += ` (${lockedCount} משתמשים נעולים לא אופסו)`
}
return NextResponse.json({ success: true, field: adminField, message, lockedCount })
} catch (error) {
console.error("Field reset error:", error)
return NextResponse.json({ error: "שגיאה באיפוס התחום" }, { status: 500 })
}
}

View File

@@ -0,0 +1,50 @@
import { NextResponse } from "next/server"
import { executeQuery } from "@/lib/database"
export async function POST(request: Request) {
try {
const { adminId } = await request.json()
if (!adminId) {
return NextResponse.json({ error: "מזהה מנהל חסר" }, { status: 400 })
}
// Get admin's field
const adminData = (await executeQuery("SELECT field FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'", [
adminId,
])) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const adminField = adminData[0].field
if (!adminField) {
return NextResponse.json({ error: "למנהל לא הוגדר תחום" }, { status: 400 })
}
// Get field stats
const results = (await executeQuery(
`
SELECT
SUM(CASE WHEN in_shelter IS NULL THEN 1 ELSE 0 END) as no_report,
SUM(CASE WHEN in_shelter = 'yes' THEN 1 ELSE 0 END) as in_shelter,
SUM(CASE WHEN in_shelter = 'no' THEN 1 ELSE 0 END) as not_in_shelter,
SUM(CASE WHEN in_shelter = 'no_alarm' THEN 1 ELSE 0 END) as no_alarm,
SUM(CASE WHEN in_shelter = 'safe_after_exit' THEN 1 ELSE 0 END) as safe_after_exit
FROM users
WHERE field = ?
`,
[adminField],
)) as any[]
return NextResponse.json({
...results[0],
field: adminField,
})
} catch (error) {
console.error("Field stats error:", error)
return NextResponse.json({ error: "שגיאה בטעינת סטטיסטיקות התחום" }, { status: 500 })
}
}

View File

@@ -0,0 +1,60 @@
import { type NextRequest, NextResponse } from "next/server"
import { executeQuery } from "@/lib/database"
export async function POST(request: NextRequest) {
try {
const { adminId, category } = await request.json()
if (!adminId || !category) {
return NextResponse.json({ error: "נתונים חסרים" }, { status: 400 })
}
// Get admin's field
const adminData = (await executeQuery("SELECT field FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'", [
adminId,
])) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const adminField = adminData[0].field
if (!adminField) {
return NextResponse.json({ error: "למנהל לא הוגדר תחום" }, { status: 400 })
}
let query = ""
const params: any[] = [adminField]
switch (category) {
case "no_report":
query =
"SELECT national_id, name, department, team FROM users WHERE field = ? AND in_shelter IS NULL ORDER BY department, team, name"
break
case "in_shelter":
query =
"SELECT national_id, name, department, team FROM users WHERE field = ? AND in_shelter = 'yes' ORDER BY department, team, name"
break
case "not_in_shelter":
query =
"SELECT national_id, name, department, team FROM users WHERE field = ? AND in_shelter = 'no' ORDER BY department, team, name"
break
case "no_alarm":
query =
"SELECT national_id, name, department, team FROM users WHERE field = ? AND in_shelter = 'no_alarm' ORDER BY department, team, name"
break
case "safe_after_exit":
query = "SELECT national_id, name, department, team FROM users WHERE in_shelter = 'safe_after_exit' ORDER BY name"
break
default:
return NextResponse.json({ error: "קטגוריה לא תקינה" }, { status: 400 })
}
const users = (await executeQuery(query, params)) as any[]
return NextResponse.json(users)
} catch (error) {
console.error("Get field users by category error:", error)
return NextResponse.json({ error: "שגיאה בטעינת משתמשי התחום" }, { status: 500 })
}
}

View File

@@ -0,0 +1,56 @@
import { NextResponse } from "next/server"
import { executeQuery } from "@/lib/database"
export async function POST(request: Request) {
try {
const { adminId } = await request.json()
if (!adminId) {
return NextResponse.json({ error: "מזהה מנהל חסר" }, { status: 400 })
}
// Get admin's field
const adminData = (await executeQuery("SELECT field FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'", [
adminId,
])) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const adminField = adminData[0].field
if (!adminField) {
return NextResponse.json({ error: "למנהל לא הוגדר תחום" }, { status: 400 })
}
// Get field users
const users = (await executeQuery(
`
SELECT
national_id,
name,
in_shelter,
last_updated,
is_admin,
must_change_password,
field,
department,
team,
lock_status
FROM users
WHERE field = ?
ORDER BY department, team, name
`,
[adminField],
)) as any[]
return NextResponse.json({
users,
field: adminField,
})
} catch (error) {
console.error("Field users error:", error)
return NextResponse.json({ error: "שגיאה בטעינת משתמשי התחום" }, { status: 500 })
}
}

View File

@@ -0,0 +1,28 @@
import { NextResponse } from "next/server"
import { executeQuery } from "@/lib/database"
export async function GET() {
try {
const results = (await executeQuery(`
SELECT aa.timestamp, u.name
FROM admin_actions aa
JOIN users u ON aa.admin_id = u.national_id
WHERE aa.action_type = 'reset_all'
ORDER BY aa.timestamp DESC
LIMIT 1
`)) as any[]
if (results.length > 0) {
const result = results[0]
return NextResponse.json({
lastReset: `${result.name} - ${new Date(result.timestamp).toLocaleString("he-IL")}`,
timestamp: result.timestamp,
})
}
return NextResponse.json({ lastReset: null })
} catch (error) {
console.error("Last reset error:", error)
return NextResponse.json({ error: "שגיאה בטעינת נתונים" }, { status: 500 })
}
}

View File

@@ -0,0 +1,122 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
export async function POST(request: NextRequest) {
try {
const { adminId } = await request.json()
if (!adminId) {
return NextResponse.json({ error: "מזהה מנהל חסר" }, { status: 400 })
}
// Get admin data
const adminData = (await safeQuery("SELECT role, field, department, team FROM users WHERE national_id = ?", [
adminId,
])) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const admin = adminData[0]
let query = ""
let params: any[] = []
// Build query based on admin role
if (admin.role === "global_admin") {
query = `
SELECT
national_id,
name,
role,
field,
department,
team,
in_shelter,
last_updated,
lock_status,
is_admin,
must_change_password
FROM users
ORDER BY field, department, team, name
`
} else if (admin.role === "field_admin") {
query = `
SELECT
national_id,
name,
role,
field,
department,
team,
in_shelter,
last_updated,
lock_status,
is_admin,
must_change_password
FROM users
WHERE field = ?
ORDER BY department, team, name
`
params = [admin.field]
} else if (admin.role === "department_admin") {
query = `
SELECT
national_id,
name,
role,
field,
department,
team,
in_shelter,
last_updated,
lock_status,
is_admin,
must_change_password
FROM users
WHERE department = ?
ORDER BY team, name
`
params = [admin.department]
} else if (admin.role === "team_admin") {
// Team admins can only manage their own team members
query = `
SELECT
national_id,
name,
role,
field,
department,
team,
in_shelter,
last_updated,
lock_status,
is_admin,
must_change_password
FROM users
WHERE team = ? AND role = 'user'
ORDER BY name
`
params = [admin.team]
} else {
return NextResponse.json({ error: "אין הרשאות ניהול" }, { status: 403 })
}
const users = (await safeQuery(query, params)) as any[]
console.log("Manageable users query result:", users) // Debug log
return NextResponse.json({
users,
adminRole: admin.role,
scope: {
field: admin.field,
department: admin.department,
team: admin.team,
},
})
} catch (error) {
console.error("Get manageable users error:", error)
return NextResponse.json({ error: "שגיאה בטעינת משתמשים" }, { status: 500 })
}
}

View File

@@ -0,0 +1,86 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
export async function POST(request: NextRequest) {
try {
const { adminId, targetUserId, status } = await request.json()
if (!adminId || !targetUserId || !status) {
return NextResponse.json({ error: "נתונים חסרים" }, { status: 400 })
}
if (!["yes", "no", "no_alarm", "safe_after_exit"].includes(status)) {
return NextResponse.json({ error: "סטטוס לא תקין" }, { status: 400 })
}
// Get admin data
const adminData = (await safeQuery("SELECT role, field, department, team, name FROM users WHERE national_id = ?", [
adminId,
])) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const admin = adminData[0]
// Get target user data
const targetData = (await safeQuery("SELECT field, department, team, name FROM users WHERE national_id = ?", [
targetUserId,
])) as any[]
if (targetData.length === 0) {
return NextResponse.json({ error: "משתמש לא נמצא" }, { status: 404 })
}
const target = targetData[0]
// Check if admin can manage this user based on hierarchy
let canManage = false
if (admin.role === "global_admin") {
canManage = true
} else if (admin.role === "field_admin" && admin.field === target.field) {
canManage = true
} else if (admin.role === "department_admin" && admin.department === target.department) {
canManage = true
} else if (admin.role === "team_admin" && admin.team === target.team) {
canManage = true
}
if (!canManage) {
return NextResponse.json({ error: "אין הרשאה לדווח עבור משתמש זה" }, { status: 403 })
}
// Update user status
await safeQuery("UPDATE users SET in_shelter = ?, last_updated = NOW() WHERE national_id = ?", [
status,
targetUserId,
])
// Log the action
await safeQuery(
'INSERT INTO admin_actions (admin_id, action_type, target_user_id) VALUES (?, "report_on_behalf", ?)',
[adminId, targetUserId],
)
const statusText =
status === "yes"
? "במקלט/חדר מוגן"
: status === "no"
? "לא במקלט"
: status === "no_alarm"
? "אין אזעקה"
: status === "safe_after_exit"
? "בטוח אחרי יציאה מהמקלט"
: "לא ידוע"
return NextResponse.json({
success: true,
message: `דווח עבור ${target.name}: ${statusText}`,
})
} catch (error) {
console.error("Report on behalf error:", error)
return NextResponse.json({ error: "שגיאה בדיווח" }, { status: 500 })
}
}

View File

@@ -0,0 +1,72 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
export async function POST(request: NextRequest) {
try {
const { adminId } = await request.json()
// Check cooldown
const lastReset = (await safeQuery(
'SELECT timestamp FROM admin_actions WHERE action_type = "reset_all" ORDER BY timestamp DESC LIMIT 1',
)) as any[]
if (lastReset.length > 0) {
const lastResetTime = new Date(lastReset[0].timestamp).getTime()
const now = new Date().getTime()
const cooldownMs = 2 * 60 * 1000 // 2 minutes in milliseconds
const timeSinceReset = now - lastResetTime
console.log("Reset cooldown check:", {
lastResetTime: new Date(lastResetTime).toISOString(),
now: new Date(now).toISOString(),
timeSinceReset: timeSinceReset,
cooldownMs: cooldownMs,
remainingMs: cooldownMs - timeSinceReset,
})
if (timeSinceReset < cooldownMs) {
const remainingSeconds = Math.ceil((cooldownMs - timeSinceReset) / 1000)
return NextResponse.json(
{
error: `יש להמתין ${remainingSeconds} שניות בין איפוסים`,
remainingSeconds,
cooldownMs,
},
{ status: 429 },
)
}
}
// Reset ALL users' statuses including admins, but exclude locked users
const result = await safeQuery("UPDATE users SET in_shelter = NULL, last_updated = NULL WHERE lock_status = FALSE")
// Get count of locked users that were skipped
const lockedUsers = (await safeQuery("SELECT COUNT(*) as count FROM users WHERE lock_status = TRUE")) as any[]
const lockedCount = lockedUsers[0]?.count || 0
// Log the action
await safeQuery('INSERT INTO admin_actions (admin_id, action_type) VALUES (?, "reset_all")', [adminId])
let message = "כל הסטטוסים אופסו בהצלחה"
if (lockedCount > 0) {
message += ` (${lockedCount} משתמשים נעולים לא אופסו)`
}
console.log("Reset completed:", {
affectedRows: (result as any).affectedRows,
lockedCount,
adminId,
})
return NextResponse.json({
success: true,
message,
lockedCount,
affectedRows: (result as any).affectedRows,
})
} catch (error) {
console.error("Reset error:", error)
return NextResponse.json({ error: "שגיאה באיפוס" }, { status: 500 })
}
}

View File

@@ -0,0 +1,56 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
import { hashPassword } from "@/lib/auth"
export async function POST(request: NextRequest) {
try {
const { adminId, targetUserId } = await request.json()
// Input validation
if (!adminId || !targetUserId) {
return NextResponse.json({ error: "נתונים חסרים" }, { status: 400 })
}
// Verify admin permissions
const admins = await safeQuery(
"SELECT role FROM users WHERE national_id = ?",
[adminId]
) as { role: string | null }[]
if (
admins.length === 0 ||
!admins[0].role ||
admins[0].role === "user"
) {
return NextResponse.json({ error: "אין הרשאות מנהל" }, { status: 403 })
}
// Check if target user exists
const targetUsers = (await safeQuery("SELECT national_id FROM users WHERE national_id = ?", [
targetUserId,
])) as any[]
if (targetUsers.length === 0) {
return NextResponse.json({ error: "משתמש לא נמצא" }, { status: 404 })
}
// Reset password to "password123"
const hashedPassword = await hashPassword("password123")
await safeQuery(
"UPDATE users SET password = ?, must_change_password = TRUE, password_changed_at = NULL WHERE national_id = ?",
[hashedPassword, targetUserId],
)
// Log the action
await safeQuery(
'INSERT INTO admin_actions (admin_id, action_type, target_user_id) VALUES (?, "reset_password", ?)',
[adminId, targetUserId],
)
return NextResponse.json({ success: true })
} catch (error) {
console.error("Reset password error:", error)
return NextResponse.json({ error: "שגיאה באיפוס סיסמה" }, { status: 500 })
}
}

View File

@@ -0,0 +1,21 @@
import { NextResponse } from "next/server"
import { executeQuery } from "@/lib/database"
export async function GET() {
try {
const results = (await executeQuery(`
SELECT
SUM(CASE WHEN in_shelter IS NULL THEN 1 ELSE 0 END) as no_report,
SUM(CASE WHEN in_shelter = 'yes' THEN 1 ELSE 0 END) as in_shelter,
SUM(CASE WHEN in_shelter = 'no' THEN 1 ELSE 0 END) as not_in_shelter,
SUM(CASE WHEN in_shelter = 'no_alarm' THEN 1 ELSE 0 END) as no_alarm,
SUM(CASE WHEN in_shelter = 'safe_after_exit' THEN 1 ELSE 0 END) as safe_after_exit
FROM users
`)) as any[]
return NextResponse.json(results[0])
} catch (error) {
console.error("Stats error:", error)
return NextResponse.json({ error: "שגיאה בטעינת סטטיסטיקות" }, { status: 500 })
}
}

View File

@@ -0,0 +1,66 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
import { revalidatePath } from 'next/cache' // Crucial for Next.js App Router caching
export async function POST(request: NextRequest) {
try {
const { adminId } = await request.json()
if (!adminId) {
return NextResponse.json({ error: "מזהה מנהל חסר" }, { status: 400 })
}
// Get admin's field, department, and team
const adminData = (await safeQuery(
"SELECT field, department, team FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
[adminId],
)) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const { field: adminField, department: adminDepartment, team: adminTeam } = adminData[0]
if (!adminField || !adminDepartment || !adminTeam) {
return NextResponse.json({ error: "למנהל לא הוגדרו תחום, מסגרת וצוות" }, { status: 400 })
}
await safeQuery(
"UPDATE users SET in_shelter = NULL, last_updated = NULL WHERE field = ? AND department = ? AND team = ? AND lock_status = FALSE",
[adminField, adminDepartment, adminTeam],
)
// Get count of locked users that were skipped
const lockedUsers = (await safeQuery(
"SELECT COUNT(*) as count FROM users WHERE field = ? AND department = ? AND team = ? AND lock_status = TRUE",
[adminField, adminDepartment, adminTeam],
)) as any[]
const lockedCount = lockedUsers[0]?.count || 0
// Log the action
await safeQuery(
'INSERT INTO admin_actions (admin_id, action_type, target_user_id) VALUES (?, "reset_team", NULL)',
[adminId],
)
revalidatePath('/admin')
let message = `כל הסטטוסים של צוות ${adminTeam} במסגרת ${adminDepartment} בתחום ${adminField} אופסו בהצלחה`
if (lockedCount > 0) {
message += ` (${lockedCount} משתמשים נעולים לא אופסו)`
}
return NextResponse.json({
success: true,
field: adminField,
department: adminDepartment,
team: adminTeam,
message,
lockedCount,
}, { status: 200 })
} catch (error) {
console.error("Team reset error:", error)
return NextResponse.json({ error: "שגיאה באיפוס הצוות" }, { status: 500 })
}
}

View File

@@ -0,0 +1,53 @@
import { NextResponse } from "next/server"
import { executeQuery } from "@/lib/database"
export async function POST(request: Request) {
try {
const { adminId } = await request.json()
if (!adminId) {
return NextResponse.json({ error: "מזהה מנהל חסר" }, { status: 400 })
}
// Get admin's field, department, and team
const adminData = (await executeQuery(
"SELECT field, department, team FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
[adminId],
)) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const { field: adminField, department: adminDepartment, team: adminTeam } = adminData[0]
if (!adminField || !adminDepartment || !adminTeam) {
return NextResponse.json({ error: "למנהל לא הוגדרו תחום, מסגרת וצוות" }, { status: 400 })
}
// Get team stats with full context (field + department + team)
const results = (await executeQuery(
`
SELECT
SUM(CASE WHEN in_shelter IS NULL THEN 1 ELSE 0 END) as no_report,
SUM(CASE WHEN in_shelter = 'yes' THEN 1 ELSE 0 END) as in_shelter,
SUM(CASE WHEN in_shelter = 'no' THEN 1 ELSE 0 END) as not_in_shelter,
SUM(CASE WHEN in_shelter = 'no_alarm' THEN 1 ELSE 0 END) as no_alarm,
SUM(CASE WHEN in_shelter = 'safe_after_exit' THEN 1 ELSE 0 END) as safe_after_exit
FROM users
WHERE field = ? AND department = ? AND team = ?
`,
[adminField, adminDepartment, adminTeam],
)) as any[]
return NextResponse.json({
...results[0],
field: adminField,
department: adminDepartment,
team: adminTeam,
})
} catch (error) {
console.error("Team stats error:", error)
return NextResponse.json({ error: "שגיאה בטעינת סטטיסטיקות הצוות" }, { status: 500 })
}
}

View File

@@ -0,0 +1,62 @@
import { type NextRequest, NextResponse } from "next/server"
import { executeQuery } from "@/lib/database"
export async function POST(request: NextRequest) {
try {
const { adminId, category } = await request.json()
if (!adminId || !category) {
return NextResponse.json({ error: "נתונים חסרים" }, { status: 400 })
}
// Get admin's field, department, and team
const adminData = (await executeQuery(
"SELECT field, department, team FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
[adminId],
)) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const { field: adminField, department: adminDepartment, team: adminTeam } = adminData[0]
if (!adminField || !adminDepartment || !adminTeam) {
return NextResponse.json({ error: "למנהל לא הוגדרו תחום, מסגרת וצוות" }, { status: 400 })
}
let query = ""
const params: any[] = [adminField, adminDepartment, adminTeam]
switch (category) {
case "no_report":
query =
"SELECT national_id, name FROM users WHERE field = ? AND department = ? AND team = ? AND in_shelter IS NULL ORDER BY name"
break
case "in_shelter":
query =
"SELECT national_id, name FROM users WHERE field = ? AND department = ? AND team = ? AND in_shelter = 'yes' ORDER BY name"
break
case "not_in_shelter":
query =
"SELECT national_id, name FROM users WHERE field = ? AND department = ? AND team = ? AND in_shelter = 'no' ORDER BY name"
break
case "no_alarm":
query =
"SELECT national_id, name FROM users WHERE field = ? AND department = ? AND team = ? AND in_shelter = 'no_alarm' ORDER BY name"
break
case "safe_after_exit":
query =
"SELECT national_id, name FROM users WHERE field = ? AND department = ? AND team = ? AND in_shelter = 'safe_after_exit' ORDER BY name"
break
default:
return NextResponse.json({ error: "קטגוריה לא תקינה" }, { status: 400 })
}
const users = (await executeQuery(query, params)) as any[]
return NextResponse.json(users)
} catch (error) {
console.error("Get team users by category error:", error)
return NextResponse.json({ error: "שגיאה בטעינת משתמשי הצוות" }, { status: 500 })
}
}

View File

@@ -0,0 +1,58 @@
import { NextResponse } from "next/server"
import { executeQuery } from "@/lib/database"
export async function POST(request: Request) {
try {
const { adminId } = await request.json()
if (!adminId) {
return NextResponse.json({ error: "מזהה מנהל חסר" }, { status: 400 })
}
// Get admin's field, department, and team
const adminData = (await executeQuery("SELECT field, department, team FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'", [
adminId,
])) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const { field: adminField, department: adminDepartment, team: adminTeam } = adminData[0]
if (!adminField || !adminDepartment || !adminTeam) {
return NextResponse.json({ error: "למנהל לא הוגדרו תחום, מסגרת וצוות" }, { status: 400 })
}
// Get team users with full context (field + department + team)
const users = (await executeQuery(
`
SELECT
national_id,
name,
in_shelter,
last_updated,
is_admin,
must_change_password,
field,
department,
team,
lock_status
FROM users
WHERE field = ? AND department = ? AND team = ?
ORDER BY name
`,
[adminField, adminDepartment, adminTeam],
)) as any[]
return NextResponse.json({
users,
field: adminField,
department: adminDepartment,
team: adminTeam,
})
} catch (error) {
console.error("Team users error:", error)
return NextResponse.json({ error: "שגיאה בטעינת משתמשי הצוות" }, { status: 500 })
}
}

View File

@@ -0,0 +1,74 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
export async function POST(request: NextRequest) {
try {
const { adminId, targetUserId, lockStatus } = await request.json()
if (!adminId || !targetUserId || typeof lockStatus !== "boolean") {
return NextResponse.json({ error: "נתונים חסרים" }, { status: 400 })
}
// Get admin data
const adminData = (await safeQuery("SELECT role, field, department, team FROM users WHERE national_id = ?", [
adminId,
])) as any[]
if (adminData.length === 0) {
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
}
const admin = adminData[0]
// Get target user data
const targetData = (await safeQuery(
"SELECT field, department, team, name, lock_status FROM users WHERE national_id = ?",
[targetUserId],
)) as any[]
if (targetData.length === 0) {
return NextResponse.json({ error: "משתמש לא נמצא" }, { status: 404 })
}
const target = targetData[0]
// Check if admin can manage this user based on hierarchy
let canManage = false
if (admin.role === "global_admin") {
canManage = true
} else if (admin.role === "field_admin" && admin.field === target.field) {
canManage = true
} else if (admin.role === "department_admin" && admin.department === target.department) {
canManage = true
} else if (admin.role === "team_admin" && admin.team === target.team) {
canManage = true
}
if (!canManage) {
return NextResponse.json({ error: "אין הרשאה לנעול/לבטל נעילה של משתמש זה" }, { status: 403 })
}
// Update user lock status
await safeQuery("UPDATE users SET lock_status = ? WHERE national_id = ?", [lockStatus, targetUserId])
// Log the action
const actionType = lockStatus ? "lock_user" : "unlock_user"
await safeQuery("INSERT INTO admin_actions (admin_id, action_type, target_user_id) VALUES (?, ?, ?)", [
adminId,
actionType,
targetUserId,
])
const statusText = lockStatus ? "נעול" : "לא נעול"
return NextResponse.json({
success: true,
message: `סטטוס נעילה של ${target.name} שונה ל: ${statusText}`,
lockStatus,
})
} catch (error) {
console.error("Toggle user lock error:", error)
return NextResponse.json({ error: "שגיאה בשינוי סטטוס נעילה" }, { status: 500 })
}
}

View File

@@ -0,0 +1,45 @@
import { type NextRequest, NextResponse } from "next/server";
import { executeQuery } from "@/lib/database";
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const category = searchParams.get("category");
let query = "";
// No params needed for these queries, as there are no WHERE conditions
// that use parameters other than the in_shelter status itself.
let params: any[] = [];
switch (category) {
case "no_report":
// Added 'department', 'team', 'field' to SELECT clause
query = "SELECT national_id, name, department, team, field FROM users WHERE in_shelter IS NULL ORDER BY name";
break;
case "in_shelter":
// Added 'department', 'team', 'field' to SELECT clause
query = "SELECT national_id, name, department, team, field FROM users WHERE in_shelter = 'yes' ORDER BY name";
break;
case "not_in_shelter":
// Added 'department', 'team', 'field' to SELECT clause
query = "SELECT national_id, name, department, team, field FROM users WHERE in_shelter = 'no' ORDER BY name";
break;
case "no_alarm":
// Added 'department', 'team', 'field' to SELECT clause
query = "SELECT national_id, name, department, team, field FROM users WHERE in_shelter = 'no_alarm' ORDER BY name";
break;
case "safe_after_exit":
// Added 'department', 'team', 'field' to SELECT clause
query = "SELECT national_id, name, department, team, field FROM users WHERE in_shelter = 'safe_after_exit' ORDER BY name";
break;
default:
return NextResponse.json({ error: "קטגוריה לא תקינה" }, { status: 400 });
}
const users = (await executeQuery(query, params)) as any[];
return NextResponse.json(users);
} catch (error) {
console.error("Get users by category error:", error);
return NextResponse.json({ error: "שגיאה בטעינת משתמשים" }, { status: 500 });
}
}

View File

@@ -0,0 +1,27 @@
import { type NextRequest, NextResponse } from "next/server"
import { executeQuery } from "@/lib/database"
export async function DELETE(request: NextRequest, { params }: { params: { id: string } }) {
try {
const nationalId = params.id
// Check if user exists
const users = (await executeQuery("SELECT national_id FROM users WHERE national_id = ?", [nationalId])) as any[]
if (users.length === 0) {
return NextResponse.json({ error: "משתמש לא נמצא" }, { status: 404 })
}
// Delete user
await executeQuery(
"DELETE FROM admin_actions WHERE admin_id = ? OR target_user_id = ?",
[nationalId, nationalId]
);
await executeQuery("DELETE FROM users WHERE national_id = ?", [nationalId])
return NextResponse.json({ success: true })
} catch (error) {
console.error("Delete user error:", error)
return NextResponse.json({ error: "שגיאה במחיקת משתמש" }, { status: 500 })
}
}

View File

@@ -0,0 +1,27 @@
import { NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
export async function GET() {
try {
const users = (await safeQuery(`
SELECT
national_id,
name,
in_shelter,
last_updated,
is_admin,
must_change_password,
field,
department,
team,
lock_status
FROM users
ORDER BY field, department, team, name
`)) as any[]
return NextResponse.json(users)
} catch (error) {
console.error("Get users error:", error)
return NextResponse.json({ error: "שגיאה בטעינת משתמשים" }, { status: 500 })
}
}

View File

@@ -0,0 +1,45 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
import { verifyPassword, hashPassword } from "@/lib/auth"
export async function POST(request: NextRequest) {
try {
const { nationalId, currentPassword, newPassword } = await request.json()
// Input validation
if (!nationalId || !currentPassword || !newPassword) {
return NextResponse.json({ error: "נתונים חסרים" }, { status: 400 })
}
if (newPassword.length < 6) {
return NextResponse.json({ error: "הסיסמה החדשה חייבת להכיל לפחות 6 תווים" }, { status: 400 })
}
// Get current user data
const users = (await safeQuery("SELECT password FROM users WHERE national_id = ?", [nationalId])) as any[]
if (users.length === 0) {
return NextResponse.json({ error: "משתמש לא נמצא" }, { status: 404 })
}
const user = users[0]
const isValidCurrentPassword = await verifyPassword(currentPassword, user.password)
if (!isValidCurrentPassword) {
return NextResponse.json({ error: "הסיסמה הנוכחית שגויה" }, { status: 401 })
}
// Hash new password and update
const hashedNewPassword = await hashPassword(newPassword)
await safeQuery(
"UPDATE users SET password = ?, must_change_password = FALSE, password_changed_at = NOW() WHERE national_id = ?",
[hashedNewPassword, nationalId],
)
return NextResponse.json({ success: true })
} catch (error) {
console.error("Change password error:", error)
return NextResponse.json({ error: "שגיאה בשינוי סיסמה" }, { status: 500 })
}
}

View File

@@ -0,0 +1,53 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
import { validateIsraeliID, verifyPassword } from "@/lib/auth"
export async function POST(request: NextRequest) {
try {
const { nationalId, password } = await request.json()
// Input validation
if (!nationalId || !password) {
return NextResponse.json({ error: "נתונים חסרים" }, { status: 400 })
}
if (!validateIsraeliID(nationalId)) {
return NextResponse.json({ error: "מספר תעודת זהות לא תקין" }, { status: 400 })
}
// Use parameterized query to prevent SQL injection
const users = (await safeQuery(
"SELECT national_id, password, name, is_admin, role, field, department, team, in_shelter, last_updated, must_change_password FROM users WHERE national_id = ?",
[nationalId],
)) as any[]
if (users.length === 0) {
return NextResponse.json({ error: "משתמש לא נמצא" }, { status: 401 })
}
const user = users[0]
const isValidPassword = await verifyPassword(password, user.password)
if (!isValidPassword) {
return NextResponse.json({ error: "סיסמה שגויה" }, { status: 401 })
}
return NextResponse.json({
user: {
national_id: user.national_id,
name: user.name,
is_admin: user.is_admin,
role: user.role,
field: user.field,
department: user.department,
team: user.team,
in_shelter: user.in_shelter,
last_updated: user.last_updated,
must_change_password: user.must_change_password,
},
})
} catch (error) {
console.error("Login error:", error)
return NextResponse.json({ error: "שגיאה בשרת" }, { status: 500 })
}
}

View File

@@ -0,0 +1,28 @@
import { type NextRequest, NextResponse } from "next/server"
import { safeQuery } from "@/lib/database"
import { broadcastUpdate } from "@/lib/websocket"
export async function POST(request: NextRequest) {
try {
const { nationalId, status } = await request.json()
if (!["yes", "no", "no_alarm", "safe_after_exit"].includes(status)) {
return NextResponse.json({ error: "סטטוס לא תקין" }, { status: 400 })
}
await safeQuery("UPDATE users SET in_shelter = ?, last_updated = NOW() WHERE national_id = ?", [status, nationalId])
// Broadcast the update to all connected admins
broadcastUpdate({
type: "status_change",
user_id: nationalId,
status: status,
timestamp: new Date().toISOString(),
})
return NextResponse.json({ success: true })
} catch (error) {
console.error("Status update error:", error)
return NextResponse.json({ error: "שגיאה בעדכון סטטוס" }, { status: 500 })
}
}

45
app/api/test-db/route.ts Normal file
View File

@@ -0,0 +1,45 @@
import { NextResponse } from "next/server"
import { testConnection, executeQuery, getPoolStats, healthCheck } from "@/lib/database"
export async function GET() {
try {
// Test basic connection
const connectionTest = await testConnection()
if (!connectionTest) {
return NextResponse.json(
{
error: "Database connection failed",
details: "Could not connect to MySQL database",
},
{ status: 500 },
)
}
// Test query execution with automatic connection management
const result = await executeQuery("SELECT COUNT(*) as user_count FROM users")
// Get pool statistics
const poolStats = getPoolStats()
// Get comprehensive health check
const health = await healthCheck()
return NextResponse.json({
success: true,
message: "Database connection successful",
userCount: (result as any)[0].user_count,
poolStats,
health,
timestamp: new Date().toISOString(),
})
} catch (error) {
console.error("Database test error:", error)
return NextResponse.json(
{
error: "Database test failed",
details: error instanceof Error ? error.message : "Unknown error",
},
{ status: 500 },
)
}
}

View File

@@ -0,0 +1,6 @@
import type { NextRequest } from "next/server"
export async function GET(request: NextRequest) {
// This will be handled by the custom server
return new Response("WebSocket endpoint", { status: 200 })
}