1
0
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:
Jaanus Sellin 2023-09-20 10:35:30 +03:00 committed by GitHub
parent 0d7c230af9
commit e4f8e1692a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 50 additions and 5 deletions

View File

@ -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 });
}

View File

@ -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);

View File

@ -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> {

View File

@ -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,

View File

@ -43,7 +43,7 @@ process.nextTick(async () => {
featureNamingPattern: true,
doraMetrics: true,
variantTypeNumber: true,
privateProjects: false,
privateProjects: true,
accessOverview: true,
datadogJsonTemplate: true,
},

View File

@ -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,
);