mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: private project filtering and store implementation (#4758)
This commit is contained in:
parent
2928857857
commit
39d2d065cd
@ -42,7 +42,7 @@ import {
|
|||||||
import StrategyStore from '../../db/strategy-store';
|
import StrategyStore from '../../db/strategy-store';
|
||||||
import FakeStrategiesStore from '../../../test/fixtures/fake-strategies-store';
|
import FakeStrategiesStore from '../../../test/fixtures/fake-strategies-store';
|
||||||
import {
|
import {
|
||||||
createFakeprivateProjectChecker,
|
createFakePrivateProjectChecker,
|
||||||
createPrivateProjectChecker,
|
createPrivateProjectChecker,
|
||||||
} from '../private-project/createPrivateProjectChecker';
|
} from '../private-project/createPrivateProjectChecker';
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ export const createFakeFeatureToggleService = (
|
|||||||
);
|
);
|
||||||
const segmentService = createFakeSegmentService(config);
|
const segmentService = createFakeSegmentService(config);
|
||||||
const changeRequestAccessReadModel = createFakeChangeRequestAccessService();
|
const changeRequestAccessReadModel = createFakeChangeRequestAccessService();
|
||||||
const fakeprivateProjectChecker = createFakeprivateProjectChecker();
|
const fakeprivateProjectChecker = createFakePrivateProjectChecker();
|
||||||
const featureToggleService = new FeatureToggleService(
|
const featureToggleService = new FeatureToggleService(
|
||||||
{
|
{
|
||||||
featureStrategiesStore,
|
featureStrategiesStore,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Db, IUnleashConfig } from 'lib/server-impl';
|
import { Db, IUnleashConfig } from 'lib/server-impl';
|
||||||
import PrivateProjectStore from './privateProjectStore';
|
import PrivateProjectStore from './privateProjectStore';
|
||||||
import { PrivateProjectChecker } from './privateProjectChecker';
|
import { PrivateProjectChecker } from './privateProjectChecker';
|
||||||
import { FakeprivateProjectChecker } from './fakePrivateProjectChecker';
|
import { FakePrivateProjectChecker } from './fakePrivateProjectChecker';
|
||||||
|
|
||||||
export const createPrivateProjectChecker = (
|
export const createPrivateProjectChecker = (
|
||||||
db: Db,
|
db: Db,
|
||||||
@ -15,7 +15,7 @@ export const createPrivateProjectChecker = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createFakeprivateProjectChecker =
|
export const createFakePrivateProjectChecker =
|
||||||
(): FakeprivateProjectChecker => {
|
(): FakePrivateProjectChecker => {
|
||||||
return new FakeprivateProjectChecker();
|
return new FakePrivateProjectChecker();
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
import { IPrivateProjectChecker } from './privateProjectCheckerType';
|
import { IPrivateProjectChecker } from './privateProjectCheckerType';
|
||||||
|
import { Promise } from 'ts-toolbelt/out/Any/Promise';
|
||||||
|
|
||||||
export class FakeprivateProjectChecker implements IPrivateProjectChecker {
|
export class FakePrivateProjectChecker implements IPrivateProjectChecker {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
async getUserAccessibleProjects(userId: number): Promise<string[]> {
|
async getUserAccessibleProjects(userId: number): Promise<string[]> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
hasAccessToProject(userId: number, projectId: string): Promise<boolean> {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,13 @@ export class PrivateProjectChecker implements IPrivateProjectChecker {
|
|||||||
async getUserAccessibleProjects(userId: number): Promise<string[]> {
|
async getUserAccessibleProjects(userId: number): Promise<string[]> {
|
||||||
return this.privateProjectStore.getUserAccessibleProjects(userId);
|
return this.privateProjectStore.getUserAccessibleProjects(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async hasAccessToProject(
|
||||||
|
userId: number,
|
||||||
|
projectId: string,
|
||||||
|
): Promise<boolean> {
|
||||||
|
return (await this.getUserAccessibleProjects(userId)).includes(
|
||||||
|
projectId,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export interface IPrivateProjectChecker {
|
export interface IPrivateProjectChecker {
|
||||||
getUserAccessibleProjects(userId: number): Promise<string[]>;
|
getUserAccessibleProjects(userId: number): Promise<string[]>;
|
||||||
|
hasAccessToProject(userId: number, projectId: string): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ const privateProjectMiddleware = (
|
|||||||
getLogger,
|
getLogger,
|
||||||
flagResolver,
|
flagResolver,
|
||||||
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>,
|
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>,
|
||||||
{ projectService, accessService }: IUnleashServices,
|
{ accessService, privateProjectChecker }: IUnleashServices,
|
||||||
): any => {
|
): any => {
|
||||||
const logger = getLogger('/middleware/project-middleware.ts');
|
const logger = getLogger('/middleware/project-middleware.ts');
|
||||||
logger.debug('Enabling private project middleware');
|
logger.debug('Enabling private project middleware');
|
||||||
@ -27,10 +27,9 @@ const privateProjectMiddleware = (
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const permissions = await accessService.getPermissionsForUser(user);
|
const permissions = await accessService.getPermissionsForUser(user);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
permissions.map((p) => p.permission).includes('ADMIN') ||
|
permissions.map((p) => p.permission).includes('ADMIN') ||
|
||||||
projectService.isProjectUser(user.id, projectId)
|
privateProjectChecker.hasAccessToProject(user.id, projectId)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
next();
|
next();
|
||||||
|
@ -15,27 +15,76 @@ class PrivateProjectStore implements IPrivateProjectStore {
|
|||||||
destroy(): void {}
|
destroy(): void {}
|
||||||
|
|
||||||
async getUserAccessibleProjects(userId: number): Promise<string[]> {
|
async getUserAccessibleProjects(userId: number): Promise<string[]> {
|
||||||
const projects = await this.db
|
const isNotViewer = await this.db('role_user')
|
||||||
|
.join('roles', 'role_user.role_id', 'roles.id')
|
||||||
|
.where('role_user.user_id', userId)
|
||||||
|
.andWhere((db) => {
|
||||||
|
db.whereNot({
|
||||||
|
'roles.name': 'Viewer',
|
||||||
|
'roles.type': 'root',
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.count('*')
|
||||||
|
.first();
|
||||||
|
|
||||||
|
if (isNotViewer && isNotViewer.count > 0) {
|
||||||
|
const allProjects = await this.db('projects').pluck('id');
|
||||||
|
return allProjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
const accessibleProjects = await this.db
|
||||||
.from((db) => {
|
.from((db) => {
|
||||||
db.select('project')
|
db.distinct('accessible_projects.project_id')
|
||||||
.from('role_user')
|
.select('projects.id as project_id')
|
||||||
.leftJoin('roles', 'role_user.role_id', 'roles.id')
|
.from('projects')
|
||||||
.where('user_id', userId)
|
.leftJoin(
|
||||||
.union((queryBuilder) => {
|
'project_settings',
|
||||||
|
'projects.id',
|
||||||
|
'project_settings.project',
|
||||||
|
)
|
||||||
|
.where('project_settings.project_mode', '!=', 'private')
|
||||||
|
.unionAll((queryBuilder) => {
|
||||||
queryBuilder
|
queryBuilder
|
||||||
.select('project')
|
.select('projects.id as project_id')
|
||||||
|
.from('projects')
|
||||||
|
.join(
|
||||||
|
'project_settings',
|
||||||
|
'projects.id',
|
||||||
|
'project_settings.project',
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
'project_settings.project_mode',
|
||||||
|
'=',
|
||||||
|
'private',
|
||||||
|
)
|
||||||
|
.whereIn('projects.id', (whereBuilder) => {
|
||||||
|
whereBuilder
|
||||||
|
.select('role_user.project')
|
||||||
|
.from('role_user')
|
||||||
|
.leftJoin(
|
||||||
|
'roles',
|
||||||
|
'role_user.role_id',
|
||||||
|
'roles.id',
|
||||||
|
)
|
||||||
|
.where('role_user.user_id', userId);
|
||||||
|
})
|
||||||
|
.orWhereIn('projects.id', (whereBuilder) => {
|
||||||
|
whereBuilder
|
||||||
|
.select('group_role.project')
|
||||||
.from('group_role')
|
.from('group_role')
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
'group_user',
|
'group_user',
|
||||||
'group_user.group_id',
|
'group_user.group_id',
|
||||||
'group_role.group_id',
|
'group_role.group_id',
|
||||||
)
|
)
|
||||||
.where('user_id', userId);
|
.where('group_user.user_id', userId);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.as('query');
|
.as('accessible_projects');
|
||||||
})
|
})
|
||||||
.pluck('project');
|
.select('*');
|
||||||
return projects;
|
|
||||||
|
return accessibleProjects;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ import ProjectStore from '../../db/project-store';
|
|||||||
import FeatureToggleStore from '../../db/feature-toggle-store';
|
import FeatureToggleStore from '../../db/feature-toggle-store';
|
||||||
import FeatureTypeStore from '../../db/feature-type-store';
|
import FeatureTypeStore from '../../db/feature-type-store';
|
||||||
import { FeatureEnvironmentStore } from '../../db/feature-environment-store';
|
import { FeatureEnvironmentStore } from '../../db/feature-environment-store';
|
||||||
import FeatureTagStore from '../../db/feature-tag-store';
|
|
||||||
import ProjectStatsStore from '../../db/project-stats-store';
|
import ProjectStatsStore from '../../db/project-stats-store';
|
||||||
import {
|
import {
|
||||||
createAccessService,
|
createAccessService,
|
||||||
@ -32,11 +31,14 @@ import FakeFeatureToggleStore from '../../../test/fixtures/fake-feature-toggle-s
|
|||||||
import FakeFeatureTypeStore from '../../../test/fixtures/fake-feature-type-store';
|
import FakeFeatureTypeStore from '../../../test/fixtures/fake-feature-type-store';
|
||||||
import FakeEnvironmentStore from '../../../test/fixtures/fake-environment-store';
|
import FakeEnvironmentStore from '../../../test/fixtures/fake-environment-store';
|
||||||
import FakeFeatureEnvironmentStore from '../../../test/fixtures/fake-feature-environment-store';
|
import FakeFeatureEnvironmentStore from '../../../test/fixtures/fake-feature-environment-store';
|
||||||
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
|
|
||||||
import FakeProjectStatsStore from '../../../test/fixtures/fake-project-stats-store';
|
import FakeProjectStatsStore from '../../../test/fixtures/fake-project-stats-store';
|
||||||
import FakeFavoriteFeaturesStore from '../../../test/fixtures/fake-favorite-features-store';
|
import FakeFavoriteFeaturesStore from '../../../test/fixtures/fake-favorite-features-store';
|
||||||
import FakeFavoriteProjectsStore from '../../../test/fixtures/fake-favorite-projects-store';
|
import FakeFavoriteProjectsStore from '../../../test/fixtures/fake-favorite-projects-store';
|
||||||
import { FakeAccountStore } from '../../../test/fixtures/fake-account-store';
|
import { FakeAccountStore } from '../../../test/fixtures/fake-account-store';
|
||||||
|
import {
|
||||||
|
createFakePrivateProjectChecker,
|
||||||
|
createPrivateProjectChecker,
|
||||||
|
} from '../private-project/createPrivateProjectChecker';
|
||||||
|
|
||||||
export const createProjectService = (
|
export const createProjectService = (
|
||||||
db: Db,
|
db: Db,
|
||||||
@ -60,7 +62,6 @@ export const createProjectService = (
|
|||||||
eventBus,
|
eventBus,
|
||||||
getLogger,
|
getLogger,
|
||||||
);
|
);
|
||||||
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
|
|
||||||
const projectStatsStore = new ProjectStatsStore(db, eventBus, getLogger);
|
const projectStatsStore = new ProjectStatsStore(db, eventBus, getLogger);
|
||||||
const accessService: AccessService = createAccessService(db, config);
|
const accessService: AccessService = createAccessService(db, config);
|
||||||
const featureToggleService = createFeatureToggleService(db, config);
|
const featureToggleService = createFeatureToggleService(db, config);
|
||||||
@ -87,6 +88,8 @@ export const createProjectService = (
|
|||||||
{ getLogger },
|
{ getLogger },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const privateProjectChecker = createPrivateProjectChecker(db, config);
|
||||||
|
|
||||||
return new ProjectService(
|
return new ProjectService(
|
||||||
{
|
{
|
||||||
projectStore,
|
projectStore,
|
||||||
@ -95,7 +98,6 @@ export const createProjectService = (
|
|||||||
featureTypeStore,
|
featureTypeStore,
|
||||||
environmentStore,
|
environmentStore,
|
||||||
featureEnvironmentStore,
|
featureEnvironmentStore,
|
||||||
featureTagStore,
|
|
||||||
accountStore,
|
accountStore,
|
||||||
projectStatsStore,
|
projectStatsStore,
|
||||||
},
|
},
|
||||||
@ -104,6 +106,7 @@ export const createProjectService = (
|
|||||||
featureToggleService,
|
featureToggleService,
|
||||||
groupService,
|
groupService,
|
||||||
favoriteService,
|
favoriteService,
|
||||||
|
privateProjectChecker,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -119,7 +122,6 @@ export const createFakeProjectService = (
|
|||||||
const accountStore = new FakeAccountStore();
|
const accountStore = new FakeAccountStore();
|
||||||
const environmentStore = new FakeEnvironmentStore();
|
const environmentStore = new FakeEnvironmentStore();
|
||||||
const featureEnvironmentStore = new FakeFeatureEnvironmentStore();
|
const featureEnvironmentStore = new FakeFeatureEnvironmentStore();
|
||||||
const featureTagStore = new FakeFeatureTagStore();
|
|
||||||
const projectStatsStore = new FakeProjectStatsStore();
|
const projectStatsStore = new FakeProjectStatsStore();
|
||||||
const accessService = createFakeAccessService(config);
|
const accessService = createFakeAccessService(config);
|
||||||
const featureToggleService = createFakeFeatureToggleService(config);
|
const featureToggleService = createFakeFeatureToggleService(config);
|
||||||
@ -138,6 +140,8 @@ export const createFakeProjectService = (
|
|||||||
{ getLogger },
|
{ getLogger },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const privateProjectChecker = createFakePrivateProjectChecker();
|
||||||
|
|
||||||
return new ProjectService(
|
return new ProjectService(
|
||||||
{
|
{
|
||||||
projectStore,
|
projectStore,
|
||||||
@ -146,7 +150,6 @@ export const createFakeProjectService = (
|
|||||||
featureTypeStore,
|
featureTypeStore,
|
||||||
environmentStore,
|
environmentStore,
|
||||||
featureEnvironmentStore,
|
featureEnvironmentStore,
|
||||||
featureTagStore,
|
|
||||||
accountStore,
|
accountStore,
|
||||||
projectStatsStore,
|
projectStatsStore,
|
||||||
},
|
},
|
||||||
@ -155,5 +158,6 @@ export const createFakeProjectService = (
|
|||||||
featureToggleService,
|
featureToggleService,
|
||||||
groupService,
|
groupService,
|
||||||
favoriteService,
|
favoriteService,
|
||||||
|
privateProjectChecker,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -122,11 +122,13 @@ export default class ArchiveController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getArchivedFeatures(
|
async getArchivedFeatures(
|
||||||
req: Request,
|
req: IAuthRequest,
|
||||||
res: Response<FeaturesSchema>,
|
res: Response<FeaturesSchema>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const { user } = req;
|
||||||
const features = await this.featureService.getMetadataForAllFeatures(
|
const features = await this.featureService.getMetadataForAllFeatures(
|
||||||
true,
|
true,
|
||||||
|
user.id,
|
||||||
);
|
);
|
||||||
this.openApiService.respondWithValidation(
|
this.openApiService.respondWithValidation(
|
||||||
200,
|
200,
|
||||||
|
@ -61,7 +61,6 @@ const checkPrivateProjectPermissions = () => async (req, res, next) => {
|
|||||||
) {
|
) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(404).end();
|
return res.status(404).end();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1854,8 +1854,17 @@ class FeatureToggleService {
|
|||||||
|
|
||||||
async getMetadataForAllFeatures(
|
async getMetadataForAllFeatures(
|
||||||
archived: boolean,
|
archived: boolean,
|
||||||
|
userId: number,
|
||||||
): Promise<FeatureToggle[]> {
|
): Promise<FeatureToggle[]> {
|
||||||
return this.featureToggleStore.getAll({ archived });
|
const features = await this.featureToggleStore.getAll({ archived });
|
||||||
|
if (this.flagResolver.isEnabled('privateProjects')) {
|
||||||
|
const projects =
|
||||||
|
await this.privateProjectChecker.getUserAccessibleProjects(
|
||||||
|
userId,
|
||||||
|
);
|
||||||
|
return features.filter((f) => projects.includes(f.project));
|
||||||
|
}
|
||||||
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getMetadataForAllFeaturesByProjectId(
|
async getMetadataForAllFeaturesByProjectId(
|
||||||
|
@ -61,7 +61,7 @@ import { createFeatureToggleService } from '../features';
|
|||||||
import EventAnnouncerService from './event-announcer-service';
|
import EventAnnouncerService from './event-announcer-service';
|
||||||
import { createGroupService } from '../features/group/createGroupService';
|
import { createGroupService } from '../features/group/createGroupService';
|
||||||
import {
|
import {
|
||||||
createFakeprivateProjectChecker,
|
createFakePrivateProjectChecker,
|
||||||
createPrivateProjectChecker,
|
createPrivateProjectChecker,
|
||||||
} from '../features/private-project/createPrivateProjectChecker';
|
} from '../features/private-project/createPrivateProjectChecker';
|
||||||
|
|
||||||
@ -190,7 +190,7 @@ export const createServices = (
|
|||||||
);
|
);
|
||||||
const privateProjectChecker = db
|
const privateProjectChecker = db
|
||||||
? createPrivateProjectChecker(db, config)
|
? createPrivateProjectChecker(db, config)
|
||||||
: createFakeprivateProjectChecker();
|
: createFakePrivateProjectChecker();
|
||||||
const featureToggleServiceV2 = new FeatureToggleService(
|
const featureToggleServiceV2 = new FeatureToggleService(
|
||||||
stores,
|
stores,
|
||||||
config,
|
config,
|
||||||
@ -209,6 +209,7 @@ export const createServices = (
|
|||||||
featureToggleServiceV2,
|
featureToggleServiceV2,
|
||||||
groupService,
|
groupService,
|
||||||
favoritesService,
|
favoritesService,
|
||||||
|
privateProjectChecker,
|
||||||
);
|
);
|
||||||
const projectHealthService = new ProjectHealthService(
|
const projectHealthService = new ProjectHealthService(
|
||||||
stores,
|
stores,
|
||||||
@ -323,6 +324,7 @@ export const createServices = (
|
|||||||
configurationRevisionService,
|
configurationRevisionService,
|
||||||
transactionalFeatureToggleService,
|
transactionalFeatureToggleService,
|
||||||
transactionalGroupService,
|
transactionalGroupService,
|
||||||
|
privateProjectChecker,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,7 +48,6 @@ import {
|
|||||||
} from '../types/stores/access-store';
|
} from '../types/stores/access-store';
|
||||||
import FeatureToggleService from './feature-toggle-service';
|
import FeatureToggleService from './feature-toggle-service';
|
||||||
import IncompatibleProjectError from '../error/incompatible-project-error';
|
import IncompatibleProjectError from '../error/incompatible-project-error';
|
||||||
import { IFeatureTagStore } from 'lib/types/stores/feature-tag-store';
|
|
||||||
import ProjectWithoutOwnerError from '../error/project-without-owner-error';
|
import ProjectWithoutOwnerError from '../error/project-without-owner-error';
|
||||||
import { arraysHaveSameItems } from '../util';
|
import { arraysHaveSameItems } from '../util';
|
||||||
import { GroupService } from './group-service';
|
import { GroupService } from './group-service';
|
||||||
@ -60,6 +59,7 @@ import { uniqueByKey } from '../util/unique';
|
|||||||
import { BadDataError, PermissionError } from '../error';
|
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';
|
||||||
|
|
||||||
const getCreatedBy = (user: IUser) => user.email || user.username || 'unknown';
|
const getCreatedBy = (user: IUser) => user.email || user.username || 'unknown';
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ export default class ProjectService {
|
|||||||
|
|
||||||
private featureToggleService: FeatureToggleService;
|
private featureToggleService: FeatureToggleService;
|
||||||
|
|
||||||
private tagStore: IFeatureTagStore;
|
private privateProjectChecker: IPrivateProjectChecker;
|
||||||
|
|
||||||
private accountStore: IAccountStore;
|
private accountStore: IAccountStore;
|
||||||
|
|
||||||
@ -121,7 +121,6 @@ export default class ProjectService {
|
|||||||
featureTypeStore,
|
featureTypeStore,
|
||||||
environmentStore,
|
environmentStore,
|
||||||
featureEnvironmentStore,
|
featureEnvironmentStore,
|
||||||
featureTagStore,
|
|
||||||
accountStore,
|
accountStore,
|
||||||
projectStatsStore,
|
projectStatsStore,
|
||||||
}: Pick<
|
}: Pick<
|
||||||
@ -132,7 +131,6 @@ export default class ProjectService {
|
|||||||
| 'featureTypeStore'
|
| 'featureTypeStore'
|
||||||
| 'environmentStore'
|
| 'environmentStore'
|
||||||
| 'featureEnvironmentStore'
|
| 'featureEnvironmentStore'
|
||||||
| 'featureTagStore'
|
|
||||||
| 'accountStore'
|
| 'accountStore'
|
||||||
| 'projectStatsStore'
|
| 'projectStatsStore'
|
||||||
>,
|
>,
|
||||||
@ -141,6 +139,7 @@ export default class ProjectService {
|
|||||||
featureToggleService: FeatureToggleService,
|
featureToggleService: FeatureToggleService,
|
||||||
groupService: GroupService,
|
groupService: GroupService,
|
||||||
favoriteService: FavoritesService,
|
favoriteService: FavoritesService,
|
||||||
|
privateProjectChecker: IPrivateProjectChecker,
|
||||||
) {
|
) {
|
||||||
this.store = projectStore;
|
this.store = projectStore;
|
||||||
this.environmentStore = environmentStore;
|
this.environmentStore = environmentStore;
|
||||||
@ -151,7 +150,7 @@ export default class ProjectService {
|
|||||||
this.featureTypeStore = featureTypeStore;
|
this.featureTypeStore = featureTypeStore;
|
||||||
this.featureToggleService = featureToggleService;
|
this.featureToggleService = featureToggleService;
|
||||||
this.favoritesService = favoriteService;
|
this.favoritesService = favoriteService;
|
||||||
this.tagStore = featureTagStore;
|
this.privateProjectChecker = privateProjectChecker;
|
||||||
this.accountStore = accountStore;
|
this.accountStore = accountStore;
|
||||||
this.groupService = groupService;
|
this.groupService = groupService;
|
||||||
this.projectStatsStore = projectStatsStore;
|
this.projectStatsStore = projectStatsStore;
|
||||||
@ -163,7 +162,17 @@ export default class ProjectService {
|
|||||||
query?: IProjectQuery,
|
query?: IProjectQuery,
|
||||||
userId?: number,
|
userId?: number,
|
||||||
): Promise<IProjectWithCount[]> {
|
): Promise<IProjectWithCount[]> {
|
||||||
return this.store.getProjectsWithCounts(query, userId);
|
const projects = await this.store.getProjectsWithCounts(query, userId);
|
||||||
|
if (this.flagResolver.isEnabled('privateProjects') && userId) {
|
||||||
|
const accessibleProjects =
|
||||||
|
await this.privateProjectChecker.getUserAccessibleProjects(
|
||||||
|
userId,
|
||||||
|
);
|
||||||
|
return projects.filter((project) =>
|
||||||
|
accessibleProjects.includes(project.id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return projects;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getProject(id: string): Promise<IProject> {
|
async getProject(id: string): Promise<IProject> {
|
||||||
|
@ -43,6 +43,7 @@ import ExportImportService from '../features/export-import-toggles/export-import
|
|||||||
import { ISegmentService } from '../segments/segment-service-interface';
|
import { ISegmentService } from '../segments/segment-service-interface';
|
||||||
import ConfigurationRevisionService from '../features/feature-toggle/configuration-revision-service';
|
import ConfigurationRevisionService from '../features/feature-toggle/configuration-revision-service';
|
||||||
import EventAnnouncerService from 'lib/services/event-announcer-service';
|
import EventAnnouncerService from 'lib/services/event-announcer-service';
|
||||||
|
import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
|
||||||
|
|
||||||
export interface IUnleashServices {
|
export interface IUnleashServices {
|
||||||
accessService: AccessService;
|
accessService: AccessService;
|
||||||
@ -97,4 +98,5 @@ export interface IUnleashServices {
|
|||||||
db: Knex.Transaction,
|
db: Knex.Transaction,
|
||||||
) => FeatureToggleService;
|
) => FeatureToggleService;
|
||||||
transactionalGroupService: (db: Knex.Transaction) => GroupService;
|
transactionalGroupService: (db: Knex.Transaction) => GroupService;
|
||||||
|
privateProjectChecker: IPrivateProjectChecker;
|
||||||
}
|
}
|
||||||
|
@ -265,6 +265,7 @@ beforeAll(async () => {
|
|||||||
featureToggleService,
|
featureToggleService,
|
||||||
groupService,
|
groupService,
|
||||||
favoritesService,
|
favoritesService,
|
||||||
|
privateProjectChecker,
|
||||||
);
|
);
|
||||||
|
|
||||||
editorUser = await createUser(editorRole.id);
|
editorUser = await createUser(editorRole.id);
|
||||||
|
@ -63,6 +63,7 @@ beforeAll(async () => {
|
|||||||
featureToggleService,
|
featureToggleService,
|
||||||
groupService,
|
groupService,
|
||||||
favoritesService,
|
favoritesService,
|
||||||
|
privateProjectChecker,
|
||||||
);
|
);
|
||||||
|
|
||||||
await projectService.createProject(project, user);
|
await projectService.createProject(project, user);
|
||||||
|
@ -58,6 +58,7 @@ beforeAll(async () => {
|
|||||||
featureToggleService,
|
featureToggleService,
|
||||||
groupService,
|
groupService,
|
||||||
favoritesService,
|
favoritesService,
|
||||||
|
privateProjectChecker,
|
||||||
);
|
);
|
||||||
projectHealthService = new ProjectHealthService(
|
projectHealthService = new ProjectHealthService(
|
||||||
stores,
|
stores,
|
||||||
|
@ -80,6 +80,7 @@ beforeAll(async () => {
|
|||||||
featureToggleService,
|
featureToggleService,
|
||||||
groupService,
|
groupService,
|
||||||
favoritesService,
|
favoritesService,
|
||||||
|
privateProjectChecker,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user