Skip to content

Commit

Permalink
feat(permissions-manager): integrate nest-commander and create first …
Browse files Browse the repository at this point in the history
…command
  • Loading branch information
getlarge committed Dec 20, 2023
1 parent 7dada27 commit 735a149
Show file tree
Hide file tree
Showing 12 changed files with 334 additions and 107 deletions.
9 changes: 9 additions & 0 deletions apps/permissions-manager/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@
}
}
},
"run": {
"executor": "nx:run-commands",
"options": {
"command": "nx run permissions-manager:build && node dist/apps/permissions-manager/main.mjs",
"env": {
"NODE_ENV": "development"
}
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"],
Expand Down
22 changes: 0 additions & 22 deletions apps/permissions-manager/src/app/app.controller.spec.ts

This file was deleted.

13 changes: 0 additions & 13 deletions apps/permissions-manager/src/app/app.controller.ts

This file was deleted.

28 changes: 23 additions & 5 deletions apps/permissions-manager/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { OryPermissionsModule } from '@ticketing/microservices/ory-client';
import { validate } from '@ticketing/microservices/shared/env';

import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CreateRelationCommand } from './create-relation.command';
import { EnvironmentVariables } from './env';

@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
imports: [
OryPermissionsModule.forRootAsync({
imports: [
ConfigModule.forRoot({
validate: validate(EnvironmentVariables),
}),
],
inject: [ConfigService],
useFactory: (
configService: ConfigService<EnvironmentVariables, true>,
) => ({
ketoAccessToken: configService.get('ORY_KETO_API_KEY'),
ketoPublicApiPath: configService.get('ORY_KETO_PUBLIC_URL'),
ketoAdminApiPath: configService.get('ORY_KETO_ADMIN_URL'),
}),
}),
],
providers: [CreateRelationCommand],
})
export class AppModule {}
21 changes: 0 additions & 21 deletions apps/permissions-manager/src/app/app.service.spec.ts

This file was deleted.

8 changes: 0 additions & 8 deletions apps/permissions-manager/src/app/app.service.ts

This file was deleted.

39 changes: 39 additions & 0 deletions apps/permissions-manager/src/app/create-relation.command.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { RelationTuple } from '@ticketing/microservices/shared/relation-tuple-parser';
import { MockOryPermissionService } from '@ticketing/microservices/shared/testing';
import { CommandTestFactory } from 'nest-commander-testing';

import { CreateRelationCommand } from './create-relation.command';

describe('CreateRelationCommand', () => {
let service: CreateRelationCommand;

beforeAll(async () => {
const app = await CommandTestFactory.createTestingCommand({
imports: [],
providers: [CreateRelationCommand, MockOryPermissionService],
}).compile();

service = app.get<CreateRelationCommand>(CreateRelationCommand);
});

describe('run', () => {
it('should process tuple and create relationship', async () => {
const expectedTuple: RelationTuple = {
namespace: 'Group',
object: 'admin',
relation: 'members',
subjectIdOrSet: {
namespace: 'User',
object: '1',
},
};

await expect(
service.run(['--tuple', 'Group:admin#members@User:1']),
).resolves.toBeUndefined();
expect(service['oryPermissionsService'].createRelation).toBeCalledWith(
expectedTuple,
);
});
});
});
42 changes: 42 additions & 0 deletions apps/permissions-manager/src/app/create-relation.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Logger } from '@nestjs/common';
import { OryPermissionsService } from '@ticketing/microservices/ory-client';
import {
type RelationTuple,
parseRelationTuple,
} from '@ticketing/microservices/shared/relation-tuple-parser';
import { Command, CommandRunner, Option } from 'nest-commander';

interface CommandOptions {
tuple?: RelationTuple;
}

@Command({ name: 'create', description: 'Create relationship on Ory Keto' })
export class CreateRelationCommand extends CommandRunner {
readonly logger = new Logger(CreateRelationCommand.name);

constructor(private readonly oryPermissionsService: OryPermissionsService) {
super();
}
async run(passedParams: string[], options?: CommandOptions): Promise<void> {
const { tuple } = options;
this.logger.debug('Creating relation', passedParams);
const isCreated = await this.oryPermissionsService.createRelation(tuple);
if (!isCreated) {
throw new Error('Failed to create relation');
}
this.logger.debug('Created relation', tuple);
}

@Option({
flags: '-t, --tuple [string]',
description: 'Relationship tuple to create, using Zanzibar notation',
required: true,
})
parseRelationTuple(val: string): RelationTuple {
const res = parseRelationTuple(val);
if (res.hasError()) {
throw res.error;
}
return res.unwrapOrThrow();
}
}
22 changes: 22 additions & 0 deletions apps/permissions-manager/src/app/env/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ConfigService } from '@nestjs/config';
import { OryKetoEnvironmentVariables } from '@ticketing/microservices/shared/env';
import { Exclude } from 'class-transformer';
import { readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { Mixin } from 'ts-mixer';

export type AppConfigService = ConfigService<EnvironmentVariables, true>;

const __dirname = dirname(fileURLToPath(import.meta.url));
const pkgPath = join(__dirname, '..', '..', '..', '..', '..', 'package.json');

export class EnvironmentVariables extends Mixin(OryKetoEnvironmentVariables) {
@Exclude()
private pkg: { [key: string]: unknown; name?: string; version?: string } =
JSON.parse(readFileSync(pkgPath, 'utf8'));

APP_NAME?: string = 'payments';

APP_VERSION?: string = this.pkg?.version || '0.0.1';
}
31 changes: 15 additions & 16 deletions apps/permissions-manager/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
/**
* This is not a production server yet!
* This is only a minimal backend to get started.
*/

import { Logger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { CommandFactory } from 'nest-commander';

import { AppModule } from './app/app.module';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
const globalPrefix = 'api';
app.setGlobalPrefix(globalPrefix);
const port = process.env.PORT || 3000;
await app.listen(port);
Logger.log(
`🚀 Application is running on: http://localhost:${port}/${globalPrefix}`,
);
async function bootstrap(): Promise<void> {
Logger.log('Starting permissions-manager', process.argv);
await CommandFactory.run(AppModule, {
logger: ['log', 'error', 'warn', 'debug', 'verbose'],
enablePositionalOptions: true,
enablePassThroughOptions: true,
cliName: 'permissions-manager',
version: '0.0.1',
usePlugins: true,
});
}

bootstrap();
bootstrap().catch((err) => {
console.error(err);
process.exit(1);
});
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@
"lodash-es": "^4.17.21",
"mongoose": "^6.1.0",
"mongoose-update-if-current": "^1.4.0",
"nest-commander": "3.12.5",
"nestjs-keyset-paginator": "3.0.4",
"nestjs-pino": "3.4.0",
"ngx-stripe": "14.1.0",
Expand Down Expand Up @@ -235,6 +236,7 @@
"jest-preset-angular": "13.1.4",
"js-yaml": "^4.1.0",
"localtunnel": "^2.0.2",
"nest-commander-testing": "3.3.0",
"ng-openapi-gen": "^0.21.0",
"nx": "17.1.3",
"openapi-merge": "^1.3.1",
Expand All @@ -245,6 +247,7 @@
"ts-node": "^10.9.1",
"ts-node-dev": "^2.0.0",
"typescript": "5.2.2",
"webpack-cli": "^5.1.4",
"yargs": "^17.2.1"
},
"config": {
Expand Down
Loading

0 comments on commit 735a149

Please sign in to comment.