import { Request, Response } from 'express'; import { IUnleashConfig } from '../../types/option'; import { IUnleashServices } from '../../types/services'; import EventService from '../../services/event-service'; import { ADMIN, NONE } from '../../types/permissions'; import { IEvent, IEventList } from '../../types/events'; import Controller from '../controller'; import { anonymise } from '../../util/anonymise'; import { OpenApiService } from '../../services/openapi-service'; import { createResponseSchema } from '../../openapi/util/create-response-schema'; import { endpointDescriptions } from '../../openapi/endpoint-descriptions'; import { eventsSchema, EventsSchema, } from '../../../lib/openapi/spec/events-schema'; import { serializeDates } from '../../../lib/types/serialize-dates'; import { featureEventsSchema, FeatureEventsSchema, } from '../../../lib/openapi/spec/feature-events-schema'; import { getStandardResponses } from '../../../lib/openapi/util/standard-responses'; import { createRequestSchema } from '../../openapi/util/create-request-schema'; import { SearchEventsSchema } from '../../openapi/spec/search-events-schema'; import { IFlagResolver } from '../../types/experimental'; const version = 1; export default class EventController extends Controller { private eventService: EventService; private flagResolver: IFlagResolver; private openApiService: OpenApiService; constructor( config: IUnleashConfig, { eventService, openApiService, }: Pick, ) { super(config); this.eventService = eventService; this.flagResolver = config.flagResolver; this.openApiService = openApiService; this.route({ method: 'get', path: '', handler: this.getEvents, permission: ADMIN, middleware: [ openApiService.validPath({ operationId: 'getEvents', tags: ['Events'], responses: { ...getStandardResponses(401), 200: createResponseSchema('eventsSchema'), }, parameters: [ { name: 'project', description: 'The name of the project whose events you want to retrieve', schema: { type: 'string' }, in: 'query', }, ], ...endpointDescriptions.admin.events, }), ], }); this.route({ method: 'get', path: '/:featureName', handler: this.getEventsForToggle, permission: NONE, middleware: [ openApiService.validPath({ operationId: 'getEventsForToggle', tags: ['Events'], responses: { ...getStandardResponses(401), 200: createResponseSchema('featureEventsSchema'), }, ...endpointDescriptions.admin.eventsPerFeature, }), ], }); this.route({ method: 'post', path: '/search', handler: this.searchEvents, permission: NONE, middleware: [ openApiService.validPath({ operationId: 'searchEvents', tags: ['Events'], requestBody: createRequestSchema('searchEventsSchema'), responses: { 200: createResponseSchema('eventsSchema') }, }), ], }); } maybeAnonymiseEvents(events: IEvent[]): IEvent[] { if (this.flagResolver.isEnabled('anonymiseEventLog')) { return events.map((e: IEvent) => ({ ...e, createdBy: anonymise(e.createdBy), data: e.data && 'email' in e.data ? { ...e.data, email: anonymise(e.data.email), } : e.data, preData: e.preData && 'email' in e.preData ? { ...e.preData, email: anonymise(e.preData.email), } : e.preData, })); } return events; } async getEvents( req: Request, res: Response, ): Promise { const { project } = req.query; let eventList: IEventList; if (project) { eventList = await this.eventService.searchEvents({ project }); } else { eventList = await this.eventService.getEvents(); } const response: EventsSchema = { version, events: serializeDates(this.maybeAnonymiseEvents(eventList.events)), totalEvents: eventList.totalEvents, }; this.openApiService.respondWithValidation( 200, res, eventsSchema.$id, response, ); } async getEventsForToggle( req: Request<{ featureName: string }>, res: Response, ): Promise { const feature = req.params.featureName; const eventList = await this.eventService.searchEvents({ feature }); const response = { version, toggleName: feature, events: serializeDates(this.maybeAnonymiseEvents(eventList.events)), totalEvents: eventList.totalEvents, }; this.openApiService.respondWithValidation( 200, res, featureEventsSchema.$id, response, ); } async searchEvents( req: Request, res: Response, ): Promise { const eventList = await this.eventService.searchEvents(req.body); const response = { version, events: serializeDates(this.maybeAnonymiseEvents(eventList.events)), totalEvents: eventList.totalEvents, }; this.openApiService.respondWithValidation( 200, res, featureEventsSchema.$id, response, ); } }