mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-20 00:08:02 +01:00
feat: walking skeleton of private projects (#4753)
This commit is contained in:
parent
387f48617d
commit
15baea1d25
@ -29,6 +29,7 @@ import maintenanceMiddleware from './middleware/maintenance-middleware';
|
||||
import { unless } from './middleware/unless-middleware';
|
||||
import { catchAllErrorHandler } from './middleware/catch-all-error-handler';
|
||||
import NotFoundError from './error/notfound-error';
|
||||
import privateProjectMiddleware from './features/private-project/privateProjectMiddleware';
|
||||
|
||||
export default async function getApp(
|
||||
config: IUnleashConfig,
|
||||
@ -157,6 +158,8 @@ export default async function getApp(
|
||||
}
|
||||
}
|
||||
|
||||
app.use(baseUriPath, privateProjectMiddleware(config, services));
|
||||
|
||||
app.use(
|
||||
baseUriPath,
|
||||
rbacMiddleware(config, stores, services.accessService),
|
||||
|
@ -36,6 +36,7 @@ import { AccountStore } from './account-store';
|
||||
import ProjectStatsStore from './project-stats-store';
|
||||
import { Db } from './db';
|
||||
import { ImportTogglesStore } from '../features/export-import-toggles/import-toggles-store';
|
||||
import PrivateProjectStore from '../features/private-project/privateProjectStore';
|
||||
|
||||
export const createStores = (
|
||||
config: IUnleashConfig,
|
||||
@ -128,6 +129,7 @@ export const createStores = (
|
||||
),
|
||||
projectStatsStore: new ProjectStatsStore(db, eventBus, getLogger),
|
||||
importTogglesStore: new ImportTogglesStore(db),
|
||||
privateProjectStore: new PrivateProjectStore(db, getLogger),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -41,6 +41,10 @@ import {
|
||||
} from '../segment/createSegmentService';
|
||||
import StrategyStore from '../../db/strategy-store';
|
||||
import FakeStrategiesStore from '../../../test/fixtures/fake-strategies-store';
|
||||
import {
|
||||
createFakeprivateProjectChecker,
|
||||
createPrivateProjectChecker,
|
||||
} from '../private-project/createPrivateProjectChecker';
|
||||
|
||||
export const createFeatureToggleService = (
|
||||
db: Db,
|
||||
@ -98,6 +102,9 @@ export const createFeatureToggleService = (
|
||||
db,
|
||||
config,
|
||||
);
|
||||
|
||||
const privateProjectChecker = createPrivateProjectChecker(db, config);
|
||||
|
||||
const featureToggleService = new FeatureToggleService(
|
||||
{
|
||||
featureStrategiesStore,
|
||||
@ -114,6 +121,7 @@ export const createFeatureToggleService = (
|
||||
segmentService,
|
||||
accessService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
);
|
||||
return featureToggleService;
|
||||
};
|
||||
@ -147,6 +155,7 @@ export const createFakeFeatureToggleService = (
|
||||
);
|
||||
const segmentService = createFakeSegmentService(config);
|
||||
const changeRequestAccessReadModel = createFakeChangeRequestAccessService();
|
||||
const fakeprivateProjectChecker = createFakeprivateProjectChecker();
|
||||
const featureToggleService = new FeatureToggleService(
|
||||
{
|
||||
featureStrategiesStore,
|
||||
@ -163,6 +172,7 @@ export const createFakeFeatureToggleService = (
|
||||
segmentService,
|
||||
accessService,
|
||||
changeRequestAccessReadModel,
|
||||
fakeprivateProjectChecker,
|
||||
);
|
||||
return featureToggleService;
|
||||
};
|
||||
|
@ -0,0 +1,21 @@
|
||||
import { Db, IUnleashConfig } from 'lib/server-impl';
|
||||
import PrivateProjectStore from './privateProjectStore';
|
||||
import { PrivateProjectChecker } from './privateProjectChecker';
|
||||
import { FakeprivateProjectChecker } from './fakePrivateProjectChecker';
|
||||
|
||||
export const createPrivateProjectChecker = (
|
||||
db: Db,
|
||||
config: IUnleashConfig,
|
||||
): PrivateProjectChecker => {
|
||||
const { getLogger } = config;
|
||||
const privateProjectStore = new PrivateProjectStore(db, getLogger);
|
||||
|
||||
return new PrivateProjectChecker({
|
||||
privateProjectStore: privateProjectStore,
|
||||
});
|
||||
};
|
||||
|
||||
export const createFakeprivateProjectChecker =
|
||||
(): FakeprivateProjectChecker => {
|
||||
return new FakeprivateProjectChecker();
|
||||
};
|
@ -0,0 +1,8 @@
|
||||
import { IPrivateProjectChecker } from './privateProjectCheckerType';
|
||||
|
||||
export class FakeprivateProjectChecker implements IPrivateProjectChecker {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async getUserAccessibleProjects(userId: number): Promise<string[]> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
17
src/lib/features/private-project/privateProjectChecker.ts
Normal file
17
src/lib/features/private-project/privateProjectChecker.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { IUnleashStores } from '../../types';
|
||||
import { IPrivateProjectStore } from './privateProjectStoreType';
|
||||
import { IPrivateProjectChecker } from './privateProjectCheckerType';
|
||||
|
||||
export class PrivateProjectChecker implements IPrivateProjectChecker {
|
||||
private privateProjectStore: IPrivateProjectStore;
|
||||
|
||||
constructor({
|
||||
privateProjectStore,
|
||||
}: Pick<IUnleashStores, 'privateProjectStore'>) {
|
||||
this.privateProjectStore = privateProjectStore;
|
||||
}
|
||||
|
||||
async getUserAccessibleProjects(userId: number): Promise<string[]> {
|
||||
return this.privateProjectStore.getUserAccessibleProjects(userId);
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
export interface IPrivateProjectChecker {
|
||||
getUserAccessibleProjects(userId: number): Promise<string[]>;
|
||||
}
|
40
src/lib/features/private-project/privateProjectMiddleware.ts
Normal file
40
src/lib/features/private-project/privateProjectMiddleware.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { IUnleashConfig, IUnleashServices } from '../../types';
|
||||
import { findParam } from '../../middleware';
|
||||
import { NextFunction, Response } from 'express';
|
||||
|
||||
const privateProjectMiddleware = (
|
||||
{
|
||||
getLogger,
|
||||
flagResolver,
|
||||
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>,
|
||||
{ projectService, accessService }: IUnleashServices,
|
||||
): any => {
|
||||
const logger = getLogger('/middleware/project-middleware.ts');
|
||||
logger.debug('Enabling private project middleware');
|
||||
|
||||
if (!flagResolver.isEnabled('privateProjects')) {
|
||||
return (req, res, next) => next();
|
||||
}
|
||||
|
||||
return async (req, res: Response, next: NextFunction) => {
|
||||
req.checkPrivateProjectPermissions = async () => {
|
||||
const { user } = req;
|
||||
|
||||
let projectId =
|
||||
findParam('projectId', req) || findParam('project', req);
|
||||
|
||||
if (projectId === undefined) {
|
||||
return true;
|
||||
}
|
||||
const permissions = await accessService.getPermissionsForUser(user);
|
||||
|
||||
return (
|
||||
permissions.map((p) => p.permission).includes('ADMIN') ||
|
||||
projectService.isProjectUser(user.id, projectId)
|
||||
);
|
||||
};
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
export default privateProjectMiddleware;
|
42
src/lib/features/private-project/privateProjectStore.ts
Normal file
42
src/lib/features/private-project/privateProjectStore.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { Db } from '../../db/db';
|
||||
import { Logger, LogProvider } from '../../logger';
|
||||
import { IPrivateProjectStore } from './privateProjectStoreType';
|
||||
|
||||
class PrivateProjectStore implements IPrivateProjectStore {
|
||||
private db: Db;
|
||||
|
||||
private logger: Logger;
|
||||
|
||||
constructor(db: Db, getLogger: LogProvider) {
|
||||
this.db = db;
|
||||
this.logger = getLogger('project-permission-store.ts');
|
||||
}
|
||||
|
||||
destroy(): void {}
|
||||
|
||||
async getUserAccessibleProjects(userId: number): Promise<string[]> {
|
||||
const projects = await this.db
|
||||
.from((db) => {
|
||||
db.select('project')
|
||||
.from('role_user')
|
||||
.leftJoin('roles', 'role_user.role_id', 'roles.id')
|
||||
.where('user_id', userId)
|
||||
.union((queryBuilder) => {
|
||||
queryBuilder
|
||||
.select('project')
|
||||
.from('group_role')
|
||||
.leftJoin(
|
||||
'group_user',
|
||||
'group_user.group_id',
|
||||
'group_role.group_id',
|
||||
)
|
||||
.where('user_id', userId);
|
||||
})
|
||||
.as('query');
|
||||
})
|
||||
.pluck('project');
|
||||
return projects;
|
||||
}
|
||||
}
|
||||
|
||||
export default PrivateProjectStore;
|
@ -0,0 +1,3 @@
|
||||
export interface IPrivateProjectStore {
|
||||
getUserAccessibleProjects(userId: number): Promise<string[]>;
|
||||
}
|
@ -7,6 +7,7 @@ import {
|
||||
import { IUnleashConfig } from '../types/option';
|
||||
import { IUnleashStores } from '../types/stores';
|
||||
import User from '../types/user';
|
||||
import { Request } from 'express';
|
||||
|
||||
interface PermissionChecker {
|
||||
hasPermission(
|
||||
@ -17,9 +18,9 @@ interface PermissionChecker {
|
||||
): Promise<boolean>;
|
||||
}
|
||||
|
||||
function findParam(
|
||||
export function findParam(
|
||||
name: string,
|
||||
{ params, body }: any,
|
||||
{ params, body }: Request,
|
||||
defaultValue?: string,
|
||||
): string | undefined {
|
||||
let found = params ? params[name] : undefined;
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { IRouter, Router, Request, Response, RequestHandler } from 'express';
|
||||
import { Logger } from 'lib/logger';
|
||||
import { IUnleashConfig } from '../types/option';
|
||||
import { NONE } from '../types/permissions';
|
||||
import { IUnleashConfig, NONE } from '../types';
|
||||
import { handleErrors } from './util';
|
||||
import requireContentType from '../middleware/content_type_checker';
|
||||
import { PermissionError } from '../error';
|
||||
@ -55,6 +54,17 @@ const checkPermission =
|
||||
return res.status(403).json(new PermissionError(permissions)).end();
|
||||
};
|
||||
|
||||
const checkPrivateProjectPermissions = () => async (req, res, next) => {
|
||||
if (
|
||||
!req.checkPrivateProjectPermissions ||
|
||||
(await req.checkPrivateProjectPermissions())
|
||||
) {
|
||||
return next();
|
||||
}
|
||||
|
||||
return res.status(404).end();
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for Controllers to standardize binding to express Router.
|
||||
*
|
||||
@ -100,6 +110,7 @@ export default class Controller {
|
||||
this.app[options.method](
|
||||
options.path,
|
||||
checkPermission(options.permission),
|
||||
checkPrivateProjectPermissions(),
|
||||
this.useContentTypeMiddleware(options),
|
||||
this.useRouteErrorHandler(options.handler.bind(this)),
|
||||
);
|
||||
@ -186,6 +197,7 @@ export default class Controller {
|
||||
this.app.post(
|
||||
path,
|
||||
checkPermission(permission),
|
||||
checkPrivateProjectPermissions(),
|
||||
filehandler.bind(this),
|
||||
this.useRouteErrorHandler(handler.bind(this)),
|
||||
);
|
||||
|
@ -9,6 +9,7 @@ import FeatureToggleService from './feature-toggle-service';
|
||||
import { AccessService } from './access-service';
|
||||
import { IChangeRequestAccessReadModel } from 'lib/features/change-request-access-service/change-request-access-read-model';
|
||||
import { ISegmentService } from 'lib/segments/segment-service-interface';
|
||||
import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
|
||||
|
||||
test('Should only store events for potentially stale on', async () => {
|
||||
expect.assertions(2);
|
||||
@ -49,6 +50,7 @@ test('Should only store events for potentially stale on', async () => {
|
||||
{} as ISegmentService,
|
||||
{} as AccessService,
|
||||
{} as IChangeRequestAccessReadModel,
|
||||
{} as IPrivateProjectChecker,
|
||||
);
|
||||
|
||||
await featureToggleService.updatePotentiallyStaleFeatures();
|
||||
|
@ -95,6 +95,7 @@ import { unique } from '../util/unique';
|
||||
import { ISegmentService } from 'lib/segments/segment-service-interface';
|
||||
import { IChangeRequestAccessReadModel } from '../features/change-request-access-service/change-request-access-read-model';
|
||||
import { checkFeatureFlagNamesAgainstPattern } from '../features/feature-naming-pattern/feature-naming-validation';
|
||||
import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
|
||||
|
||||
interface IFeatureContext {
|
||||
featureName: string;
|
||||
@ -154,6 +155,8 @@ class FeatureToggleService {
|
||||
|
||||
private changeRequestAccessReadModel: IChangeRequestAccessReadModel;
|
||||
|
||||
private privateProjectChecker: IPrivateProjectChecker;
|
||||
|
||||
constructor(
|
||||
{
|
||||
featureStrategiesStore,
|
||||
@ -184,6 +187,7 @@ class FeatureToggleService {
|
||||
segmentService: ISegmentService,
|
||||
accessService: AccessService,
|
||||
changeRequestAccessReadModel: IChangeRequestAccessReadModel,
|
||||
privateProjectChecker: IPrivateProjectChecker,
|
||||
) {
|
||||
this.logger = getLogger('services/feature-toggle-service.ts');
|
||||
this.featureStrategiesStore = featureStrategiesStore;
|
||||
@ -199,6 +203,7 @@ class FeatureToggleService {
|
||||
this.accessService = accessService;
|
||||
this.flagResolver = flagResolver;
|
||||
this.changeRequestAccessReadModel = changeRequestAccessReadModel;
|
||||
this.privateProjectChecker = privateProjectChecker;
|
||||
}
|
||||
|
||||
async validateFeaturesContext(
|
||||
@ -1017,11 +1022,20 @@ class FeatureToggleService {
|
||||
userId?: number,
|
||||
archived: boolean = false,
|
||||
): Promise<FeatureToggle[]> {
|
||||
return this.featureToggleClientStore.getAdmin({
|
||||
const features = await this.featureToggleClientStore.getAdmin({
|
||||
featureQuery: query,
|
||||
userId,
|
||||
archived,
|
||||
});
|
||||
|
||||
if (this.flagResolver.isEnabled('privateProjects') && userId) {
|
||||
const projects =
|
||||
await this.privateProjectChecker.getUserAccessibleProjects(
|
||||
userId,
|
||||
);
|
||||
return features.filter((f) => projects.includes(f.project));
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
async getFeatureOverview(
|
||||
|
@ -60,6 +60,10 @@ import ConfigurationRevisionService from '../features/feature-toggle/configurati
|
||||
import { createFeatureToggleService } from '../features';
|
||||
import EventAnnouncerService from './event-announcer-service';
|
||||
import { createGroupService } from '../features/group/createGroupService';
|
||||
import {
|
||||
createFakeprivateProjectChecker,
|
||||
createPrivateProjectChecker,
|
||||
} from '../features/private-project/createPrivateProjectChecker';
|
||||
|
||||
// TODO: will be moved to scheduler feature directory
|
||||
export const scheduleServices = async (
|
||||
@ -184,12 +188,16 @@ export const createServices = (
|
||||
changeRequestAccessReadModel,
|
||||
config,
|
||||
);
|
||||
const privateProjectChecker = db
|
||||
? createPrivateProjectChecker(db, config)
|
||||
: createFakeprivateProjectChecker();
|
||||
const featureToggleServiceV2 = new FeatureToggleService(
|
||||
stores,
|
||||
config,
|
||||
segmentService,
|
||||
accessService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
);
|
||||
const environmentService = new EnvironmentService(stores, config);
|
||||
const featureTagService = new FeatureTagService(stores, config);
|
||||
|
@ -33,6 +33,7 @@ import { IFavoriteProjectsStore } from './stores/favorite-projects';
|
||||
import { IAccountStore } from './stores/account-store';
|
||||
import { IProjectStatsStore } from './stores/project-stats-store-type';
|
||||
import { IImportTogglesStore } from '../features/export-import-toggles/import-toggles-store-type';
|
||||
import { IPrivateProjectStore } from '../features/private-project/privateProjectStoreType';
|
||||
|
||||
export interface IUnleashStores {
|
||||
accessStore: IAccessStore;
|
||||
@ -70,6 +71,7 @@ export interface IUnleashStores {
|
||||
favoriteProjectsStore: IFavoriteProjectsStore;
|
||||
projectStatsStore: IProjectStatsStore;
|
||||
importTogglesStore: IImportTogglesStore;
|
||||
privateProjectStore: IPrivateProjectStore;
|
||||
}
|
||||
|
||||
export {
|
||||
@ -107,4 +109,5 @@ export {
|
||||
IFavoriteFeaturesStore,
|
||||
IFavoriteProjectsStore,
|
||||
IImportTogglesStore,
|
||||
IPrivateProjectStore,
|
||||
};
|
||||
|
@ -43,7 +43,7 @@ process.nextTick(async () => {
|
||||
featureNamingPattern: true,
|
||||
doraMetrics: true,
|
||||
variantTypeNumber: true,
|
||||
privateProjects: true,
|
||||
privateProjects: false,
|
||||
accessOverview: true,
|
||||
},
|
||||
},
|
||||
|
@ -21,6 +21,7 @@ import { SegmentService } from '../../../lib/services/segment-service';
|
||||
import { GroupService } from '../../../lib/services/group-service';
|
||||
import { FavoritesService } from '../../../lib/services';
|
||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
||||
|
||||
let db: ITestDb;
|
||||
let stores: IUnleashStores;
|
||||
@ -244,12 +245,17 @@ beforeAll(async () => {
|
||||
db.rawDatabase,
|
||||
accessService,
|
||||
);
|
||||
const privateProjectChecker = createPrivateProjectChecker(
|
||||
db.rawDatabase,
|
||||
config,
|
||||
);
|
||||
featureToggleService = new FeatureToggleService(
|
||||
stores,
|
||||
config,
|
||||
new SegmentService(stores, changeRequestAccessReadModel, config),
|
||||
accessService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
);
|
||||
favoritesService = new FavoritesService(stores, config);
|
||||
projectService = new ProjectService(
|
||||
|
@ -12,6 +12,7 @@ import { SegmentService } from '../../../lib/services/segment-service';
|
||||
import { GroupService } from '../../../lib/services/group-service';
|
||||
import { FavoritesService } from '../../../lib/services';
|
||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
||||
|
||||
let db;
|
||||
let stores;
|
||||
@ -31,12 +32,17 @@ beforeAll(async () => {
|
||||
db.rawDatabase,
|
||||
accessService,
|
||||
);
|
||||
const privateProjectChecker = createPrivateProjectChecker(
|
||||
db.rawDatabase,
|
||||
config,
|
||||
);
|
||||
const featureToggleService = new FeatureToggleService(
|
||||
stores,
|
||||
config,
|
||||
new SegmentService(stores, changeRequestAccessReadModel, config),
|
||||
accessService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
);
|
||||
const project = {
|
||||
id: 'test-project',
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
} from '../../../lib/error';
|
||||
import { ISegmentService } from '../../../lib/segments/segment-service-interface';
|
||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
||||
|
||||
let stores;
|
||||
let db;
|
||||
@ -58,12 +59,17 @@ beforeAll(async () => {
|
||||
changeRequestAccessReadModel,
|
||||
config,
|
||||
);
|
||||
const privateProjectChecker = createPrivateProjectChecker(
|
||||
db.rawDatabase,
|
||||
config,
|
||||
);
|
||||
service = new FeatureToggleService(
|
||||
stores,
|
||||
config,
|
||||
segmentService,
|
||||
accessService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
);
|
||||
});
|
||||
|
||||
@ -449,6 +455,10 @@ test('If change requests are enabled, cannot change variants without going via C
|
||||
db.rawDatabase,
|
||||
accessService,
|
||||
);
|
||||
const privateProjectChecker = createPrivateProjectChecker(
|
||||
db.rawDatabase,
|
||||
unleashConfig,
|
||||
);
|
||||
// Force all feature flags on to make sure we have Change requests on
|
||||
const customFeatureService = new FeatureToggleService(
|
||||
stores,
|
||||
@ -461,6 +471,7 @@ test('If change requests are enabled, cannot change variants without going via C
|
||||
segmentService,
|
||||
accessService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
);
|
||||
|
||||
const newVariant: IVariant = {
|
||||
@ -532,6 +543,10 @@ test('If CRs are protected for any environment in the project stops bulk update
|
||||
db.rawDatabase,
|
||||
accessService,
|
||||
);
|
||||
const privateProjectChecker = createPrivateProjectChecker(
|
||||
db.rawDatabase,
|
||||
unleashConfig,
|
||||
);
|
||||
// Force all feature flags on to make sure we have Change requests on
|
||||
const customFeatureService = new FeatureToggleService(
|
||||
stores,
|
||||
@ -544,6 +559,7 @@ test('If CRs are protected for any environment in the project stops bulk update
|
||||
segmentService,
|
||||
accessService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
);
|
||||
|
||||
const toggle = await service.createFeatureToggle(
|
||||
|
@ -25,6 +25,7 @@ import { GroupService } from '../../../lib/services/group-service';
|
||||
import { AccessService } from '../../../lib/services/access-service';
|
||||
import { ISegmentService } from '../../../lib/segments/segment-service-interface';
|
||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
||||
|
||||
let stores: IUnleashStores;
|
||||
let db: ITestDb;
|
||||
@ -47,12 +48,17 @@ beforeAll(async () => {
|
||||
changeRequestAccessReadModel,
|
||||
config,
|
||||
);
|
||||
const privateProjectChecker = createPrivateProjectChecker(
|
||||
db.rawDatabase,
|
||||
config,
|
||||
);
|
||||
featureToggleService = new FeatureToggleService(
|
||||
stores,
|
||||
config,
|
||||
segmentService,
|
||||
accessService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
);
|
||||
service = new PlaygroundService(config, {
|
||||
featureToggleServiceV2: featureToggleService,
|
||||
|
@ -11,6 +11,7 @@ import { SegmentService } from '../../../lib/services/segment-service';
|
||||
import { GroupService } from '../../../lib/services/group-service';
|
||||
import { FavoritesService } from '../../../lib/services';
|
||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
||||
|
||||
let stores: IUnleashStores;
|
||||
let db: ITestDb;
|
||||
@ -36,12 +37,17 @@ beforeAll(async () => {
|
||||
db.rawDatabase,
|
||||
accessService,
|
||||
);
|
||||
const privateProjectChecker = createPrivateProjectChecker(
|
||||
db.rawDatabase,
|
||||
config,
|
||||
);
|
||||
featureToggleService = new FeatureToggleService(
|
||||
stores,
|
||||
config,
|
||||
new SegmentService(stores, changeRequestAccessReadModel, config),
|
||||
accessService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
);
|
||||
favoritesService = new FavoritesService(stores, config);
|
||||
|
||||
|
@ -15,6 +15,7 @@ import { FavoritesService } from '../../../lib/services';
|
||||
import { FeatureEnvironmentEvent } from '../../../lib/types/events';
|
||||
import { addDays, subDays } from 'date-fns';
|
||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
||||
|
||||
let stores;
|
||||
let db: ITestDb;
|
||||
@ -57,12 +58,17 @@ beforeAll(async () => {
|
||||
db.rawDatabase,
|
||||
accessService,
|
||||
);
|
||||
const privateProjectChecker = createPrivateProjectChecker(
|
||||
db.rawDatabase,
|
||||
config,
|
||||
);
|
||||
featureToggleService = new FeatureToggleService(
|
||||
stores,
|
||||
config,
|
||||
new SegmentService(stores, changeRequestAccessReadModel, config),
|
||||
accessService,
|
||||
changeRequestAccessReadModel,
|
||||
privateProjectChecker,
|
||||
);
|
||||
|
||||
favoritesService = new FavoritesService(stores, config);
|
||||
|
7
src/test/fixtures/store.ts
vendored
7
src/test/fixtures/store.ts
vendored
@ -15,7 +15,11 @@ import FakeUserFeedbackStore from './fake-user-feedback-store';
|
||||
import FakeFeatureTagStore from './fake-feature-tag-store';
|
||||
import FakeEnvironmentStore from './fake-environment-store';
|
||||
import FakeStrategiesStore from './fake-strategies-store';
|
||||
import { IImportTogglesStore, IUnleashStores } from '../../lib/types';
|
||||
import {
|
||||
IImportTogglesStore,
|
||||
IPrivateProjectStore,
|
||||
IUnleashStores,
|
||||
} from '../../lib/types';
|
||||
import FakeSessionStore from './fake-session-store';
|
||||
import FakeFeatureEnvironmentStore from './fake-feature-environment-store';
|
||||
import FakeApiTokenStore from './fake-api-token-store';
|
||||
@ -78,6 +82,7 @@ const createStores: () => IUnleashStores = () => {
|
||||
favoriteProjectsStore: new FakeFavoriteProjectsStore(),
|
||||
projectStatsStore: new FakeProjectStatsStore(),
|
||||
importTogglesStore: {} as IImportTogglesStore,
|
||||
privateProjectStore: {} as IPrivateProjectStore,
|
||||
};
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user