Skip to content

Commit d4a3516

Browse files
committed
feat: enhance keyrings management with roles and new commands
- Added roles property to ApiSession and KeyringsCreateDto for better role management. - Implemented KeyringsListCommand and KeyringsDeleteCommand for listing and deleting keyrings. - Updated error handling in console.ts to exit gracefully on help command.
1 parent 9b469cb commit d4a3516

File tree

5 files changed

+84
-2
lines changed

5 files changed

+84
-2
lines changed

apps/api/src/_common/data/api-session.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export class ApiSession {
33
public readonly username: string;
44
public readonly displayName: string;
55
public readonly token: string;
6+
public readonly roles: string[];
67

78
public constructor(data: Partial<ApiSession>) {
89
for (const key in data) {

apps/api/src/console.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ import { InternalLogger } from './core/logger/internal.logger'
5151
const app = await CommandFactory.runWithoutClosing(AppModule, {
5252
logger,
5353
errorHandler: (err) => {
54+
if (err instanceof Error && 'code' in err && err.code === 'commander.help') {
55+
process.exit(0)
56+
}
5457
console.error(err)
5558
process.exit(1)
5659
},

apps/api/src/core/keyrings/_dto/keyrings.dto.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ApiProperty } from '@nestjs/swagger';
2-
import { IsDateString, IsIP, IsMongoId, IsNotEmpty, IsString } from 'class-validator';
2+
import { IsDateString, IsIP, IsMongoId, IsNotEmpty, IsOptional, IsString } from 'class-validator';
33
import { CustomFieldsDto } from '~/_common/abstracts/dto/custom-fields.dto';
44

55
export class KeyringsCreateDto extends CustomFieldsDto {
@@ -19,6 +19,10 @@ export class KeyringsCreateDto extends CustomFieldsDto {
1919

2020
@IsDateString()
2121
public suspendedAt?: Date;
22+
23+
@IsString({ each: true })
24+
@IsOptional()
25+
public roles?: string[];
2226
}
2327

2428
export class KeyringsDto extends KeyringsCreateDto {

apps/api/src/core/keyrings/_schemas/keyrings.schema.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ export class Keyrings extends AbstractSchema {
2424
})
2525
public allowedNetworks?: string[];
2626

27+
@Prop({
28+
type: [String],
29+
default: [],
30+
})
31+
public roles?: string[];
32+
2733
@Prop({ type: Date })
2834
public suspendedAt?: Date;
2935
}

apps/api/src/core/keyrings/keyrings.command.ts

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ export class KeyringsCreateQuestions {
1515
parseName(val: string) {
1616
return val;
1717
}
18+
19+
@Question({
20+
message: 'Roles (separés par une virgule, si vide: "admin") ?',
21+
name: 'roles',
22+
})
23+
parseRoles(val: string) {
24+
const roles = val?.split(',').map((role) => role.trim()).filter((role) => role !== '');
25+
26+
if (roles.length === 0) {
27+
return ['admin'];
28+
}
29+
30+
return roles;
31+
}
1832
}
1933

2034
@SubCommand({ name: 'create' })
@@ -48,6 +62,7 @@ export class KeyringsCreateCommand extends CommandRunner {
4862
username: key.name,
4963
displayName: key.name,
5064
token: key.token,
65+
roles: key.roles,
5166
}),
5267
false,
5368
options,
@@ -59,7 +74,60 @@ export class KeyringsCreateCommand extends CommandRunner {
5974
}
6075
}
6176

62-
@Command({ name: 'keyrings', arguments: '<task>', subCommands: [KeyringsCreateCommand] })
77+
@SubCommand({ name: 'list' })
78+
export class KeyringsListCommand extends CommandRunner {
79+
public constructor(
80+
protected moduleRef: ModuleRef,
81+
private readonly keyringsService: KeyringsService,
82+
) {
83+
super();
84+
}
85+
86+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
87+
async run(inputs: string[], options: any): Promise<void> {
88+
try {
89+
const keyrings = (await this.keyringsService.find<Keyrings>({})) as unknown as Keyrings[];
90+
console.table(
91+
keyrings.map((keyring) => ({
92+
name: keyring.name,
93+
suspendedAt: keyring.suspendedAt ?? null,
94+
allowedNetworks: keyring.allowedNetworks ?? [],
95+
})),
96+
);
97+
} catch (error) {
98+
console.error('Error listing keyrings', error);
99+
}
100+
}
101+
}
102+
103+
@SubCommand({ name: 'delete' })
104+
export class KeyringsDeleteCommand extends CommandRunner {
105+
public constructor(
106+
protected moduleRef: ModuleRef,
107+
private readonly keyringsService: KeyringsService,
108+
) {
109+
super();
110+
}
111+
112+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
113+
async run(inputs: string[], options: any): Promise<void> {
114+
const name = inputs[0];
115+
if (!name) {
116+
console.error('Missing keyring name. Usage: console keyrings delete <name>');
117+
return;
118+
}
119+
120+
try {
121+
const keyring = (await this.keyringsService.findOne<Keyrings>({ name })) as unknown as Keyrings;
122+
await this.keyringsService.delete<Keyrings>(keyring._id);
123+
console.log(`Keyring "${name}" deleted successfully`);
124+
} catch (error) {
125+
console.error(`Error deleting keyring "${name}"`, error);
126+
}
127+
}
128+
}
129+
130+
@Command({ name: 'keyrings', arguments: '<task>', subCommands: [KeyringsCreateCommand, KeyringsListCommand, KeyringsDeleteCommand] })
63131
export class KeyringsCommand extends CommandRunner {
64132
public constructor(protected moduleRef: ModuleRef) {
65133
super();

0 commit comments

Comments
 (0)