mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 08:32:09 +01:00
feat: comprehensive Biome linting fixes and code quality improvements
Major code quality overhaul addressing 58% of all linting issues: • Type Safety Improvements: - Replace all any types with proper TypeScript interfaces - Fix Map component shadowing (renamed to CountryMap) - Add comprehensive custom error classes system - Enhance API route type safety • Accessibility Enhancements: - Add explicit button types to all interactive elements - Implement useId() hooks for form element accessibility - Add SVG title attributes for screen readers - Fix static element interactions with keyboard handlers • React Best Practices: - Resolve exhaustive dependencies warnings with useCallback - Extract nested component definitions to top level - Fix array index keys with proper unique identifiers - Improve component organization and prop typing • Code Organization: - Automatic import organization and type import optimization - Fix unused function parameters and variables - Enhanced error handling with structured error responses - Improve component reusability and maintainability Results: 248 → 104 total issues (58% reduction) - Fixed all critical type safety and security issues - Enhanced accessibility compliance significantly - Improved code maintainability and performance
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { fetchAndParseCsv } from "../../../../lib/csvFetcher";
|
||||
import { processQueuedImports } from "../../../../lib/importProcessor";
|
||||
import { prisma } from "../../../../lib/prisma";
|
||||
@ -47,10 +47,10 @@ export async function POST(request: NextRequest) {
|
||||
// Check if company is active and can process data
|
||||
if (company.status !== "ACTIVE") {
|
||||
return NextResponse.json(
|
||||
{
|
||||
{
|
||||
error: `Data processing is disabled for ${company.status.toLowerCase()} companies`,
|
||||
companyStatus: company.status
|
||||
},
|
||||
companyStatus: company.status,
|
||||
},
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { ProcessingStage } from "@prisma/client";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "../../../../lib/auth";
|
||||
import { prisma } from "../../../../lib/prisma";
|
||||
import { processUnprocessedSessions } from "../../../../lib/processingScheduler";
|
||||
import { ProcessingStatusManager } from "../../../../lib/processingStatusManager";
|
||||
import { ProcessingStage } from "@prisma/client";
|
||||
|
||||
interface SessionUser {
|
||||
email: string;
|
||||
@ -34,7 +34,7 @@ export async function POST(request: NextRequest) {
|
||||
id: true,
|
||||
name: true,
|
||||
status: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -86,7 +86,7 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
|
||||
// Start processing (this will run asynchronously)
|
||||
const startTime = Date.now();
|
||||
const _startTime = Date.now();
|
||||
|
||||
// Note: We're calling the function but not awaiting it to avoid timeout
|
||||
// The processing will continue in the background
|
||||
|
||||
@ -3,4 +3,4 @@ import { authOptions } from "../../../../lib/auth";
|
||||
|
||||
const handler = NextAuth(authOptions);
|
||||
|
||||
export { handler as GET, handler as POST };
|
||||
export { handler as GET, handler as POST };
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { prisma } from "../../../../lib/prisma";
|
||||
import { authOptions } from "../../../../lib/auth";
|
||||
import { prisma } from "../../../../lib/prisma";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
export async function GET(_request: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: "Not logged in" }, { status: 401 });
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { prisma } from "../../../../lib/prisma";
|
||||
import { sessionMetrics } from "../../../../lib/metrics";
|
||||
import { authOptions } from "../../../../lib/auth";
|
||||
import { ChatSession } from "../../../../lib/types";
|
||||
import { sessionMetrics } from "../../../../lib/metrics";
|
||||
import { prisma } from "../../../../lib/prisma";
|
||||
import type { ChatSession } from "../../../../lib/types";
|
||||
|
||||
interface SessionUser {
|
||||
email: string;
|
||||
@ -31,7 +31,7 @@ export async function GET(request: NextRequest) {
|
||||
name: true,
|
||||
csvUrl: true,
|
||||
status: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -46,14 +46,20 @@ export async function GET(request: NextRequest) {
|
||||
const endDate = searchParams.get("endDate");
|
||||
|
||||
// Build where clause with optional date filtering
|
||||
const whereClause: any = {
|
||||
const whereClause: {
|
||||
companyId: string;
|
||||
startTime?: {
|
||||
gte: Date;
|
||||
lte: Date;
|
||||
};
|
||||
} = {
|
||||
companyId: user.companyId,
|
||||
};
|
||||
|
||||
if (startDate && endDate) {
|
||||
whereClause.startTime = {
|
||||
gte: new Date(startDate),
|
||||
lte: new Date(endDate + "T23:59:59.999Z"), // Include full end date
|
||||
lte: new Date(`${endDate}T23:59:59.999Z`), // Include full end date
|
||||
};
|
||||
}
|
||||
|
||||
@ -82,25 +88,28 @@ export async function GET(request: NextRequest) {
|
||||
});
|
||||
|
||||
// Batch fetch questions for all sessions at once if needed for metrics
|
||||
const sessionIds = prismaSessions.map(s => s.id);
|
||||
const sessionIds = prismaSessions.map((s) => s.id);
|
||||
const sessionQuestions = await prisma.sessionQuestion.findMany({
|
||||
where: { sessionId: { in: sessionIds } },
|
||||
include: { question: true },
|
||||
orderBy: { order: 'asc' },
|
||||
orderBy: { order: "asc" },
|
||||
});
|
||||
|
||||
// Group questions by session
|
||||
const questionsBySession = sessionQuestions.reduce((acc, sq) => {
|
||||
if (!acc[sq.sessionId]) acc[sq.sessionId] = [];
|
||||
acc[sq.sessionId].push(sq.question.content);
|
||||
return acc;
|
||||
}, {} as Record<string, string[]>);
|
||||
const questionsBySession = sessionQuestions.reduce(
|
||||
(acc, sq) => {
|
||||
if (!acc[sq.sessionId]) acc[sq.sessionId] = [];
|
||||
acc[sq.sessionId].push(sq.question.content);
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, string[]>
|
||||
);
|
||||
|
||||
// Convert Prisma sessions to ChatSession[] type for sessionMetrics
|
||||
const chatSessions: ChatSession[] = prismaSessions.map((ps) => {
|
||||
// Get questions for this session or empty array
|
||||
const questions = questionsBySession[ps.id] || [];
|
||||
|
||||
|
||||
// Convert questions to mock messages for backward compatibility
|
||||
const mockMessages = questions.map((q, index) => ({
|
||||
id: `question-${index}`,
|
||||
@ -127,7 +136,8 @@ export async function GET(request: NextRequest) {
|
||||
ipAddress: ps.ipAddress || undefined,
|
||||
sentiment: ps.sentiment === null ? undefined : ps.sentiment,
|
||||
messagesSent: ps.messagesSent === null ? undefined : ps.messagesSent,
|
||||
avgResponseTime: ps.avgResponseTime === null ? undefined : ps.avgResponseTime,
|
||||
avgResponseTime:
|
||||
ps.avgResponseTime === null ? undefined : ps.avgResponseTime,
|
||||
escalated: ps.escalated || false,
|
||||
forwardedHr: ps.forwardedHr || false,
|
||||
initialMsg: ps.initialMsg || undefined,
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { getServerSession } from "next-auth/next";
|
||||
import { authOptions } from "../../../../lib/auth";
|
||||
import { prisma } from "../../../../lib/prisma";
|
||||
import { SessionFilterOptions } from "../../../../lib/types";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
export async function GET(_request: NextRequest) {
|
||||
const authSession = await getServerSession(authOptions);
|
||||
|
||||
if (!authSession || !authSession.user?.companyId) {
|
||||
@ -17,23 +16,23 @@ export async function GET(request: NextRequest) {
|
||||
// Use groupBy for better performance with distinct values
|
||||
const [categoryGroups, languageGroups] = await Promise.all([
|
||||
prisma.session.groupBy({
|
||||
by: ['category'],
|
||||
by: ["category"],
|
||||
where: {
|
||||
companyId,
|
||||
category: { not: null },
|
||||
},
|
||||
orderBy: {
|
||||
category: 'asc',
|
||||
category: "asc",
|
||||
},
|
||||
}),
|
||||
prisma.session.groupBy({
|
||||
by: ['language'],
|
||||
by: ["language"],
|
||||
where: {
|
||||
companyId,
|
||||
language: { not: null },
|
||||
},
|
||||
orderBy: {
|
||||
language: 'asc',
|
||||
language: "asc",
|
||||
},
|
||||
}),
|
||||
]);
|
||||
@ -41,7 +40,7 @@ export async function GET(request: NextRequest) {
|
||||
const distinctCategories = categoryGroups
|
||||
.map((g) => g.category)
|
||||
.filter(Boolean) as string[];
|
||||
|
||||
|
||||
const distinctLanguages = languageGroups
|
||||
.map((g) => g.language)
|
||||
.filter(Boolean) as string[];
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "../../../../../lib/prisma";
|
||||
import { ChatSession } from "../../../../../lib/types";
|
||||
import type { ChatSession } from "../../../../../lib/types";
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
_request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const { id } = await params;
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import type { Prisma } from "@prisma/client";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { getServerSession } from "next-auth/next";
|
||||
import { authOptions } from "../../../../lib/auth";
|
||||
import { prisma } from "../../../../lib/prisma";
|
||||
import {
|
||||
ChatSession,
|
||||
SessionApiResponse,
|
||||
SessionQuery,
|
||||
} from "../../../../lib/types";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import type { ChatSession } from "../../../../lib/types";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const authSession = await getServerSession(authOptions);
|
||||
@ -48,7 +44,7 @@ export async function GET(request: NextRequest) {
|
||||
// Category Filter
|
||||
if (category && category.trim() !== "") {
|
||||
// Cast to SessionCategory enum if it's a valid value
|
||||
whereClause.category = category as any;
|
||||
whereClause.category = category;
|
||||
}
|
||||
|
||||
// Language Filter
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import crypto from "crypto";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { prisma } from "../../../../lib/prisma";
|
||||
import crypto from "node:crypto";
|
||||
import bcrypt from "bcryptjs";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "../../../../lib/auth";
|
||||
import { prisma } from "../../../../lib/prisma";
|
||||
|
||||
interface UserBasicInfo {
|
||||
id: string;
|
||||
@ -11,7 +11,7 @@ interface UserBasicInfo {
|
||||
role: string;
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
export async function GET(_request: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user || session.user.role !== "ADMIN") {
|
||||
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import crypto from "node:crypto";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "../../../lib/prisma";
|
||||
import { sendEmail } from "../../../lib/sendEmail";
|
||||
import { forgotPasswordSchema, validateInput } from "../../../lib/validation";
|
||||
import crypto from "crypto";
|
||||
|
||||
// In-memory rate limiting for password reset requests
|
||||
const resetAttempts = new Map<string, { count: number; resetTime: number }>();
|
||||
@ -28,7 +28,10 @@ function checkRateLimit(ip: string): boolean {
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
// Rate limiting check
|
||||
const ip = request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || "unknown";
|
||||
const ip =
|
||||
request.headers.get("x-forwarded-for") ||
|
||||
request.headers.get("x-real-ip") ||
|
||||
"unknown";
|
||||
if (!checkRateLimit(ip)) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
|
||||
@ -3,4 +3,4 @@ import { platformAuthOptions } from "../../../../../lib/platform-auth";
|
||||
|
||||
const handler = NextAuth(platformAuthOptions);
|
||||
|
||||
export { handler as GET, handler as POST };
|
||||
export { handler as GET, handler as POST };
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { CompanyStatus } from "@prisma/client";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { platformAuthOptions } from "../../../../../lib/platform-auth";
|
||||
import { prisma } from "../../../../../lib/prisma";
|
||||
import { CompanyStatus } from "@prisma/client";
|
||||
|
||||
interface PlatformSession {
|
||||
user: {
|
||||
@ -16,14 +16,19 @@ interface PlatformSession {
|
||||
|
||||
// GET /api/platform/companies/[id] - Get company details
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
_request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await getServerSession(platformAuthOptions) as PlatformSession | null;
|
||||
const session = (await getServerSession(
|
||||
platformAuthOptions
|
||||
)) as PlatformSession | null;
|
||||
|
||||
if (!session?.user?.isPlatformUser) {
|
||||
return NextResponse.json({ error: "Platform access required" }, { status: 401 });
|
||||
return NextResponse.json(
|
||||
{ error: "Platform access required" },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
@ -59,7 +64,10 @@ export async function GET(
|
||||
return NextResponse.json(company);
|
||||
} catch (error) {
|
||||
console.error("Platform company details error:", error);
|
||||
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
||||
return NextResponse.json(
|
||||
{ error: "Internal server error" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,15 +79,30 @@ export async function PATCH(
|
||||
try {
|
||||
const session = await getServerSession(platformAuthOptions);
|
||||
|
||||
if (!session?.user?.isPlatformUser || session.user.platformRole === "SUPPORT") {
|
||||
return NextResponse.json({ error: "Admin access required" }, { status: 403 });
|
||||
if (
|
||||
!session?.user?.isPlatformUser ||
|
||||
session.user.platformRole === "SUPPORT"
|
||||
) {
|
||||
return NextResponse.json(
|
||||
{ error: "Admin access required" },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
const body = await request.json();
|
||||
const { name, email, maxUsers, csvUrl, csvUsername, csvPassword, status } = body;
|
||||
const { name, email, maxUsers, csvUrl, csvUsername, csvPassword, status } =
|
||||
body;
|
||||
|
||||
const updateData: any = {};
|
||||
const updateData: {
|
||||
name?: string;
|
||||
email?: string;
|
||||
maxUsers?: number;
|
||||
csvUrl?: string;
|
||||
csvUsername?: string;
|
||||
csvPassword?: string;
|
||||
status?: CompanyStatus;
|
||||
} = {};
|
||||
if (name !== undefined) updateData.name = name;
|
||||
if (email !== undefined) updateData.email = email;
|
||||
if (maxUsers !== undefined) updateData.maxUsers = maxUsers;
|
||||
@ -96,20 +119,29 @@ export async function PATCH(
|
||||
return NextResponse.json({ company });
|
||||
} catch (error) {
|
||||
console.error("Platform company update error:", error);
|
||||
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
||||
return NextResponse.json(
|
||||
{ error: "Internal server error" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE /api/platform/companies/[id] - Delete company (archives instead)
|
||||
export async function DELETE(
|
||||
request: NextRequest,
|
||||
_request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await getServerSession(platformAuthOptions);
|
||||
|
||||
if (!session?.user?.isPlatformUser || session.user.platformRole !== "SUPER_ADMIN") {
|
||||
return NextResponse.json({ error: "Super admin access required" }, { status: 403 });
|
||||
if (
|
||||
!session?.user?.isPlatformUser ||
|
||||
session.user.platformRole !== "SUPER_ADMIN"
|
||||
) {
|
||||
return NextResponse.json(
|
||||
{ error: "Super admin access required" },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
@ -123,6 +155,9 @@ export async function DELETE(
|
||||
return NextResponse.json({ company });
|
||||
} catch (error) {
|
||||
console.error("Platform company archive error:", error);
|
||||
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
||||
return NextResponse.json(
|
||||
{ error: "Internal server error" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { hash } from "bcryptjs";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { platformAuthOptions } from "../../../../../../lib/platform-auth";
|
||||
import { prisma } from "../../../../../../lib/prisma";
|
||||
import { hash } from "bcryptjs";
|
||||
|
||||
// POST /api/platform/companies/[id]/users - Invite user to company
|
||||
export async function POST(
|
||||
@ -12,8 +12,14 @@ export async function POST(
|
||||
try {
|
||||
const session = await getServerSession(platformAuthOptions);
|
||||
|
||||
if (!session?.user?.isPlatformUser || session.user.platformRole === "SUPPORT") {
|
||||
return NextResponse.json({ error: "Admin access required" }, { status: 403 });
|
||||
if (
|
||||
!session?.user?.isPlatformUser ||
|
||||
session.user.platformRole === "SUPPORT"
|
||||
) {
|
||||
return NextResponse.json(
|
||||
{ error: "Admin access required" },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const { id: companyId } = await params;
|
||||
@ -21,7 +27,10 @@ export async function POST(
|
||||
const { name, email, role = "USER" } = body;
|
||||
|
||||
if (!name || !email) {
|
||||
return NextResponse.json({ error: "Name and email are required" }, { status: 400 });
|
||||
return NextResponse.json(
|
||||
{ error: "Name and email are required" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Check if company exists
|
||||
@ -88,24 +97,31 @@ export async function POST(
|
||||
return NextResponse.json({
|
||||
user,
|
||||
tempPassword, // Remove this in production and send via email
|
||||
message: "User invited successfully. In production, credentials would be sent via email.",
|
||||
message:
|
||||
"User invited successfully. In production, credentials would be sent via email.",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Platform user invitation error:", error);
|
||||
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
||||
return NextResponse.json(
|
||||
{ error: "Internal server error" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/platform/companies/[id]/users - Get company users
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
_request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await getServerSession(platformAuthOptions);
|
||||
|
||||
if (!session?.user?.isPlatformUser) {
|
||||
return NextResponse.json({ error: "Platform access required" }, { status: 401 });
|
||||
return NextResponse.json(
|
||||
{ error: "Platform access required" },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const { id: companyId } = await params;
|
||||
@ -127,6 +143,9 @@ export async function GET(
|
||||
return NextResponse.json({ users });
|
||||
} catch (error) {
|
||||
console.error("Platform users list error:", error);
|
||||
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
||||
return NextResponse.json(
|
||||
{ error: "Internal server error" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import type { CompanyStatus } from "@prisma/client";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { platformAuthOptions } from "../../../../lib/platform-auth";
|
||||
import { prisma } from "../../../../lib/prisma";
|
||||
import { CompanyStatus } from "@prisma/client";
|
||||
|
||||
// GET /api/platform/companies - List all companies
|
||||
export async function GET(request: NextRequest) {
|
||||
@ -10,7 +10,10 @@ export async function GET(request: NextRequest) {
|
||||
const session = await getServerSession(platformAuthOptions);
|
||||
|
||||
if (!session?.user?.isPlatformUser) {
|
||||
return NextResponse.json({ error: "Platform access required" }, { status: 401 });
|
||||
return NextResponse.json(
|
||||
{ error: "Platform access required" },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
@ -20,7 +23,13 @@ export async function GET(request: NextRequest) {
|
||||
const limit = parseInt(searchParams.get("limit") || "20");
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
const where: any = {};
|
||||
const where: {
|
||||
status?: CompanyStatus;
|
||||
name?: {
|
||||
contains: string;
|
||||
mode: "insensitive";
|
||||
};
|
||||
} = {};
|
||||
if (status) where.status = status;
|
||||
if (search) {
|
||||
where.name = {
|
||||
@ -65,7 +74,10 @@ export async function GET(request: NextRequest) {
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Platform companies list error:", error);
|
||||
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
||||
return NextResponse.json(
|
||||
{ error: "Internal server error" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,33 +86,46 @@ export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const session = await getServerSession(platformAuthOptions);
|
||||
|
||||
if (!session?.user?.isPlatformUser || session.user.platformRole === "SUPPORT") {
|
||||
return NextResponse.json({ error: "Admin access required" }, { status: 403 });
|
||||
if (
|
||||
!session?.user?.isPlatformUser ||
|
||||
session.user.platformRole === "SUPPORT"
|
||||
) {
|
||||
return NextResponse.json(
|
||||
{ error: "Admin access required" },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const {
|
||||
name,
|
||||
csvUrl,
|
||||
csvUsername,
|
||||
csvPassword,
|
||||
const {
|
||||
name,
|
||||
csvUrl,
|
||||
csvUsername,
|
||||
csvPassword,
|
||||
adminEmail,
|
||||
adminName,
|
||||
adminPassword,
|
||||
maxUsers = 10,
|
||||
status = "TRIAL"
|
||||
status = "TRIAL",
|
||||
} = body;
|
||||
|
||||
if (!name || !csvUrl) {
|
||||
return NextResponse.json({ error: "Name and CSV URL required" }, { status: 400 });
|
||||
return NextResponse.json(
|
||||
{ error: "Name and CSV URL required" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (!adminEmail || !adminName) {
|
||||
return NextResponse.json({ error: "Admin email and name required" }, { status: 400 });
|
||||
return NextResponse.json(
|
||||
{ error: "Admin email and name required" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Generate password if not provided
|
||||
const finalAdminPassword = adminPassword || `Temp${Math.random().toString(36).slice(2, 8)}!`;
|
||||
const finalAdminPassword =
|
||||
adminPassword || `Temp${Math.random().toString(36).slice(2, 8)}!`;
|
||||
|
||||
// Hash the admin password
|
||||
const bcrypt = await import("bcryptjs");
|
||||
@ -133,20 +158,30 @@ export async function POST(request: NextRequest) {
|
||||
},
|
||||
});
|
||||
|
||||
return { company, adminUser, generatedPassword: adminPassword ? null : finalAdminPassword };
|
||||
return {
|
||||
company,
|
||||
adminUser,
|
||||
generatedPassword: adminPassword ? null : finalAdminPassword,
|
||||
};
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
company: result.company,
|
||||
adminUser: {
|
||||
email: result.adminUser.email,
|
||||
name: result.adminUser.name,
|
||||
role: result.adminUser.role,
|
||||
return NextResponse.json(
|
||||
{
|
||||
company: result.company,
|
||||
adminUser: {
|
||||
email: result.adminUser.email,
|
||||
name: result.adminUser.name,
|
||||
role: result.adminUser.role,
|
||||
},
|
||||
generatedPassword: result.generatedPassword,
|
||||
},
|
||||
generatedPassword: result.generatedPassword,
|
||||
}, { status: 201 });
|
||||
{ status: 201 }
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Platform company creation error:", error);
|
||||
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
||||
return NextResponse.json(
|
||||
{ error: "Internal server error" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import bcrypt from "bcryptjs";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "../../../lib/prisma";
|
||||
import { registerSchema, validateInput } from "../../../lib/validation";
|
||||
import bcrypt from "bcryptjs";
|
||||
|
||||
// In-memory rate limiting (for production, use Redis or similar)
|
||||
const registrationAttempts = new Map<
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import crypto from "node:crypto";
|
||||
import bcrypt from "bcryptjs";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "../../../lib/prisma";
|
||||
import { resetPasswordSchema, validateInput } from "../../../lib/validation";
|
||||
import bcrypt from "bcryptjs";
|
||||
import crypto from "crypto";
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user