Skip to content

Commit

Permalink
feat: initial analysis-permission implementation (#502)
Browse files Browse the repository at this point in the history
* feat: add relational entity/interface between analysis + permission

* feat: initial http controller for policy domain

* feat: setup authup permission aggregation

* feat: extend get{One,Many} policy handler output with authup resources

* test: set up basic test suite for http endpoints

* feat: initial http client for analysis-permission endpoints

* test: create authup permission in test suite if client is usable

* fix: adjusted analysis-permission validation
  • Loading branch information
tada5hi committed Jun 26, 2024
1 parent 6b261fb commit 63cfdbe
Show file tree
Hide file tree
Showing 25 changed files with 802 additions and 2 deletions.
4 changes: 4 additions & 0 deletions packages/core-http-kit/src/client/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
AnalysisAPI,
AnalysisBucketFileAPI,
AnalysisLogAPI,
AnalysisPermissionAPI,
MasterImageAPI,
MasterImageGroupAPI,
NodeAPI,
Expand Down Expand Up @@ -48,6 +49,8 @@ export class Client extends BaseClient {

public readonly analysisNode : TrainStationAPI;

public readonly analysisPermission : AnalysisPermissionAPI;

public readonly service : ServiceAPI;

constructor(config: RequestBaseOptions) {
Expand All @@ -65,6 +68,7 @@ export class Client extends BaseClient {
this.analysisBucketFile = new AnalysisBucketFileAPI({ client: this });
this.analysisLog = new AnalysisLogAPI({ client: this });
this.analysisNode = new TrainStationAPI({ client: this });
this.analysisPermission = new AnalysisPermissionAPI({ client: this });
this.service = new ServiceAPI({ client: this });

this.on(HookName.RESPONSE_ERROR, ((error) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright (c) 2021-2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

export * from './module';
43 changes: 43 additions & 0 deletions packages/core-http-kit/src/domains/analysis-permission/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2021-2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

import type { BuildInput } from 'rapiq';
import { buildQuery } from 'rapiq';
import type { AnalysisPermission } from '@privateaim/core-kit';
import { BaseAPI } from '../base';
import type { CollectionResourceResponse, SingleResourceResponse } from '../types-base';

export class AnalysisPermissionAPI extends BaseAPI {
async getMany(options?: BuildInput<AnalysisPermission>): Promise<CollectionResourceResponse<AnalysisPermission>> {
const { data: response } = await this.client.get(`analysis-permissions${buildQuery(options)}`);
return response;
}

async getOne(id: AnalysisPermission['id']): Promise<SingleResourceResponse<AnalysisPermission>> {
const { data: response } = await this.client.get(`analysis-permissions/${id}`);

return response;
}

async delete(id: AnalysisPermission['id']): Promise<SingleResourceResponse<AnalysisPermission>> {
const { data: response } = await this.client.delete(`analysis-permissions/${id}`);

return response;
}

async update(id: AnalysisPermission['id'], data: Partial<AnalysisPermission>): Promise<SingleResourceResponse<AnalysisPermission>> {
const { data: response } = await this.client.post(`analysis-permissions/${id}`, data);

return response;
}

async create(data: Partial<AnalysisPermission>): Promise<SingleResourceResponse<AnalysisPermission>> {
const { data: response } = await this.client.post('analysis-permissions', data);

return response;
}
}
1 change: 1 addition & 0 deletions packages/core-http-kit/src/domains/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ export * from './analysis';
export * from './analysis-bucket-file';
export * from './analysis-log';
export * from './analysis-node';
export * from './analysis-permission';
export * from './service';
export * from './types-base';
38 changes: 38 additions & 0 deletions packages/core-kit/src/domains/analysis-permission/entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2022-2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

import type { PermissionRelation, Realm } from '@authup/core-kit';
import type { Analysis } from '../analysis';
import type { DomainType } from '../constants';
import type { DomainEventBaseContext } from '../types-base';

export interface AnalysisPermission extends PermissionRelation {
id: string;

// ------------------------------------------------------------------

analysis_id: Analysis['id'];

analysis: Analysis;

// ------------------------------------------------------------------

analysis_realm: Realm | null;

analysis_realm_id: Realm['id'] | null;

// ------------------------------------------------------------------

created_at: Date | string;

updated_at: Date | string;
}

export type AnalysisPermissionEventContext = DomainEventBaseContext & {
type: `${DomainType.ANALYSIS_PERMISSION}`,
data: AnalysisPermission
};
8 changes: 8 additions & 0 deletions packages/core-kit/src/domains/analysis-permission/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright (c) 2021-2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

export * from './entity';
2 changes: 1 addition & 1 deletion packages/core-kit/src/domains/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ export enum DomainType {
REGISTRY = 'registry',
REGISTRY_PROJECT = 'registryProject',
NODE = 'node',
SERVICE = 'service',
ANALYSIS = 'analysis',
ANALYSIS_BUCKET = 'analysisBucket',
ANALYSIS_BUCKET_FILE = 'analysisBucketFile',
ANALYSIS_LOG = 'analysisLog',
ANALYSIS_NODE = 'analysisNode',
ANALYSIS_PERMISSION = 'analysisPermission',
}

export enum DomainSubType {
Expand Down
1 change: 1 addition & 0 deletions packages/core-kit/src/domains/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from './analysis-bucket';
export * from './analysis-bucket-file';
export * from './analysis-log';
export * from './analysis-node';
export * from './analysis-permission';
export * from './permission';
export * from './realm';
export * from './master-image-group';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* view the LICENSE file that was distributed with this source code.
*/

export * from './permission';
export * from './realm';
export * from './robot';
export * from './user';
23 changes: 23 additions & 0 deletions packages/server-core/src/aggregators/authup/entities/permission.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2023-2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/
import type { PermissionEventContext } from '@authup/core-kit';
import { useDataSource } from 'typeorm-extension';
import { AnalysisPermissionEntity } from '../../../domains';

export async function handleAuthupPermissionEvent(context: PermissionEventContext) {
if (context.event !== 'deleted') {
return;
}

const dataSource = await useDataSource();
const repository = dataSource.getRepository(AnalysisPermissionEntity);
const entities = await repository.findBy({
permission_id: context.data.id,
});

await repository.remove(entities);
}
13 changes: 12 additions & 1 deletion packages/server-core/src/aggregators/authup/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { isRedisClientUsable, useLogger, useRedisSubscribeClient } from '@privat
import type { Aggregator } from '@privateaim/server-kit';
import { EnvironmentName, useEnv } from '../../config';
import {
handleAuthupPermissionEvent,
handleAuthupRealmEvent, handleAuthupRobotEvent,
handleAuthupUserEvent,
} from './entities';
Expand All @@ -22,17 +23,27 @@ export function createAuthupAggregator() : Aggregator {
},
};
}

return {
start() {
const redisSub = useRedisSubscribeClient();

redisSub.subscribe('realm', 'user', 'robot');
redisSub.subscribe(
'permission',
'realm',
'user',
'robot',
);

redisSub.on('message', async (channel, message) => {
useLogger().info(`Received event from channel ${channel}`);
const event = JSON.parse(message);

switch (event.type) {
case DomainType.PERMISSION: {
await handleAuthupPermissionEvent(event);
break;
}
case DomainType.REALM: {
await handleAuthupRealmEvent(event);
break;
Expand Down
2 changes: 2 additions & 0 deletions packages/server-core/src/database/utils/extend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
AnalysisEntity,
AnalysisLogEntity,
AnalysisNodeEntity,
AnalysisPermissionEntity,
MasterImageEntity,
MasterImageGroupEntity,
NodeEntity,
Expand Down Expand Up @@ -52,6 +53,7 @@ export async function extendDataSourceOptions(options: DataSourceOptions) : Prom
AnalysisLogEntity,
AnalysisBucketFileEntity,
AnalysisNodeEntity,
AnalysisPermissionEntity,
],
migrations: [],
migrationsTransactionMode: 'each',
Expand Down
73 changes: 73 additions & 0 deletions packages/server-core/src/domains/analysis-permission/entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2021-2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

import {
Column,
CreateDateColumn,
Entity,
JoinColumn,
ManyToOne,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import type {
Analysis,
AnalysisPermission,
} from '@privateaim/core-kit';
import type { Permission, Policy, Realm } from '@authup/core-kit';
import { AnalysisEntity } from '../analysis';

@Entity({ name: 'analysis_permissions' })
export class AnalysisPermissionEntity implements AnalysisPermission {
@PrimaryGeneratedColumn('uuid')
id: string;

// ------------------------------------------------------------------

@CreateDateColumn()
created_at: Date;

@UpdateDateColumn()
updated_at: Date;

// ------------------------------------------------------------------

@Column()
analysis_id: Analysis['id'];

@ManyToOne(() => AnalysisEntity, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'analysis_id' })
analysis: AnalysisEntity;

// ------------------------------------------------------------------

analysis_realm: Realm | null;

@Column({ type: 'uuid', nullable: true })
analysis_realm_id: Realm['id'] | null;

// ------------------------------------------------------------------

@Column({ type: 'uuid' })
permission_id: Permission['id'];

permission: Permission;

// ------------------------------------------------------------------

@Column({ type: 'uuid', nullable: true })
policy_id: Policy['id'] | null;

policy: Policy | null;

// ------------------------------------------------------------------

@Column({ type: 'uuid', nullable: true })
permission_realm_id: Realm['id'] | null;

permission_realm: Realm | null;
}
8 changes: 8 additions & 0 deletions packages/server-core/src/domains/analysis-permission/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright (c) 2022-2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

export * from './entity';
1 change: 1 addition & 0 deletions packages/server-core/src/domains/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from './analysis-bucket';
export * from './analysis-bucket-file';
export * from './analysis-log';
export * from './anaylsis-node';
export * from './analysis-permission';
export * from './master-image';
export * from './master-image-group';
export * from './node';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2022-2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

import { ForbiddenError } from '@ebec/http';
import { PermissionID } from '@privateaim/core-kit';
import type { Request, Response } from 'routup';
import { sendCreated } from 'routup';
import { useDataSource } from 'typeorm-extension';
import { useRequestEnv } from '@privateaim/server-http-kit';
import { AnalysisPermissionEntity } from '../../../../../domains';
import { runAnalysisPermissionValidation } from '../utils';

export async function createAnalysisPermissionRouteHandler(req: Request, res: Response) : Promise<any> {
const ability = useRequestEnv(req, 'abilities');
if (!ability.has(PermissionID.ANALYSIS_EDIT)) {
throw new ForbiddenError();
}

const result = await runAnalysisPermissionValidation(req, 'create');

const dataSource = await useDataSource();
const repository = dataSource.getRepository(AnalysisPermissionEntity);

let entity = repository.create(result.data);

entity = await repository.save(entity);

entity.analysis = result.relation.analysis;

return sendCreated(res, entity);
}
Loading

0 comments on commit 63cfdbe

Please sign in to comment.