Data management tab

This commit is contained in:
Dries Augustyns
2025-12-02 09:46:12 +01:00
parent 61cb93d04c
commit 2e6b485532
6 changed files with 812 additions and 3 deletions
+54
View File
@@ -324,4 +324,58 @@ export class Contacts {
});
}
}
/**
* GET /contacts/fields/:field/usage
* Check if a field is used in segments/campaigns and get usage statistics
* Returns information about where the field is used and whether it can be safely deleted
*/
@Get('fields/:field/usage')
@Middleware([requireAuth])
@CatchAsync
public async getFieldUsage(req: Request, res: Response, next: NextFunction) {
const auth = res.locals.auth as AuthResponse;
const field = req.params.field;
if (!field) {
return res.status(400).json({error: 'Field is required'});
}
try {
const usage = await ContactService.getFieldUsage(auth.projectId!, field);
return res.status(200).json(usage);
} catch (error) {
console.error('[CONTACTS] Failed to get field usage:', error);
return res.status(500).json({
error: error instanceof Error ? error.message : 'Failed to get field usage',
});
}
}
/**
* DELETE /contacts/fields/:field
* Delete a custom field from all contacts
* Only works if the field is not used in any segments or campaigns
*/
@Delete('fields/:field')
@Middleware([requireAuth])
@CatchAsync
public async deleteField(req: Request, res: Response, next: NextFunction) {
const auth = res.locals.auth as AuthResponse;
const field = req.params.field;
if (!field) {
return res.status(400).json({error: 'Field is required'});
}
try {
const result = await ContactService.deleteField(auth.projectId!, field);
return res.status(200).json(result);
} catch (error) {
console.error('[CONTACTS] Failed to delete field:', error);
return res.status(error instanceof Error && error.message.includes('Cannot delete') ? 400 : 500).json({
error: error instanceof Error ? error.message : 'Failed to delete field',
});
}
}
}
+55 -1
View File
@@ -1,4 +1,4 @@
import {Controller, Get, Middleware, Post} from '@overnightjs/core';
import {Controller, Delete, Get, Middleware, Post} from '@overnightjs/core';
import type {NextFunction, Request, Response} from 'express';
import type {AuthResponse} from '../middleware/auth.js';
@@ -97,4 +97,58 @@ export class Events {
return res.status(200).json({eventNames});
}
/**
* GET /events/:eventName/usage
* Check if an event is used in segments/workflows and get usage statistics
* Returns information about where the event is used and whether it can be safely deleted
*/
@Get(':eventName/usage')
@Middleware([requireAuth])
@CatchAsync
public async getEventUsage(req: Request, res: Response, next: NextFunction) {
const auth = res.locals.auth as AuthResponse;
const eventName = req.params.eventName;
if (!eventName) {
return res.status(400).json({error: 'Event name is required'});
}
try {
const usage = await EventService.getEventUsage(auth.projectId!, eventName);
return res.status(200).json(usage);
} catch (error) {
console.error('[EVENTS] Failed to get event usage:', error);
return res.status(500).json({
error: error instanceof Error ? error.message : 'Failed to get event usage',
});
}
}
/**
* DELETE /events/:eventName
* Delete all events with a specific name
* Only works if the event is not used in any segments or workflows
*/
@Delete(':eventName')
@Middleware([requireAuth])
@CatchAsync
public async deleteEvent(req: Request, res: Response, next: NextFunction) {
const auth = res.locals.auth as AuthResponse;
const eventName = req.params.eventName;
if (!eventName) {
return res.status(400).json({error: 'Event name is required'});
}
try {
const result = await EventService.deleteEvent(auth.projectId!, eventName);
return res.status(200).json(result);
} catch (error) {
console.error('[EVENTS] Failed to delete event:', error);
return res.status(error instanceof Error && error.message.includes('Cannot delete') ? 400 : 500).json({
error: error instanceof Error ? error.message : 'Failed to delete event',
});
}
}
}