mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-26 01:17:00 +02:00
refactor: prefer eventService.storeEvent methods (#4830)
https://linear.app/unleash/issue/2-1403/consider-refactoring-the-way-tags-are-fetched-for-the-events This adds 2 methods to `EventService`: - `storeEvent`; - `storeEvents`; This allows us to run event-specific logic inside these methods. In the case of this PR, this means fetching the feature tags in case the event contains a `featureName` and there are no tags specified in the event. This prevents us from having to remember to fetch the tags in order to store feature-related events except for very specific cases, like the deletion of a feature - You can't fetch tags for a feature that no longer exists, so in that case we need to pre-fetch the tags before deleting the feature. This also allows us to do any event-specific post-processing to the event before reaching the DB layer. In general I think it's also nicer that we reference the event service instead of the event store directly. There's a lot of changes and a lot of files touched, but most of it is boilerplate to inject the `eventService` where needed instead of using the `eventStore` directly. Hopefully this will be a better approach than https://github.com/Unleash/unleash/pull/4729 --------- Co-authored-by: Gastón Fournier <gaston@getunleash.io>
This commit is contained in:
parent
a06037625d
commit
87d9497be9
@ -5,13 +5,15 @@ import { AccountStore } from '../../db/account-store';
|
||||
import RoleStore from '../../db/role-store';
|
||||
import EnvironmentStore from '../../db/environment-store';
|
||||
import { AccessStore } from '../../db/access-store';
|
||||
import { AccessService, GroupService } from '../../services';
|
||||
import { AccessService, EventService, GroupService } from '../../services';
|
||||
import FakeGroupStore from '../../../test/fixtures/fake-group-store';
|
||||
import FakeEventStore from '../../../test/fixtures/fake-event-store';
|
||||
import { FakeAccountStore } from '../../../test/fixtures/fake-account-store';
|
||||
import FakeRoleStore from '../../../test/fixtures/fake-role-store';
|
||||
import FakeEnvironmentStore from '../../../test/fixtures/fake-environment-store';
|
||||
import FakeAccessStore from '../../../test/fixtures/fake-access-store';
|
||||
import FeatureTagStore from '../../db/feature-tag-store';
|
||||
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
|
||||
|
||||
export const createAccessService = (
|
||||
db: Db,
|
||||
@ -24,9 +26,15 @@ export const createAccessService = (
|
||||
const roleStore = new RoleStore(db, eventBus, getLogger);
|
||||
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
|
||||
const accessStore = new AccessStore(db, eventBus, getLogger);
|
||||
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore },
|
||||
config,
|
||||
);
|
||||
const groupService = new GroupService(
|
||||
{ groupStore, eventStore, accountStore },
|
||||
{ groupStore, accountStore },
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
|
||||
return new AccessService(
|
||||
@ -46,9 +54,15 @@ export const createFakeAccessService = (
|
||||
const roleStore = new FakeRoleStore();
|
||||
const environmentStore = new FakeEnvironmentStore();
|
||||
const accessStore = new FakeAccessStore(roleStore);
|
||||
const featureTagStore = new FakeFeatureTagStore();
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore },
|
||||
config,
|
||||
);
|
||||
const groupService = new GroupService(
|
||||
{ groupStore, eventStore, accountStore },
|
||||
{ groupStore, accountStore },
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
|
||||
return new AccessService(
|
||||
|
@ -12,6 +12,7 @@ import ContextFieldStore from '../../db/context-field-store';
|
||||
import FeatureStrategiesStore from '../../db/feature-strategy-store';
|
||||
import {
|
||||
ContextService,
|
||||
EventService,
|
||||
FeatureTagService,
|
||||
StrategyService,
|
||||
TagTypeService,
|
||||
@ -63,36 +64,45 @@ export const createFakeExportImportTogglesService = (
|
||||
const featureToggleService = createFakeFeatureToggleService(config);
|
||||
const privateProjectChecker = createFakePrivateProjectChecker();
|
||||
|
||||
const eventService = new EventService(
|
||||
{
|
||||
eventStore,
|
||||
featureTagStore,
|
||||
},
|
||||
config,
|
||||
);
|
||||
|
||||
const featureTagService = new FeatureTagService(
|
||||
{
|
||||
tagStore,
|
||||
featureTagStore,
|
||||
eventStore,
|
||||
featureToggleStore,
|
||||
},
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
const contextService = new ContextService(
|
||||
{
|
||||
projectStore,
|
||||
eventStore,
|
||||
contextFieldStore,
|
||||
featureStrategiesStore,
|
||||
},
|
||||
{ getLogger, flagResolver },
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
const strategyService = new StrategyService(
|
||||
{ strategyStore, eventStore },
|
||||
{ strategyStore },
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
const tagTypeService = new TagTypeService(
|
||||
{ tagTypeStore, eventStore },
|
||||
{ tagTypeStore },
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
const exportImportService = new ExportImportService(
|
||||
{
|
||||
eventStore,
|
||||
importTogglesStore,
|
||||
featureStrategiesStore,
|
||||
contextFieldStore,
|
||||
@ -107,6 +117,7 @@ export const createFakeExportImportTogglesService = (
|
||||
featureToggleService,
|
||||
featureTagService,
|
||||
accessService,
|
||||
eventService,
|
||||
contextService,
|
||||
strategyService,
|
||||
tagTypeService,
|
||||
@ -160,36 +171,45 @@ export const createExportImportTogglesService = (
|
||||
const featureToggleService = createFeatureToggleService(db, config);
|
||||
const privateProjectChecker = createPrivateProjectChecker(db, config);
|
||||
|
||||
const eventService = new EventService(
|
||||
{
|
||||
eventStore,
|
||||
featureTagStore,
|
||||
},
|
||||
config,
|
||||
);
|
||||
|
||||
const featureTagService = new FeatureTagService(
|
||||
{
|
||||
tagStore,
|
||||
featureTagStore,
|
||||
eventStore,
|
||||
featureToggleStore,
|
||||
},
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
const contextService = new ContextService(
|
||||
{
|
||||
projectStore,
|
||||
eventStore,
|
||||
contextFieldStore,
|
||||
featureStrategiesStore,
|
||||
},
|
||||
{ getLogger, flagResolver },
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
const strategyService = new StrategyService(
|
||||
{ strategyStore, eventStore },
|
||||
{ strategyStore },
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
const tagTypeService = new TagTypeService(
|
||||
{ tagTypeStore, eventStore },
|
||||
{ tagTypeStore },
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
const exportImportService = new ExportImportService(
|
||||
{
|
||||
eventStore,
|
||||
importTogglesStore,
|
||||
featureStrategiesStore,
|
||||
contextFieldStore,
|
||||
@ -204,6 +224,7 @@ export const createExportImportTogglesService = (
|
||||
featureToggleService,
|
||||
featureTagService,
|
||||
accessService,
|
||||
eventService,
|
||||
contextService,
|
||||
strategyService,
|
||||
tagTypeService,
|
||||
|
@ -8,7 +8,6 @@ import {
|
||||
import { Logger } from '../../logger';
|
||||
import { IFeatureTagStore } from '../../types/stores/feature-tag-store';
|
||||
import { ITagTypeStore } from '../../types/stores/tag-type-store';
|
||||
import { IEventStore } from '../../types/stores/event-store';
|
||||
import { IStrategy } from '../../types/stores/strategy-store';
|
||||
import { IFeatureToggleStore } from '../../types/stores/feature-toggle-store';
|
||||
import { IFeatureStrategiesStore } from '../../types/stores/feature-strategies-store';
|
||||
@ -35,6 +34,7 @@ import { extractUsernameFromUser } from '../../util';
|
||||
import {
|
||||
AccessService,
|
||||
ContextService,
|
||||
EventService,
|
||||
FeatureTagService,
|
||||
FeatureToggleService,
|
||||
StrategyService,
|
||||
@ -57,8 +57,6 @@ export default class ExportImportService {
|
||||
|
||||
private featureStrategiesStore: IFeatureStrategiesStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
|
||||
private importTogglesStore: IImportTogglesStore;
|
||||
|
||||
private tagTypeStore: ITagTypeStore;
|
||||
@ -81,6 +79,8 @@ export default class ExportImportService {
|
||||
|
||||
private accessService: AccessService;
|
||||
|
||||
private eventService: EventService;
|
||||
|
||||
private tagTypeService: TagTypeService;
|
||||
|
||||
private featureTagService: FeatureTagService;
|
||||
@ -91,7 +91,6 @@ export default class ExportImportService {
|
||||
stores: Pick<
|
||||
IUnleashStores,
|
||||
| 'importTogglesStore'
|
||||
| 'eventStore'
|
||||
| 'featureStrategiesStore'
|
||||
| 'featureToggleStore'
|
||||
| 'featureEnvironmentStore'
|
||||
@ -109,6 +108,7 @@ export default class ExportImportService {
|
||||
strategyService,
|
||||
contextService,
|
||||
accessService,
|
||||
eventService,
|
||||
tagTypeService,
|
||||
featureTagService,
|
||||
}: Pick<
|
||||
@ -117,11 +117,11 @@ export default class ExportImportService {
|
||||
| 'strategyService'
|
||||
| 'contextService'
|
||||
| 'accessService'
|
||||
| 'eventService'
|
||||
| 'tagTypeService'
|
||||
| 'featureTagService'
|
||||
>,
|
||||
) {
|
||||
this.eventStore = stores.eventStore;
|
||||
this.toggleStore = stores.featureToggleStore;
|
||||
this.importTogglesStore = stores.importTogglesStore;
|
||||
this.featureStrategiesStore = stores.featureStrategiesStore;
|
||||
@ -135,6 +135,7 @@ export default class ExportImportService {
|
||||
this.strategyService = strategyService;
|
||||
this.contextService = contextService;
|
||||
this.accessService = accessService;
|
||||
this.eventService = eventService;
|
||||
this.tagTypeService = tagTypeService;
|
||||
this.featureTagService = featureTagService;
|
||||
this.importPermissionsService = new ImportPermissionsService(
|
||||
@ -237,7 +238,7 @@ export default class ExportImportService {
|
||||
await this.importToggleLevelInfo(cleanedDto, user);
|
||||
|
||||
await this.importDefault(cleanedDto, user);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
project: cleanedDto.project,
|
||||
environment: cleanedDto.environment,
|
||||
type: FEATURES_IMPORTED,
|
||||
@ -726,7 +727,7 @@ export default class ExportImportService {
|
||||
}),
|
||||
tagTypes: filteredTagTypes,
|
||||
};
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: FEATURES_EXPORTED,
|
||||
createdBy: userName,
|
||||
data: result,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {
|
||||
AccessService,
|
||||
EventService,
|
||||
FeatureToggleService,
|
||||
GroupService,
|
||||
} from '../../services';
|
||||
@ -7,7 +8,6 @@ import FeatureStrategiesStore from '../../db/feature-strategy-store';
|
||||
import FeatureToggleStore from '../../db/feature-toggle-store';
|
||||
import FeatureToggleClientStore from '../../db/feature-toggle-client-store';
|
||||
import ProjectStore from '../../db/project-store';
|
||||
import FeatureTagStore from '../../db/feature-tag-store';
|
||||
import { FeatureEnvironmentStore } from '../../db/feature-environment-store';
|
||||
import ContextFieldStore from '../../db/context-field-store';
|
||||
import GroupStore from '../../db/group-store';
|
||||
@ -22,7 +22,6 @@ import FakeFeatureStrategiesStore from '../../../test/fixtures/fake-feature-stra
|
||||
import FakeFeatureToggleStore from '../../../test/fixtures/fake-feature-toggle-store';
|
||||
import FakeFeatureToggleClientStore from '../../../test/fixtures/fake-feature-toggle-client-store';
|
||||
import FakeProjectStore from '../../../test/fixtures/fake-project-store';
|
||||
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
|
||||
import FakeFeatureEnvironmentStore from '../../../test/fixtures/fake-feature-environment-store';
|
||||
import FakeContextFieldStore from '../../../test/fixtures/fake-context-field-store';
|
||||
import FakeGroupStore from '../../../test/fixtures/fake-group-store';
|
||||
@ -47,6 +46,8 @@ import {
|
||||
} from '../private-project/createPrivateProjectChecker';
|
||||
import { DependentFeaturesReadModel } from '../dependent-features/dependent-features-read-model';
|
||||
import { FakeDependentFeaturesReadModel } from '../dependent-features/fake-dependent-features-read-model';
|
||||
import FeatureTagStore from '../../db/feature-tag-store';
|
||||
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
|
||||
|
||||
export const createFeatureToggleService = (
|
||||
db: Db,
|
||||
@ -72,7 +73,6 @@ export const createFeatureToggleService = (
|
||||
getLogger,
|
||||
flagResolver,
|
||||
);
|
||||
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
|
||||
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
||||
db,
|
||||
eventBus,
|
||||
@ -87,13 +87,19 @@ export const createFeatureToggleService = (
|
||||
const strategyStore = new StrategyStore(db, getLogger);
|
||||
const accountStore = new AccountStore(db, getLogger);
|
||||
const accessStore = new AccessStore(db, eventBus, getLogger);
|
||||
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
|
||||
const roleStore = new RoleStore(db, eventBus, getLogger);
|
||||
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
|
||||
const eventStore = new EventStore(db, getLogger);
|
||||
const groupService = new GroupService(
|
||||
{ groupStore, eventStore, accountStore },
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore },
|
||||
{ getLogger },
|
||||
);
|
||||
const groupService = new GroupService(
|
||||
{ groupStore, accountStore },
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
const accessService = new AccessService(
|
||||
{ accessStore, accountStore, roleStore, environmentStore, groupStore },
|
||||
{ getLogger, flagResolver },
|
||||
@ -115,7 +121,6 @@ export const createFeatureToggleService = (
|
||||
featureToggleStore,
|
||||
featureToggleClientStore,
|
||||
projectStore,
|
||||
eventStore,
|
||||
featureTagStore,
|
||||
featureEnvironmentStore,
|
||||
contextFieldStore,
|
||||
@ -124,6 +129,7 @@ export const createFeatureToggleService = (
|
||||
{ getLogger, flagResolver },
|
||||
segmentService,
|
||||
accessService,
|
||||
eventService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
dependentFeaturesReadModel,
|
||||
@ -141,18 +147,23 @@ export const createFakeFeatureToggleService = (
|
||||
const featureToggleStore = new FakeFeatureToggleStore();
|
||||
const featureToggleClientStore = new FakeFeatureToggleClientStore();
|
||||
const projectStore = new FakeProjectStore();
|
||||
const featureTagStore = new FakeFeatureTagStore();
|
||||
const featureEnvironmentStore = new FakeFeatureEnvironmentStore();
|
||||
const contextFieldStore = new FakeContextFieldStore();
|
||||
const groupStore = new FakeGroupStore();
|
||||
const accountStore = new FakeAccountStore();
|
||||
const accessStore = new FakeAccessStore();
|
||||
const featureTagStore = new FakeFeatureTagStore();
|
||||
const roleStore = new FakeRoleStore();
|
||||
const environmentStore = new FakeEnvironmentStore();
|
||||
const groupService = new GroupService(
|
||||
{ groupStore, eventStore, accountStore },
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore },
|
||||
{ getLogger },
|
||||
);
|
||||
const groupService = new GroupService(
|
||||
{ groupStore, accountStore },
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
const accessService = new AccessService(
|
||||
{ accessStore, accountStore, roleStore, environmentStore, groupStore },
|
||||
{ getLogger, flagResolver },
|
||||
@ -168,7 +179,6 @@ export const createFakeFeatureToggleService = (
|
||||
featureToggleStore,
|
||||
featureToggleClientStore,
|
||||
projectStore,
|
||||
eventStore,
|
||||
featureTagStore,
|
||||
featureEnvironmentStore,
|
||||
contextFieldStore,
|
||||
@ -177,6 +187,7 @@ export const createFakeFeatureToggleService = (
|
||||
{ getLogger, flagResolver },
|
||||
segmentService,
|
||||
accessService,
|
||||
eventService,
|
||||
changeRequestAccessReadModel,
|
||||
fakePrivateProjectChecker,
|
||||
dependentFeaturesReadModel,
|
||||
|
@ -1,21 +1,28 @@
|
||||
import { IUnleashConfig } from '../../types';
|
||||
import { GroupService } from '../../services';
|
||||
import { EventService, GroupService } from '../../services';
|
||||
import { Db } from '../../db/db';
|
||||
import GroupStore from '../../db/group-store';
|
||||
import { AccountStore } from '../../db/account-store';
|
||||
import EventStore from '../../db/event-store';
|
||||
import FeatureTagStore from '../../db/feature-tag-store';
|
||||
|
||||
export const createGroupService = (
|
||||
db: Db,
|
||||
config: IUnleashConfig,
|
||||
): GroupService => {
|
||||
const { getLogger } = config;
|
||||
const { getLogger, eventBus } = config;
|
||||
const groupStore = new GroupStore(db);
|
||||
const accountStore = new AccountStore(db, getLogger);
|
||||
const eventStore = new EventStore(db, getLogger);
|
||||
const groupService = new GroupService(
|
||||
{ groupStore, eventStore, accountStore },
|
||||
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore },
|
||||
{ getLogger },
|
||||
);
|
||||
const groupService = new GroupService(
|
||||
{ groupStore, accountStore },
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
return groupService;
|
||||
};
|
||||
|
@ -5,6 +5,7 @@ import { AccountStore } from '../../db/account-store';
|
||||
import EnvironmentStore from '../../db/environment-store';
|
||||
import {
|
||||
AccessService,
|
||||
EventService,
|
||||
FavoritesService,
|
||||
GroupService,
|
||||
ProjectService,
|
||||
@ -39,6 +40,7 @@ import {
|
||||
createFakePrivateProjectChecker,
|
||||
createPrivateProjectChecker,
|
||||
} from '../private-project/createPrivateProjectChecker';
|
||||
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
|
||||
|
||||
export const createProjectService = (
|
||||
db: Db,
|
||||
@ -75,17 +77,25 @@ export const createProjectService = (
|
||||
eventBus,
|
||||
getLogger,
|
||||
);
|
||||
const eventService = new EventService(
|
||||
{
|
||||
eventStore,
|
||||
featureTagStore: new FakeFeatureTagStore(),
|
||||
},
|
||||
config,
|
||||
);
|
||||
const favoriteService = new FavoritesService(
|
||||
{
|
||||
favoriteFeaturesStore,
|
||||
favoriteProjectsStore,
|
||||
eventStore,
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
const groupService = new GroupService(
|
||||
{ groupStore, eventStore, accountStore },
|
||||
{ groupStore, accountStore },
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
|
||||
const privateProjectChecker = createPrivateProjectChecker(db, config);
|
||||
@ -106,6 +116,7 @@ export const createProjectService = (
|
||||
featureToggleService,
|
||||
groupService,
|
||||
favoriteService,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
};
|
||||
@ -127,17 +138,25 @@ export const createFakeProjectService = (
|
||||
const featureToggleService = createFakeFeatureToggleService(config);
|
||||
const favoriteFeaturesStore = new FakeFavoriteFeaturesStore();
|
||||
const favoriteProjectsStore = new FakeFavoriteProjectsStore();
|
||||
const eventService = new EventService(
|
||||
{
|
||||
eventStore,
|
||||
featureTagStore: new FakeFeatureTagStore(),
|
||||
},
|
||||
config,
|
||||
);
|
||||
const favoriteService = new FavoritesService(
|
||||
{
|
||||
favoriteFeaturesStore,
|
||||
favoriteProjectsStore,
|
||||
eventStore,
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
const groupService = new GroupService(
|
||||
{ groupStore, eventStore, accountStore },
|
||||
{ groupStore, accountStore },
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
|
||||
const privateProjectChecker = createFakePrivateProjectChecker();
|
||||
@ -158,6 +177,7 @@ export const createFakeProjectService = (
|
||||
featureToggleService,
|
||||
groupService,
|
||||
favoriteService,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Db, IUnleashConfig } from 'lib/server-impl';
|
||||
import EventStore from '../../db/event-store';
|
||||
import { SegmentService } from '../../services';
|
||||
import { EventService, SegmentService } from '../../services';
|
||||
import FakeEventStore from '../../../test/fixtures/fake-event-store';
|
||||
import { ISegmentService } from '../../segments/segment-service-interface';
|
||||
import FeatureStrategiesStore from '../../db/feature-strategy-store';
|
||||
@ -15,6 +15,8 @@ import {
|
||||
createFakePrivateProjectChecker,
|
||||
createPrivateProjectChecker,
|
||||
} from '../private-project/createPrivateProjectChecker';
|
||||
import FeatureTagStore from '../../db/feature-tag-store';
|
||||
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
|
||||
|
||||
export const createSegmentService = (
|
||||
db: Db,
|
||||
@ -40,10 +42,19 @@ export const createSegmentService = (
|
||||
);
|
||||
const privateProjectChecker = createPrivateProjectChecker(db, config);
|
||||
|
||||
const eventService = new EventService(
|
||||
{
|
||||
eventStore,
|
||||
featureTagStore: new FeatureTagStore(db, eventBus, getLogger),
|
||||
},
|
||||
config,
|
||||
);
|
||||
|
||||
return new SegmentService(
|
||||
{ segmentStore, featureStrategiesStore, eventStore },
|
||||
{ segmentStore, featureStrategiesStore },
|
||||
changeRequestAccessReadModel,
|
||||
config,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
};
|
||||
@ -58,10 +69,19 @@ export const createFakeSegmentService = (
|
||||
|
||||
const privateProjectChecker = createFakePrivateProjectChecker();
|
||||
|
||||
const eventService = new EventService(
|
||||
{
|
||||
eventStore,
|
||||
featureTagStore: new FakeFeatureTagStore(),
|
||||
},
|
||||
config,
|
||||
);
|
||||
|
||||
return new SegmentService(
|
||||
{ segmentStore, featureStrategiesStore, eventStore },
|
||||
{ segmentStore, featureStrategiesStore },
|
||||
changeRequestAccessReadModel,
|
||||
config,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
};
|
||||
|
@ -4,10 +4,11 @@ import { createTestConfig } from '../../test/config/test-config';
|
||||
import FakeEventStore from '../../test/fixtures/fake-event-store';
|
||||
import { randomId } from '../util/random-id';
|
||||
import FakeProjectStore from '../../test/fixtures/fake-project-store';
|
||||
import { ProxyService, SettingService } from '../../lib/services';
|
||||
import { EventService, ProxyService, SettingService } from '../../lib/services';
|
||||
import { ISettingStore } from '../../lib/types';
|
||||
import { frontendSettingsKey } from '../../lib/types/settings/frontend-settings';
|
||||
import { minutesToMilliseconds } from 'date-fns';
|
||||
import FakeFeatureTagStore from '../../test/fixtures/fake-feature-tag-store';
|
||||
|
||||
const createSettingService = (
|
||||
frontendApiOrigins: string[],
|
||||
@ -17,11 +18,14 @@ const createSettingService = (
|
||||
const stores = {
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
featureTagStore: new FakeFeatureTagStore(),
|
||||
projectStore: new FakeProjectStore(),
|
||||
};
|
||||
|
||||
const eventService = new EventService(stores, config);
|
||||
|
||||
const services = {
|
||||
settingService: new SettingService(stores, config),
|
||||
settingService: new SettingService(stores, config, eventService),
|
||||
};
|
||||
|
||||
return {
|
||||
@ -135,8 +139,8 @@ test('corsOriginMiddleware with caching enabled', async () => {
|
||||
|
||||
/*
|
||||
This is needed because it is not enough to fake time to test the
|
||||
updated cache, we also need to make sure that all promises are
|
||||
executed and completed, in the right order.
|
||||
updated cache, we also need to make sure that all promises are
|
||||
executed and completed, in the right order.
|
||||
*/
|
||||
await new Promise<void>((resolve) =>
|
||||
process.nextTick(async () => {
|
||||
|
@ -22,7 +22,11 @@ async function getSetup(anonymise: boolean = false) {
|
||||
const services = createServices(stores, config);
|
||||
const app = await getApp(config, stores, services);
|
||||
|
||||
return { base, eventStore: stores.eventStore, request: supertest(app) };
|
||||
return {
|
||||
base,
|
||||
eventService: services.eventService,
|
||||
request: supertest(app),
|
||||
};
|
||||
}
|
||||
|
||||
test('should get empty events list via admin', async () => {
|
||||
@ -38,14 +42,13 @@ test('should get empty events list via admin', async () => {
|
||||
});
|
||||
|
||||
test('should get events list via admin', async () => {
|
||||
const { request, base, eventStore } = await getSetup();
|
||||
eventStore.store(
|
||||
const { request, base, eventService } = await getSetup();
|
||||
eventService.storeEvent(
|
||||
new FeatureCreatedEvent({
|
||||
createdBy: 'some@email.com',
|
||||
data: { name: 'test', project: 'default' },
|
||||
featureName: 'test',
|
||||
project: 'default',
|
||||
tags: [],
|
||||
}),
|
||||
);
|
||||
const { body } = await request
|
||||
@ -58,14 +61,13 @@ test('should get events list via admin', async () => {
|
||||
});
|
||||
|
||||
test('should anonymise events list via admin', async () => {
|
||||
const { request, base, eventStore } = await getSetup(true);
|
||||
eventStore.store(
|
||||
const { request, base, eventService } = await getSetup(true);
|
||||
eventService.storeEvent(
|
||||
new FeatureCreatedEvent({
|
||||
createdBy: 'some@email.com',
|
||||
data: { name: 'test', project: 'default' },
|
||||
featureName: 'test',
|
||||
project: 'default',
|
||||
tags: [],
|
||||
}),
|
||||
);
|
||||
const { body } = await request
|
||||
@ -81,15 +83,15 @@ test('should also anonymise email fields in data and preData properties', async
|
||||
const email1 = 'test1@email.com';
|
||||
const email2 = 'test2@email.com';
|
||||
|
||||
const { request, base, eventStore } = await getSetup(true);
|
||||
eventStore.store(
|
||||
const { request, base, eventService } = await getSetup(true);
|
||||
eventService.storeEvent(
|
||||
new ProjectUserAddedEvent({
|
||||
createdBy: 'some@email.com',
|
||||
data: { name: 'test', project: 'default', email: email1 },
|
||||
project: 'default',
|
||||
}),
|
||||
);
|
||||
eventStore.store(
|
||||
eventService.storeEvent(
|
||||
new ProjectUserRemovedEvent({
|
||||
createdBy: 'some@email.com',
|
||||
preData: { name: 'test', project: 'default', email: email2 },
|
||||
@ -109,8 +111,8 @@ test('should also anonymise email fields in data and preData properties', async
|
||||
test('should anonymise any PII fields, no matter the depth', async () => {
|
||||
const testUsername = 'test-username';
|
||||
|
||||
const { request, base, eventStore } = await getSetup(true);
|
||||
eventStore.store(
|
||||
const { request, base, eventService } = await getSetup(true);
|
||||
eventService.storeEvent(
|
||||
new ProjectAccessAddedEvent({
|
||||
createdBy: 'some@email.com',
|
||||
data: {
|
||||
|
@ -13,6 +13,8 @@ import { GroupService } from '../services/group-service';
|
||||
import FakeEventStore from '../../test/fixtures/fake-event-store';
|
||||
import { IRole } from 'lib/types/stores/access-store';
|
||||
import { IGroup } from 'lib/types';
|
||||
import EventService from './event-service';
|
||||
import FakeFeatureTagStore from '../../test/fixtures/fake-feature-tag-store';
|
||||
|
||||
function getSetup(customRootRolesKillSwitch: boolean = true) {
|
||||
const config = createTestConfig({
|
||||
@ -204,9 +206,14 @@ test('throws error when trying to delete a project role in use by group', async
|
||||
accessStore.get = async (): Promise<IRole> => {
|
||||
return { id: 1, type: 'custom', name: 'project role' };
|
||||
};
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore: new FakeFeatureTagStore() },
|
||||
config,
|
||||
);
|
||||
const groupService = new GroupService(
|
||||
{ groupStore, eventStore, accountStore },
|
||||
{ groupStore, accountStore },
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
|
||||
const accessService = new AccessService(
|
||||
|
@ -23,7 +23,7 @@ export class AccountService {
|
||||
private lastSeenSecrets: Set<string> = new Set<string>();
|
||||
|
||||
constructor(
|
||||
stores: Pick<IUnleashStores, 'accountStore' | 'eventStore'>,
|
||||
stores: Pick<IUnleashStores, 'accountStore'>,
|
||||
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
||||
services: {
|
||||
accessService: AccessService;
|
||||
|
@ -14,6 +14,7 @@ import AddonService from './addon-service';
|
||||
import { IAddonDto } from '../types/stores/addon-store';
|
||||
import SimpleAddon from './addon-service-test-simple-addon';
|
||||
import { IAddonProviders } from '../addons';
|
||||
import EventService from './event-service';
|
||||
|
||||
const MASKED_VALUE = '*****';
|
||||
|
||||
@ -21,7 +22,12 @@ let addonProvider: IAddonProviders;
|
||||
|
||||
function getSetup() {
|
||||
const stores = createStores();
|
||||
const tagTypeService = new TagTypeService(stores, { getLogger });
|
||||
const eventService = new EventService(stores, { getLogger });
|
||||
const tagTypeService = new TagTypeService(
|
||||
stores,
|
||||
{ getLogger },
|
||||
eventService,
|
||||
);
|
||||
|
||||
addonProvider = { simple: new SimpleAddon() };
|
||||
return {
|
||||
@ -33,8 +39,10 @@ function getSetup() {
|
||||
server: { unleashUrl: 'http://test' },
|
||||
},
|
||||
tagTypeService,
|
||||
eventService,
|
||||
addonProvider,
|
||||
),
|
||||
eventService,
|
||||
stores,
|
||||
tagTypeService,
|
||||
};
|
||||
@ -77,7 +85,7 @@ test('should not allow addon-config for unknown provider', async () => {
|
||||
});
|
||||
|
||||
test('should trigger simple-addon eventHandler', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const { addonService, eventService } = getSetup();
|
||||
|
||||
const config = {
|
||||
provider: 'simple',
|
||||
@ -93,7 +101,7 @@ test('should trigger simple-addon eventHandler', async () => {
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
|
||||
// Feature toggle was created
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
data: {
|
||||
@ -113,7 +121,7 @@ test('should trigger simple-addon eventHandler', async () => {
|
||||
});
|
||||
|
||||
test('should not trigger event handler if project of event is different from addon', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const { addonService, eventService } = getSetup();
|
||||
const config = {
|
||||
provider: 'simple',
|
||||
enabled: true,
|
||||
@ -126,7 +134,7 @@ test('should not trigger event handler if project of event is different from add
|
||||
};
|
||||
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: 'someotherproject',
|
||||
@ -144,7 +152,7 @@ test('should not trigger event handler if project of event is different from add
|
||||
});
|
||||
|
||||
test('should trigger event handler if project for event is one of the desired projects for addon', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const { addonService, eventService } = getSetup();
|
||||
const desiredProject = 'desired';
|
||||
const otherProject = 'other';
|
||||
const config = {
|
||||
@ -159,7 +167,7 @@ test('should trigger event handler if project for event is one of the desired pr
|
||||
};
|
||||
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProject,
|
||||
@ -169,7 +177,7 @@ test('should trigger event handler if project for event is one of the desired pr
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: otherProject,
|
||||
@ -189,7 +197,7 @@ test('should trigger event handler if project for event is one of the desired pr
|
||||
});
|
||||
|
||||
test('should trigger events for multiple projects if addon is setup to filter multiple projects', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const { addonService, eventService } = getSetup();
|
||||
const desiredProjects = ['desired', 'desired2'];
|
||||
const otherProject = 'other';
|
||||
const config = {
|
||||
@ -204,7 +212,7 @@ test('should trigger events for multiple projects if addon is setup to filter mu
|
||||
};
|
||||
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[0],
|
||||
@ -214,7 +222,7 @@ test('should trigger events for multiple projects if addon is setup to filter mu
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: otherProject,
|
||||
@ -224,7 +232,7 @@ test('should trigger events for multiple projects if addon is setup to filter mu
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[1],
|
||||
@ -246,7 +254,7 @@ test('should trigger events for multiple projects if addon is setup to filter mu
|
||||
});
|
||||
|
||||
test('should filter events on environment if addon is setup to filter for it', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const { addonService, eventService } = getSetup();
|
||||
const desiredEnvironment = 'desired';
|
||||
const otherEnvironment = 'other';
|
||||
const config = {
|
||||
@ -262,7 +270,7 @@ test('should filter events on environment if addon is setup to filter for it', a
|
||||
};
|
||||
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredEnvironment,
|
||||
@ -273,7 +281,7 @@ test('should filter events on environment if addon is setup to filter for it', a
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
environment: otherEnvironment,
|
||||
@ -293,7 +301,7 @@ test('should filter events on environment if addon is setup to filter for it', a
|
||||
});
|
||||
|
||||
test('should not filter out global events (no specific environment) even if addon is setup to filter for environments', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const { addonService, eventService } = getSetup();
|
||||
const filteredEnvironment = 'filtered';
|
||||
const config = {
|
||||
provider: 'simple',
|
||||
@ -319,7 +327,7 @@ test('should not filter out global events (no specific environment) even if addo
|
||||
};
|
||||
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store(globalEventWithNoEnvironment);
|
||||
await eventService.storeEvent(globalEventWithNoEnvironment);
|
||||
const simpleProvider = addonService.addonProviders.simple;
|
||||
// @ts-expect-error
|
||||
const events = simpleProvider.getEvents();
|
||||
@ -330,7 +338,7 @@ test('should not filter out global events (no specific environment) even if addo
|
||||
});
|
||||
|
||||
test('should not filter out global events (no specific project) even if addon is setup to filter for projects', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const { addonService, eventService } = getSetup();
|
||||
const filteredProject = 'filtered';
|
||||
const config = {
|
||||
provider: 'simple',
|
||||
@ -355,7 +363,7 @@ test('should not filter out global events (no specific project) even if addon is
|
||||
};
|
||||
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store(globalEventWithNoProject);
|
||||
await eventService.storeEvent(globalEventWithNoProject);
|
||||
const simpleProvider = addonService.addonProviders.simple;
|
||||
// @ts-expect-error
|
||||
const events = simpleProvider.getEvents();
|
||||
@ -366,7 +374,7 @@ test('should not filter out global events (no specific project) even if addon is
|
||||
});
|
||||
|
||||
test('should support wildcard option for filtering addons', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const { addonService, eventService } = getSetup();
|
||||
const desiredProjects = ['desired', 'desired2'];
|
||||
const otherProject = 'other';
|
||||
const config = {
|
||||
@ -381,7 +389,7 @@ test('should support wildcard option for filtering addons', async () => {
|
||||
};
|
||||
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[0],
|
||||
@ -391,7 +399,7 @@ test('should support wildcard option for filtering addons', async () => {
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: otherProject,
|
||||
@ -401,7 +409,7 @@ test('should support wildcard option for filtering addons', async () => {
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[1],
|
||||
@ -425,7 +433,7 @@ test('should support wildcard option for filtering addons', async () => {
|
||||
});
|
||||
|
||||
test('Should support filtering by both project and environment', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const { addonService, eventService } = getSetup();
|
||||
const desiredProjects = ['desired1', 'desired2', 'desired3'];
|
||||
const desiredEnvironments = ['env1', 'env2', 'env3'];
|
||||
const config = {
|
||||
@ -445,7 +453,7 @@ test('Should support filtering by both project and environment', async () => {
|
||||
'desired-toggle3',
|
||||
];
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[0],
|
||||
@ -456,7 +464,7 @@ test('Should support filtering by both project and environment', async () => {
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[0],
|
||||
@ -467,7 +475,7 @@ test('Should support filtering by both project and environment', async () => {
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[2],
|
||||
@ -478,7 +486,7 @@ test('Should support filtering by both project and environment', async () => {
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[2],
|
||||
@ -489,7 +497,7 @@ test('Should support filtering by both project and environment', async () => {
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: 'wrongproject',
|
||||
@ -556,7 +564,7 @@ test('should create tag type for simple-addon', async () => {
|
||||
});
|
||||
|
||||
test('should store ADDON_CONFIG_CREATE event', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const { addonService, eventService } = getSetup();
|
||||
|
||||
const config = {
|
||||
provider: 'simple',
|
||||
@ -571,7 +579,7 @@ test('should store ADDON_CONFIG_CREATE event', async () => {
|
||||
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
|
||||
const events = await stores.eventStore.getEvents();
|
||||
const { events } = await eventService.getEvents();
|
||||
|
||||
expect(events.length).toBe(2); // Also tag-types where created
|
||||
expect(events[1].type).toBe(ADDON_CONFIG_CREATED);
|
||||
@ -579,7 +587,7 @@ test('should store ADDON_CONFIG_CREATE event', async () => {
|
||||
});
|
||||
|
||||
test('should store ADDON_CONFIG_UPDATE event', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const { addonService, eventService } = getSetup();
|
||||
|
||||
const config: IAddonDto = {
|
||||
description: '',
|
||||
@ -597,7 +605,7 @@ test('should store ADDON_CONFIG_UPDATE event', async () => {
|
||||
const updated = { ...addonConfig, description: 'test' };
|
||||
await addonService.updateAddon(addonConfig.id, updated, 'me@mail.com');
|
||||
|
||||
const events = await stores.eventStore.getEvents();
|
||||
const { events } = await eventService.getEvents();
|
||||
|
||||
expect(events.length).toBe(3);
|
||||
expect(events[2].type).toBe(ADDON_CONFIG_UPDATED);
|
||||
@ -605,7 +613,7 @@ test('should store ADDON_CONFIG_UPDATE event', async () => {
|
||||
});
|
||||
|
||||
test('should store ADDON_CONFIG_REMOVE event', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const { addonService, eventService } = getSetup();
|
||||
|
||||
const config: IAddonDto = {
|
||||
provider: 'simple',
|
||||
@ -622,7 +630,7 @@ test('should store ADDON_CONFIG_REMOVE event', async () => {
|
||||
|
||||
await addonService.removeAddon(addonConfig.id, 'me@mail.com');
|
||||
|
||||
const events = await stores.eventStore.getEvents();
|
||||
const { events } = await eventService.getEvents();
|
||||
|
||||
expect(events.length).toBe(3);
|
||||
expect(events[2].type).toBe(ADDON_CONFIG_DELETED);
|
||||
|
@ -4,7 +4,6 @@ import { getAddons, IAddonProviders } from '../addons';
|
||||
import * as events from '../types/events';
|
||||
import { addonSchema } from './addon-schema';
|
||||
import NameExistsError from '../error/name-exists-error';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import { IFeatureToggleStore } from '../types/stores/feature-toggle-store';
|
||||
import { Logger } from '../logger';
|
||||
import TagTypeService from './tag-type-service';
|
||||
@ -12,6 +11,7 @@ import { IAddon, IAddonDto, IAddonStore } from '../types/stores/addon-store';
|
||||
import { IUnleashStores, IUnleashConfig } from '../types';
|
||||
import { IAddonDefinition } from '../types/model';
|
||||
import { minutesToMilliseconds } from 'date-fns';
|
||||
import EventService from './event-service';
|
||||
|
||||
const SUPPORTED_EVENTS = Object.keys(events).map((k) => events[k]);
|
||||
|
||||
@ -23,8 +23,6 @@ interface ISensitiveParams {
|
||||
[key: string]: string[];
|
||||
}
|
||||
export default class AddonService {
|
||||
eventStore: IEventStore;
|
||||
|
||||
addonStore: IAddonStore;
|
||||
|
||||
featureToggleStore: IFeatureToggleStore;
|
||||
@ -33,6 +31,8 @@ export default class AddonService {
|
||||
|
||||
tagTypeService: TagTypeService;
|
||||
|
||||
eventService: EventService;
|
||||
|
||||
addonProviders: IAddonProviders;
|
||||
|
||||
sensitiveParams: ISensitiveParams;
|
||||
@ -43,25 +43,22 @@ export default class AddonService {
|
||||
constructor(
|
||||
{
|
||||
addonStore,
|
||||
eventStore,
|
||||
featureToggleStore,
|
||||
}: Pick<
|
||||
IUnleashStores,
|
||||
'addonStore' | 'eventStore' | 'featureToggleStore'
|
||||
>,
|
||||
}: Pick<IUnleashStores, 'addonStore' | 'featureToggleStore'>,
|
||||
{
|
||||
getLogger,
|
||||
server,
|
||||
flagResolver,
|
||||
}: Pick<IUnleashConfig, 'getLogger' | 'server' | 'flagResolver'>,
|
||||
tagTypeService: TagTypeService,
|
||||
eventService: EventService,
|
||||
addons?: IAddonProviders,
|
||||
) {
|
||||
this.eventStore = eventStore;
|
||||
this.addonStore = addonStore;
|
||||
this.featureToggleStore = featureToggleStore;
|
||||
this.logger = getLogger('services/addon-service.js');
|
||||
this.tagTypeService = tagTypeService;
|
||||
this.eventService = eventService;
|
||||
|
||||
this.addonProviders =
|
||||
addons ||
|
||||
@ -102,7 +99,7 @@ export default class AddonService {
|
||||
|
||||
registerEventHandler(): void {
|
||||
SUPPORTED_EVENTS.forEach((eventName) =>
|
||||
this.eventStore.on(eventName, this.handleEvent(eventName)),
|
||||
this.eventService.onEvent(eventName, this.handleEvent(eventName)),
|
||||
);
|
||||
}
|
||||
|
||||
@ -205,7 +202,7 @@ export default class AddonService {
|
||||
`User ${userName} created addon ${addonConfig.provider}`,
|
||||
);
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: events.ADDON_CONFIG_CREATED,
|
||||
createdBy: userName,
|
||||
data: { provider: addonConfig.provider },
|
||||
@ -238,7 +235,7 @@ export default class AddonService {
|
||||
);
|
||||
}
|
||||
const result = await this.addonStore.update(id, addonConfig);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: events.ADDON_CONFIG_UPDATED,
|
||||
createdBy: userName,
|
||||
data: { id, provider: addonConfig.provider },
|
||||
@ -249,7 +246,7 @@ export default class AddonService {
|
||||
|
||||
async removeAddon(id: number, userName: string): Promise<void> {
|
||||
await this.addonStore.delete(id);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: events.ADDON_CONFIG_DELETED,
|
||||
createdBy: userName,
|
||||
data: { id },
|
||||
|
@ -11,6 +11,8 @@ import {
|
||||
API_TOKEN_UPDATED,
|
||||
} from '../types';
|
||||
import { addDays } from 'date-fns';
|
||||
import EventService from './event-service';
|
||||
import FakeFeatureTagStore from '../../test/fixtures/fake-feature-tag-store';
|
||||
|
||||
test('Should init api token', async () => {
|
||||
const token = {
|
||||
@ -28,16 +30,24 @@ test('Should init api token', async () => {
|
||||
});
|
||||
const apiTokenStore = new FakeApiTokenStore();
|
||||
const environmentStore = new FakeEnvironmentStore();
|
||||
const eventStore = new FakeEventStore();
|
||||
const insertCalled = new Promise((resolve) => {
|
||||
apiTokenStore.on('insert', resolve);
|
||||
});
|
||||
|
||||
new ApiTokenService(
|
||||
{ apiTokenStore, environmentStore, eventStore },
|
||||
const eventService = new EventService(
|
||||
{
|
||||
eventStore: new FakeEventStore(),
|
||||
featureTagStore: new FakeFeatureTagStore(),
|
||||
},
|
||||
config,
|
||||
);
|
||||
|
||||
new ApiTokenService(
|
||||
{ apiTokenStore, environmentStore },
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
await insertCalled;
|
||||
|
||||
const tokens = await apiTokenStore.getAll();
|
||||
@ -58,7 +68,14 @@ test("Shouldn't return frontend token when secret is undefined", async () => {
|
||||
const config: IUnleashConfig = createTestConfig({});
|
||||
const apiTokenStore = new FakeApiTokenStore();
|
||||
const environmentStore = new FakeEnvironmentStore();
|
||||
const eventStore = new FakeEventStore();
|
||||
|
||||
const eventService = new EventService(
|
||||
{
|
||||
eventStore: new FakeEventStore(),
|
||||
featureTagStore: new FakeFeatureTagStore(),
|
||||
},
|
||||
config,
|
||||
);
|
||||
|
||||
await environmentStore.create({
|
||||
name: 'default',
|
||||
@ -69,8 +86,9 @@ test("Shouldn't return frontend token when secret is undefined", async () => {
|
||||
});
|
||||
|
||||
const apiTokenService = new ApiTokenService(
|
||||
{ apiTokenStore, environmentStore, eventStore },
|
||||
{ apiTokenStore, environmentStore },
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
await apiTokenService.createApiTokenWithProjects(token);
|
||||
@ -93,7 +111,14 @@ test('Api token operations should all have events attached', async () => {
|
||||
const config: IUnleashConfig = createTestConfig({});
|
||||
const apiTokenStore = new FakeApiTokenStore();
|
||||
const environmentStore = new FakeEnvironmentStore();
|
||||
const eventStore = new FakeEventStore();
|
||||
|
||||
const eventService = new EventService(
|
||||
{
|
||||
eventStore: new FakeEventStore(),
|
||||
featureTagStore: new FakeFeatureTagStore(),
|
||||
},
|
||||
config,
|
||||
);
|
||||
|
||||
await environmentStore.create({
|
||||
name: 'default',
|
||||
@ -104,14 +129,15 @@ test('Api token operations should all have events attached', async () => {
|
||||
});
|
||||
|
||||
const apiTokenService = new ApiTokenService(
|
||||
{ apiTokenStore, environmentStore, eventStore },
|
||||
{ apiTokenStore, environmentStore },
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
let saved = await apiTokenService.createApiTokenWithProjects(token);
|
||||
let newExpiry = addDays(new Date(), 30);
|
||||
await apiTokenService.updateExpiry(saved.secret, newExpiry, 'test');
|
||||
await apiTokenService.delete(saved.secret, 'test');
|
||||
const events = await eventStore.getEvents();
|
||||
const { events } = await eventService.getEvents();
|
||||
const createdApiTokenEvents = events.filter(
|
||||
(e) => e.type === API_TOKEN_CREATED,
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import crypto from 'crypto';
|
||||
import { Logger } from '../logger';
|
||||
import { ADMIN, CLIENT, FRONTEND } from '../types/permissions';
|
||||
import { IEventStore, IUnleashStores } from '../types/stores';
|
||||
import { IUnleashStores } from '../types/stores';
|
||||
import { IUnleashConfig } from '../types/option';
|
||||
import ApiUser from '../types/api-user';
|
||||
import {
|
||||
@ -25,6 +25,7 @@ import {
|
||||
ApiTokenUpdatedEvent,
|
||||
} from '../types';
|
||||
import { omitKeys } from '../util';
|
||||
import EventService from './event-service';
|
||||
|
||||
const resolveTokenPermissions = (tokenType: string) => {
|
||||
if (tokenType === ApiTokenType.ADMIN) {
|
||||
@ -51,7 +52,7 @@ export class ApiTokenService {
|
||||
|
||||
private activeTokens: IApiToken[] = [];
|
||||
|
||||
private eventStore: IEventStore;
|
||||
private eventService: EventService;
|
||||
|
||||
private lastSeenSecrets: Set<string> = new Set<string>();
|
||||
|
||||
@ -59,15 +60,12 @@ export class ApiTokenService {
|
||||
{
|
||||
apiTokenStore,
|
||||
environmentStore,
|
||||
eventStore,
|
||||
}: Pick<
|
||||
IUnleashStores,
|
||||
'apiTokenStore' | 'environmentStore' | 'eventStore'
|
||||
>,
|
||||
}: Pick<IUnleashStores, 'apiTokenStore' | 'environmentStore'>,
|
||||
config: Pick<IUnleashConfig, 'getLogger' | 'authentication'>,
|
||||
eventService: EventService,
|
||||
) {
|
||||
this.store = apiTokenStore;
|
||||
this.eventStore = eventStore;
|
||||
this.eventService = eventService;
|
||||
this.environmentStore = environmentStore;
|
||||
this.logger = config.getLogger('/services/api-token-service.ts');
|
||||
this.fetchActiveTokens();
|
||||
@ -167,7 +165,7 @@ export class ApiTokenService {
|
||||
): Promise<IApiToken> {
|
||||
const previous = await this.store.get(secret);
|
||||
const token = await this.store.setExpiry(secret, expiresAt);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ApiTokenUpdatedEvent({
|
||||
createdBy: updatedBy,
|
||||
previousToken: omitKeys(previous, 'secret'),
|
||||
@ -181,7 +179,7 @@ export class ApiTokenService {
|
||||
if (await this.store.exists(secret)) {
|
||||
const token = await this.store.get(secret);
|
||||
await this.store.delete(secret);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ApiTokenDeletedEvent({
|
||||
createdBy: deletedBy,
|
||||
apiToken: omitKeys(token, 'secret'),
|
||||
@ -233,7 +231,7 @@ export class ApiTokenService {
|
||||
try {
|
||||
const token = await this.store.insert(newApiToken);
|
||||
this.activeTokens.push(token);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ApiTokenCreatedEvent({
|
||||
createdBy,
|
||||
apiToken: omitKeys(token, 'secret'),
|
||||
|
@ -4,13 +4,13 @@ import {
|
||||
IContextFieldDto,
|
||||
IContextFieldStore,
|
||||
} from '../types/stores/context-field-store';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import { IProjectStore } from '../types/stores/project-store';
|
||||
import { IFeatureStrategiesStore, IUnleashStores } from '../types/stores';
|
||||
import { IUnleashConfig } from '../types/option';
|
||||
import { ContextFieldStrategiesSchema } from '../openapi/spec/context-field-strategies-schema';
|
||||
import { IFeatureStrategy, IFlagResolver } from '../types';
|
||||
import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
|
||||
import EventService from './event-service';
|
||||
|
||||
const { contextSchema, nameSchema } = require('./context-schema');
|
||||
const NameExistsError = require('../error/name-exists-error');
|
||||
@ -24,7 +24,7 @@ const {
|
||||
class ContextService {
|
||||
private projectStore: IProjectStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
private eventService: EventService;
|
||||
|
||||
private contextFieldStore: IContextFieldStore;
|
||||
|
||||
@ -39,25 +39,22 @@ class ContextService {
|
||||
constructor(
|
||||
{
|
||||
projectStore,
|
||||
eventStore,
|
||||
contextFieldStore,
|
||||
featureStrategiesStore,
|
||||
}: Pick<
|
||||
IUnleashStores,
|
||||
| 'projectStore'
|
||||
| 'eventStore'
|
||||
| 'contextFieldStore'
|
||||
| 'featureStrategiesStore'
|
||||
'projectStore' | 'contextFieldStore' | 'featureStrategiesStore'
|
||||
>,
|
||||
{
|
||||
getLogger,
|
||||
flagResolver,
|
||||
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>,
|
||||
eventService: EventService,
|
||||
privateProjectChecker: IPrivateProjectChecker,
|
||||
) {
|
||||
this.privateProjectChecker = privateProjectChecker;
|
||||
this.projectStore = projectStore;
|
||||
this.eventStore = eventStore;
|
||||
this.eventService = eventService;
|
||||
this.flagResolver = flagResolver;
|
||||
this.contextFieldStore = contextFieldStore;
|
||||
this.featureStrategiesStore = featureStrategiesStore;
|
||||
@ -120,7 +117,7 @@ class ContextService {
|
||||
|
||||
// creations
|
||||
const createdField = await this.contextFieldStore.create(value);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: CONTEXT_FIELD_CREATED,
|
||||
createdBy: userName,
|
||||
data: contextField,
|
||||
@ -139,7 +136,7 @@ class ContextService {
|
||||
|
||||
// update
|
||||
await this.contextFieldStore.update(value);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: CONTEXT_FIELD_UPDATED,
|
||||
createdBy: userName,
|
||||
data: value,
|
||||
@ -152,7 +149,7 @@ class ContextService {
|
||||
|
||||
// delete
|
||||
await this.contextFieldStore.delete(name);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: CONTEXT_FIELD_DELETED,
|
||||
createdBy: userName,
|
||||
data: { name },
|
||||
|
@ -1,21 +1,29 @@
|
||||
import { IUnleashConfig } from '../types/option';
|
||||
import { IUnleashStores } from '../types/stores';
|
||||
import { IFeatureTagStore, IUnleashStores } from '../types/stores';
|
||||
import { Logger } from '../logger';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import { IEventList } from '../types/events';
|
||||
import { IBaseEvent, IEventList } from '../types/events';
|
||||
import { SearchEventsSchema } from '../openapi/spec/search-events-schema';
|
||||
import EventEmitter from 'events';
|
||||
import { ITag } from '../types';
|
||||
|
||||
export default class EventService {
|
||||
private logger: Logger;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
|
||||
private featureTagStore: IFeatureTagStore;
|
||||
|
||||
constructor(
|
||||
{ eventStore }: Pick<IUnleashStores, 'eventStore'>,
|
||||
{
|
||||
eventStore,
|
||||
featureTagStore,
|
||||
}: Pick<IUnleashStores, 'eventStore' | 'featureTagStore'>,
|
||||
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
||||
) {
|
||||
this.logger = getLogger('services/event-service.ts');
|
||||
this.eventStore = eventStore;
|
||||
this.featureTagStore = featureTagStore;
|
||||
}
|
||||
|
||||
async getEvents(): Promise<IEventList> {
|
||||
@ -35,4 +43,53 @@ export default class EventService {
|
||||
totalEvents,
|
||||
};
|
||||
}
|
||||
|
||||
async onEvent(
|
||||
eventName: string | symbol,
|
||||
listener: (...args: any[]) => void,
|
||||
): Promise<EventEmitter> {
|
||||
return this.eventStore.on(eventName, listener);
|
||||
}
|
||||
|
||||
private async enhanceEventsWithTags(
|
||||
events: IBaseEvent[],
|
||||
): Promise<IBaseEvent[]> {
|
||||
const featureNamesSet = new Set<string>();
|
||||
for (const event of events) {
|
||||
if (event.featureName && !event.tags) {
|
||||
featureNamesSet.add(event.featureName);
|
||||
}
|
||||
}
|
||||
|
||||
const featureTagsMap: Map<string, ITag[]> = new Map();
|
||||
const allTagsInFeatures = await this.featureTagStore.getAllByFeatures(
|
||||
Array.from(featureNamesSet),
|
||||
);
|
||||
|
||||
for (const tag of allTagsInFeatures) {
|
||||
const featureTags = featureTagsMap.get(tag.featureName) || [];
|
||||
featureTags.push({ value: tag.tagValue, type: tag.tagType });
|
||||
featureTagsMap.set(tag.featureName, featureTags);
|
||||
}
|
||||
|
||||
for (const event of events) {
|
||||
if (event.featureName && !event.tags) {
|
||||
event.tags = featureTagsMap.get(event.featureName);
|
||||
}
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
async storeEvent(event: IBaseEvent): Promise<void> {
|
||||
return this.storeEvents([event]);
|
||||
}
|
||||
|
||||
async storeEvents(events: IBaseEvent[]): Promise<void> {
|
||||
let enhancedEvents = events;
|
||||
for (const enhancer of [this.enhanceEventsWithTags.bind(this)]) {
|
||||
enhancedEvents = await enhancer(enhancedEvents);
|
||||
}
|
||||
return this.eventStore.batchStore(enhancedEvents);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,5 @@
|
||||
import { IUnleashConfig } from '../types/option';
|
||||
import {
|
||||
IEventStore,
|
||||
IFavoriteProjectsStore,
|
||||
IUnleashStores,
|
||||
} from '../types/stores';
|
||||
import { IFavoriteProjectsStore, IUnleashStores } from '../types/stores';
|
||||
import { Logger } from '../logger';
|
||||
import { IFavoriteFeaturesStore } from '../types/stores/favorite-features';
|
||||
import { IFavoriteFeature, IFavoriteProject } from '../types/favorites';
|
||||
@ -16,6 +12,7 @@ import {
|
||||
import User from '../types/user';
|
||||
import { extractUsernameFromUser } from '../util';
|
||||
import { IFavoriteProjectKey } from '../types/stores/favorite-projects';
|
||||
import EventService from './event-service';
|
||||
|
||||
export interface IFavoriteFeatureProps {
|
||||
feature: string;
|
||||
@ -36,24 +33,24 @@ export class FavoritesService {
|
||||
|
||||
private favoriteProjectsStore: IFavoriteProjectsStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
private eventService: EventService;
|
||||
|
||||
constructor(
|
||||
{
|
||||
favoriteFeaturesStore,
|
||||
favoriteProjectsStore,
|
||||
eventStore,
|
||||
}: Pick<
|
||||
IUnleashStores,
|
||||
'favoriteFeaturesStore' | 'favoriteProjectsStore' | 'eventStore'
|
||||
'favoriteFeaturesStore' | 'favoriteProjectsStore'
|
||||
>,
|
||||
config: IUnleashConfig,
|
||||
eventService: EventService,
|
||||
) {
|
||||
this.config = config;
|
||||
this.logger = config.getLogger('services/favorites-service.ts');
|
||||
this.favoriteFeaturesStore = favoriteFeaturesStore;
|
||||
this.favoriteProjectsStore = favoriteProjectsStore;
|
||||
this.eventStore = eventStore;
|
||||
this.eventService = eventService;
|
||||
}
|
||||
|
||||
async favoriteFeature({
|
||||
@ -64,8 +61,9 @@ export class FavoritesService {
|
||||
feature: feature,
|
||||
userId: user.id,
|
||||
});
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: FEATURE_FAVORITED,
|
||||
featureName: feature,
|
||||
createdBy: extractUsernameFromUser(user),
|
||||
data: {
|
||||
feature,
|
||||
@ -82,8 +80,9 @@ export class FavoritesService {
|
||||
feature: feature,
|
||||
userId: user.id,
|
||||
});
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: FEATURE_UNFAVORITED,
|
||||
featureName: feature,
|
||||
createdBy: extractUsernameFromUser(user),
|
||||
data: {
|
||||
feature,
|
||||
@ -100,7 +99,7 @@ export class FavoritesService {
|
||||
project,
|
||||
userId: user.id,
|
||||
});
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: PROJECT_FAVORITED,
|
||||
createdBy: extractUsernameFromUser(user),
|
||||
data: {
|
||||
@ -118,7 +117,7 @@ export class FavoritesService {
|
||||
project: project,
|
||||
userId: user.id,
|
||||
});
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: PROJECT_UNFAVORITED,
|
||||
createdBy: extractUsernameFromUser(user),
|
||||
data: {
|
||||
|
@ -11,6 +11,8 @@ import { IChangeRequestAccessReadModel } from 'lib/features/change-request-acces
|
||||
import { ISegmentService } from 'lib/segments/segment-service-interface';
|
||||
import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
|
||||
import { IDependentFeaturesReadModel } from '../features/dependent-features/dependent-features-read-model-type';
|
||||
import EventService from './event-service';
|
||||
import FakeFeatureTagStore from '../../test/fixtures/fake-feature-tag-store';
|
||||
|
||||
test('Should only store events for potentially stale on', async () => {
|
||||
expect.assertions(2);
|
||||
@ -20,16 +22,11 @@ test('Should only store events for potentially stale on', async () => {
|
||||
];
|
||||
|
||||
const config = createTestConfig();
|
||||
const featureToggleService = new FeatureToggleService(
|
||||
const eventService = new EventService(
|
||||
{
|
||||
featureToggleStore: {
|
||||
updatePotentiallyStaleFeatures: () => featureUpdates,
|
||||
},
|
||||
featureTagStore: {
|
||||
getAllTagsForFeature: () => [],
|
||||
},
|
||||
// @ts-expect-error
|
||||
eventStore: {
|
||||
batchStore: (events: IEvent[]) => {
|
||||
batchStore: async (events: IEvent[]) => {
|
||||
expect(events.length).toBe(1);
|
||||
const [event1] = events;
|
||||
|
||||
@ -40,6 +37,19 @@ test('Should only store events for potentially stale on', async () => {
|
||||
});
|
||||
},
|
||||
},
|
||||
featureTagStore: new FakeFeatureTagStore(),
|
||||
},
|
||||
config,
|
||||
);
|
||||
|
||||
const featureToggleService = new FeatureToggleService(
|
||||
{
|
||||
featureToggleStore: {
|
||||
updatePotentiallyStaleFeatures: () => featureUpdates,
|
||||
},
|
||||
featureTagStore: {
|
||||
getAllTagsForFeature: () => [],
|
||||
},
|
||||
} as unknown as IUnleashStores,
|
||||
{
|
||||
...config,
|
||||
@ -50,6 +60,7 @@ test('Should only store events for potentially stale on', async () => {
|
||||
} as unknown as IUnleashConfig,
|
||||
{} as ISegmentService,
|
||||
{} as AccessService,
|
||||
eventService,
|
||||
{} as IChangeRequestAccessReadModel,
|
||||
{} as IPrivateProjectChecker,
|
||||
{} as IDependentFeaturesReadModel,
|
||||
|
@ -8,10 +8,10 @@ import {
|
||||
IFeatureTag,
|
||||
IFeatureTagStore,
|
||||
} from '../types/stores/feature-tag-store';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import { ITagStore } from '../types/stores/tag-store';
|
||||
import { ITag } from '../types/model';
|
||||
import { BadDataError, FOREIGN_KEY_VIOLATION } from '../../lib/error';
|
||||
import EventService from './event-service';
|
||||
|
||||
class FeatureTagService {
|
||||
private tagStore: ITagStore;
|
||||
@ -20,7 +20,7 @@ class FeatureTagService {
|
||||
|
||||
private featureToggleStore: IFeatureToggleStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
private eventService: EventService;
|
||||
|
||||
private logger: Logger;
|
||||
|
||||
@ -28,19 +28,19 @@ class FeatureTagService {
|
||||
{
|
||||
tagStore,
|
||||
featureTagStore,
|
||||
eventStore,
|
||||
featureToggleStore,
|
||||
}: Pick<
|
||||
IUnleashStores,
|
||||
'tagStore' | 'featureTagStore' | 'eventStore' | 'featureToggleStore'
|
||||
'tagStore' | 'featureTagStore' | 'featureToggleStore'
|
||||
>,
|
||||
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
||||
eventService: EventService,
|
||||
) {
|
||||
this.logger = getLogger('/services/feature-tag-service.ts');
|
||||
this.tagStore = tagStore;
|
||||
this.featureTagStore = featureTagStore;
|
||||
this.featureToggleStore = featureToggleStore;
|
||||
this.eventStore = eventStore;
|
||||
this.eventService = eventService;
|
||||
}
|
||||
|
||||
async listTags(featureName: string): Promise<ITag[]> {
|
||||
@ -62,7 +62,7 @@ class FeatureTagService {
|
||||
await this.createTagIfNeeded(validatedTag, userName);
|
||||
await this.featureTagStore.tagFeature(featureName, validatedTag);
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: FEATURE_TAGGED,
|
||||
createdBy: userName,
|
||||
featureName,
|
||||
@ -126,7 +126,10 @@ class FeatureTagService {
|
||||
})),
|
||||
);
|
||||
|
||||
await this.eventStore.batchStore([...creationEvents, ...removalEvents]);
|
||||
await this.eventService.storeEvents([
|
||||
...creationEvents,
|
||||
...removalEvents,
|
||||
]);
|
||||
}
|
||||
|
||||
async createTagIfNeeded(tag: ITag, userName: string): Promise<void> {
|
||||
@ -136,7 +139,7 @@ class FeatureTagService {
|
||||
if (error instanceof NotFoundError) {
|
||||
try {
|
||||
await this.tagStore.createTag(tag);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: TAG_CREATED,
|
||||
createdBy: userName,
|
||||
data: tag,
|
||||
@ -159,13 +162,17 @@ class FeatureTagService {
|
||||
userName: string,
|
||||
): Promise<void> {
|
||||
const featureToggle = await this.featureToggleStore.get(featureName);
|
||||
const tags = await this.featureTagStore.getAllTagsForFeature(
|
||||
featureName,
|
||||
);
|
||||
await this.featureTagStore.untagFeature(featureName, tag);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: FEATURE_UNTAGGED,
|
||||
createdBy: userName,
|
||||
featureName,
|
||||
project: featureToggle.project,
|
||||
data: tag,
|
||||
tags,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import {
|
||||
FeatureVariantEvent,
|
||||
IConstraint,
|
||||
IDependency,
|
||||
IEventStore,
|
||||
IFeatureEnvironmentInfo,
|
||||
IFeatureEnvironmentStore,
|
||||
IFeatureNaming,
|
||||
@ -99,6 +98,7 @@ import { IChangeRequestAccessReadModel } from '../features/change-request-access
|
||||
import { checkFeatureFlagNamesAgainstPattern } from '../features/feature-naming-pattern/feature-naming-validation';
|
||||
import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
|
||||
import { IDependentFeaturesReadModel } from '../features/dependent-features/dependent-features-read-model-type';
|
||||
import EventService from './event-service';
|
||||
|
||||
interface IFeatureContext {
|
||||
featureName: string;
|
||||
@ -146,14 +146,14 @@ class FeatureToggleService {
|
||||
|
||||
private projectStore: IProjectStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
|
||||
private contextFieldStore: IContextFieldStore;
|
||||
|
||||
private segmentService: ISegmentService;
|
||||
|
||||
private accessService: AccessService;
|
||||
|
||||
private eventService: EventService;
|
||||
|
||||
private flagResolver: IFlagResolver;
|
||||
|
||||
private changeRequestAccessReadModel: IChangeRequestAccessReadModel;
|
||||
@ -168,7 +168,6 @@ class FeatureToggleService {
|
||||
featureToggleStore,
|
||||
featureToggleClientStore,
|
||||
projectStore,
|
||||
eventStore,
|
||||
featureTagStore,
|
||||
featureEnvironmentStore,
|
||||
contextFieldStore,
|
||||
@ -179,7 +178,6 @@ class FeatureToggleService {
|
||||
| 'featureToggleStore'
|
||||
| 'featureToggleClientStore'
|
||||
| 'projectStore'
|
||||
| 'eventStore'
|
||||
| 'featureTagStore'
|
||||
| 'featureEnvironmentStore'
|
||||
| 'contextFieldStore'
|
||||
@ -191,6 +189,7 @@ class FeatureToggleService {
|
||||
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>,
|
||||
segmentService: ISegmentService,
|
||||
accessService: AccessService,
|
||||
eventService: EventService,
|
||||
changeRequestAccessReadModel: IChangeRequestAccessReadModel,
|
||||
privateProjectChecker: IPrivateProjectChecker,
|
||||
dependentFeaturesReadModel: IDependentFeaturesReadModel,
|
||||
@ -202,11 +201,11 @@ class FeatureToggleService {
|
||||
this.featureToggleClientStore = featureToggleClientStore;
|
||||
this.tagStore = featureTagStore;
|
||||
this.projectStore = projectStore;
|
||||
this.eventStore = eventStore;
|
||||
this.featureEnvironmentStore = featureEnvironmentStore;
|
||||
this.contextFieldStore = contextFieldStore;
|
||||
this.segmentService = segmentService;
|
||||
this.accessService = accessService;
|
||||
this.eventService = eventService;
|
||||
this.flagResolver = flagResolver;
|
||||
this.changeRequestAccessReadModel = changeRequestAccessReadModel;
|
||||
this.privateProjectChecker = privateProjectChecker;
|
||||
@ -394,15 +393,12 @@ class FeatureToggleService {
|
||||
);
|
||||
|
||||
if (featureToggle.stale !== newDocument.stale) {
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureStaleEvent({
|
||||
stale: newDocument.stale,
|
||||
project,
|
||||
featureName,
|
||||
createdBy,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -502,7 +498,6 @@ class FeatureToggleService {
|
||||
|
||||
const eventData: StrategyIds = { strategyIds: newOrder };
|
||||
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
const event = new StrategiesOrderChangedEvent({
|
||||
featureName,
|
||||
environment,
|
||||
@ -510,9 +505,8 @@ class FeatureToggleService {
|
||||
createdBy,
|
||||
preData: eventPreData,
|
||||
data: eventData,
|
||||
tags: tags,
|
||||
});
|
||||
await this.eventStore.store(event);
|
||||
await this.eventService.storeEvent(event);
|
||||
}
|
||||
|
||||
async createStrategy(
|
||||
@ -606,16 +600,13 @@ class FeatureToggleService {
|
||||
segments,
|
||||
);
|
||||
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureStrategyAddEvent({
|
||||
project: projectId,
|
||||
featureName,
|
||||
createdBy,
|
||||
environment,
|
||||
data: strategy,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
return strategy;
|
||||
@ -724,13 +715,12 @@ class FeatureToggleService {
|
||||
);
|
||||
|
||||
// Store event!
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
const data = this.featureStrategyToPublic(strategy, segments);
|
||||
const preData = this.featureStrategyToPublic(
|
||||
existingStrategy,
|
||||
segments,
|
||||
);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureStrategyUpdateEvent({
|
||||
project: projectId,
|
||||
featureName,
|
||||
@ -738,7 +728,6 @@ class FeatureToggleService {
|
||||
createdBy: userName,
|
||||
data,
|
||||
preData,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
await this.optionallyDisableFeature(
|
||||
@ -770,7 +759,6 @@ class FeatureToggleService {
|
||||
id,
|
||||
existingStrategy,
|
||||
);
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
const segments = await this.segmentService.getByStrategy(
|
||||
strategy.id,
|
||||
);
|
||||
@ -779,7 +767,7 @@ class FeatureToggleService {
|
||||
existingStrategy,
|
||||
segments,
|
||||
);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureStrategyUpdateEvent({
|
||||
featureName,
|
||||
project: projectId,
|
||||
@ -787,7 +775,6 @@ class FeatureToggleService {
|
||||
createdBy: userName,
|
||||
data,
|
||||
preData,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
return data;
|
||||
@ -852,17 +839,15 @@ class FeatureToggleService {
|
||||
);
|
||||
}
|
||||
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
const preData = this.featureStrategyToPublic(existingStrategy);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureStrategyRemoveEvent({
|
||||
featureName,
|
||||
project: projectId,
|
||||
environment,
|
||||
createdBy,
|
||||
preData,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
|
||||
@ -1125,15 +1110,12 @@ class FeatureToggleService {
|
||||
);
|
||||
}
|
||||
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureCreatedEvent({
|
||||
featureName,
|
||||
createdBy,
|
||||
project: projectId,
|
||||
data: createdToggle,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
|
||||
@ -1283,16 +1265,13 @@ class FeatureToggleService {
|
||||
name: featureName,
|
||||
});
|
||||
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureMetadataUpdateEvent({
|
||||
createdBy: userName,
|
||||
data: featureToggle,
|
||||
preData,
|
||||
featureName,
|
||||
project: projectId,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
return featureToggle;
|
||||
@ -1419,15 +1398,13 @@ class FeatureToggleService {
|
||||
const { project } = feature;
|
||||
feature.stale = isStale;
|
||||
await this.featureToggleStore.update(project, feature);
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureStaleEvent({
|
||||
stale: isStale,
|
||||
project,
|
||||
featureName,
|
||||
createdBy,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
|
||||
@ -1449,13 +1426,12 @@ class FeatureToggleService {
|
||||
}
|
||||
|
||||
await this.featureToggleStore.archive(featureName);
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
await this.eventStore.store(
|
||||
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureArchivedEvent({
|
||||
featureName,
|
||||
createdBy,
|
||||
project: feature.project,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -1471,20 +1447,14 @@ class FeatureToggleService {
|
||||
featureNames,
|
||||
);
|
||||
await this.featureToggleStore.batchArchive(featureNames);
|
||||
const tags = await this.tagStore.getAllByFeatures(featureNames);
|
||||
await this.eventStore.batchStore(
|
||||
|
||||
await this.eventService.storeEvents(
|
||||
features.map(
|
||||
(feature) =>
|
||||
new FeatureArchivedEvent({
|
||||
featureName: feature.name,
|
||||
createdBy,
|
||||
project: feature.project,
|
||||
tags: tags
|
||||
.filter((tag) => tag.featureName === feature.name)
|
||||
.map((tag) => ({
|
||||
value: tag.tagValue,
|
||||
type: tag.tagType,
|
||||
})),
|
||||
}),
|
||||
),
|
||||
);
|
||||
@ -1508,8 +1478,8 @@ class FeatureToggleService {
|
||||
(feature) => feature.name,
|
||||
);
|
||||
await this.featureToggleStore.batchStale(relevantFeatureNames, stale);
|
||||
const tags = await this.tagStore.getAllByFeatures(relevantFeatureNames);
|
||||
await this.eventStore.batchStore(
|
||||
|
||||
await this.eventService.storeEvents(
|
||||
relevantFeatures.map(
|
||||
(feature) =>
|
||||
new FeatureStaleEvent({
|
||||
@ -1517,12 +1487,6 @@ class FeatureToggleService {
|
||||
project: projectId,
|
||||
featureName: feature.name,
|
||||
createdBy,
|
||||
tags: tags
|
||||
.filter((tag) => tag.featureName === feature.name)
|
||||
.map((tag) => ({
|
||||
value: tag.tagValue,
|
||||
type: tag.tagType,
|
||||
})),
|
||||
}),
|
||||
),
|
||||
);
|
||||
@ -1667,15 +1631,13 @@ class FeatureToggleService {
|
||||
const feature = await this.featureToggleStore.get(featureName);
|
||||
|
||||
if (updatedEnvironmentStatus > 0) {
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureEnvironmentEvent({
|
||||
enabled,
|
||||
project,
|
||||
featureName,
|
||||
environment,
|
||||
createdBy,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -1687,17 +1649,15 @@ class FeatureToggleService {
|
||||
featureName: string,
|
||||
createdBy: string,
|
||||
): Promise<FeatureToggleLegacy> {
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
const feature = await this.getFeatureToggleLegacy(featureName);
|
||||
|
||||
// Legacy event. Will not be used from v4.3.
|
||||
// We do not include 'preData' on purpose.
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: FEATURE_UPDATED,
|
||||
createdBy,
|
||||
featureName,
|
||||
data: feature,
|
||||
tags,
|
||||
project: feature.project,
|
||||
});
|
||||
return feature;
|
||||
@ -1759,14 +1719,12 @@ class FeatureToggleService {
|
||||
feature.project = newProject;
|
||||
await this.featureToggleStore.update(newProject, feature);
|
||||
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureChangeProjectEvent({
|
||||
createdBy,
|
||||
oldProject,
|
||||
newProject,
|
||||
featureName,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -1780,7 +1738,8 @@ class FeatureToggleService {
|
||||
const toggle = await this.featureToggleStore.get(featureName);
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
await this.featureToggleStore.delete(featureName);
|
||||
await this.eventStore.store(
|
||||
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureDeletedEvent({
|
||||
featureName,
|
||||
project: toggle.project,
|
||||
@ -1809,7 +1768,8 @@ class FeatureToggleService {
|
||||
);
|
||||
const tags = await this.tagStore.getAllByFeatures(eligibleFeatureNames);
|
||||
await this.featureToggleStore.batchDelete(eligibleFeatureNames);
|
||||
await this.eventStore.batchStore(
|
||||
|
||||
await this.eventService.storeEvents(
|
||||
eligibleFeatures.map(
|
||||
(feature) =>
|
||||
new FeatureDeletedEvent({
|
||||
@ -1844,21 +1804,15 @@ class FeatureToggleService {
|
||||
const eligibleFeatureNames = eligibleFeatures.map(
|
||||
(toggle) => toggle.name,
|
||||
);
|
||||
const tags = await this.tagStore.getAllByFeatures(eligibleFeatureNames);
|
||||
await this.featureToggleStore.batchRevive(eligibleFeatureNames);
|
||||
await this.eventStore.batchStore(
|
||||
|
||||
await this.eventService.storeEvents(
|
||||
eligibleFeatures.map(
|
||||
(feature) =>
|
||||
new FeatureRevivedEvent({
|
||||
featureName: feature.name,
|
||||
createdBy,
|
||||
project: feature.project,
|
||||
tags: tags
|
||||
.filter((tag) => tag.featureName === feature.name)
|
||||
.map((tag) => ({
|
||||
value: tag.tagValue,
|
||||
type: tag.tagType,
|
||||
})),
|
||||
}),
|
||||
),
|
||||
);
|
||||
@ -1867,13 +1821,12 @@ class FeatureToggleService {
|
||||
// TODO: add project id.
|
||||
async reviveFeature(featureName: string, createdBy: string): Promise<void> {
|
||||
const toggle = await this.featureToggleStore.revive(featureName);
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
await this.eventStore.store(
|
||||
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureRevivedEvent({
|
||||
createdBy,
|
||||
featureName,
|
||||
project: toggle.project,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -1985,13 +1938,12 @@ class FeatureToggleService {
|
||||
featureName,
|
||||
fixedVariants,
|
||||
);
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
await this.eventStore.store(
|
||||
|
||||
await this.eventService.storeEvent(
|
||||
new FeatureVariantEvent({
|
||||
project,
|
||||
featureName,
|
||||
createdBy,
|
||||
tags,
|
||||
oldVariants,
|
||||
newVariants: featureToggle.variants as IVariant[],
|
||||
}),
|
||||
@ -2019,9 +1971,7 @@ class FeatureToggleService {
|
||||
).variants ||
|
||||
[];
|
||||
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new EnvironmentVariantEvent({
|
||||
featureName,
|
||||
environment,
|
||||
@ -2029,7 +1979,6 @@ class FeatureToggleService {
|
||||
createdBy: user,
|
||||
oldVariants: theOldVariants,
|
||||
newVariants: fixedVariants,
|
||||
tags,
|
||||
}),
|
||||
);
|
||||
await this.featureEnvironmentStore.setVariantsToFeatureEnvironments(
|
||||
@ -2096,9 +2045,7 @@ class FeatureToggleService {
|
||||
oldVariants[env] = featureEnv.variants || [];
|
||||
}
|
||||
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
|
||||
await this.eventStore.batchStore(
|
||||
await this.eventService.storeEvents(
|
||||
environments.map(
|
||||
(environment) =>
|
||||
new EnvironmentVariantEvent({
|
||||
@ -2108,7 +2055,6 @@ class FeatureToggleService {
|
||||
createdBy: user,
|
||||
oldVariants: oldVariants[environment],
|
||||
newVariants: fixedVariants,
|
||||
tags,
|
||||
}),
|
||||
),
|
||||
);
|
||||
@ -2214,22 +2160,18 @@ class FeatureToggleService {
|
||||
async updatePotentiallyStaleFeatures(): Promise<void> {
|
||||
const potentiallyStaleFeatures =
|
||||
await this.featureToggleStore.updatePotentiallyStaleFeatures();
|
||||
|
||||
if (potentiallyStaleFeatures.length > 0) {
|
||||
return this.eventStore.batchStore(
|
||||
await Promise.all(
|
||||
potentiallyStaleFeatures
|
||||
.filter((feature) => feature.potentiallyStale)
|
||||
.map(
|
||||
async ({ name, project }) =>
|
||||
new PotentiallyStaleOnEvent({
|
||||
featureName: name,
|
||||
project,
|
||||
tags: await this.tagStore.getAllTagsForFeature(
|
||||
name,
|
||||
),
|
||||
}),
|
||||
),
|
||||
),
|
||||
return this.eventService.storeEvents(
|
||||
potentiallyStaleFeatures
|
||||
.filter((feature) => feature.potentiallyStale)
|
||||
.map(
|
||||
({ name, project }) =>
|
||||
new PotentiallyStaleOnEvent({
|
||||
featureName: name,
|
||||
project,
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -12,30 +12,28 @@ import { IGroupStore } from '../types/stores/group-store';
|
||||
import { Logger } from '../logger';
|
||||
import BadDataError from '../error/bad-data-error';
|
||||
import { GROUP_CREATED, GROUP_DELETED, GROUP_UPDATED } from '../types/events';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import NameExistsError from '../error/name-exists-error';
|
||||
import { IAccountStore } from '../types/stores/account-store';
|
||||
import { IUser } from '../types/user';
|
||||
import EventService from './event-service';
|
||||
|
||||
export class GroupService {
|
||||
private groupStore: IGroupStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
private eventService: EventService;
|
||||
|
||||
private accountStore: IAccountStore;
|
||||
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
stores: Pick<
|
||||
IUnleashStores,
|
||||
'groupStore' | 'eventStore' | 'accountStore'
|
||||
>,
|
||||
stores: Pick<IUnleashStores, 'groupStore' | 'accountStore'>,
|
||||
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
||||
eventService: EventService,
|
||||
) {
|
||||
this.logger = getLogger('service/group-service.js');
|
||||
this.groupStore = stores.groupStore;
|
||||
this.eventStore = stores.eventStore;
|
||||
this.eventService = eventService;
|
||||
this.accountStore = stores.accountStore;
|
||||
}
|
||||
|
||||
@ -96,7 +94,7 @@ export class GroupService {
|
||||
userName,
|
||||
);
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: GROUP_CREATED,
|
||||
createdBy: userName,
|
||||
data: group,
|
||||
@ -133,7 +131,7 @@ export class GroupService {
|
||||
userName,
|
||||
);
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: GROUP_UPDATED,
|
||||
createdBy: userName,
|
||||
data: newGroup,
|
||||
@ -175,7 +173,7 @@ export class GroupService {
|
||||
|
||||
await this.groupStore.delete(id);
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: GROUP_DELETED,
|
||||
createdBy: userName,
|
||||
data: group,
|
||||
|
@ -165,9 +165,10 @@ export const createServices = (
|
||||
config: IUnleashConfig,
|
||||
db?: Db,
|
||||
): IUnleashServices => {
|
||||
const groupService = new GroupService(stores, config);
|
||||
const eventService = new EventService(stores, config);
|
||||
const groupService = new GroupService(stores, config, eventService);
|
||||
const accessService = new AccessService(stores, config, groupService);
|
||||
const apiTokenService = new ApiTokenService(stores, config);
|
||||
const apiTokenService = new ApiTokenService(stores, config, eventService);
|
||||
const lastSeenService = new LastSeenService(stores, config);
|
||||
const clientMetricsServiceV2 = new ClientMetricsServiceV2(
|
||||
stores,
|
||||
@ -184,23 +185,29 @@ export const createServices = (
|
||||
const contextService = new ContextService(
|
||||
stores,
|
||||
config,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
const emailService = new EmailService(config.email, config.getLogger);
|
||||
const eventService = new EventService(stores, config);
|
||||
const featureTypeService = new FeatureTypeService(stores, config);
|
||||
const resetTokenService = new ResetTokenService(stores, config);
|
||||
const stateService = new StateService(stores, config);
|
||||
const strategyService = new StrategyService(stores, config);
|
||||
const tagService = new TagService(stores, config);
|
||||
const tagTypeService = new TagTypeService(stores, config);
|
||||
const addonService = new AddonService(stores, config, tagTypeService);
|
||||
const stateService = new StateService(stores, config, eventService);
|
||||
const strategyService = new StrategyService(stores, config, eventService);
|
||||
const tagService = new TagService(stores, config, eventService);
|
||||
const tagTypeService = new TagTypeService(stores, config, eventService);
|
||||
const addonService = new AddonService(
|
||||
stores,
|
||||
config,
|
||||
tagTypeService,
|
||||
eventService,
|
||||
);
|
||||
const sessionService = new SessionService(stores, config);
|
||||
const settingService = new SettingService(stores, config);
|
||||
const settingService = new SettingService(stores, config, eventService);
|
||||
const userService = new UserService(stores, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
@ -217,6 +224,7 @@ export const createServices = (
|
||||
stores,
|
||||
changeRequestAccessReadModel,
|
||||
config,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
|
||||
@ -230,13 +238,18 @@ export const createServices = (
|
||||
config,
|
||||
segmentService,
|
||||
accessService,
|
||||
eventService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
dependentFeaturesReadModel,
|
||||
);
|
||||
const environmentService = new EnvironmentService(stores, config);
|
||||
const featureTagService = new FeatureTagService(stores, config);
|
||||
const favoritesService = new FavoritesService(stores, config);
|
||||
const featureTagService = new FeatureTagService(
|
||||
stores,
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
const favoritesService = new FavoritesService(stores, config, eventService);
|
||||
const projectService = new ProjectService(
|
||||
stores,
|
||||
config,
|
||||
@ -244,6 +257,7 @@ export const createServices = (
|
||||
featureToggleServiceV2,
|
||||
groupService,
|
||||
favoritesService,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
const projectHealthService = new ProjectHealthService(
|
||||
@ -286,12 +300,13 @@ export const createServices = (
|
||||
|
||||
const edgeService = new EdgeService(stores, config);
|
||||
|
||||
const patService = new PatService(stores, config);
|
||||
const patService = new PatService(stores, config, eventService);
|
||||
|
||||
const publicSignupTokenService = new PublicSignupTokenService(
|
||||
stores,
|
||||
config,
|
||||
userService,
|
||||
eventService,
|
||||
);
|
||||
|
||||
const instanceStatsService = new InstanceStatsService(
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { IUnleashConfig, IUnleashStores } from '../types';
|
||||
import { Logger } from '../logger';
|
||||
import { IPatStore } from '../types/stores/pat-store';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import { PAT_CREATED, PAT_DELETED } from '../types/events';
|
||||
import { IPat } from '../types/models/pat';
|
||||
import crypto from 'crypto';
|
||||
@ -10,6 +9,7 @@ import BadDataError from '../error/bad-data-error';
|
||||
import NameExistsError from '../error/name-exists-error';
|
||||
import { OperationDeniedError } from '../error/operation-denied-error';
|
||||
import { PAT_LIMIT } from '../util/constants';
|
||||
import EventService from './event-service';
|
||||
|
||||
export default class PatService {
|
||||
private config: IUnleashConfig;
|
||||
@ -18,19 +18,17 @@ export default class PatService {
|
||||
|
||||
private patStore: IPatStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
private eventService: EventService;
|
||||
|
||||
constructor(
|
||||
{
|
||||
patStore,
|
||||
eventStore,
|
||||
}: Pick<IUnleashStores, 'patStore' | 'eventStore'>,
|
||||
{ patStore }: Pick<IUnleashStores, 'patStore'>,
|
||||
config: IUnleashConfig,
|
||||
eventService: EventService,
|
||||
) {
|
||||
this.config = config;
|
||||
this.logger = config.getLogger('services/pat-service.ts');
|
||||
this.patStore = patStore;
|
||||
this.eventStore = eventStore;
|
||||
this.eventService = eventService;
|
||||
}
|
||||
|
||||
async createPat(pat: IPat, forUserId: number, editor: User): Promise<IPat> {
|
||||
@ -40,7 +38,7 @@ export default class PatService {
|
||||
const newPat = await this.patStore.create(pat);
|
||||
|
||||
pat.secret = '***';
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: PAT_CREATED,
|
||||
createdBy: editor.email || editor.username,
|
||||
data: pat,
|
||||
@ -61,7 +59,7 @@ export default class PatService {
|
||||
const pat = await this.patStore.get(id);
|
||||
|
||||
pat.secret = '***';
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: PAT_DELETED,
|
||||
createdBy: editor.email || editor.username,
|
||||
data: pat,
|
||||
|
@ -64,6 +64,7 @@ import { BadDataError, PermissionError } from '../error';
|
||||
import { ProjectDoraMetricsSchema } from 'lib/openapi';
|
||||
import { checkFeatureNamingData } from '../features/feature-naming-pattern/feature-naming-validation';
|
||||
import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
|
||||
import EventService from './event-service';
|
||||
|
||||
const getCreatedBy = (user: IUser) => user.email || user.username || 'unknown';
|
||||
|
||||
@ -113,6 +114,8 @@ export default class ProjectService {
|
||||
|
||||
private favoritesService: FavoritesService;
|
||||
|
||||
private eventService: EventService;
|
||||
|
||||
private projectStatsStore: IProjectStatsStore;
|
||||
|
||||
private flagResolver: IFlagResolver;
|
||||
@ -145,6 +148,7 @@ export default class ProjectService {
|
||||
featureToggleService: FeatureToggleService,
|
||||
groupService: GroupService,
|
||||
favoriteService: FavoritesService,
|
||||
eventService: EventService,
|
||||
privateProjectChecker: IPrivateProjectChecker,
|
||||
) {
|
||||
this.projectStore = projectStore;
|
||||
@ -159,6 +163,7 @@ export default class ProjectService {
|
||||
this.privateProjectChecker = privateProjectChecker;
|
||||
this.accountStore = accountStore;
|
||||
this.groupService = groupService;
|
||||
this.eventService = eventService;
|
||||
this.projectStatsStore = projectStatsStore;
|
||||
this.logger = config.getLogger('services/project-service.js');
|
||||
this.flagResolver = config.flagResolver;
|
||||
@ -246,7 +251,7 @@ export default class ProjectService {
|
||||
|
||||
await this.accessService.createDefaultProjectRoles(user, data.id);
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: PROJECT_CREATED,
|
||||
createdBy: getCreatedBy(user),
|
||||
data,
|
||||
@ -284,7 +289,7 @@ export default class ProjectService {
|
||||
|
||||
await this.projectStore.updateProjectEnterpriseSettings(updatedProject);
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: PROJECT_UPDATED,
|
||||
project: updatedProject.id,
|
||||
createdBy: getCreatedBy(user),
|
||||
@ -381,7 +386,7 @@ export default class ProjectService {
|
||||
|
||||
await this.projectStore.delete(id);
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: PROJECT_DELETED,
|
||||
createdBy: getCreatedBy(user),
|
||||
project: id,
|
||||
@ -434,7 +439,7 @@ export default class ProjectService {
|
||||
|
||||
await this.accessService.addUserToRole(userId, role.id, projectId);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ProjectUserAddedEvent({
|
||||
project: projectId,
|
||||
createdBy: createdBy || 'system-user',
|
||||
@ -462,7 +467,7 @@ export default class ProjectService {
|
||||
|
||||
const user = await this.accountStore.get(userId);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ProjectUserRemovedEvent({
|
||||
project: projectId,
|
||||
createdBy,
|
||||
@ -488,7 +493,7 @@ export default class ProjectService {
|
||||
|
||||
await this.accessService.removeUserAccess(projectId, userId);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ProjectAccessUserRolesDeleted({
|
||||
project: projectId,
|
||||
createdBy,
|
||||
@ -512,7 +517,7 @@ export default class ProjectService {
|
||||
|
||||
await this.accessService.removeGroupAccess(projectId, groupId);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ProjectAccessUserRolesDeleted({
|
||||
project: projectId,
|
||||
createdBy,
|
||||
@ -547,7 +552,7 @@ export default class ProjectService {
|
||||
project.id,
|
||||
);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ProjectGroupAddedEvent({
|
||||
project: project.id,
|
||||
createdBy: modifiedBy,
|
||||
@ -582,7 +587,7 @@ export default class ProjectService {
|
||||
project.id,
|
||||
);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ProjectGroupRemovedEvent({
|
||||
project: projectId,
|
||||
createdBy: modifiedBy,
|
||||
@ -609,7 +614,7 @@ export default class ProjectService {
|
||||
createdBy,
|
||||
);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ProjectAccessAddedEvent({
|
||||
project: projectId,
|
||||
createdBy,
|
||||
@ -637,7 +642,7 @@ export default class ProjectService {
|
||||
createdBy,
|
||||
);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ProjectAccessAddedEvent({
|
||||
project: projectId,
|
||||
createdBy,
|
||||
@ -665,7 +670,7 @@ export default class ProjectService {
|
||||
userId,
|
||||
roles,
|
||||
);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ProjectAccessUserRolesUpdated({
|
||||
project: projectId,
|
||||
createdBy: createdByUserName,
|
||||
@ -697,7 +702,7 @@ export default class ProjectService {
|
||||
roles,
|
||||
createdBy,
|
||||
);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ProjectAccessGroupRolesUpdated({
|
||||
project: projectId,
|
||||
createdBy,
|
||||
@ -823,7 +828,7 @@ export default class ProjectService {
|
||||
);
|
||||
const role = await this.findProjectRole(projectId, roleId);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ProjectUserUpdateRoleEvent({
|
||||
project: projectId,
|
||||
createdBy,
|
||||
@ -877,7 +882,7 @@ export default class ProjectService {
|
||||
);
|
||||
const role = await this.findProjectGroupRole(projectId, roleId);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new ProjectGroupUpdateRoleEvent({
|
||||
project: projectId,
|
||||
createdBy,
|
||||
|
@ -8,7 +8,6 @@ import { IPublicSignupTokenCreate } from '../types/models/public-signup-token';
|
||||
import { PublicSignupTokenCreateSchema } from '../openapi/spec/public-signup-token-create-schema';
|
||||
import { CreateInvitedUserSchema } from 'lib/openapi/spec/create-invited-user-schema';
|
||||
import { RoleName } from '../types/model';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import {
|
||||
PublicSignupTokenCreatedEvent,
|
||||
PublicSignupTokenUpdatedEvent,
|
||||
@ -18,16 +17,17 @@ import UserService from './user-service';
|
||||
import { IUser } from '../types/user';
|
||||
import { URL } from 'url';
|
||||
import { add } from 'date-fns';
|
||||
import EventService from './event-service';
|
||||
|
||||
export class PublicSignupTokenService {
|
||||
private store: IPublicSignupTokenStore;
|
||||
|
||||
private roleStore: IRoleStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
|
||||
private userService: UserService;
|
||||
|
||||
private eventService: EventService;
|
||||
|
||||
private logger: Logger;
|
||||
|
||||
private timer: NodeJS.Timeout;
|
||||
@ -38,18 +38,15 @@ export class PublicSignupTokenService {
|
||||
{
|
||||
publicSignupTokenStore,
|
||||
roleStore,
|
||||
eventStore,
|
||||
}: Pick<
|
||||
IUnleashStores,
|
||||
'publicSignupTokenStore' | 'roleStore' | 'eventStore'
|
||||
>,
|
||||
}: Pick<IUnleashStores, 'publicSignupTokenStore' | 'roleStore'>,
|
||||
config: Pick<IUnleashConfig, 'getLogger' | 'authentication' | 'server'>,
|
||||
userService: UserService,
|
||||
eventService: EventService,
|
||||
) {
|
||||
this.store = publicSignupTokenStore;
|
||||
this.userService = userService;
|
||||
this.eventService = eventService;
|
||||
this.roleStore = roleStore;
|
||||
this.eventStore = eventStore;
|
||||
this.logger = config.getLogger(
|
||||
'/services/public-signup-token-service.ts',
|
||||
);
|
||||
@ -84,7 +81,7 @@ export class PublicSignupTokenService {
|
||||
createdBy: string,
|
||||
): Promise<PublicSignupTokenSchema> {
|
||||
const result = await this.store.update(secret, { expiresAt, enabled });
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new PublicSignupTokenUpdatedEvent({
|
||||
createdBy,
|
||||
data: { secret, enabled, expiresAt },
|
||||
@ -103,7 +100,7 @@ export class PublicSignupTokenService {
|
||||
rootRole: token.role.id,
|
||||
});
|
||||
await this.store.addTokenUser(secret, user.id);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new PublicSignupTokenUserAddedEvent({
|
||||
createdBy: 'System',
|
||||
data: { secret, userId: user.id },
|
||||
@ -133,7 +130,7 @@ export class PublicSignupTokenService {
|
||||
};
|
||||
const token = await this.store.insert(newToken);
|
||||
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new PublicSignupTokenCreatedEvent({
|
||||
createdBy: createdBy,
|
||||
data: token,
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { IUnleashConfig } from '../types/option';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import {
|
||||
IClientSegment,
|
||||
IFlagResolver,
|
||||
@ -23,6 +22,7 @@ import { ISegmentService } from '../segments/segment-service-interface';
|
||||
import { PermissionError } from '../error';
|
||||
import { IChangeRequestAccessReadModel } from '../features/change-request-access-service/change-request-access-read-model';
|
||||
import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
|
||||
import EventService from './event-service';
|
||||
|
||||
export class SegmentService implements ISegmentService {
|
||||
private logger: Logger;
|
||||
@ -31,32 +31,29 @@ export class SegmentService implements ISegmentService {
|
||||
|
||||
private featureStrategiesStore: IFeatureStrategiesStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
|
||||
private changeRequestAccessReadModel: IChangeRequestAccessReadModel;
|
||||
|
||||
private config: IUnleashConfig;
|
||||
|
||||
private flagResolver: IFlagResolver;
|
||||
|
||||
private eventService: EventService;
|
||||
|
||||
private privateProjectChecker: IPrivateProjectChecker;
|
||||
|
||||
constructor(
|
||||
{
|
||||
segmentStore,
|
||||
featureStrategiesStore,
|
||||
eventStore,
|
||||
}: Pick<
|
||||
IUnleashStores,
|
||||
'segmentStore' | 'featureStrategiesStore' | 'eventStore'
|
||||
>,
|
||||
}: Pick<IUnleashStores, 'segmentStore' | 'featureStrategiesStore'>,
|
||||
changeRequestAccessReadModel: IChangeRequestAccessReadModel,
|
||||
config: IUnleashConfig,
|
||||
eventService: EventService,
|
||||
privateProjectChecker: IPrivateProjectChecker,
|
||||
) {
|
||||
this.segmentStore = segmentStore;
|
||||
this.featureStrategiesStore = featureStrategiesStore;
|
||||
this.eventStore = eventStore;
|
||||
this.eventService = eventService;
|
||||
this.changeRequestAccessReadModel = changeRequestAccessReadModel;
|
||||
this.privateProjectChecker = privateProjectChecker;
|
||||
this.logger = config.getLogger('services/segment-service.ts');
|
||||
@ -117,7 +114,7 @@ export class SegmentService implements ISegmentService {
|
||||
await this.validateName(input.name);
|
||||
const segment = await this.segmentStore.create(input, user);
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: SEGMENT_CREATED,
|
||||
createdBy: user.email || user.username || 'unknown',
|
||||
data: segment,
|
||||
@ -149,7 +146,7 @@ export class SegmentService implements ISegmentService {
|
||||
|
||||
const segment = await this.segmentStore.update(id, input);
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: SEGMENT_UPDATED,
|
||||
createdBy: user.email || user.username || 'unknown',
|
||||
data: segment,
|
||||
@ -161,7 +158,7 @@ export class SegmentService implements ISegmentService {
|
||||
const segment = await this.segmentStore.get(id);
|
||||
await this.stopWhenChangeRequestsEnabled(segment.project, user);
|
||||
await this.segmentStore.delete(id);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: SEGMENT_DELETED,
|
||||
createdBy: user.email || user.username,
|
||||
data: segment,
|
||||
@ -171,7 +168,7 @@ export class SegmentService implements ISegmentService {
|
||||
async unprotectedDelete(id: number, user: User): Promise<void> {
|
||||
const segment = await this.segmentStore.get(id);
|
||||
await this.segmentStore.delete(id);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: SEGMENT_DELETED,
|
||||
createdBy: user.email || user.username,
|
||||
data: segment,
|
||||
|
@ -2,12 +2,12 @@ import { IUnleashConfig } from '../types/option';
|
||||
import { IUnleashStores } from '../types/stores';
|
||||
import { Logger } from '../logger';
|
||||
import { ISettingStore } from '../types/stores/settings-store';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import {
|
||||
SettingCreatedEvent,
|
||||
SettingDeletedEvent,
|
||||
SettingUpdatedEvent,
|
||||
} from '../types/events';
|
||||
import EventService from './event-service';
|
||||
|
||||
export default class SettingService {
|
||||
private config: IUnleashConfig;
|
||||
@ -16,19 +16,17 @@ export default class SettingService {
|
||||
|
||||
private settingStore: ISettingStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
private eventService: EventService;
|
||||
|
||||
constructor(
|
||||
{
|
||||
settingStore,
|
||||
eventStore,
|
||||
}: Pick<IUnleashStores, 'settingStore' | 'eventStore'>,
|
||||
{ settingStore }: Pick<IUnleashStores, 'settingStore'>,
|
||||
config: IUnleashConfig,
|
||||
eventService: EventService,
|
||||
) {
|
||||
this.config = config;
|
||||
this.logger = config.getLogger('services/setting-service.ts');
|
||||
this.settingStore = settingStore;
|
||||
this.eventStore = eventStore;
|
||||
this.eventService = eventService;
|
||||
}
|
||||
|
||||
async get<T>(id: string, defaultValue?: T): Promise<T> {
|
||||
@ -40,7 +38,7 @@ export default class SettingService {
|
||||
const exists = await this.settingStore.exists(id);
|
||||
if (exists) {
|
||||
await this.settingStore.updateRow(id, value);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new SettingUpdatedEvent({
|
||||
createdBy,
|
||||
data: { id },
|
||||
@ -48,7 +46,7 @@ export default class SettingService {
|
||||
);
|
||||
} else {
|
||||
await this.settingStore.insert(id, value);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new SettingCreatedEvent({
|
||||
createdBy,
|
||||
data: { id },
|
||||
@ -59,7 +57,7 @@ export default class SettingService {
|
||||
|
||||
async delete(id: string, createdBy: string): Promise<void> {
|
||||
await this.settingStore.delete(id);
|
||||
await this.eventStore.store(
|
||||
await this.eventService.storeEvent(
|
||||
new SettingDeletedEvent({
|
||||
createdBy,
|
||||
data: {
|
||||
|
@ -13,14 +13,20 @@ import {
|
||||
} from '../types/events';
|
||||
import { GLOBAL_ENV } from '../types/environment';
|
||||
import variantsExportV3 from '../../test/examples/variantsexport_v3.json';
|
||||
import EventService from './event-service';
|
||||
const oldExportExample = require('./state-service-export-v1.json');
|
||||
|
||||
function getSetup() {
|
||||
const stores = createStores();
|
||||
const eventService = new EventService(stores, { getLogger });
|
||||
return {
|
||||
stateService: new StateService(stores, {
|
||||
getLogger,
|
||||
}),
|
||||
stateService: new StateService(
|
||||
stores,
|
||||
{
|
||||
getLogger,
|
||||
},
|
||||
eventService,
|
||||
),
|
||||
stores,
|
||||
};
|
||||
}
|
||||
@ -61,10 +67,15 @@ async function setupV3VariantsCompatibilityScenario(
|
||||
],
|
||||
);
|
||||
});
|
||||
const eventService = new EventService(stores, { getLogger });
|
||||
return {
|
||||
stateService: new StateService(stores, {
|
||||
getLogger,
|
||||
}),
|
||||
stateService: new StateService(
|
||||
stores,
|
||||
{
|
||||
getLogger,
|
||||
},
|
||||
eventService,
|
||||
),
|
||||
stores,
|
||||
};
|
||||
}
|
||||
@ -576,9 +587,14 @@ test('Should export projects', async () => {
|
||||
|
||||
test('exporting to new format works', async () => {
|
||||
const stores = createStores();
|
||||
const stateService = new StateService(stores, {
|
||||
getLogger,
|
||||
});
|
||||
const eventService = new EventService(stores, { getLogger });
|
||||
const stateService = new StateService(
|
||||
stores,
|
||||
{
|
||||
getLogger,
|
||||
},
|
||||
eventService,
|
||||
);
|
||||
await stores.projectStore.create({
|
||||
id: 'fancy',
|
||||
name: 'extra',
|
||||
|
@ -39,7 +39,6 @@ import {
|
||||
import { IProjectStore } from '../types/stores/project-store';
|
||||
import { ITagType, ITagTypeStore } from '../types/stores/tag-type-store';
|
||||
import { ITagStore } from '../types/stores/tag-store';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import { IStrategy, IStrategyStore } from '../types/stores/strategy-store';
|
||||
import { IFeatureToggleStore } from '../types/stores/feature-toggle-store';
|
||||
import { IFeatureStrategiesStore } from '../types/stores/feature-strategies-store';
|
||||
@ -50,6 +49,7 @@ import { DEFAULT_ENV } from '../util/constants';
|
||||
import { GLOBAL_ENV } from '../types/environment';
|
||||
import { ISegmentStore } from '../types/stores/segment-store';
|
||||
import { PartialSome } from '../types/partial';
|
||||
import EventService from './event-service';
|
||||
|
||||
export interface IBackupOption {
|
||||
includeFeatureToggles: boolean;
|
||||
@ -76,7 +76,7 @@ export default class StateService {
|
||||
|
||||
private strategyStore: IStrategyStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
private eventService: EventService;
|
||||
|
||||
private tagStore: ITagStore;
|
||||
|
||||
@ -95,8 +95,9 @@ export default class StateService {
|
||||
constructor(
|
||||
stores: IUnleashStores,
|
||||
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
||||
eventService: EventService,
|
||||
) {
|
||||
this.eventStore = stores.eventStore;
|
||||
this.eventService = eventService;
|
||||
this.toggleStore = stores.featureToggleStore;
|
||||
this.strategyStore = stores.strategyStore;
|
||||
this.tagStore = stores.tagStore;
|
||||
@ -369,7 +370,7 @@ export default class StateService {
|
||||
if (dropBeforeImport) {
|
||||
this.logger.info('Dropping existing feature toggles');
|
||||
await this.toggleStore.deleteAll();
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: DROP_FEATURES,
|
||||
createdBy: userName,
|
||||
data: { name: 'all-features' },
|
||||
@ -387,7 +388,7 @@ export default class StateService {
|
||||
feature.project,
|
||||
this.enabledIn(feature.name, featureEnvironments),
|
||||
);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: FEATURE_IMPORT,
|
||||
createdBy: userName,
|
||||
data: feature,
|
||||
@ -411,7 +412,7 @@ export default class StateService {
|
||||
if (dropBeforeImport) {
|
||||
this.logger.info('Dropping existing strategies');
|
||||
await this.strategyStore.dropCustomStrategies();
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: DROP_STRATEGIES,
|
||||
createdBy: userName,
|
||||
data: { name: 'all-strategies' },
|
||||
@ -424,7 +425,7 @@ export default class StateService {
|
||||
.filter(filterEqual(oldStrategies))
|
||||
.map((strategy) =>
|
||||
this.strategyStore.importStrategy(strategy).then(() => {
|
||||
this.eventStore.store({
|
||||
this.eventService.storeEvent({
|
||||
type: STRATEGY_IMPORT,
|
||||
createdBy: userName,
|
||||
data: strategy,
|
||||
@ -448,7 +449,7 @@ export default class StateService {
|
||||
if (dropBeforeImport) {
|
||||
this.logger.info('Dropping existing environments');
|
||||
await this.environmentStore.deleteAll();
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: DROP_ENVIRONMENTS,
|
||||
createdBy: userName,
|
||||
data: { name: 'all-environments' },
|
||||
@ -467,7 +468,7 @@ export default class StateService {
|
||||
createdBy: userName,
|
||||
data: env,
|
||||
}));
|
||||
await this.eventStore.batchStore(importedEnvironmentEvents);
|
||||
await this.eventService.storeEvents(importedEnvironmentEvents);
|
||||
}
|
||||
return importedEnvs;
|
||||
}
|
||||
@ -487,7 +488,7 @@ export default class StateService {
|
||||
if (dropBeforeImport) {
|
||||
this.logger.info('Dropping existing projects');
|
||||
await this.projectStore.deleteAll();
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: DROP_PROJECTS,
|
||||
createdBy: userName,
|
||||
data: { name: 'all-projects' },
|
||||
@ -508,7 +509,7 @@ export default class StateService {
|
||||
createdBy: userName,
|
||||
data: project,
|
||||
}));
|
||||
await this.eventStore.batchStore(importedProjectEvents);
|
||||
await this.eventService.storeEvents(importedProjectEvents);
|
||||
}
|
||||
}
|
||||
|
||||
@ -538,7 +539,7 @@ export default class StateService {
|
||||
await this.featureTagStore.deleteAll();
|
||||
await this.tagStore.deleteAll();
|
||||
await this.tagTypeStore.deleteAll();
|
||||
await this.eventStore.batchStore([
|
||||
await this.eventService.storeEvents([
|
||||
{
|
||||
type: DROP_FEATURE_TAGS,
|
||||
createdBy: userName,
|
||||
@ -601,7 +602,7 @@ export default class StateService {
|
||||
createdBy: userName,
|
||||
data: tag,
|
||||
}));
|
||||
await this.eventStore.batchStore(importedFeatureTagEvents);
|
||||
await this.eventService.storeEvents(importedFeatureTagEvents);
|
||||
}
|
||||
}
|
||||
|
||||
@ -626,7 +627,7 @@ export default class StateService {
|
||||
createdBy: userName,
|
||||
data: tag,
|
||||
}));
|
||||
await this.eventStore.batchStore(importedTagEvents);
|
||||
await this.eventService.storeEvents(importedTagEvents);
|
||||
}
|
||||
}
|
||||
|
||||
@ -650,7 +651,7 @@ export default class StateService {
|
||||
createdBy: userName,
|
||||
data: tagType,
|
||||
}));
|
||||
await this.eventStore.batchStore(importedTagTypeEvents);
|
||||
await this.eventService.storeEvents(importedTagTypeEvents);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { Logger } from '../logger';
|
||||
import { IUnleashConfig } from '../types/option';
|
||||
import { IUnleashStores } from '../types/stores';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import {
|
||||
IMinimalStrategy,
|
||||
IStrategy,
|
||||
IStrategyStore,
|
||||
} from '../types/stores/strategy-store';
|
||||
import NotFoundError from '../error/notfound-error';
|
||||
import EventService from './event-service';
|
||||
|
||||
const strategySchema = require('./strategy-schema');
|
||||
const NameExistsError = require('../error/name-exists-error');
|
||||
@ -24,17 +24,15 @@ class StrategyService {
|
||||
|
||||
private strategyStore: IStrategyStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
private eventService: EventService;
|
||||
|
||||
constructor(
|
||||
{
|
||||
strategyStore,
|
||||
eventStore,
|
||||
}: Pick<IUnleashStores, 'strategyStore' | 'eventStore'>,
|
||||
{ strategyStore }: Pick<IUnleashStores, 'strategyStore'>,
|
||||
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
||||
eventService: EventService,
|
||||
) {
|
||||
this.strategyStore = strategyStore;
|
||||
this.eventStore = eventStore;
|
||||
this.eventService = eventService;
|
||||
this.logger = getLogger('services/strategy-service.js');
|
||||
}
|
||||
|
||||
@ -53,7 +51,7 @@ class StrategyService {
|
||||
const strategy = await this.strategyStore.get(strategyName);
|
||||
await this._validateEditable(strategy);
|
||||
await this.strategyStore.delete(strategyName);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: STRATEGY_DELETED,
|
||||
createdBy: userName,
|
||||
data: {
|
||||
@ -69,7 +67,7 @@ class StrategyService {
|
||||
if (await this.strategyStore.exists(strategyName)) {
|
||||
// Check existence
|
||||
await this.strategyStore.deprecateStrategy({ name: strategyName });
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: STRATEGY_DEPRECATED,
|
||||
createdBy: userName,
|
||||
data: {
|
||||
@ -89,7 +87,7 @@ class StrategyService {
|
||||
): Promise<void> {
|
||||
await this.strategyStore.get(strategyName); // Check existence
|
||||
await this.strategyStore.reactivateStrategy({ name: strategyName });
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: STRATEGY_REACTIVATED,
|
||||
createdBy: userName,
|
||||
data: {
|
||||
@ -106,7 +104,7 @@ class StrategyService {
|
||||
strategy.deprecated = false;
|
||||
await this._validateStrategyName(strategy);
|
||||
await this.strategyStore.createStrategy(strategy);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: STRATEGY_CREATED,
|
||||
createdBy: userName,
|
||||
data: strategy,
|
||||
@ -122,7 +120,7 @@ class StrategyService {
|
||||
const strategy = await this.strategyStore.get(input.name);
|
||||
await this._validateEditable(strategy);
|
||||
await this.strategyStore.updateStrategy(value);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: STRATEGY_UPDATED,
|
||||
createdBy: userName,
|
||||
data: value,
|
||||
|
@ -5,25 +5,23 @@ import { Logger } from '../logger';
|
||||
import { IUnleashStores } from '../types/stores';
|
||||
import { IUnleashConfig } from '../types/option';
|
||||
import { ITagStore } from '../types/stores/tag-store';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import { ITag } from '../types/model';
|
||||
import EventService from './event-service';
|
||||
|
||||
export default class TagService {
|
||||
private tagStore: ITagStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
private eventService: EventService;
|
||||
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
{
|
||||
tagStore,
|
||||
eventStore,
|
||||
}: Pick<IUnleashStores, 'tagStore' | 'eventStore'>,
|
||||
{ tagStore }: Pick<IUnleashStores, 'tagStore'>,
|
||||
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
||||
eventService: EventService,
|
||||
) {
|
||||
this.tagStore = tagStore;
|
||||
this.eventStore = eventStore;
|
||||
this.eventService = eventService;
|
||||
this.logger = getLogger('services/tag-service.js');
|
||||
}
|
||||
|
||||
@ -55,7 +53,7 @@ export default class TagService {
|
||||
async createTag(tag: ITag, userName: string): Promise<ITag> {
|
||||
const data = await this.validate(tag);
|
||||
await this.tagStore.createTag(data);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: TAG_CREATED,
|
||||
createdBy: userName,
|
||||
data,
|
||||
@ -66,7 +64,7 @@ export default class TagService {
|
||||
|
||||
async deleteTag(tag: ITag, userName: string): Promise<void> {
|
||||
await this.tagStore.delete(tag);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: TAG_DELETED,
|
||||
createdBy: userName,
|
||||
data: tag,
|
||||
|
@ -11,25 +11,23 @@ import {
|
||||
|
||||
import { Logger } from '../logger';
|
||||
import { ITagType, ITagTypeStore } from '../types/stores/tag-type-store';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import { IUnleashConfig } from '../types/option';
|
||||
import EventService from './event-service';
|
||||
|
||||
export default class TagTypeService {
|
||||
private tagTypeStore: ITagTypeStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
private eventService: EventService;
|
||||
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
{
|
||||
tagTypeStore,
|
||||
eventStore,
|
||||
}: Pick<IUnleashStores, 'tagTypeStore' | 'eventStore'>,
|
||||
{ tagTypeStore }: Pick<IUnleashStores, 'tagTypeStore'>,
|
||||
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
||||
eventService: EventService,
|
||||
) {
|
||||
this.tagTypeStore = tagTypeStore;
|
||||
this.eventStore = eventStore;
|
||||
this.eventService = eventService;
|
||||
this.logger = getLogger('services/tag-type-service.js');
|
||||
}
|
||||
|
||||
@ -50,7 +48,7 @@ export default class TagTypeService {
|
||||
)) as ITagType;
|
||||
await this.validateUnique(data.name);
|
||||
await this.tagTypeStore.createTagType(data);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: TAG_TYPE_CREATED,
|
||||
createdBy: userName || 'unleash-system',
|
||||
data,
|
||||
@ -77,7 +75,7 @@ export default class TagTypeService {
|
||||
|
||||
async deleteTagType(name: string, userName: string): Promise<void> {
|
||||
await this.tagTypeStore.delete(name);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: TAG_TYPE_DELETED,
|
||||
createdBy: userName || 'unleash-system',
|
||||
data: { name },
|
||||
@ -90,7 +88,7 @@ export default class TagTypeService {
|
||||
): Promise<ITagType> {
|
||||
const data = await tagTypeSchema.validateAsync(updatedTagType);
|
||||
await this.tagTypeStore.updateTagType(data);
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: TAG_TYPE_UPDATED,
|
||||
createdBy: userName || 'unleash-system',
|
||||
data,
|
||||
|
@ -14,7 +14,8 @@ import User from '../types/user';
|
||||
import FakeResetTokenStore from '../../test/fixtures/fake-reset-token-store';
|
||||
import SettingService from './setting-service';
|
||||
import FakeSettingStore from '../../test/fixtures/fake-setting-store';
|
||||
import FakeEventStore from '../../test/fixtures/fake-event-store';
|
||||
import EventService from './event-service';
|
||||
import FakeFeatureTagStore from '../../test/fixtures/fake-feature-tag-store';
|
||||
|
||||
const config: IUnleashConfig = createTestConfig();
|
||||
|
||||
@ -32,18 +33,23 @@ test('Should create new user', async () => {
|
||||
const sessionStore = new FakeSessionStore();
|
||||
const sessionService = new SessionService({ sessionStore }, config);
|
||||
const emailService = new EmailService(config.email, config.getLogger);
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore: new FakeFeatureTagStore() },
|
||||
config,
|
||||
);
|
||||
const settingService = new SettingService(
|
||||
{
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
const service = new UserService({ userStore, eventStore }, config, {
|
||||
const service = new UserService({ userStore }, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
@ -75,18 +81,23 @@ test('Should create default user', async () => {
|
||||
const emailService = new EmailService(config.email, config.getLogger);
|
||||
const sessionStore = new FakeSessionStore();
|
||||
const sessionService = new SessionService({ sessionStore }, config);
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore: new FakeFeatureTagStore() },
|
||||
config,
|
||||
);
|
||||
const settingService = new SettingService(
|
||||
{
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
const service = new UserService({ userStore, eventStore }, config, {
|
||||
const service = new UserService({ userStore }, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
@ -110,18 +121,23 @@ test('Should be a valid password', async () => {
|
||||
const emailService = new EmailService(config.email, config.getLogger);
|
||||
const sessionStore = new FakeSessionStore();
|
||||
const sessionService = new SessionService({ sessionStore }, config);
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore: new FakeFeatureTagStore() },
|
||||
config,
|
||||
);
|
||||
const settingService = new SettingService(
|
||||
{
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
const service = new UserService({ userStore, eventStore }, config, {
|
||||
const service = new UserService({ userStore }, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
@ -143,18 +159,23 @@ test('Password must be at least 10 chars', async () => {
|
||||
const emailService = new EmailService(config.email, config.getLogger);
|
||||
const sessionStore = new FakeSessionStore();
|
||||
const sessionService = new SessionService({ sessionStore }, config);
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore: new FakeFeatureTagStore() },
|
||||
config,
|
||||
);
|
||||
const settingService = new SettingService(
|
||||
{
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
const service = new UserService({ userStore, eventStore }, config, {
|
||||
const service = new UserService({ userStore }, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
@ -178,18 +199,23 @@ test('The password must contain at least one uppercase letter.', async () => {
|
||||
const emailService = new EmailService(config.email, config.getLogger);
|
||||
const sessionStore = new FakeSessionStore();
|
||||
const sessionService = new SessionService({ sessionStore }, config);
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore: new FakeFeatureTagStore() },
|
||||
config,
|
||||
);
|
||||
const settingService = new SettingService(
|
||||
{
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
const service = new UserService({ userStore, eventStore }, config, {
|
||||
const service = new UserService({ userStore }, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
@ -215,18 +241,23 @@ test('The password must contain at least one number', async () => {
|
||||
const emailService = new EmailService(config.email, config.getLogger);
|
||||
const sessionStore = new FakeSessionStore();
|
||||
const sessionService = new SessionService({ sessionStore }, config);
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore: new FakeFeatureTagStore() },
|
||||
config,
|
||||
);
|
||||
const settingService = new SettingService(
|
||||
{
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
const service = new UserService({ userStore, eventStore }, config, {
|
||||
const service = new UserService({ userStore }, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
@ -251,18 +282,23 @@ test('The password must contain at least one special character', async () => {
|
||||
const emailService = new EmailService(config.email, config.getLogger);
|
||||
const sessionStore = new FakeSessionStore();
|
||||
const sessionService = new SessionService({ sessionStore }, config);
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore: new FakeFeatureTagStore() },
|
||||
config,
|
||||
);
|
||||
const settingService = new SettingService(
|
||||
{
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
const service = new UserService({ userStore, eventStore }, config, {
|
||||
const service = new UserService({ userStore }, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
@ -287,18 +323,23 @@ test('Should be a valid password with special chars', async () => {
|
||||
const emailService = new EmailService(config.email, config.getLogger);
|
||||
const sessionStore = new FakeSessionStore();
|
||||
const sessionService = new SessionService({ sessionStore }, config);
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore: new FakeFeatureTagStore() },
|
||||
config,
|
||||
);
|
||||
const settingService = new SettingService(
|
||||
{
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
const service = new UserService({ userStore, eventStore }, config, {
|
||||
const service = new UserService({ userStore }, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
@ -320,18 +361,23 @@ test('Should send password reset email if user exists', async () => {
|
||||
const emailService = new EmailService(config.email, config.getLogger);
|
||||
const sessionStore = new FakeSessionStore();
|
||||
const sessionService = new SessionService({ sessionStore }, config);
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore: new FakeFeatureTagStore() },
|
||||
config,
|
||||
);
|
||||
const settingService = new SettingService(
|
||||
{
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
const service = new UserService({ userStore, eventStore }, config, {
|
||||
const service = new UserService({ userStore }, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
@ -369,18 +415,23 @@ test('Should throttle password reset email', async () => {
|
||||
const emailService = new EmailService(config.email, config.getLogger);
|
||||
const sessionStore = new FakeSessionStore();
|
||||
const sessionService = new SessionService({ sessionStore }, config);
|
||||
const eventService = new EventService(
|
||||
{ eventStore, featureTagStore: new FakeFeatureTagStore() },
|
||||
config,
|
||||
);
|
||||
const settingService = new SettingService(
|
||||
{
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
const service = new UserService({ userStore, eventStore }, config, {
|
||||
const service = new UserService({ userStore }, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
|
@ -17,7 +17,6 @@ import SessionService from './session-service';
|
||||
import { IUnleashStores } from '../types/stores';
|
||||
import PasswordUndefinedError from '../error/password-undefined';
|
||||
import { USER_UPDATED, USER_CREATED, USER_DELETED } from '../types/events';
|
||||
import { IEventStore } from '../types/stores/event-store';
|
||||
import { IUserStore } from '../types/stores/user-store';
|
||||
import { RoleName } from '../types/model';
|
||||
import SettingService from './setting-service';
|
||||
@ -28,6 +27,7 @@ import BadDataError from '../error/bad-data-error';
|
||||
import { isDefined } from '../util/isDefined';
|
||||
import { TokenUserSchema } from '../openapi/spec/token-user-schema';
|
||||
import PasswordMismatch from '../error/password-mismatch';
|
||||
import EventService from './event-service';
|
||||
|
||||
const systemUser = new User({ id: -1, username: 'system' });
|
||||
|
||||
@ -64,7 +64,7 @@ class UserService {
|
||||
|
||||
private store: IUserStore;
|
||||
|
||||
private eventStore: IEventStore;
|
||||
private eventService: EventService;
|
||||
|
||||
private accessService: AccessService;
|
||||
|
||||
@ -81,7 +81,7 @@ class UserService {
|
||||
private baseUriPath: string;
|
||||
|
||||
constructor(
|
||||
stores: Pick<IUnleashStores, 'userStore' | 'eventStore'>,
|
||||
stores: Pick<IUnleashStores, 'userStore'>,
|
||||
{
|
||||
server,
|
||||
getLogger,
|
||||
@ -91,13 +91,14 @@ class UserService {
|
||||
accessService: AccessService;
|
||||
resetTokenService: ResetTokenService;
|
||||
emailService: EmailService;
|
||||
eventService: EventService;
|
||||
sessionService: SessionService;
|
||||
settingService: SettingService;
|
||||
},
|
||||
) {
|
||||
this.logger = getLogger('service/user-service.js');
|
||||
this.store = stores.userStore;
|
||||
this.eventStore = stores.eventStore;
|
||||
this.eventService = services.eventService;
|
||||
this.accessService = services.accessService;
|
||||
this.resetTokenService = services.resetTokenService;
|
||||
this.emailService = services.emailService;
|
||||
@ -208,7 +209,7 @@ class UserService {
|
||||
await this.store.setPasswordHash(user.id, passwordHash);
|
||||
}
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: USER_CREATED,
|
||||
createdBy: this.getCreatedBy(updatedBy),
|
||||
data: this.mapUserToData(user),
|
||||
@ -257,7 +258,7 @@ class UserService {
|
||||
? await this.store.update(id, payload)
|
||||
: preUser;
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: USER_UPDATED,
|
||||
createdBy: this.getCreatedBy(updatedBy),
|
||||
data: this.mapUserToData(user),
|
||||
@ -274,7 +275,7 @@ class UserService {
|
||||
|
||||
await this.store.delete(userId);
|
||||
|
||||
await this.eventStore.store({
|
||||
await this.eventService.storeEvent({
|
||||
type: USER_DELETED,
|
||||
createdBy: this.getCreatedBy(updatedBy),
|
||||
preData: this.mapUserToData(user),
|
||||
|
@ -278,22 +278,15 @@ class BaseEvent implements IBaseEvent {
|
||||
|
||||
readonly createdBy: string;
|
||||
|
||||
readonly tags: ITag[];
|
||||
|
||||
/**
|
||||
* @param createdBy accepts a string for backward compatibility. Prefer using IUser for standardization
|
||||
*/
|
||||
constructor(
|
||||
type: IEventType,
|
||||
createdBy: string | IUser,
|
||||
tags: ITag[] = [],
|
||||
) {
|
||||
constructor(type: IEventType, createdBy: string | IUser) {
|
||||
this.type = type;
|
||||
this.createdBy =
|
||||
typeof createdBy === 'string'
|
||||
? createdBy
|
||||
: extractUsernameFromUser(createdBy);
|
||||
this.tags = tags;
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,13 +303,8 @@ export class FeatureStaleEvent extends BaseEvent {
|
||||
project: string;
|
||||
featureName: string;
|
||||
createdBy: string | IUser;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(
|
||||
p.stale ? FEATURE_STALE_ON : FEATURE_STALE_OFF,
|
||||
p.createdBy,
|
||||
p.tags,
|
||||
);
|
||||
super(p.stale ? FEATURE_STALE_ON : FEATURE_STALE_OFF, p.createdBy);
|
||||
this.project = p.project;
|
||||
this.featureName = p.featureName;
|
||||
}
|
||||
@ -338,14 +326,12 @@ export class FeatureEnvironmentEvent extends BaseEvent {
|
||||
featureName: string;
|
||||
environment: string;
|
||||
createdBy: string | IUser;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(
|
||||
p.enabled
|
||||
? FEATURE_ENVIRONMENT_ENABLED
|
||||
: FEATURE_ENVIRONMENT_DISABLED,
|
||||
p.createdBy,
|
||||
p.tags,
|
||||
);
|
||||
this.project = p.project;
|
||||
this.featureName = p.featureName;
|
||||
@ -374,9 +360,8 @@ export class StrategiesOrderChangedEvent extends BaseEvent {
|
||||
createdBy: string | IUser;
|
||||
data: StrategyIds;
|
||||
preData: StrategyIds;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(STRATEGY_ORDER_CHANGED, p.createdBy, p.tags);
|
||||
super(STRATEGY_ORDER_CHANGED, p.createdBy);
|
||||
const { project, featureName, environment, data, preData } = p;
|
||||
this.project = project;
|
||||
this.featureName = featureName;
|
||||
@ -402,11 +387,10 @@ export class FeatureVariantEvent extends BaseEvent {
|
||||
project: string;
|
||||
featureName: string;
|
||||
createdBy: string | IUser;
|
||||
tags: ITag[];
|
||||
newVariants: IVariant[];
|
||||
oldVariants: IVariant[];
|
||||
}) {
|
||||
super(FEATURE_VARIANTS_UPDATED, p.createdBy, p.tags);
|
||||
super(FEATURE_VARIANTS_UPDATED, p.createdBy);
|
||||
this.project = p.project;
|
||||
this.featureName = p.featureName;
|
||||
this.data = { variants: p.newVariants };
|
||||
@ -433,11 +417,10 @@ export class EnvironmentVariantEvent extends BaseEvent {
|
||||
environment: string;
|
||||
project: string;
|
||||
createdBy: string | IUser;
|
||||
tags: ITag[];
|
||||
newVariants: IVariant[];
|
||||
oldVariants: IVariant[];
|
||||
}) {
|
||||
super(FEATURE_ENVIRONMENT_VARIANTS_UPDATED, p.createdBy, p.tags);
|
||||
super(FEATURE_ENVIRONMENT_VARIANTS_UPDATED, p.createdBy);
|
||||
this.featureName = p.featureName;
|
||||
this.environment = p.environment;
|
||||
this.project = p.project;
|
||||
@ -464,9 +447,8 @@ export class FeatureChangeProjectEvent extends BaseEvent {
|
||||
newProject: string;
|
||||
featureName: string;
|
||||
createdBy: string | IUser;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(FEATURE_PROJECT_CHANGE, p.createdBy, p.tags);
|
||||
super(FEATURE_PROJECT_CHANGE, p.createdBy);
|
||||
const { newProject, oldProject, featureName } = p;
|
||||
this.project = newProject;
|
||||
this.featureName = featureName;
|
||||
@ -489,9 +471,8 @@ export class FeatureCreatedEvent extends BaseEvent {
|
||||
featureName: string;
|
||||
createdBy: string | IUser;
|
||||
data: FeatureToggle;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(FEATURE_CREATED, p.createdBy, p.tags);
|
||||
super(FEATURE_CREATED, p.createdBy);
|
||||
const { project, featureName, data } = p;
|
||||
this.project = project;
|
||||
this.featureName = featureName;
|
||||
@ -511,9 +492,8 @@ export class FeatureArchivedEvent extends BaseEvent {
|
||||
project: string;
|
||||
featureName: string;
|
||||
createdBy: string | IUser;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(FEATURE_ARCHIVED, p.createdBy, p.tags);
|
||||
super(FEATURE_ARCHIVED, p.createdBy);
|
||||
const { project, featureName } = p;
|
||||
this.project = project;
|
||||
this.featureName = featureName;
|
||||
@ -532,9 +512,8 @@ export class FeatureRevivedEvent extends BaseEvent {
|
||||
project: string;
|
||||
featureName: string;
|
||||
createdBy: string | IUser;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(FEATURE_REVIVED, p.createdBy, p.tags);
|
||||
super(FEATURE_REVIVED, p.createdBy);
|
||||
const { project, featureName } = p;
|
||||
this.project = project;
|
||||
this.featureName = featureName;
|
||||
@ -548,6 +527,8 @@ export class FeatureDeletedEvent extends BaseEvent {
|
||||
|
||||
readonly preData: FeatureToggle;
|
||||
|
||||
readonly tags: ITag[];
|
||||
|
||||
/**
|
||||
* @param createdBy accepts a string for backward compatibility. Prefer using IUser for standardization
|
||||
*/
|
||||
@ -558,11 +539,12 @@ export class FeatureDeletedEvent extends BaseEvent {
|
||||
createdBy: string | IUser;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(FEATURE_DELETED, p.createdBy, p.tags);
|
||||
super(FEATURE_DELETED, p.createdBy);
|
||||
const { project, featureName, preData } = p;
|
||||
this.project = project;
|
||||
this.featureName = featureName;
|
||||
this.preData = preData;
|
||||
this.tags = p.tags;
|
||||
}
|
||||
}
|
||||
|
||||
@ -584,9 +566,8 @@ export class FeatureMetadataUpdateEvent extends BaseEvent {
|
||||
project: string;
|
||||
data: FeatureToggle;
|
||||
preData: FeatureToggle;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(FEATURE_METADATA_UPDATED, p.createdBy, p.tags);
|
||||
super(FEATURE_METADATA_UPDATED, p.createdBy);
|
||||
const { project, featureName, data, preData } = p;
|
||||
this.project = project;
|
||||
this.featureName = featureName;
|
||||
@ -613,9 +594,8 @@ export class FeatureStrategyAddEvent extends BaseEvent {
|
||||
environment: string;
|
||||
createdBy: string | IUser;
|
||||
data: IStrategyConfig;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(FEATURE_STRATEGY_ADD, p.createdBy, p.tags);
|
||||
super(FEATURE_STRATEGY_ADD, p.createdBy);
|
||||
const { project, featureName, environment, data } = p;
|
||||
this.project = project;
|
||||
this.featureName = featureName;
|
||||
@ -645,9 +625,8 @@ export class FeatureStrategyUpdateEvent extends BaseEvent {
|
||||
createdBy: string | IUser;
|
||||
data: IStrategyConfig;
|
||||
preData: IStrategyConfig;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(FEATURE_STRATEGY_UPDATE, p.createdBy, p.tags);
|
||||
super(FEATURE_STRATEGY_UPDATE, p.createdBy);
|
||||
const { project, featureName, environment, data, preData } = p;
|
||||
this.project = project;
|
||||
this.featureName = featureName;
|
||||
@ -675,9 +654,8 @@ export class FeatureStrategyRemoveEvent extends BaseEvent {
|
||||
environment: string;
|
||||
createdBy: string | IUser;
|
||||
preData: IStrategyConfig;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(FEATURE_STRATEGY_REMOVE, p.createdBy, p.tags);
|
||||
super(FEATURE_STRATEGY_REMOVE, p.createdBy);
|
||||
const { project, featureName, environment, preData } = p;
|
||||
this.project = project;
|
||||
this.featureName = featureName;
|
||||
@ -1075,12 +1053,8 @@ export class PotentiallyStaleOnEvent extends BaseEvent {
|
||||
|
||||
readonly project: string;
|
||||
|
||||
constructor(eventData: {
|
||||
featureName: string;
|
||||
project: string;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(FEATURE_POTENTIALLY_STALE_ON, 'unleash-system', eventData.tags);
|
||||
constructor(eventData: { featureName: string; project: string }) {
|
||||
super(FEATURE_POTENTIALLY_STALE_ON, 'unleash-system');
|
||||
this.featureName = eventData.featureName;
|
||||
this.project = eventData.project;
|
||||
}
|
||||
|
@ -5,12 +5,12 @@ import {
|
||||
import dbInit, { ITestDb } from '../../helpers/database-init';
|
||||
import getLogger from '../../../fixtures/no-logger';
|
||||
import { FEATURE_CREATED, IBaseEvent } from '../../../../lib/types/events';
|
||||
import { IEventStore } from '../../../../lib/types/stores/event-store';
|
||||
import { randomId } from '../../../../lib/util/random-id';
|
||||
import { EventService } from '../../../../lib/services';
|
||||
|
||||
let app: IUnleashTest;
|
||||
let db: ITestDb;
|
||||
let eventStore: IEventStore;
|
||||
let eventService: EventService;
|
||||
|
||||
beforeAll(async () => {
|
||||
db = await dbInit('event_api_serial', getLogger);
|
||||
@ -21,11 +21,11 @@ beforeAll(async () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
eventStore = db.stores.eventStore;
|
||||
eventService = new EventService(db.stores, { getLogger });
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await eventStore.deleteAll();
|
||||
await db.stores.eventStore.deleteAll();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
@ -50,7 +50,7 @@ test('returns events given a name', async () => {
|
||||
});
|
||||
|
||||
test('Can filter by project', async () => {
|
||||
await eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
project: 'something-else',
|
||||
data: { id: 'some-other-feature' },
|
||||
@ -58,7 +58,7 @@ test('Can filter by project', async () => {
|
||||
createdBy: 'test-user',
|
||||
environment: 'test',
|
||||
});
|
||||
await eventStore.store({
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
project: 'default',
|
||||
data: { id: 'feature' },
|
||||
@ -96,7 +96,7 @@ test('can search for events', async () => {
|
||||
|
||||
await Promise.all(
|
||||
events.map((event) => {
|
||||
return eventStore.store(event);
|
||||
return eventService.storeEvent(event);
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -16,7 +16,7 @@ import { RoleName } from '../../../../lib/types/model';
|
||||
import SettingService from '../../../../lib/services/setting-service';
|
||||
import FakeSettingStore from '../../../fixtures/fake-setting-store';
|
||||
import { GroupService } from '../../../../lib/services/group-service';
|
||||
import FakeEventStore from '../../../fixtures/fake-event-store';
|
||||
import { EventService } from '../../../../lib/services';
|
||||
|
||||
let app;
|
||||
let stores;
|
||||
@ -49,7 +49,8 @@ beforeAll(async () => {
|
||||
db = await dbInit('reset_password_api_serial', getLogger);
|
||||
stores = db.stores;
|
||||
app = await setupApp(stores);
|
||||
const groupService = new GroupService(stores, config);
|
||||
const eventService = new EventService(stores, config);
|
||||
const groupService = new GroupService(stores, config, eventService);
|
||||
accessService = new AccessService(stores, config, groupService);
|
||||
const emailService = new EmailService(config.email, config.getLogger);
|
||||
const sessionStore = new SessionStore(
|
||||
@ -61,14 +62,15 @@ beforeAll(async () => {
|
||||
const settingService = new SettingService(
|
||||
{
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
userService = new UserService(stores, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
|
@ -12,6 +12,7 @@ import { RoleName } from '../../../../lib/types/model';
|
||||
import SettingService from '../../../../lib/services/setting-service';
|
||||
import { GroupService } from '../../../../lib/services/group-service';
|
||||
import ResetTokenService from '../../../../lib/services/reset-token-service';
|
||||
import { EventService } from '../../../../lib/services';
|
||||
|
||||
let app;
|
||||
let stores;
|
||||
@ -34,18 +35,20 @@ beforeEach(async () => {
|
||||
db = await dbInit('simple_password_provider_api_serial', getLogger);
|
||||
stores = db.stores;
|
||||
app = await setupApp(stores);
|
||||
const groupService = new GroupService(stores, config);
|
||||
const eventService = new EventService(stores, config);
|
||||
const groupService = new GroupService(stores, config, eventService);
|
||||
const accessService = new AccessService(stores, config, groupService);
|
||||
const resetTokenService = new ResetTokenService(stores, config);
|
||||
// @ts-ignore
|
||||
const emailService = new EmailService(undefined, config.getLogger);
|
||||
const sessionService = new SessionService(stores, config);
|
||||
const settingService = new SettingService(stores, config);
|
||||
const settingService = new SettingService(stores, config, eventService);
|
||||
|
||||
userService = new UserService(stores, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
|
@ -20,7 +20,7 @@ import { DEFAULT_PROJECT } from '../../../lib/types/project';
|
||||
import { ALL_PROJECTS } from '../../../lib/util/constants';
|
||||
import { SegmentService } from '../../../lib/services/segment-service';
|
||||
import { GroupService } from '../../../lib/services/group-service';
|
||||
import { FavoritesService } from '../../../lib/services';
|
||||
import { EventService, FavoritesService } from '../../../lib/services';
|
||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
||||
import { DependentFeaturesReadModel } from '../../../lib/features/dependent-features/dependent-features-read-model';
|
||||
@ -28,6 +28,7 @@ import { DependentFeaturesReadModel } from '../../../lib/features/dependent-feat
|
||||
let db: ITestDb;
|
||||
let stores: IUnleashStores;
|
||||
let accessService: AccessService;
|
||||
let eventService: EventService;
|
||||
let groupService: GroupService;
|
||||
let featureToggleService;
|
||||
let favoritesService;
|
||||
@ -237,7 +238,8 @@ beforeAll(async () => {
|
||||
// @ts-ignore
|
||||
experimental: { environments: { enabled: true } },
|
||||
});
|
||||
groupService = new GroupService(stores, { getLogger });
|
||||
eventService = new EventService(stores, config);
|
||||
groupService = new GroupService(stores, { getLogger }, eventService);
|
||||
accessService = new AccessService(stores, config, groupService);
|
||||
const roles = await accessService.getRootRoles();
|
||||
editorRole = roles.find((r) => r.name === RoleName.EDITOR);
|
||||
@ -261,14 +263,16 @@ beforeAll(async () => {
|
||||
stores,
|
||||
changeRequestAccessReadModel,
|
||||
config,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
),
|
||||
accessService,
|
||||
eventService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
dependentFeaturesReadModel,
|
||||
);
|
||||
favoritesService = new FavoritesService(stores, config);
|
||||
favoritesService = new FavoritesService(stores, config, eventService);
|
||||
projectService = new ProjectService(
|
||||
stores,
|
||||
config,
|
||||
@ -276,6 +280,7 @@ beforeAll(async () => {
|
||||
featureToggleService,
|
||||
groupService,
|
||||
favoritesService,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
|
||||
|
@ -7,6 +7,7 @@ import { IUnleashStores } from '../../../lib/types';
|
||||
import SimpleAddon from '../../../lib/services/addon-service-test-simple-addon';
|
||||
import TagTypeService from '../../../lib/services/tag-type-service';
|
||||
import { FEATURE_CREATED } from '../../../lib/types/events';
|
||||
import { EventService } from '../../../lib/services';
|
||||
|
||||
const addonProvider = { simple: new SimpleAddon() };
|
||||
|
||||
@ -20,11 +21,13 @@ beforeAll(async () => {
|
||||
});
|
||||
db = await dbInit('addon_service_serial', getLogger);
|
||||
stores = db.stores;
|
||||
const tagTypeService = new TagTypeService(stores, config);
|
||||
const eventService = new EventService(stores, config);
|
||||
const tagTypeService = new TagTypeService(stores, config, eventService);
|
||||
addonService = new AddonService(
|
||||
stores,
|
||||
config,
|
||||
tagTypeService,
|
||||
eventService,
|
||||
addonProvider,
|
||||
);
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ import FeatureToggleService from '../../../lib/services/feature-toggle-service';
|
||||
import { AccessService } from '../../../lib/services/access-service';
|
||||
import { SegmentService } from '../../../lib/services/segment-service';
|
||||
import { GroupService } from '../../../lib/services/group-service';
|
||||
import { FavoritesService } from '../../../lib/services';
|
||||
import { EventService, FavoritesService } from '../../../lib/services';
|
||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
||||
import { DependentFeaturesReadModel } from '../../../lib/features/dependent-features/dependent-features-read-model';
|
||||
@ -27,7 +27,8 @@ beforeAll(async () => {
|
||||
});
|
||||
db = await dbInit('api_token_service_serial', getLogger);
|
||||
stores = db.stores;
|
||||
const groupService = new GroupService(stores, config);
|
||||
const eventService = new EventService(stores, config);
|
||||
const groupService = new GroupService(stores, config, eventService);
|
||||
const accessService = new AccessService(stores, config, groupService);
|
||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
||||
db.rawDatabase,
|
||||
@ -47,9 +48,11 @@ beforeAll(async () => {
|
||||
stores,
|
||||
changeRequestAccessReadModel,
|
||||
config,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
),
|
||||
accessService,
|
||||
eventService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
dependentFeaturesReadModel,
|
||||
@ -65,7 +68,7 @@ beforeAll(async () => {
|
||||
name: 'Some Name',
|
||||
email: 'test@getunleash.io',
|
||||
});
|
||||
favoritesService = new FavoritesService(stores, config);
|
||||
favoritesService = new FavoritesService(stores, config, eventService);
|
||||
projectService = new ProjectService(
|
||||
stores,
|
||||
config,
|
||||
@ -73,12 +76,13 @@ beforeAll(async () => {
|
||||
featureToggleService,
|
||||
groupService,
|
||||
favoritesService,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
|
||||
await projectService.createProject(project, user);
|
||||
|
||||
apiTokenService = new ApiTokenService(stores, config);
|
||||
apiTokenService = new ApiTokenService(stores, config, eventService);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
|
@ -4,6 +4,7 @@ import dbInit from '../helpers/database-init';
|
||||
import { DEFAULT_ENV } from '../../../lib/util';
|
||||
import {
|
||||
AccessService,
|
||||
EventService,
|
||||
GroupService,
|
||||
SegmentService,
|
||||
} from '../../../lib/services';
|
||||
@ -53,8 +54,8 @@ beforeAll(async () => {
|
||||
);
|
||||
unleashConfig = config;
|
||||
stores = db.stores;
|
||||
|
||||
const groupService = new GroupService(stores, config);
|
||||
const eventService = new EventService(stores, config);
|
||||
const groupService = new GroupService(stores, config, eventService);
|
||||
const accessService = new AccessService(stores, config, groupService);
|
||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
||||
db.rawDatabase,
|
||||
@ -71,6 +72,7 @@ beforeAll(async () => {
|
||||
stores,
|
||||
changeRequestAccessReadModel,
|
||||
config,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
|
||||
@ -79,6 +81,7 @@ beforeAll(async () => {
|
||||
config,
|
||||
segmentService,
|
||||
accessService,
|
||||
eventService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
dependentFeaturesReadModel,
|
||||
@ -457,7 +460,8 @@ test('If change requests are enabled, cannot change variants without going via C
|
||||
{ name: featureName },
|
||||
'test-user',
|
||||
);
|
||||
const groupService = new GroupService(stores, unleashConfig);
|
||||
const eventService = new EventService(stores, unleashConfig);
|
||||
const groupService = new GroupService(stores, unleashConfig, eventService);
|
||||
const accessService = new AccessService(
|
||||
stores,
|
||||
unleashConfig,
|
||||
@ -485,6 +489,7 @@ test('If change requests are enabled, cannot change variants without going via C
|
||||
},
|
||||
segmentService,
|
||||
accessService,
|
||||
eventService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
dependentFeaturesReadModel,
|
||||
@ -549,7 +554,8 @@ test('If CRs are protected for any environment in the project stops bulk update
|
||||
project.id,
|
||||
disabledEnv.name,
|
||||
);
|
||||
const groupService = new GroupService(stores, unleashConfig);
|
||||
const eventService = new EventService(stores, unleashConfig);
|
||||
const groupService = new GroupService(stores, unleashConfig, eventService);
|
||||
const accessService = new AccessService(
|
||||
stores,
|
||||
unleashConfig,
|
||||
@ -577,6 +583,7 @@ test('If CRs are protected for any environment in the project stops bulk update
|
||||
},
|
||||
segmentService,
|
||||
accessService,
|
||||
eventService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
dependentFeaturesReadModel,
|
||||
|
@ -3,10 +3,12 @@ import getLogger from '../../fixtures/no-logger';
|
||||
import { createTestConfig } from '../../config/test-config';
|
||||
import { GroupService } from '../../../lib/services/group-service';
|
||||
import GroupStore from '../../../lib/db/group-store';
|
||||
import { EventService } from '../../../lib/services';
|
||||
|
||||
let stores;
|
||||
let db: ITestDb;
|
||||
|
||||
let eventService: EventService;
|
||||
let groupService: GroupService;
|
||||
let groupStore: GroupStore;
|
||||
let user;
|
||||
@ -21,7 +23,8 @@ beforeAll(async () => {
|
||||
const config = createTestConfig({
|
||||
getLogger,
|
||||
});
|
||||
groupService = new GroupService(stores, config);
|
||||
eventService = new EventService(stores, config);
|
||||
groupService = new GroupService(stores, config, eventService);
|
||||
groupStore = stores.groupStore;
|
||||
|
||||
await stores.groupStore.create({
|
||||
|
@ -27,6 +27,7 @@ import { ISegmentService } from '../../../lib/segments/segment-service-interface
|
||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
||||
import { DependentFeaturesReadModel } from '../../../lib/features/dependent-features/dependent-features-read-model';
|
||||
import { EventService } from '../../../lib/services';
|
||||
|
||||
let stores: IUnleashStores;
|
||||
let db: ITestDb;
|
||||
@ -38,7 +39,8 @@ beforeAll(async () => {
|
||||
const config = createTestConfig();
|
||||
db = await dbInit('playground_service_serial', config.getLogger);
|
||||
stores = db.stores;
|
||||
const groupService = new GroupService(stores, config);
|
||||
const eventService = new EventService(stores, config);
|
||||
const groupService = new GroupService(stores, config, eventService);
|
||||
const accessService = new AccessService(stores, config, groupService);
|
||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
||||
db.rawDatabase,
|
||||
@ -55,6 +57,7 @@ beforeAll(async () => {
|
||||
stores,
|
||||
changeRequestAccessReadModel,
|
||||
config,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
|
||||
@ -63,6 +66,7 @@ beforeAll(async () => {
|
||||
config,
|
||||
segmentService,
|
||||
accessService,
|
||||
eventService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
dependentFeaturesReadModel,
|
||||
|
@ -9,7 +9,7 @@ import { IUnleashStores } from '../../../lib/types';
|
||||
import { IUser } from '../../../lib/server-impl';
|
||||
import { SegmentService } from '../../../lib/services/segment-service';
|
||||
import { GroupService } from '../../../lib/services/group-service';
|
||||
import { FavoritesService } from '../../../lib/services';
|
||||
import { EventService, FavoritesService } from '../../../lib/services';
|
||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
||||
import { DependentFeaturesReadModel } from '../../../lib/features/dependent-features/dependent-features-read-model';
|
||||
@ -19,6 +19,7 @@ let db: ITestDb;
|
||||
let projectService;
|
||||
let groupService;
|
||||
let accessService;
|
||||
let eventService: EventService;
|
||||
let projectHealthService;
|
||||
let featureToggleService;
|
||||
let favoritesService;
|
||||
@ -32,7 +33,8 @@ beforeAll(async () => {
|
||||
name: 'Some Name',
|
||||
email: 'test@getunleash.io',
|
||||
});
|
||||
groupService = new GroupService(stores, config);
|
||||
eventService = new EventService(stores, config);
|
||||
groupService = new GroupService(stores, config, eventService);
|
||||
accessService = new AccessService(stores, config, groupService);
|
||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
||||
db.rawDatabase,
|
||||
@ -52,14 +54,16 @@ beforeAll(async () => {
|
||||
stores,
|
||||
changeRequestAccessReadModel,
|
||||
config,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
),
|
||||
accessService,
|
||||
eventService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
dependentFeaturesReadModel,
|
||||
);
|
||||
favoritesService = new FavoritesService(stores, config);
|
||||
favoritesService = new FavoritesService(stores, config, eventService);
|
||||
|
||||
projectService = new ProjectService(
|
||||
stores,
|
||||
@ -68,6 +72,7 @@ beforeAll(async () => {
|
||||
featureToggleService,
|
||||
groupService,
|
||||
favoritesService,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
projectHealthService = new ProjectHealthService(
|
||||
|
@ -11,7 +11,7 @@ import EnvironmentService from '../../../lib/services/environment-service';
|
||||
import IncompatibleProjectError from '../../../lib/error/incompatible-project-error';
|
||||
import { SegmentService } from '../../../lib/services/segment-service';
|
||||
import { GroupService } from '../../../lib/services/group-service';
|
||||
import { FavoritesService } from '../../../lib/services';
|
||||
import { EventService, FavoritesService } from '../../../lib/services';
|
||||
import { FeatureEnvironmentEvent } from '../../../lib/types/events';
|
||||
import { addDays, subDays } from 'date-fns';
|
||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
||||
@ -24,6 +24,7 @@ let db: ITestDb;
|
||||
let projectService: ProjectService;
|
||||
let groupService: GroupService;
|
||||
let accessService: AccessService;
|
||||
let eventService: EventService;
|
||||
let environmentService: EnvironmentService;
|
||||
let featureToggleService: FeatureToggleService;
|
||||
let favoritesService: FavoritesService;
|
||||
@ -53,7 +54,8 @@ beforeAll(async () => {
|
||||
flags: { privateProjects: true },
|
||||
},
|
||||
});
|
||||
groupService = new GroupService(stores, config);
|
||||
eventService = new EventService(stores, config);
|
||||
groupService = new GroupService(stores, config, eventService);
|
||||
accessService = new AccessService(stores, config, groupService);
|
||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
||||
db.rawDatabase,
|
||||
@ -73,15 +75,17 @@ beforeAll(async () => {
|
||||
stores,
|
||||
changeRequestAccessReadModel,
|
||||
config,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
),
|
||||
accessService,
|
||||
eventService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
dependentFeaturesReadModel,
|
||||
);
|
||||
|
||||
favoritesService = new FavoritesService(stores, config);
|
||||
favoritesService = new FavoritesService(stores, config, eventService);
|
||||
environmentService = new EnvironmentService(stores, config);
|
||||
projectService = new ProjectService(
|
||||
stores,
|
||||
@ -90,6 +94,7 @@ beforeAll(async () => {
|
||||
featureToggleService,
|
||||
groupService,
|
||||
favoritesService,
|
||||
eventService,
|
||||
privateProjectChecker,
|
||||
);
|
||||
});
|
||||
@ -1349,14 +1354,13 @@ test('should calculate average time to production', async () => {
|
||||
|
||||
await Promise.all(
|
||||
featureToggles.map((toggle) => {
|
||||
return stores.eventStore.store(
|
||||
return eventService.storeEvent(
|
||||
new FeatureEnvironmentEvent({
|
||||
enabled: true,
|
||||
project: project.id,
|
||||
featureName: toggle.name,
|
||||
environment: 'default',
|
||||
createdBy: 'Fredrik',
|
||||
tags: [],
|
||||
}),
|
||||
);
|
||||
}),
|
||||
@ -1407,19 +1411,19 @@ test('should calculate average time to production ignoring some items', async ()
|
||||
await updateFeature(toggle.name, {
|
||||
created_at: subDays(new Date(), 20),
|
||||
});
|
||||
await stores.eventStore.store(
|
||||
await eventService.storeEvent(
|
||||
new FeatureEnvironmentEvent(makeEvent(toggle.name)),
|
||||
);
|
||||
// ignore events added after first enabled
|
||||
await updateEventCreatedAt(addDays(new Date(), 1), toggle.name);
|
||||
await stores.eventStore.store(
|
||||
await eventService.storeEvent(
|
||||
new FeatureEnvironmentEvent(makeEvent(toggle.name)),
|
||||
);
|
||||
|
||||
// ignore toggles enabled in non-prod envs
|
||||
const devToggle = { name: 'dev-toggle' };
|
||||
await featureToggleService.createFeatureToggle(project.id, devToggle, user);
|
||||
await stores.eventStore.store(
|
||||
await eventService.storeEvent(
|
||||
new FeatureEnvironmentEvent({
|
||||
...makeEvent(devToggle.name),
|
||||
environment: 'customEnv',
|
||||
@ -1433,7 +1437,7 @@ test('should calculate average time to production ignoring some items', async ()
|
||||
otherProjectToggle,
|
||||
user,
|
||||
);
|
||||
await stores.eventStore.store(
|
||||
await eventService.storeEvent(
|
||||
new FeatureEnvironmentEvent(makeEvent(otherProjectToggle.name)),
|
||||
);
|
||||
|
||||
@ -1444,7 +1448,7 @@ test('should calculate average time to production ignoring some items', async ()
|
||||
nonReleaseToggle,
|
||||
user,
|
||||
);
|
||||
await stores.eventStore.store(
|
||||
await eventService.storeEvent(
|
||||
new FeatureEnvironmentEvent(makeEvent(nonReleaseToggle.name)),
|
||||
);
|
||||
|
||||
@ -1455,7 +1459,7 @@ test('should calculate average time to production ignoring some items', async ()
|
||||
previouslyDeleteToggle,
|
||||
user,
|
||||
);
|
||||
await stores.eventStore.store(
|
||||
await eventService.storeEvent(
|
||||
new FeatureEnvironmentEvent(makeEvent(previouslyDeleteToggle.name)),
|
||||
);
|
||||
await updateEventCreatedAt(
|
||||
@ -1625,14 +1629,13 @@ test('should return average time to production per toggle', async () => {
|
||||
|
||||
await Promise.all(
|
||||
featureToggles.map((toggle) => {
|
||||
return stores.eventStore.store(
|
||||
return eventService.storeEvent(
|
||||
new FeatureEnvironmentEvent({
|
||||
enabled: true,
|
||||
project: project.id,
|
||||
featureName: toggle.name,
|
||||
environment: 'default',
|
||||
createdBy: 'Fredrik',
|
||||
tags: [],
|
||||
}),
|
||||
);
|
||||
}),
|
||||
@ -1704,14 +1707,13 @@ test('should return average time to production per toggle for a specific project
|
||||
|
||||
await Promise.all(
|
||||
featureTogglesProject1.map((toggle) => {
|
||||
return stores.eventStore.store(
|
||||
return eventService.storeEvent(
|
||||
new FeatureEnvironmentEvent({
|
||||
enabled: true,
|
||||
project: project1.id,
|
||||
featureName: toggle.name,
|
||||
environment: 'default',
|
||||
createdBy: 'Fredrik',
|
||||
tags: [],
|
||||
}),
|
||||
);
|
||||
}),
|
||||
@ -1719,14 +1721,13 @@ test('should return average time to production per toggle for a specific project
|
||||
|
||||
await Promise.all(
|
||||
featureTogglesProject2.map((toggle) => {
|
||||
return stores.eventStore.store(
|
||||
return eventService.storeEvent(
|
||||
new FeatureEnvironmentEvent({
|
||||
enabled: true,
|
||||
project: project2.id,
|
||||
featureName: toggle.name,
|
||||
environment: 'default',
|
||||
createdBy: 'Fredrik',
|
||||
tags: [],
|
||||
}),
|
||||
);
|
||||
}),
|
||||
@ -1783,14 +1784,13 @@ test('should return average time to production per toggle and include archived t
|
||||
|
||||
await Promise.all(
|
||||
featureTogglesProject1.map((toggle) => {
|
||||
return stores.eventStore.store(
|
||||
return eventService.storeEvent(
|
||||
new FeatureEnvironmentEvent({
|
||||
enabled: true,
|
||||
project: project1.id,
|
||||
featureName: toggle.name,
|
||||
environment: 'default',
|
||||
createdBy: 'Fredrik',
|
||||
tags: [],
|
||||
}),
|
||||
);
|
||||
}),
|
||||
|
@ -12,7 +12,7 @@ import { IUser } from '../../../lib/types/user';
|
||||
import SettingService from '../../../lib/services/setting-service';
|
||||
import FakeSettingStore from '../../fixtures/fake-setting-store';
|
||||
import { GroupService } from '../../../lib/services/group-service';
|
||||
import FakeEventStore from '../../fixtures/fake-event-store';
|
||||
import { EventService } from '../../../lib/services';
|
||||
|
||||
const config: IUnleashConfig = createTestConfig();
|
||||
|
||||
@ -28,7 +28,8 @@ let sessionService: SessionService;
|
||||
beforeAll(async () => {
|
||||
db = await dbInit('reset_token_service_serial', getLogger);
|
||||
stores = db.stores;
|
||||
const groupService = new GroupService(stores, config);
|
||||
const eventService = new EventService(stores, config);
|
||||
const groupService = new GroupService(stores, config, eventService);
|
||||
accessService = new AccessService(stores, config, groupService);
|
||||
resetTokenService = new ResetTokenService(stores, config);
|
||||
sessionService = new SessionService(stores, config);
|
||||
@ -36,15 +37,16 @@ beforeAll(async () => {
|
||||
const settingService = new SettingService(
|
||||
{
|
||||
settingStore: new FakeSettingStore(),
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
|
||||
userService = new UserService(stores, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
SETTING_DELETED,
|
||||
SETTING_UPDATED,
|
||||
} from '../../../lib/types/events';
|
||||
import { EventService } from '../../../lib/services';
|
||||
|
||||
let stores: IUnleashStores;
|
||||
let db;
|
||||
@ -16,7 +17,8 @@ beforeAll(async () => {
|
||||
const config = createTestConfig();
|
||||
db = await dbInit('setting_service_serial', config.getLogger);
|
||||
stores = db.stores;
|
||||
service = new SettingService(stores, config);
|
||||
const eventService = new EventService(stores, config);
|
||||
service = new SettingService(stores, config, eventService);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await stores.eventStore.deleteAll();
|
||||
|
@ -3,6 +3,7 @@ import dbInit from '../helpers/database-init';
|
||||
import StateService from '../../../lib/services/state-service';
|
||||
import oldFormat from '../../examples/variantsexport_v3.json';
|
||||
import { WeightType } from '../../../lib/types/model';
|
||||
import { EventService } from '../../../lib/services';
|
||||
|
||||
let stores;
|
||||
let db;
|
||||
@ -12,7 +13,8 @@ beforeAll(async () => {
|
||||
const config = createTestConfig();
|
||||
db = await dbInit('state_service_serial', config.getLogger);
|
||||
stores = db.stores;
|
||||
stateService = new StateService(stores, config);
|
||||
const eventService = new EventService(stores, config);
|
||||
stateService = new StateService(stores, config, eventService);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
|
@ -17,6 +17,7 @@ import { GroupService } from '../../../lib/services/group-service';
|
||||
import { randomId } from '../../../lib/util/random-id';
|
||||
import { BadDataError } from '../../../lib/error';
|
||||
import PasswordMismatch from '../../../lib/error/password-mismatch';
|
||||
import { EventService } from '../../../lib/services';
|
||||
|
||||
let db;
|
||||
let stores;
|
||||
@ -31,17 +32,19 @@ beforeAll(async () => {
|
||||
db = await dbInit('user_service_serial', getLogger);
|
||||
stores = db.stores;
|
||||
const config = createTestConfig();
|
||||
const groupService = new GroupService(stores, config);
|
||||
const eventService = new EventService(stores, config);
|
||||
const groupService = new GroupService(stores, config, eventService);
|
||||
const accessService = new AccessService(stores, config, groupService);
|
||||
const resetTokenService = new ResetTokenService(stores, config);
|
||||
const emailService = new EmailService(undefined, config.getLogger);
|
||||
sessionService = new SessionService(stores, config);
|
||||
settingService = new SettingService(stores, config);
|
||||
settingService = new SettingService(stores, config, eventService);
|
||||
|
||||
userService = new UserService(stores, config, {
|
||||
accessService,
|
||||
resetTokenService,
|
||||
emailService,
|
||||
eventService,
|
||||
sessionService,
|
||||
settingService,
|
||||
});
|
||||
|
@ -198,7 +198,6 @@ test('Should get all events of type', async () => {
|
||||
featureName: data.name,
|
||||
createdBy: 'test-user',
|
||||
data,
|
||||
tags: [],
|
||||
})
|
||||
: new FeatureDeletedEvent({
|
||||
project: data.project,
|
||||
|
Loading…
Reference in New Issue
Block a user