first commit

This commit is contained in:
2025-11-24 16:30:37 +00:00
commit 843e93a274
114 changed files with 25585 additions and 0 deletions

View File

@@ -0,0 +1,149 @@
import { NextResponse } from 'next/server';
import { auth } from '@/lib/auth';
import { settingsDb } from '@/lib/settings-db';
import { emailService } from '@/lib/email-service';
import { SMTPConfig, SMTPConfigResponse } from '@/lib/types/smtp';
/**
* GET /api/admin/settings/smtp
* Returns current SMTP configuration (password masked)
*/
export async function GET() {
try {
const session = await auth();
if (!session?.user || (session.user as any).role !== 'ADMIN') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const dbConfig = settingsDb.getSMTPConfig();
let response: SMTPConfigResponse;
if (dbConfig) {
// Mask password
const maskedConfig = {
...dbConfig,
auth: {
...dbConfig.auth,
pass: '***',
},
};
response = { config: maskedConfig, source: 'database' };
} else {
// Check if env config exists
const hasEnvConfig =
process.env.SMTP_HOST &&
process.env.SMTP_USER &&
process.env.SMTP_PASS;
if (hasEnvConfig) {
const envConfig: SMTPConfig = {
host: process.env.SMTP_HOST!,
port: parseInt(process.env.SMTP_PORT || '587', 10),
secure: process.env.SMTP_SECURE === 'true',
auth: {
user: process.env.SMTP_USER!,
pass: '***',
},
from: {
email: process.env.SMTP_FROM_EMAIL || '',
name: process.env.SMTP_FROM_NAME || 'Location Tracker',
},
replyTo: process.env.SMTP_REPLY_TO,
timeout: 10000,
};
response = { config: envConfig, source: 'env' };
} else {
response = { config: null, source: 'env' };
}
}
return NextResponse.json(response);
} catch (error) {
console.error('[API] Failed to get SMTP config:', error);
return NextResponse.json(
{ error: 'Failed to get SMTP configuration' },
{ status: 500 }
);
}
}
/**
* POST /api/admin/settings/smtp
* Save SMTP configuration to database
*/
export async function POST(request: Request) {
try {
const session = await auth();
if (!session?.user || (session.user as any).role !== 'ADMIN') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const body = await request.json();
const config = body.config as SMTPConfig;
// Trim whitespace from credentials to prevent auth errors
if (config.host) config.host = config.host.trim();
if (config.auth?.user) config.auth.user = config.auth.user.trim();
if (config.auth?.pass) config.auth.pass = config.auth.pass.trim();
if (config.from?.email) config.from.email = config.from.email.trim();
// Validation
if (!config.host || !config.port || !config.auth?.user || !config.auth?.pass) {
return NextResponse.json(
{ error: 'Missing required SMTP configuration fields' },
{ status: 400 }
);
}
if (config.port < 1 || config.port > 65535) {
return NextResponse.json(
{ error: 'Port must be between 1 and 65535' },
{ status: 400 }
);
}
// Save to database (password will be encrypted)
settingsDb.setSMTPConfig(config);
// Reset the cached transporter to use new config
emailService.resetTransporter();
return NextResponse.json({ success: true });
} catch (error) {
console.error('[API] Failed to save SMTP config:', error);
return NextResponse.json(
{ error: 'Failed to save SMTP configuration' },
{ status: 500 }
);
}
}
/**
* DELETE /api/admin/settings/smtp
* Reset to environment config
*/
export async function DELETE() {
try {
const session = await auth();
if (!session?.user || (session.user as any).role !== 'ADMIN') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
settingsDb.delete('smtp_config');
// Reset the cached transporter to use env config
emailService.resetTransporter();
return NextResponse.json({ success: true });
} catch (error) {
console.error('[API] Failed to delete SMTP config:', error);
return NextResponse.json(
{ error: 'Failed to reset SMTP configuration' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,78 @@
import { NextResponse } from 'next/server';
import { auth } from '@/lib/auth';
import { emailService } from '@/lib/email-service';
import { SMTPConfig } from '@/lib/types/smtp';
/**
* POST /api/admin/settings/smtp/test
* Test SMTP configuration by sending a test email
*/
export async function POST(request: Request) {
try {
const session = await auth();
if (!session?.user || (session.user as any).role !== 'ADMIN') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const body = await request.json();
const { config, testEmail } = body as { config?: SMTPConfig; testEmail: string };
if (!testEmail) {
return NextResponse.json(
{ error: 'Test email address is required' },
{ status: 400 }
);
}
// Email validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(testEmail)) {
return NextResponse.json(
{ error: 'Invalid email address' },
{ status: 400 }
);
}
// Test connection
try {
await emailService.testConnection(config);
} catch (error) {
return NextResponse.json(
{
error: error instanceof Error ? error.message : 'SMTP connection failed. Please check your settings.'
},
{ status: 500 }
);
}
// Send test email
try {
await emailService.sendWelcomeEmail({
email: testEmail,
username: 'Test User',
loginUrl: `${process.env.NEXTAUTH_URL || 'http://localhost:3000'}/login`,
temporaryPassword: undefined,
});
return NextResponse.json({
success: true,
message: `Test email sent successfully to ${testEmail}`,
});
} catch (sendError) {
console.error('[API] Test email send failed:', sendError);
return NextResponse.json(
{
error: `Email send failed: ${sendError instanceof Error ? sendError.message : 'Unknown error'}`,
},
{ status: 500 }
);
}
} catch (error) {
console.error('[API] SMTP test failed:', error);
return NextResponse.json(
{ error: 'SMTP test failed' },
{ status: 500 }
);
}
}