190 lines
5.4 KiB
TypeScript
190 lines
5.4 KiB
TypeScript
/**
|
|
* Price Alerts Controller
|
|
* Handles price alert endpoints
|
|
*/
|
|
|
|
import type { Request, Response, NextFunction } from 'express';
|
|
import { alertsService, AlertCondition } from '../services/alerts.service';
|
|
import type { AuthenticatedRequest } from '../../../core/guards/auth.guard';
|
|
|
|
// ============================================================================
|
|
// CRUD Operations
|
|
// ============================================================================
|
|
|
|
export async function createAlert(req: Request, res: Response, next: NextFunction): Promise<void> {
|
|
try {
|
|
const authReq = req as AuthenticatedRequest;
|
|
const { symbol, condition, price, note, notifyEmail, notifyPush, isRecurring } = req.body;
|
|
|
|
if (!symbol || !condition || price === undefined) {
|
|
res.status(400).json({
|
|
success: false,
|
|
error: 'Symbol, condition, and price are required',
|
|
});
|
|
return;
|
|
}
|
|
|
|
const validConditions: AlertCondition[] = ['above', 'below', 'crosses_above', 'crosses_below'];
|
|
if (!validConditions.includes(condition)) {
|
|
res.status(400).json({
|
|
success: false,
|
|
error: `Invalid condition. Must be one of: ${validConditions.join(', ')}`,
|
|
});
|
|
return;
|
|
}
|
|
|
|
const alert = await alertsService.createAlert({
|
|
userId: authReq.user.id,
|
|
symbol,
|
|
condition,
|
|
price,
|
|
note,
|
|
notifyEmail,
|
|
notifyPush,
|
|
isRecurring,
|
|
});
|
|
|
|
res.status(201).json({ success: true, data: alert });
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
export async function getAlerts(req: Request, res: Response, next: NextFunction): Promise<void> {
|
|
try {
|
|
const authReq = req as AuthenticatedRequest;
|
|
const { isActive, symbol, condition } = req.query;
|
|
|
|
const alerts = await alertsService.getUserAlerts(authReq.user.id, {
|
|
isActive: isActive === 'true' ? true : isActive === 'false' ? false : undefined,
|
|
symbol: symbol as string,
|
|
condition: condition as AlertCondition,
|
|
});
|
|
|
|
res.json({ success: true, data: alerts });
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
export async function getAlertById(req: Request, res: Response, next: NextFunction): Promise<void> {
|
|
try {
|
|
const authReq = req as AuthenticatedRequest;
|
|
const { alertId } = req.params;
|
|
|
|
const alert = await alertsService.getAlertById(alertId);
|
|
|
|
if (!alert) {
|
|
res.status(404).json({ success: false, error: 'Alert not found' });
|
|
return;
|
|
}
|
|
|
|
if (alert.userId !== authReq.user.id) {
|
|
res.status(403).json({ success: false, error: 'Unauthorized' });
|
|
return;
|
|
}
|
|
|
|
res.json({ success: true, data: alert });
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
export async function updateAlert(req: Request, res: Response, next: NextFunction): Promise<void> {
|
|
try {
|
|
const authReq = req as AuthenticatedRequest;
|
|
const { alertId } = req.params;
|
|
const { price, note, notifyEmail, notifyPush, isRecurring, isActive } = req.body;
|
|
|
|
const alert = await alertsService.updateAlert(alertId, authReq.user.id, {
|
|
price,
|
|
note,
|
|
notifyEmail,
|
|
notifyPush,
|
|
isRecurring,
|
|
isActive,
|
|
});
|
|
|
|
if (!alert) {
|
|
res.status(404).json({ success: false, error: 'Alert not found or unauthorized' });
|
|
return;
|
|
}
|
|
|
|
res.json({ success: true, data: alert });
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
export async function deleteAlert(req: Request, res: Response, next: NextFunction): Promise<void> {
|
|
try {
|
|
const authReq = req as AuthenticatedRequest;
|
|
const { alertId } = req.params;
|
|
|
|
const deleted = await alertsService.deleteAlert(alertId, authReq.user.id);
|
|
|
|
if (!deleted) {
|
|
res.status(404).json({ success: false, error: 'Alert not found or unauthorized' });
|
|
return;
|
|
}
|
|
|
|
res.json({ success: true, message: 'Alert deleted' });
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// Enable/Disable
|
|
// ============================================================================
|
|
|
|
export async function enableAlert(req: Request, res: Response, next: NextFunction): Promise<void> {
|
|
try {
|
|
const authReq = req as AuthenticatedRequest;
|
|
const { alertId } = req.params;
|
|
|
|
const alert = await alertsService.enableAlert(alertId, authReq.user.id);
|
|
|
|
if (!alert) {
|
|
res.status(404).json({ success: false, error: 'Alert not found or unauthorized' });
|
|
return;
|
|
}
|
|
|
|
res.json({ success: true, data: alert });
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
export async function disableAlert(req: Request, res: Response, next: NextFunction): Promise<void> {
|
|
try {
|
|
const authReq = req as AuthenticatedRequest;
|
|
const { alertId } = req.params;
|
|
|
|
const alert = await alertsService.disableAlert(alertId, authReq.user.id);
|
|
|
|
if (!alert) {
|
|
res.status(404).json({ success: false, error: 'Alert not found or unauthorized' });
|
|
return;
|
|
}
|
|
|
|
res.json({ success: true, data: alert });
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// Statistics
|
|
// ============================================================================
|
|
|
|
export async function getAlertStats(req: Request, res: Response, next: NextFunction): Promise<void> {
|
|
try {
|
|
const authReq = req as AuthenticatedRequest;
|
|
const stats = await alertsService.getUserAlertStats(authReq.user.id);
|
|
res.json({ success: true, data: stats });
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|