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