mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-27 01:19:00 +02:00
chore: prefer searchEvents over deprecated methods (#10031)
https://linear.app/unleash/issue/2-3577/prefer-the-new-searchevents-method-over-deprecated-methods We should favor our new `searchEvents` method over the other deprecated methods. This PR removes these deprecated methods, replaces them with the new `searchEvents` and `searchEventsCount` methods, and marks the old endpoints as deprecated. Follow-up to: https://github.com/Unleash/unleash/pull/10030
This commit is contained in:
parent
2879ce9dd6
commit
a419b8e098
@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Generated by Orval
|
||||
* Do not edit manually.
|
||||
* See `gen:api` script in package.json
|
||||
*/
|
||||
import type { DeprecatedSearchEventsSchemaType } from './deprecatedSearchEventsSchemaType.js';
|
||||
|
||||
/**
|
||||
*
|
||||
Search for events by type, project, feature, free-text query,
|
||||
or a combination thereof. Pass an empty object to fetch all events.
|
||||
|
||||
*/
|
||||
export interface DeprecatedSearchEventsSchema {
|
||||
/** Find events by feature flag name (case-sensitive). */
|
||||
feature?: string;
|
||||
/**
|
||||
* The maximum amount of events to return in the search result
|
||||
* @minimum 1
|
||||
* @maximum 100
|
||||
*/
|
||||
limit?: number;
|
||||
/**
|
||||
* Which event id to start listing from
|
||||
* @minimum 0
|
||||
*/
|
||||
offset?: number;
|
||||
/** Find events by project ID (case-sensitive). */
|
||||
project?: string;
|
||||
/** Find events by a free-text search query. The query will be matched against the event type, the username or email that created the event (if any), and the event data payload (if any). */
|
||||
query?: string;
|
||||
/** Find events by event type (case-sensitive). */
|
||||
type?: DeprecatedSearchEventsSchemaType;
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
/**
|
||||
* Generated by Orval
|
||||
* Do not edit manually.
|
||||
* See `gen:api` script in package.json
|
||||
*/
|
||||
|
||||
/**
|
||||
* Find events by event type (case-sensitive).
|
||||
*/
|
||||
export type DeprecatedSearchEventsSchemaType =
|
||||
(typeof DeprecatedSearchEventsSchemaType)[keyof typeof DeprecatedSearchEventsSchemaType];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
||||
export const DeprecatedSearchEventsSchemaType = {
|
||||
'application-created': 'application-created',
|
||||
'feature-created': 'feature-created',
|
||||
'feature-deleted': 'feature-deleted',
|
||||
'feature-updated': 'feature-updated',
|
||||
'feature-metadata-updated': 'feature-metadata-updated',
|
||||
'feature-variants-updated': 'feature-variants-updated',
|
||||
'feature-environment-variants-updated':
|
||||
'feature-environment-variants-updated',
|
||||
'feature-project-change': 'feature-project-change',
|
||||
'feature-archived': 'feature-archived',
|
||||
'feature-revived': 'feature-revived',
|
||||
'feature-import': 'feature-import',
|
||||
'feature-tagged': 'feature-tagged',
|
||||
'feature-tag-import': 'feature-tag-import',
|
||||
'feature-strategy-update': 'feature-strategy-update',
|
||||
'feature-strategy-add': 'feature-strategy-add',
|
||||
'feature-strategy-remove': 'feature-strategy-remove',
|
||||
'feature-type-updated': 'feature-type-updated',
|
||||
'feature-completed': 'feature-completed',
|
||||
'feature-uncompleted': 'feature-uncompleted',
|
||||
'feature-link-added': 'feature-link-added',
|
||||
'feature-link-removed': 'feature-link-removed',
|
||||
'feature-link-updated': 'feature-link-updated',
|
||||
'strategy-order-changed': 'strategy-order-changed',
|
||||
'drop-feature-tags': 'drop-feature-tags',
|
||||
'feature-untagged': 'feature-untagged',
|
||||
'feature-stale-on': 'feature-stale-on',
|
||||
'feature-stale-off': 'feature-stale-off',
|
||||
'drop-features': 'drop-features',
|
||||
'feature-environment-enabled': 'feature-environment-enabled',
|
||||
'feature-environment-disabled': 'feature-environment-disabled',
|
||||
'strategy-created': 'strategy-created',
|
||||
'strategy-deleted': 'strategy-deleted',
|
||||
'strategy-deprecated': 'strategy-deprecated',
|
||||
'strategy-reactivated': 'strategy-reactivated',
|
||||
'strategy-updated': 'strategy-updated',
|
||||
'strategy-import': 'strategy-import',
|
||||
'drop-strategies': 'drop-strategies',
|
||||
'context-field-created': 'context-field-created',
|
||||
'context-field-updated': 'context-field-updated',
|
||||
'context-field-deleted': 'context-field-deleted',
|
||||
'project-access-added': 'project-access-added',
|
||||
'project-access-user-roles-updated': 'project-access-user-roles-updated',
|
||||
'project-access-group-roles-updated': 'project-access-group-roles-updated',
|
||||
'project-access-user-roles-deleted': 'project-access-user-roles-deleted',
|
||||
'project-access-group-roles-deleted': 'project-access-group-roles-deleted',
|
||||
'project-access-updated': 'project-access-updated',
|
||||
'project-created': 'project-created',
|
||||
'project-updated': 'project-updated',
|
||||
'project-deleted': 'project-deleted',
|
||||
'project-archived': 'project-archived',
|
||||
'project-revived': 'project-revived',
|
||||
'project-import': 'project-import',
|
||||
'project-user-added': 'project-user-added',
|
||||
'project-user-removed': 'project-user-removed',
|
||||
'project-user-role-changed': 'project-user-role-changed',
|
||||
'project-group-role-changed': 'project-group-role-changed',
|
||||
'project-group-added': 'project-group-added',
|
||||
'project-group-removed': 'project-group-removed',
|
||||
'role-created': 'role-created',
|
||||
'role-updated': 'role-updated',
|
||||
'role-deleted': 'role-deleted',
|
||||
'drop-projects': 'drop-projects',
|
||||
'tag-created': 'tag-created',
|
||||
'tag-deleted': 'tag-deleted',
|
||||
'tag-import': 'tag-import',
|
||||
'drop-tags': 'drop-tags',
|
||||
'tag-type-created': 'tag-type-created',
|
||||
'tag-type-deleted': 'tag-type-deleted',
|
||||
'tag-type-updated': 'tag-type-updated',
|
||||
'tag-type-import': 'tag-type-import',
|
||||
'drop-tag-types': 'drop-tag-types',
|
||||
'addon-config-created': 'addon-config-created',
|
||||
'addon-config-updated': 'addon-config-updated',
|
||||
'addon-config-deleted': 'addon-config-deleted',
|
||||
'db-pool-update': 'db-pool-update',
|
||||
'user-created': 'user-created',
|
||||
'user-updated': 'user-updated',
|
||||
'user-deleted': 'user-deleted',
|
||||
'drop-environments': 'drop-environments',
|
||||
'environment-import': 'environment-import',
|
||||
'environment-created': 'environment-created',
|
||||
'environment-updated': 'environment-updated',
|
||||
'environment-deleted': 'environment-deleted',
|
||||
'segment-created': 'segment-created',
|
||||
'segment-updated': 'segment-updated',
|
||||
'segment-deleted': 'segment-deleted',
|
||||
'group-created': 'group-created',
|
||||
'group-updated': 'group-updated',
|
||||
'group-deleted': 'group-deleted',
|
||||
'group-user-added': 'group-user-added',
|
||||
'group-user-removed': 'group-user-removed',
|
||||
'setting-created': 'setting-created',
|
||||
'setting-updated': 'setting-updated',
|
||||
'setting-deleted': 'setting-deleted',
|
||||
'client-metrics': 'client-metrics',
|
||||
'client-register': 'client-register',
|
||||
'pat-created': 'pat-created',
|
||||
'pat-deleted': 'pat-deleted',
|
||||
'public-signup-token-created': 'public-signup-token-created',
|
||||
'public-signup-token-user-added': 'public-signup-token-user-added',
|
||||
'public-signup-token-updated': 'public-signup-token-updated',
|
||||
'change-request-created': 'change-request-created',
|
||||
'change-request-discarded': 'change-request-discarded',
|
||||
'change-added': 'change-added',
|
||||
'change-discarded': 'change-discarded',
|
||||
'change-edited': 'change-edited',
|
||||
'change-request-rejected': 'change-request-rejected',
|
||||
'change-request-approved': 'change-request-approved',
|
||||
'change-request-approval-added': 'change-request-approval-added',
|
||||
'change-request-cancelled': 'change-request-cancelled',
|
||||
'change-request-sent-to-review': 'change-request-sent-to-review',
|
||||
'change-request-schedule-suspended': 'change-request-schedule-suspended',
|
||||
'change-request-applied': 'change-request-applied',
|
||||
'change-request-scheduled': 'change-request-scheduled',
|
||||
'change-request-scheduled-application-success':
|
||||
'change-request-scheduled-application-success',
|
||||
'change-request-scheduled-application-failure':
|
||||
'change-request-scheduled-application-failure',
|
||||
'change-request-configuration-updated':
|
||||
'change-request-configuration-updated',
|
||||
'api-token-created': 'api-token-created',
|
||||
'api-token-updated': 'api-token-updated',
|
||||
'api-token-deleted': 'api-token-deleted',
|
||||
'feature-favorited': 'feature-favorited',
|
||||
'feature-unfavorited': 'feature-unfavorited',
|
||||
'project-favorited': 'project-favorited',
|
||||
'project-unfavorited': 'project-unfavorited',
|
||||
'features-exported': 'features-exported',
|
||||
'features-imported': 'features-imported',
|
||||
'service-account-created': 'service-account-created',
|
||||
'service-account-deleted': 'service-account-deleted',
|
||||
'service-account-updated': 'service-account-updated',
|
||||
'feature-potentially-stale-on': 'feature-potentially-stale-on',
|
||||
'feature-dependency-added': 'feature-dependency-added',
|
||||
'feature-dependency-removed': 'feature-dependency-removed',
|
||||
'feature-dependencies-removed': 'feature-dependencies-removed',
|
||||
'banner-created': 'banner-created',
|
||||
'banner-updated': 'banner-updated',
|
||||
'banner-deleted': 'banner-deleted',
|
||||
'project-environment-added': 'project-environment-added',
|
||||
'project-environment-removed': 'project-environment-removed',
|
||||
'default-strategy-updated': 'default-strategy-updated',
|
||||
'segment-import': 'segment-import',
|
||||
'signal-endpoint-created': 'signal-endpoint-created',
|
||||
'signal-endpoint-updated': 'signal-endpoint-updated',
|
||||
'signal-endpoint-deleted': 'signal-endpoint-deleted',
|
||||
'signal-endpoint-token-created': 'signal-endpoint-token-created',
|
||||
'signal-endpoint-token-updated': 'signal-endpoint-token-updated',
|
||||
'signal-endpoint-token-deleted': 'signal-endpoint-token-deleted',
|
||||
'actions-created': 'actions-created',
|
||||
'actions-updated': 'actions-updated',
|
||||
'actions-deleted': 'actions-deleted',
|
||||
'release-plan-template-created': 'release-plan-template-created',
|
||||
'release-plan-template-updated': 'release-plan-template-updated',
|
||||
'release-plan-template-deleted': 'release-plan-template-deleted',
|
||||
'release-plan-template-archived': 'release-plan-template-archived',
|
||||
'release-plan-added': 'release-plan-added',
|
||||
'release-plan-removed': 'release-plan-removed',
|
||||
'release-plan-milestone-started': 'release-plan-milestone-started',
|
||||
'user-preference-updated': 'user-preference-updated',
|
||||
'scim-users-deleted': 'scim-users-deleted',
|
||||
'scim-groups-deleted': 'scim-groups-deleted',
|
||||
} as const;
|
@ -577,8 +577,6 @@ export * from './deprecateStrategy403.js';
|
||||
export * from './deprecateStrategy404.js';
|
||||
export * from './deprecatedProjectOverviewSchema.js';
|
||||
export * from './deprecatedProjectOverviewSchemaMode.js';
|
||||
export * from './deprecatedSearchEventsSchema.js';
|
||||
export * from './deprecatedSearchEventsSchemaType.js';
|
||||
export * from './disableBanner401.js';
|
||||
export * from './disableBanner403.js';
|
||||
export * from './disableBanner404.js';
|
||||
|
@ -6,7 +6,6 @@ import type {
|
||||
IEventStore,
|
||||
} from '../../types/stores/event-store.js';
|
||||
import type { IApiUser, IUser } from '../../types/index.js';
|
||||
import type { DeprecatedSearchEventsSchema } from '../../openapi/index.js';
|
||||
import type EventEmitter from 'node:events';
|
||||
import { ApiTokenType } from '../../types/model.js';
|
||||
import { EVENTS_CREATED_BY_PROCESSED } from '../../metric-events.js';
|
||||
@ -67,18 +66,6 @@ export default class EventService {
|
||||
};
|
||||
}
|
||||
|
||||
async deprecatedSearchEvents(
|
||||
search: DeprecatedSearchEventsSchema,
|
||||
): Promise<IEventList> {
|
||||
const totalEvents =
|
||||
await this.eventStore.deprecatedFilteredCount(search);
|
||||
const events = await this.eventStore.deprecatedSearchEvents(search);
|
||||
return {
|
||||
events,
|
||||
totalEvents,
|
||||
};
|
||||
}
|
||||
|
||||
async searchEvents(
|
||||
search: IEventSearchParams,
|
||||
userId: number,
|
||||
@ -96,12 +83,8 @@ export default class EventService {
|
||||
queryParams.push(...projectFilter);
|
||||
|
||||
const totalEvents = await this.eventStore.searchEventsCount(
|
||||
{
|
||||
limit: search.limit,
|
||||
offset: search.offset,
|
||||
query: search.query,
|
||||
},
|
||||
queryParams,
|
||||
search.query,
|
||||
);
|
||||
const events = await this.eventStore.searchEvents(
|
||||
{
|
||||
|
@ -3,6 +3,7 @@ import EventStore from './event-store.js';
|
||||
import getLogger from '../../../test/fixtures/no-logger.js';
|
||||
import { subHours, formatRFC3339 } from 'date-fns';
|
||||
import dbInit from '../../../test/e2e/helpers/database-init.js';
|
||||
import { APPLICATION_CREATED } from '../../events/index.js';
|
||||
|
||||
beforeAll(() => {
|
||||
getLogger.setMuteError(true);
|
||||
@ -27,9 +28,19 @@ test('Trying to get events by name if db fails should yield empty list', async (
|
||||
client: 'pg',
|
||||
});
|
||||
const store = new EventStore(db, getLogger);
|
||||
const events = await store.deprecatedSearchEvents({
|
||||
type: 'application-created',
|
||||
});
|
||||
const events = await store.searchEvents(
|
||||
{
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
},
|
||||
[
|
||||
{
|
||||
field: 'type',
|
||||
operator: 'IS',
|
||||
values: [APPLICATION_CREATED],
|
||||
},
|
||||
],
|
||||
);
|
||||
expect(events).toBeTruthy();
|
||||
expect(events.length).toBe(0);
|
||||
await db.destroy();
|
||||
|
@ -24,10 +24,7 @@ import {
|
||||
SYSTEM_USER,
|
||||
SYSTEM_USER_ID,
|
||||
} from '../../types/index.js';
|
||||
import type {
|
||||
DeprecatedSearchEventsSchema,
|
||||
ProjectActivitySchema,
|
||||
} from '../../openapi/index.js';
|
||||
import type { ProjectActivitySchema } from '../../openapi/index.js';
|
||||
import type { IQueryParam } from '../feature-toggle/types/feature-toggle-strategies-store-type.js';
|
||||
import { applyGenericQueryParams } from '../feature-search/search-utils.js';
|
||||
import type { ITag } from '../../tags/index.js';
|
||||
@ -142,36 +139,12 @@ class EventStore implements IEventStore {
|
||||
}
|
||||
}
|
||||
|
||||
async deprecatedFilteredCount(
|
||||
eventSearch: DeprecatedSearchEventsSchema,
|
||||
): Promise<number> {
|
||||
let query = this.db(TABLE);
|
||||
if (eventSearch.type) {
|
||||
query = query.andWhere({ type: eventSearch.type });
|
||||
}
|
||||
if (eventSearch.project) {
|
||||
query = query.andWhere({ project: eventSearch.project });
|
||||
}
|
||||
if (eventSearch.feature) {
|
||||
query = query.andWhere({ feature_name: eventSearch.feature });
|
||||
}
|
||||
const count = await query.count().first();
|
||||
if (!count) {
|
||||
return 0;
|
||||
}
|
||||
if (typeof count.count === 'string') {
|
||||
return Number.parseInt(count.count, 10);
|
||||
} else {
|
||||
return count.count;
|
||||
}
|
||||
}
|
||||
|
||||
async searchEventsCount(
|
||||
params: IEventSearchParams,
|
||||
queryParams: IQueryParam[],
|
||||
query?: IEventSearchParams['query'],
|
||||
): Promise<number> {
|
||||
const query = this.buildSearchQuery(params, queryParams);
|
||||
const count = await query.count().first();
|
||||
const searchQuery = this.buildSearchQuery(queryParams, query);
|
||||
const count = await searchQuery.count().first();
|
||||
if (!count) {
|
||||
return 0;
|
||||
}
|
||||
@ -397,7 +370,7 @@ class EventStore implements IEventStore {
|
||||
queryParams: IQueryParam[],
|
||||
options?: { withIp?: boolean },
|
||||
): Promise<IEvent[]> {
|
||||
const query = this.buildSearchQuery(params, queryParams)
|
||||
const query = this.buildSearchQuery(queryParams, params.query)
|
||||
.select(options?.withIp ? [...EVENT_COLUMNS, 'ip'] : EVENT_COLUMNS)
|
||||
.orderBy('created_at', 'desc')
|
||||
.limit(Number(params.limit) ?? 100)
|
||||
@ -415,23 +388,23 @@ class EventStore implements IEventStore {
|
||||
}
|
||||
|
||||
private buildSearchQuery(
|
||||
params: IEventSearchParams,
|
||||
queryParams: IQueryParam[],
|
||||
query?: IEventSearchParams['query'],
|
||||
) {
|
||||
let query = this.db.from<IEventTable>(TABLE);
|
||||
let searchQuery = this.db.from<IEventTable>(TABLE);
|
||||
|
||||
applyGenericQueryParams(query, queryParams);
|
||||
applyGenericQueryParams(searchQuery, queryParams);
|
||||
|
||||
if (params.query) {
|
||||
query = query.where((where) =>
|
||||
if (query) {
|
||||
searchQuery = searchQuery.where((where) =>
|
||||
where
|
||||
.orWhereRaw('data::text ILIKE ?', `%${params.query}%`)
|
||||
.orWhereRaw('tags::text ILIKE ?', `%${params.query}%`)
|
||||
.orWhereRaw('pre_data::text ILIKE ?', `%${params.query}%`),
|
||||
.orWhereRaw('data::text ILIKE ?', `%${query}%`)
|
||||
.orWhereRaw('tags::text ILIKE ?', `%${query}%`)
|
||||
.orWhereRaw('pre_data::text ILIKE ?', `%${query}%`),
|
||||
);
|
||||
}
|
||||
|
||||
return query;
|
||||
return searchQuery;
|
||||
}
|
||||
|
||||
async getEventCreators(): Promise<Array<{ id: number; name: string }>> {
|
||||
@ -483,52 +456,6 @@ class EventStore implements IEventStore {
|
||||
}));
|
||||
}
|
||||
|
||||
async deprecatedSearchEvents(
|
||||
search: DeprecatedSearchEventsSchema = {},
|
||||
): Promise<IEvent[]> {
|
||||
let query = this.db
|
||||
.select(EVENT_COLUMNS)
|
||||
.from<IEventTable>(TABLE)
|
||||
.limit(search.limit ?? 100)
|
||||
.offset(search.offset ?? 0)
|
||||
.orderBy('created_at', 'desc');
|
||||
|
||||
if (search.type) {
|
||||
query = query.andWhere({
|
||||
type: search.type,
|
||||
});
|
||||
}
|
||||
|
||||
if (search.project) {
|
||||
query = query.andWhere({
|
||||
project: search.project,
|
||||
});
|
||||
}
|
||||
|
||||
if (search.feature) {
|
||||
query = query.andWhere({
|
||||
feature_name: search.feature,
|
||||
});
|
||||
}
|
||||
|
||||
if (search.query) {
|
||||
query = query.where((where) =>
|
||||
where
|
||||
.orWhereRaw('type::text ILIKE ?', `%${search.query}%`)
|
||||
.orWhereRaw('created_by::text ILIKE ?', `%${search.query}%`)
|
||||
.orWhereRaw('data::text ILIKE ?', `%${search.query}%`)
|
||||
.orWhereRaw('tags::text ILIKE ?', `%${search.query}%`)
|
||||
.orWhereRaw('pre_data::text ILIKE ?', `%${search.query}%`),
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
return (await query).map(this.rowToEvent);
|
||||
} catch (err) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
rowToEvent(row: IEventTable): IEvent {
|
||||
return {
|
||||
id: row.id,
|
||||
|
@ -492,18 +492,26 @@ export class InstanceStatsService {
|
||||
}
|
||||
|
||||
featuresExported(): Promise<number> {
|
||||
return this.memorize('deprecatedFilteredCountFeaturesExported', () =>
|
||||
this.eventStore.deprecatedFilteredCount({
|
||||
type: FEATURES_EXPORTED,
|
||||
}),
|
||||
return this.memorize('searchEventsCountFeaturesExported', () =>
|
||||
this.eventStore.searchEventsCount([
|
||||
{
|
||||
field: 'type',
|
||||
operator: 'IS',
|
||||
values: [FEATURES_EXPORTED],
|
||||
},
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
featuresImported(): Promise<number> {
|
||||
return this.memorize('deprecatedFilteredCountFeaturesImported', () =>
|
||||
this.eventStore.deprecatedFilteredCount({
|
||||
type: FEATURES_IMPORTED,
|
||||
}),
|
||||
return this.memorize('searchEventsCountFeaturesImported', () =>
|
||||
this.eventStore.searchEventsCount([
|
||||
{
|
||||
field: 'type',
|
||||
operator: 'IS',
|
||||
values: [FEATURES_IMPORTED],
|
||||
},
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,55 +0,0 @@
|
||||
import type { FromSchema } from 'json-schema-to-ts';
|
||||
import { IEventTypes } from '../../events/index.js';
|
||||
|
||||
export const deprecatedSearchEventsSchema = {
|
||||
$id: '#/components/schemas/deprecatedSearchEventsSchema',
|
||||
type: 'object',
|
||||
description: `
|
||||
Search for events by type, project, feature, free-text query,
|
||||
or a combination thereof. Pass an empty object to fetch all events.
|
||||
`,
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string',
|
||||
description: 'Find events by event type (case-sensitive).',
|
||||
enum: IEventTypes,
|
||||
example: 'feature-created',
|
||||
},
|
||||
project: {
|
||||
type: 'string',
|
||||
description: 'Find events by project ID (case-sensitive).',
|
||||
example: 'default',
|
||||
},
|
||||
feature: {
|
||||
type: 'string',
|
||||
description: 'Find events by feature flag name (case-sensitive).',
|
||||
example: 'my.first.flag',
|
||||
},
|
||||
query: {
|
||||
type: 'string',
|
||||
description: `Find events by a free-text search query. The query will be matched against the event type, the username or email that created the event (if any), and the event data payload (if any).`,
|
||||
example: 'admin@example.com',
|
||||
},
|
||||
limit: {
|
||||
type: 'integer',
|
||||
description:
|
||||
'The maximum amount of events to return in the search result',
|
||||
minimum: 1,
|
||||
maximum: 100,
|
||||
default: 100,
|
||||
example: 50,
|
||||
},
|
||||
offset: {
|
||||
description: 'Which event id to start listing from',
|
||||
type: 'integer',
|
||||
minimum: 0,
|
||||
default: 0,
|
||||
example: 100,
|
||||
},
|
||||
},
|
||||
components: {},
|
||||
} as const;
|
||||
|
||||
export type DeprecatedSearchEventsSchema = FromSchema<
|
||||
typeof deprecatedSearchEventsSchema
|
||||
>;
|
@ -64,7 +64,6 @@ export * from './date-schema.js';
|
||||
export * from './dependencies-exist-schema.js';
|
||||
export * from './dependent-feature-schema.js';
|
||||
export * from './deprecated-project-overview-schema.js';
|
||||
export * from './deprecated-search-events-schema.js';
|
||||
export * from './dora-features-schema.js';
|
||||
export * from './edge-token-schema.js';
|
||||
export * from './email-schema.js';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { Request, Response } from 'express';
|
||||
import type { Response } from 'express';
|
||||
import type { IUnleashConfig } from '../../types/option.js';
|
||||
import type { IUnleashServices } from '../../services/index.js';
|
||||
import type EventService from '../../features/events/event-service.js';
|
||||
@ -24,6 +24,7 @@ import {
|
||||
eventCreatorsSchema,
|
||||
type ProjectFlagCreatorsSchema,
|
||||
} from '../../openapi/index.js';
|
||||
import { extractUserIdFromUser } from '../../util/index.js';
|
||||
|
||||
const ANON_KEYS = ['email', 'username', 'createdBy'];
|
||||
const version = 1 as const;
|
||||
@ -53,6 +54,7 @@ export default class EventController extends Controller {
|
||||
permission: ADMIN,
|
||||
middleware: [
|
||||
openApiService.validPath({
|
||||
deprecated: true,
|
||||
operationId: 'getEvents',
|
||||
tags: ['Events'],
|
||||
responses: {
|
||||
@ -84,6 +86,7 @@ export default class EventController extends Controller {
|
||||
permission: NONE,
|
||||
middleware: [
|
||||
openApiService.validPath({
|
||||
deprecated: true,
|
||||
operationId: 'getEventsForToggle',
|
||||
tags: ['Events'],
|
||||
responses: {
|
||||
@ -127,15 +130,21 @@ export default class EventController extends Controller {
|
||||
}
|
||||
|
||||
async getEvents(
|
||||
req: Request<any, any, any, { project?: string }>,
|
||||
req: IAuthRequest<any, any, any, { project?: string }>,
|
||||
res: Response<EventsSchema>,
|
||||
): Promise<void> {
|
||||
const { project } = req.query;
|
||||
const { user, query } = req;
|
||||
const { project } = query;
|
||||
let eventList: IEventList;
|
||||
if (project) {
|
||||
eventList = await this.eventService.deprecatedSearchEvents({
|
||||
project,
|
||||
});
|
||||
eventList = await this.eventService.searchEvents(
|
||||
{
|
||||
project: `IS:${project}`,
|
||||
offset: 0,
|
||||
limit: 50,
|
||||
},
|
||||
extractUserIdFromUser(user),
|
||||
);
|
||||
} else {
|
||||
eventList = await this.eventService.getEvents();
|
||||
}
|
||||
@ -155,17 +164,23 @@ export default class EventController extends Controller {
|
||||
}
|
||||
|
||||
async getEventsForToggle(
|
||||
req: Request<{ featureName: string }>,
|
||||
req: IAuthRequest<{ featureName: string }>,
|
||||
res: Response<FeatureEventsSchema>,
|
||||
): Promise<void> {
|
||||
const feature = req.params.featureName;
|
||||
const eventList = await this.eventService.deprecatedSearchEvents({
|
||||
feature,
|
||||
});
|
||||
const { user, params } = req;
|
||||
const { featureName } = params;
|
||||
const eventList = await this.eventService.searchEvents(
|
||||
{
|
||||
feature: `IS:${featureName}`,
|
||||
offset: 0,
|
||||
limit: 50,
|
||||
},
|
||||
extractUserIdFromUser(user),
|
||||
);
|
||||
|
||||
const response = {
|
||||
version,
|
||||
toggleName: feature,
|
||||
toggleName: featureName,
|
||||
events: serializeDates(this.maybeAnonymiseEvents(eventList.events)),
|
||||
totalEvents: eventList.totalEvents,
|
||||
};
|
||||
|
@ -1,9 +1,6 @@
|
||||
import type { IBaseEvent, IEvent } from '../../events/index.js';
|
||||
import type { Store } from './store.js';
|
||||
import type {
|
||||
DeprecatedSearchEventsSchema,
|
||||
ProjectActivitySchema,
|
||||
} from '../../openapi/index.js';
|
||||
import type { ProjectActivitySchema } from '../../openapi/index.js';
|
||||
import type EventEmitter from 'events';
|
||||
import type { IQueryOperations } from '../../features/events/event-store.js';
|
||||
import type { IQueryParam } from '../../features/feature-toggle/types/feature-toggle-strategies-store-type.js';
|
||||
@ -29,16 +26,10 @@ export interface IEventStore
|
||||
batchStore(events: IBaseEvent[]): Promise<void>;
|
||||
getEvents(): Promise<IEvent[]>;
|
||||
count(): Promise<number>;
|
||||
deprecatedFilteredCount(
|
||||
search: DeprecatedSearchEventsSchema,
|
||||
): Promise<number>;
|
||||
searchEventsCount(
|
||||
params: IEventSearchParams,
|
||||
queryParams: IQueryParam[],
|
||||
query?: IEventSearchParams['query'],
|
||||
): Promise<number>;
|
||||
deprecatedSearchEvents(
|
||||
search: DeprecatedSearchEventsSchema,
|
||||
): Promise<IEvent[]>;
|
||||
searchEvents(
|
||||
params: IEventSearchParams,
|
||||
queryParams: IQueryParam[],
|
||||
|
@ -36,9 +36,19 @@ test('Can create new setting', async () => {
|
||||
|
||||
expect(actual).toStrictEqual(someData);
|
||||
const { eventStore } = stores;
|
||||
const createdEvents = await eventStore.deprecatedSearchEvents({
|
||||
type: SETTING_CREATED,
|
||||
});
|
||||
const createdEvents = await eventStore.searchEvents(
|
||||
{
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
},
|
||||
[
|
||||
{
|
||||
field: 'type',
|
||||
operator: 'IS',
|
||||
values: [SETTING_CREATED],
|
||||
},
|
||||
],
|
||||
);
|
||||
expect(createdEvents).toHaveLength(1);
|
||||
expect(createdEvents[0].data).toEqual({ id: 'some-setting', some: 'blob' });
|
||||
});
|
||||
@ -51,9 +61,19 @@ test('Can delete setting', async () => {
|
||||
const actual = await service.get('some-setting');
|
||||
expect(actual).toBeUndefined();
|
||||
const { eventStore } = stores;
|
||||
const createdEvents = await eventStore.deprecatedSearchEvents({
|
||||
type: SETTING_DELETED,
|
||||
});
|
||||
const createdEvents = await eventStore.searchEvents(
|
||||
{
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
},
|
||||
[
|
||||
{
|
||||
field: 'type',
|
||||
operator: 'IS',
|
||||
values: [SETTING_DELETED],
|
||||
},
|
||||
],
|
||||
);
|
||||
expect(createdEvents).toHaveLength(1);
|
||||
});
|
||||
|
||||
@ -66,9 +86,19 @@ test('Sentitive SSO settings are redacted in event log', async () => {
|
||||
const actual = await service.get(property);
|
||||
const { eventStore } = stores;
|
||||
|
||||
const updatedEvents = await eventStore.deprecatedSearchEvents({
|
||||
type: SETTING_UPDATED,
|
||||
});
|
||||
const updatedEvents = await eventStore.searchEvents(
|
||||
{
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
},
|
||||
[
|
||||
{
|
||||
field: 'type',
|
||||
operator: 'IS',
|
||||
values: [SETTING_UPDATED],
|
||||
},
|
||||
],
|
||||
);
|
||||
expect(updatedEvents[0].preData).toEqual({ hideEventDetails: true });
|
||||
await service.delete(property, TEST_AUDIT_USER);
|
||||
});
|
||||
@ -83,9 +113,19 @@ test('Can update setting', async () => {
|
||||
TEST_AUDIT_USER,
|
||||
false,
|
||||
);
|
||||
const updatedEvents = await eventStore.deprecatedSearchEvents({
|
||||
type: SETTING_UPDATED,
|
||||
});
|
||||
const updatedEvents = await eventStore.searchEvents(
|
||||
{
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
},
|
||||
[
|
||||
{
|
||||
field: 'type',
|
||||
operator: 'IS',
|
||||
values: [SETTING_UPDATED],
|
||||
},
|
||||
],
|
||||
);
|
||||
expect(updatedEvents).toHaveLength(1);
|
||||
expect(updatedEvents[0].data).toEqual({
|
||||
id: 'updated-setting',
|
||||
|
@ -243,13 +243,33 @@ test('Should get all events of type', async () => {
|
||||
return eventStore.store(event);
|
||||
}),
|
||||
);
|
||||
const featureCreatedEvents = await eventStore.deprecatedSearchEvents({
|
||||
type: FEATURE_CREATED,
|
||||
});
|
||||
const featureCreatedEvents = await eventStore.searchEvents(
|
||||
{
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
},
|
||||
[
|
||||
{
|
||||
field: 'type',
|
||||
operator: 'IS',
|
||||
values: [FEATURE_CREATED],
|
||||
},
|
||||
],
|
||||
);
|
||||
expect(featureCreatedEvents).toHaveLength(3);
|
||||
const featureDeletedEvents = await eventStore.deprecatedSearchEvents({
|
||||
type: FEATURE_DELETED,
|
||||
});
|
||||
const featureDeletedEvents = await eventStore.searchEvents(
|
||||
{
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
},
|
||||
[
|
||||
{
|
||||
field: 'type',
|
||||
operator: 'IS',
|
||||
values: [FEATURE_DELETED],
|
||||
},
|
||||
],
|
||||
);
|
||||
expect(featureDeletedEvents).toHaveLength(3);
|
||||
});
|
||||
|
||||
|
14
src/test/fixtures/fake-event-store.ts
vendored
14
src/test/fixtures/fake-event-store.ts
vendored
@ -2,10 +2,7 @@ import type { IEventStore } from '../../lib/types/stores/event-store.js';
|
||||
import type { IBaseEvent, IEvent } from '../../lib/events/index.js';
|
||||
import { sharedEventEmitter } from '../../lib/util/anyEventEmitter.js';
|
||||
import type { IQueryOperations } from '../../lib/features/events/event-store.js';
|
||||
import type {
|
||||
DeprecatedSearchEventsSchema,
|
||||
ProjectActivitySchema,
|
||||
} from '../../lib/openapi/index.js';
|
||||
import type { ProjectActivitySchema } from '../../lib/openapi/index.js';
|
||||
import type EventEmitter from 'events';
|
||||
|
||||
class FakeEventStore implements IEventStore {
|
||||
@ -81,12 +78,6 @@ class FakeEventStore implements IEventStore {
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
deprecatedFilteredCount(
|
||||
search: DeprecatedSearchEventsSchema,
|
||||
): Promise<number> {
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
destroy(): void {}
|
||||
|
||||
async exists(key: number): Promise<boolean> {
|
||||
@ -101,9 +92,6 @@ class FakeEventStore implements IEventStore {
|
||||
return this.events;
|
||||
}
|
||||
|
||||
async deprecatedSearchEvents(): Promise<IEvent[]> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
async searchEvents(): Promise<IEvent[]> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user