mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-20 00:08:02 +01:00
feat: make application usage private through project (#4786)
This commit is contained in:
parent
0d7c230af9
commit
e4f8e1692a
@ -14,6 +14,7 @@ import {
|
||||
getStandardResponses,
|
||||
} from '../../openapi/util/standard-responses';
|
||||
import { CreateApplicationSchema } from '../../openapi/spec/create-application-schema';
|
||||
import { IAuthRequest } from '../unleash-types';
|
||||
|
||||
class MetricsController extends Controller {
|
||||
private logger: Logger;
|
||||
@ -148,14 +149,16 @@ class MetricsController extends Controller {
|
||||
}
|
||||
|
||||
async getApplications(
|
||||
req: Request,
|
||||
req: IAuthRequest,
|
||||
res: Response<ApplicationsSchema>,
|
||||
): Promise<void> {
|
||||
const { user } = req;
|
||||
const query = req.query.strategyName
|
||||
? { strategyName: req.query.strategyName as string }
|
||||
: {};
|
||||
const applications = await this.clientInstanceService.getApplications(
|
||||
query,
|
||||
user.id,
|
||||
);
|
||||
res.json({ applications });
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { IClientApp } from '../../types/model';
|
||||
import { secondsToMilliseconds } from 'date-fns';
|
||||
import FakeEventStore from '../../../test/fixtures/fake-event-store';
|
||||
import { createTestConfig } from '../../../test/config/test-config';
|
||||
import { FakePrivateProjectChecker } from '../../features/private-project/fakePrivateProjectChecker';
|
||||
|
||||
/**
|
||||
* A utility to wait for any pending promises in the test subject code.
|
||||
@ -61,6 +62,7 @@ test('Multiple registrations of same appname and instanceid within same time per
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
new FakePrivateProjectChecker(),
|
||||
);
|
||||
const client1: IClientApp = {
|
||||
appName: 'test_app',
|
||||
@ -111,6 +113,7 @@ test('Multiple unique clients causes multiple registrations', async () => {
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
new FakePrivateProjectChecker(),
|
||||
);
|
||||
const client1 = {
|
||||
appName: 'test_app',
|
||||
@ -164,6 +167,7 @@ test('Same client registered outside of dedup interval will be registered twice'
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
new FakePrivateProjectChecker(),
|
||||
bulkInterval,
|
||||
);
|
||||
const client1 = {
|
||||
@ -217,6 +221,7 @@ test('No registrations during a time period will not call stores', async () => {
|
||||
eventStore: new FakeEventStore(),
|
||||
},
|
||||
config,
|
||||
new FakePrivateProjectChecker(),
|
||||
);
|
||||
jest.advanceTimersByTime(6000);
|
||||
expect(appStoreSpy).toHaveBeenCalledTimes(0);
|
||||
|
@ -18,6 +18,8 @@ import { minutesToMilliseconds, secondsToMilliseconds } from 'date-fns';
|
||||
import { IClientMetricsStoreV2 } from '../../types/stores/client-metrics-store-v2';
|
||||
import { clientMetricsSchema } from './schema';
|
||||
import { PartialSome } from '../../types/partial';
|
||||
import { IPrivateProjectChecker } from '../../features/private-project/privateProjectCheckerType';
|
||||
import { IFlagResolver } from '../../types';
|
||||
|
||||
export default class ClientInstanceService {
|
||||
apps = {};
|
||||
@ -40,6 +42,10 @@ export default class ClientInstanceService {
|
||||
|
||||
private eventStore: IEventStore;
|
||||
|
||||
private privateProjectChecker: IPrivateProjectChecker;
|
||||
|
||||
private flagResolver: IFlagResolver;
|
||||
|
||||
private bulkInterval: number;
|
||||
|
||||
private announcementInterval: number;
|
||||
@ -61,7 +67,11 @@ export default class ClientInstanceService {
|
||||
| 'clientInstanceStore'
|
||||
| 'eventStore'
|
||||
>,
|
||||
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
||||
{
|
||||
getLogger,
|
||||
flagResolver,
|
||||
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>,
|
||||
privateProjectChecker: IPrivateProjectChecker,
|
||||
bulkInterval = secondsToMilliseconds(5),
|
||||
announcementInterval = minutesToMilliseconds(5),
|
||||
) {
|
||||
@ -71,6 +81,8 @@ export default class ClientInstanceService {
|
||||
this.clientApplicationsStore = clientApplicationsStore;
|
||||
this.clientInstanceStore = clientInstanceStore;
|
||||
this.eventStore = eventStore;
|
||||
this.privateProjectChecker = privateProjectChecker;
|
||||
this.flagResolver = flagResolver;
|
||||
this.logger = getLogger(
|
||||
'/services/client-metrics/client-instance-service.ts',
|
||||
);
|
||||
@ -162,8 +174,27 @@ export default class ClientInstanceService {
|
||||
|
||||
async getApplications(
|
||||
query: IApplicationQuery,
|
||||
userId: number,
|
||||
): Promise<IClientApplication[]> {
|
||||
return this.clientApplicationsStore.getAppsForStrategy(query);
|
||||
const applications =
|
||||
await this.clientApplicationsStore.getAppsForStrategy(query);
|
||||
if (this.flagResolver.isEnabled('privateProjects') && userId) {
|
||||
const accessibleProjects =
|
||||
await this.privateProjectChecker.getUserAccessibleProjects(
|
||||
userId,
|
||||
);
|
||||
return applications.map((application) => {
|
||||
return {
|
||||
...application,
|
||||
usage: application.usage?.filter(
|
||||
(usageItem) =>
|
||||
usageItem.project === '*' ||
|
||||
accessibleProjects.includes(usageItem.project),
|
||||
),
|
||||
};
|
||||
});
|
||||
}
|
||||
return applications;
|
||||
}
|
||||
|
||||
async getApplication(appName: string): Promise<IApplication> {
|
||||
|
@ -162,7 +162,6 @@ export const createServices = (
|
||||
const groupService = new GroupService(stores, config);
|
||||
const accessService = new AccessService(stores, config, groupService);
|
||||
const apiTokenService = new ApiTokenService(stores, config);
|
||||
const clientInstanceService = new ClientInstanceService(stores, config);
|
||||
const lastSeenService = new LastSeenService(stores, config);
|
||||
const clientMetricsServiceV2 = new ClientMetricsServiceV2(
|
||||
stores,
|
||||
@ -205,6 +204,11 @@ export const createServices = (
|
||||
const privateProjectChecker = db
|
||||
? createPrivateProjectChecker(db, config)
|
||||
: createFakePrivateProjectChecker();
|
||||
const clientInstanceService = new ClientInstanceService(
|
||||
stores,
|
||||
config,
|
||||
privateProjectChecker,
|
||||
);
|
||||
const featureToggleServiceV2 = new FeatureToggleService(
|
||||
stores,
|
||||
config,
|
||||
|
@ -43,7 +43,7 @@ process.nextTick(async () => {
|
||||
featureNamingPattern: true,
|
||||
doraMetrics: true,
|
||||
variantTypeNumber: true,
|
||||
privateProjects: false,
|
||||
privateProjects: true,
|
||||
accessOverview: true,
|
||||
datadogJsonTemplate: true,
|
||||
},
|
||||
|
@ -3,6 +3,7 @@ import { IClientApp } from '../../../lib/types/model';
|
||||
import { secondsToMilliseconds } from 'date-fns';
|
||||
import { createTestConfig } from '../../config/test-config';
|
||||
import { IUnleashConfig } from '../../../lib/types';
|
||||
import { FakePrivateProjectChecker } from '../../../lib/features/private-project/fakePrivateProjectChecker';
|
||||
|
||||
const faker = require('faker');
|
||||
const dbInit = require('../helpers/database-init');
|
||||
@ -23,6 +24,7 @@ beforeAll(async () => {
|
||||
clientInstanceService = new ClientInstanceService(
|
||||
stores,
|
||||
config,
|
||||
new FakePrivateProjectChecker(),
|
||||
bulkInterval,
|
||||
announcementInterval,
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user