1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-09-05 17:53:12 +02:00

feat: start extracting project from token

This commit is contained in:
sjaanus 2024-04-15 13:07:02 +03:00
parent 9aee1a7c42
commit 573a04531a
No known key found for this signature in database
GPG Key ID: 20E007C0248BA7FF
6 changed files with 71 additions and 18 deletions

View File

@ -10,6 +10,7 @@ import type { Logger, LogProvider } from '../logger';
import type { Db } from './db'; import type { Db } from './db';
import type { IApplicationOverview } from '../features/metrics/instance/models'; import type { IApplicationOverview } from '../features/metrics/instance/models';
import { applySearchFilters } from '../features/feature-search/search-utils'; import { applySearchFilters } from '../features/feature-search/search-utils';
import type { IFlagResolver } from '../types';
const COLUMNS = [ const COLUMNS = [
'app_name', 'app_name',
@ -110,14 +111,6 @@ const remapRow = (input) => {
return temp; return temp;
}; };
const remapUsageRow = (input) => {
return {
app_name: input.appName,
project: input.project || '*',
environment: input.environment || '*',
};
};
export default class ClientApplicationsStore export default class ClientApplicationsStore
implements IClientApplicationsStore implements IClientApplicationsStore
{ {
@ -125,24 +118,32 @@ export default class ClientApplicationsStore
private logger: Logger; private logger: Logger;
constructor(db: Db, eventBus: EventEmitter, getLogger: LogProvider) { private flagResolver: IFlagResolver;
constructor(
db: Db,
eventBus: EventEmitter,
getLogger: LogProvider,
flagResolver: IFlagResolver,
) {
this.db = db; this.db = db;
this.flagResolver = flagResolver;
this.logger = getLogger('client-applications-store.ts'); this.logger = getLogger('client-applications-store.ts');
} }
async upsert(details: Partial<IClientApplication>): Promise<void> { async upsert(details: Partial<IClientApplication>): Promise<void> {
const row = remapRow(details); const row = remapRow(details);
await this.db(TABLE).insert(row).onConflict('app_name').merge(); await this.db(TABLE).insert(row).onConflict('app_name').merge();
const usageRow = remapUsageRow(details); const usageRows = this.remapUsageRow(details);
await this.db(TABLE_USAGE) await this.db(TABLE_USAGE)
.insert(usageRow) .insert(usageRows)
.onConflict(['app_name', 'project', 'environment']) .onConflict(['app_name', 'project', 'environment'])
.merge(); .merge();
} }
async bulkUpsert(apps: Partial<IClientApplication>[]): Promise<void> { async bulkUpsert(apps: Partial<IClientApplication>[]): Promise<void> {
const rows = apps.map(remapRow); const rows = apps.map(remapRow);
const usageRows = apps.map(remapUsageRow); const usageRows = apps.flatMap(this.remapUsageRow);
await this.db(TABLE).insert(rows).onConflict('app_name').merge(); await this.db(TABLE).insert(rows).onConflict('app_name').merge();
await this.db(TABLE_USAGE) await this.db(TABLE_USAGE)
.insert(usageRows) .insert(usageRows)
@ -420,4 +421,31 @@ export default class ClientApplicationsStore
}, },
}; };
} }
private remapUsageRow = (input) => {
console.log(input);
if (this.flagResolver.isEnabled('parseProjectFromSession')) {
if (!input.projects || input.projects.length === 0) {
return [
{
app_name: input.appName,
project: '*',
environment: input.environment || '*',
},
];
} else {
return input.projects.map((project) => ({
app_name: input.appName,
project: project,
environment: input.environment || '*',
}));
}
} else {
return {
app_name: input.appName,
project: input.project || '*',
environment: input.environment || '*',
};
}
};
} }

View File

