200 lines
5.4 KiB
TypeScript
200 lines
5.4 KiB
TypeScript
import { Router, Request, Response } from 'express';
|
|
import { Target } from '../models/Target.js';
|
|
import { logger } from '../utils/logger.js';
|
|
|
|
export const targetsRouter = Router();
|
|
|
|
// Get all targets
|
|
targetsRouter.get('/', async (req: Request, res: Response) => {
|
|
try {
|
|
const targets = await Target.find()
|
|
.sort({ updatedAt: -1 })
|
|
.lean();
|
|
|
|
// Add profile count
|
|
const targetsWithCount = targets.map(t => ({
|
|
...t,
|
|
id: t._id,
|
|
profile_count: t.profiles?.length || 0,
|
|
}));
|
|
|
|
res.json(targetsWithCount);
|
|
} catch (error) {
|
|
logger.error('Error fetching targets:', error);
|
|
res.status(500).json({ error: 'Failed to fetch targets' });
|
|
}
|
|
});
|
|
|
|
// Get single target with profiles
|
|
targetsRouter.get('/:id', async (req: Request, res: Response) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const target = await Target.findById(id).lean();
|
|
|
|
if (!target) {
|
|
res.status(404).json({ error: 'Target not found' });
|
|
return;
|
|
}
|
|
|
|
res.json({
|
|
...target,
|
|
id: target._id,
|
|
profiles: target.profiles?.map(p => ({
|
|
...p,
|
|
id: p._id,
|
|
target_id: target._id,
|
|
profile_url: p.profileUrl,
|
|
profile_data: p.profileData ? JSON.stringify(p.profileData) : null,
|
|
last_scraped: p.lastScraped,
|
|
created_at: p.createdAt,
|
|
})) || [],
|
|
});
|
|
} catch (error) {
|
|
logger.error('Error fetching target:', error);
|
|
res.status(500).json({ error: 'Failed to fetch target' });
|
|
}
|
|
});
|
|
|
|
// Create target
|
|
targetsRouter.post('/', async (req: Request, res: Response) => {
|
|
try {
|
|
const { name, notes } = req.body;
|
|
|
|
if (!name) {
|
|
res.status(400).json({ error: 'Name is required' });
|
|
return;
|
|
}
|
|
|
|
const target = new Target({ name, notes, profiles: [] });
|
|
await target.save();
|
|
|
|
logger.info(`Created target: ${name} (${target._id})`);
|
|
res.status(201).json({
|
|
...target.toObject(),
|
|
id: target._id,
|
|
profile_count: 0,
|
|
});
|
|
} catch (error) {
|
|
logger.error('Error creating target:', error);
|
|
res.status(500).json({ error: 'Failed to create target' });
|
|
}
|
|
});
|
|
|
|
// Update target
|
|
targetsRouter.put('/:id', async (req: Request, res: Response) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { name, notes } = req.body;
|
|
|
|
const target = await Target.findByIdAndUpdate(
|
|
id,
|
|
{ name, notes },
|
|
{ new: true }
|
|
).lean();
|
|
|
|
if (!target) {
|
|
res.status(404).json({ error: 'Target not found' });
|
|
return;
|
|
}
|
|
|
|
res.json({ ...target, id: target._id });
|
|
} catch (error) {
|
|
logger.error('Error updating target:', error);
|
|
res.status(500).json({ error: 'Failed to update target' });
|
|
}
|
|
});
|
|
|
|
// Delete target
|
|
targetsRouter.delete('/:id', async (req: Request, res: Response) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const result = await Target.findByIdAndDelete(id);
|
|
|
|
if (!result) {
|
|
res.status(404).json({ error: 'Target not found' });
|
|
return;
|
|
}
|
|
|
|
logger.info(`Deleted target: ${id}`);
|
|
res.json({ success: true });
|
|
} catch (error) {
|
|
logger.error('Error deleting target:', error);
|
|
res.status(500).json({ error: 'Failed to delete target' });
|
|
}
|
|
});
|
|
|
|
// Add profile to target
|
|
targetsRouter.post('/:id/profiles', async (req: Request, res: Response) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { platform, username, profile_url } = req.body;
|
|
|
|
if (!platform) {
|
|
res.status(400).json({ error: 'Platform is required' });
|
|
return;
|
|
}
|
|
|
|
const target = await Target.findById(id);
|
|
if (!target) {
|
|
res.status(404).json({ error: 'Target not found' });
|
|
return;
|
|
}
|
|
|
|
const newProfile = {
|
|
platform,
|
|
username: username || undefined,
|
|
profileUrl: profile_url || undefined,
|
|
createdAt: new Date(),
|
|
};
|
|
|
|
target.profiles.push(newProfile as any);
|
|
await target.save();
|
|
|
|
const addedProfile = target.profiles[target.profiles.length - 1];
|
|
|
|
logger.info(`Added ${platform} profile to target ${id}`);
|
|
res.status(201).json({
|
|
id: addedProfile._id,
|
|
target_id: id,
|
|
platform: addedProfile.platform,
|
|
username: addedProfile.username,
|
|
profile_url: addedProfile.profileUrl,
|
|
created_at: addedProfile.createdAt,
|
|
});
|
|
} catch (error) {
|
|
logger.error('Error adding profile:', error);
|
|
res.status(500).json({ error: 'Failed to add profile' });
|
|
}
|
|
});
|
|
|
|
// Delete profile
|
|
targetsRouter.delete('/:id/profiles/:profileId', async (req: Request, res: Response) => {
|
|
try {
|
|
const { id, profileId } = req.params;
|
|
|
|
const target = await Target.findById(id);
|
|
if (!target) {
|
|
res.status(404).json({ error: 'Target not found' });
|
|
return;
|
|
}
|
|
|
|
const profileIndex = target.profiles.findIndex(
|
|
p => p._id.toString() === profileId
|
|
);
|
|
|
|
if (profileIndex === -1) {
|
|
res.status(404).json({ error: 'Profile not found' });
|
|
return;
|
|
}
|
|
|
|
target.profiles.splice(profileIndex, 1);
|
|
await target.save();
|
|
|
|
logger.info(`Deleted profile ${profileId} from target ${id}`);
|
|
res.json({ success: true });
|
|
} catch (error) {
|
|
logger.error('Error deleting profile:', error);
|
|
res.status(500).json({ error: 'Failed to delete profile' });
|
|
}
|
|
});
|