@ -65,6 +65,7 @@ export const createStores = (
db, db,
eventBus, eventBus,
getLogger, getLogger,
config.flagResolver,
), ),
clientInstanceStore: new ClientInstanceStore(db, eventBus, getLogger), clientInstanceStore: new ClientInstanceStore(db, eventBus, getLogger),
clientMetricsStoreV2: new ClientMetricsStoreV2( clientMetricsStoreV2: new ClientMetricsStoreV2(

View File

@ -1,6 +1,6 @@
import type { Response } from 'express'; import type { Response } from 'express';
import Controller from '../../../routes/controller'; import Controller from '../../../routes/controller';
import type { IUnleashServices } from '../../../types'; import type { IFlagResolver, IUnleashServices } from '../../../types';
import type { IUnleashConfig } from '../../../types/option'; import type { IUnleashConfig } from '../../../types/option';
import type { Logger } from '../../../logger'; import type { Logger } from '../../../logger';
import type ClientInstanceService from './instance-service'; import type ClientInstanceService from './instance-service';
@ -24,6 +24,8 @@ export default class RegisterController extends Controller {
openApiService: OpenApiService; openApiService: OpenApiService;
flagResolver: IFlagResolver;
constructor( constructor(
{ {
clientInstanceService, clientInstanceService,
@ -35,6 +37,7 @@ export default class RegisterController extends Controller {
this.logger = config.getLogger('/api/client/register'); this.logger = config.getLogger('/api/client/register');
this.clientInstanceService = clientInstanceService; this.clientInstanceService = clientInstanceService;
this.openApiService = openApiService; this.openApiService = openApiService;
this.flagResolver = config.flagResolver;
this.route({ this.route({
method: 'post', method: 'post',
@ -62,7 +65,7 @@ export default class RegisterController extends Controller {
}); });
} }
private static resolveEnvironment( private resolveEnvironment(
user: IUser | IApiUser, user: IUser | IApiUser,
data: Partial<IClientApp>, data: Partial<IClientApp>,
) { ) {
@ -76,7 +79,14 @@ export default class RegisterController extends Controller {
return 'default'; return 'default';
} }
private static extractProjectFromRequest( private resolveProject(user: IUser | IApiUser) {
if (user instanceof ApiUser) {
return user.projects;
}
return ['default'];
}
private extractProjectFromRequest(
req: IAuthRequest<unknown, void, ClientApplicationSchema>, req: IAuthRequest<unknown, void, ClientApplicationSchema>,
) { ) {
const token = req.get('Authorisation') || req.headers.authorization; const token = req.get('Authorisation') || req.headers.authorization;
@ -91,8 +101,15 @@ export default class RegisterController extends Controller {
res: Response<void>, res: Response<void>,
): Promise<void> { ): Promise<void> {
const { body: data, ip: clientIp, user } = req; const { body: data, ip: clientIp, user } = req;
data.environment = RegisterController.resolveEnvironment(user, data); data.environment = this.resolveEnvironment(user, data);
data.project = RegisterController.extractProjectFromRequest(req); if (this.flagResolver.isEnabled('parseProjectFromSession')) {
data.projects = this.resolveProject(user);
console.log('Project from session: ', data.projects);
} else {
data.project = this.extractProjectFromRequest(req);
console.log('Project from request: ', data.project);
}
await this.clientInstanceService.registerClient(data, clientIp); await this.clientInstanceService.registerClient(data, clientIp);
res.header('X-Unleash-Version', version).status(202).end(); res.header('X-Unleash-Version', version).status(202).end();
} }

View File

@ -92,4 +92,5 @@ export const clientRegisterSchema = joi
interval: joi.number().required(), interval: joi.number().required(),
environment: joi.string().optional(), environment: joi.string().optional(),
project: joi.string().optional(), project: joi.string().optional(),
projects: joi.array().optional().items(joi.string()),
}); });

View File

@ -59,7 +59,8 @@ export type IFlagKey =
| 'bearerTokenMiddleware' | 'bearerTokenMiddleware'
| 'projectOverviewRefactorFeedback' | 'projectOverviewRefactorFeedback'
| 'featureLifecycle' | 'featureLifecycle'
| 'projectListFilterMyProjects'; | 'projectListFilterMyProjects'
| 'parseProjectFromSession';
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>; export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
@ -293,6 +294,10 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENTAL_PROJECTS_LIST_MY_PROJECTS, process.env.UNLEASH_EXPERIMENTAL_PROJECTS_LIST_MY_PROJECTS,
false, false,
), ),
parseProjectFromSession: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_PARSE_PROJECT_FROM_SESSION,
false,
),
}; };
export const defaultExperimentalOptions: IExperimentalOptions = { export const defaultExperimentalOptions: IExperimentalOptions = {

View File

@ -56,6 +56,7 @@ process.nextTick(async () => {
projectOverviewRefactorFeedback: true, projectOverviewRefactorFeedback: true,
featureLifecycle: true, featureLifecycle: true,
projectListFilterMyProjects: true, projectListFilterMyProjects: true,
parseProjectFromSession: false,
}, },
}, },
authentication: { authentication: {