@ftisindia/create-app 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/LICENSE +144 -0
  2. package/bin/index.mjs +2 -0
  3. package/package.json +36 -0
  4. package/src/copy.mjs +45 -0
  5. package/src/log.mjs +23 -0
  6. package/src/main.mjs +221 -0
  7. package/src/run.mjs +52 -0
  8. package/src/substitute.mjs +40 -0
  9. package/template/.env.example +36 -0
  10. package/template/.github/workflows/ci.yml +36 -0
  11. package/template/.husky/pre-commit +1 -0
  12. package/template/README.md +146 -0
  13. package/template/_editorconfig +8 -0
  14. package/template/_gitignore +7 -0
  15. package/template/_nvmrc +1 -0
  16. package/template/_package.json +107 -0
  17. package/template/_prettierignore +5 -0
  18. package/template/_prettierrc +6 -0
  19. package/template/docs/API_REFERENCE.md +123 -0
  20. package/template/docs/GETTING_STARTED.md +65 -0
  21. package/template/docs/MODULE_COMPLETION_CHECKLIST.md +40 -0
  22. package/template/docs/OAUTH.md +46 -0
  23. package/template/docs/SAMPLE_MODULE.md +23 -0
  24. package/template/docs/api.http +269 -0
  25. package/template/eslint.config.mjs +51 -0
  26. package/template/nest-cli.json +8 -0
  27. package/template/prisma/migrations/20260530000000_init/migration.sql +248 -0
  28. package/template/prisma/schema.prisma +299 -0
  29. package/template/prisma/seed.ts +44 -0
  30. package/template/scripts/db-create.mjs +126 -0
  31. package/template/scripts/gen-module.mjs +217 -0
  32. package/template/scripts/seed-test-user-org.ts +264 -0
  33. package/template/scripts/setup-local.mjs +224 -0
  34. package/template/scripts/test-db.mjs +69 -0
  35. package/template/src/app.module.ts +58 -0
  36. package/template/src/common/decorators/.gitkeep +1 -0
  37. package/template/src/common/dto/error-response.dto.ts +17 -0
  38. package/template/src/common/dto/membership-response.dto.ts +51 -0
  39. package/template/src/common/dto/mutation-response.dto.ts +11 -0
  40. package/template/src/common/dto/role-summary.dto.ts +18 -0
  41. package/template/src/common/dto/user-summary.dto.ts +23 -0
  42. package/template/src/common/enums/.gitkeep +1 -0
  43. package/template/src/common/filters/.gitkeep +1 -0
  44. package/template/src/common/filters/http-exception.filter.ts +78 -0
  45. package/template/src/common/guards/.gitkeep +1 -0
  46. package/template/src/common/interceptors/.gitkeep +1 -0
  47. package/template/src/common/pipes/.gitkeep +1 -0
  48. package/template/src/common/swagger/api-error-responses.ts +54 -0
  49. package/template/src/common/types/.gitkeep +1 -0
  50. package/template/src/config/app.config.ts +7 -0
  51. package/template/src/config/auth.config.ts +33 -0
  52. package/template/src/config/database.config.ts +6 -0
  53. package/template/src/config/env.validation.ts +131 -0
  54. package/template/src/config/index.ts +5 -0
  55. package/template/src/config/rbac.config.ts +6 -0
  56. package/template/src/database/prisma/prisma-transaction.ts +22 -0
  57. package/template/src/database/prisma/prisma.module.ts +9 -0
  58. package/template/src/database/prisma/prisma.service.ts +16 -0
  59. package/template/src/main.ts +42 -0
  60. package/template/src/modules/access-control/access-control.module.ts +24 -0
  61. package/template/src/modules/access-control/application/route-registry.validator.ts +289 -0
  62. package/template/src/modules/access-control/application/services/ability.factory.ts +28 -0
  63. package/template/src/modules/access-control/application/services/access-control.service.ts +478 -0
  64. package/template/src/modules/access-control/application/services/permission.guard.ts +77 -0
  65. package/template/src/modules/access-control/application/services/rbac-cache.service.ts +148 -0
  66. package/template/src/modules/access-control/dto/access-control-response.dto.ts +79 -0
  67. package/template/src/modules/access-control/dto/create-role.dto.ts +18 -0
  68. package/template/src/modules/access-control/dto/update-role-permissions.dto.ts +23 -0
  69. package/template/src/modules/access-control/dto/update-role.dto.ts +19 -0
  70. package/template/src/modules/access-control/presentation/access-control.controller.ts +157 -0
  71. package/template/src/modules/access-control/presentation/permissions.decorator.ts +8 -0
  72. package/template/src/modules/access-control/presentation/public.decorator.ts +7 -0
  73. package/template/src/modules/access-control/types/permission-key.ts +37 -0
  74. package/template/src/modules/access-control/types/rbac-context.ts +11 -0
  75. package/template/src/modules/access-control/types/route-permission-registry.ts +129 -0
  76. package/template/src/modules/audit/application/services/audit.service.ts +97 -0
  77. package/template/src/modules/audit/audit.module.ts +13 -0
  78. package/template/src/modules/audit/dto/audit-response.dto.ts +75 -0
  79. package/template/src/modules/audit/dto/list-audit-logs-query.dto.ts +75 -0
  80. package/template/src/modules/audit/presentation/audit.controller.ts +37 -0
  81. package/template/src/modules/auth/application/services/auth.service.ts +509 -0
  82. package/template/src/modules/auth/application/services/password.service.ts +15 -0
  83. package/template/src/modules/auth/application/services/token.service.ts +95 -0
  84. package/template/src/modules/auth/auth.module.ts +73 -0
  85. package/template/src/modules/auth/dto/auth-response.dto.ts +29 -0
  86. package/template/src/modules/auth/dto/login.dto.ts +15 -0
  87. package/template/src/modules/auth/dto/logout.dto.ts +3 -0
  88. package/template/src/modules/auth/dto/oauth-exchange.dto.ts +15 -0
  89. package/template/src/modules/auth/dto/refresh-token.dto.ts +14 -0
  90. package/template/src/modules/auth/dto/signup.dto.ts +27 -0
  91. package/template/src/modules/auth/infrastructure/passport/google-auth.guard.ts +27 -0
  92. package/template/src/modules/auth/infrastructure/passport/google.strategy.ts +56 -0
  93. package/template/src/modules/auth/infrastructure/passport/jwt-auth.guard.ts +5 -0
  94. package/template/src/modules/auth/infrastructure/passport/jwt.strategy.ts +43 -0
  95. package/template/src/modules/auth/presentation/auth.controller.ts +148 -0
  96. package/template/src/modules/auth/presentation/current-user.decorator.ts +11 -0
  97. package/template/src/modules/auth/presentation/google-oauth-exception.filter.ts +33 -0
  98. package/template/src/modules/auth/types/authenticated-user.ts +7 -0
  99. package/template/src/modules/auth/types/google-auth-profile.ts +6 -0
  100. package/template/src/modules/auth/types/jwt-payload.ts +5 -0
  101. package/template/src/modules/health/dto/health-response.dto.ts +9 -0
  102. package/template/src/modules/health/health.module.ts +7 -0
  103. package/template/src/modules/health/presentation/health.controller.ts +33 -0
  104. package/template/src/modules/invitations/application/services/invitations.service.ts +967 -0
  105. package/template/src/modules/invitations/dto/accept-invitation.dto.ts +24 -0
  106. package/template/src/modules/invitations/dto/create-invitation.dto.ts +100 -0
  107. package/template/src/modules/invitations/dto/invitation-response.dto.ts +108 -0
  108. package/template/src/modules/invitations/dto/invitation-token.dto.ts +15 -0
  109. package/template/src/modules/invitations/invitations.module.ts +12 -0
  110. package/template/src/modules/invitations/presentation/invitations.controller.ts +149 -0
  111. package/template/src/modules/memberships/application/services/memberships.service.ts +455 -0
  112. package/template/src/modules/memberships/dto/transfer-owner.dto.ts +11 -0
  113. package/template/src/modules/memberships/dto/update-billing-contact.dto.ts +8 -0
  114. package/template/src/modules/memberships/dto/update-membership-owner.dto.ts +8 -0
  115. package/template/src/modules/memberships/dto/update-membership-role.dto.ts +11 -0
  116. package/template/src/modules/memberships/dto/update-membership-status.dto.ts +9 -0
  117. package/template/src/modules/memberships/memberships.module.ts +12 -0
  118. package/template/src/modules/memberships/presentation/memberships.controller.ts +193 -0
  119. package/template/src/modules/organisations/application/services/organisations.service.ts +147 -0
  120. package/template/src/modules/organisations/dto/create-organisation.dto.ts +32 -0
  121. package/template/src/modules/organisations/dto/organisation-response.dto.ts +62 -0
  122. package/template/src/modules/organisations/infrastructure/repositories/organisations.repository.ts +24 -0
  123. package/template/src/modules/organisations/organisations.module.ts +12 -0
  124. package/template/src/modules/organisations/presentation/organisations.controller.ts +37 -0
  125. package/template/src/modules/organisations/types/default-organisation-data.ts +18 -0
  126. package/template/src/modules/platform-admin/.gitkeep +1 -0
  127. package/template/src/modules/request-context/application/services/request-context.service.ts +79 -0
  128. package/template/src/modules/request-context/presentation/org-scope.guard.ts +26 -0
  129. package/template/src/modules/request-context/presentation/request-context.interceptor.ts +26 -0
  130. package/template/src/modules/request-context/presentation/request-context.middleware.ts +31 -0
  131. package/template/src/modules/request-context/request-context.module.ts +25 -0
  132. package/template/src/modules/request-context/types/request-context.ts +29 -0
  133. package/template/src/modules/sample/application/services/sample.service.ts +67 -0
  134. package/template/src/modules/sample/dto/sample-echo.dto.ts +10 -0
  135. package/template/src/modules/sample/dto/sample-response.dto.ts +41 -0
  136. package/template/src/modules/sample/presentation/sample.controller.ts +63 -0
  137. package/template/src/modules/sample/sample.module.ts +11 -0
  138. package/template/src/modules/settings/application/services/settings.service.ts +139 -0
  139. package/template/src/modules/settings/dto/setting-response.dto.ts +27 -0
  140. package/template/src/modules/settings/dto/update-setting.dto.ts +16 -0
  141. package/template/src/modules/settings/presentation/settings.controller.ts +66 -0
  142. package/template/src/modules/settings/settings.module.ts +12 -0
  143. package/template/src/modules/settings/types/setting-definitions.ts +104 -0
  144. package/template/src/modules/users/.gitkeep +1 -0
  145. package/template/test/.gitkeep +1 -0
  146. package/template/test/jest-e2e.json +9 -0
  147. package/template/test/permission.guard.spec.ts +22 -0
  148. package/template/test/route-registry.validator.spec.ts +90 -0
  149. package/template/test/security.e2e-spec.ts +102 -0
  150. package/template/tsconfig.build.json +4 -0
  151. package/template/tsconfig.json +18 -0
@@ -0,0 +1,24 @@
1
+ import { ApiPropertyOptional } from "@nestjs/swagger";
2
+ import { IsOptional, IsString, MaxLength, MinLength } from "class-validator";
3
+ import { InvitationTokenDto } from "./invitation-token.dto";
4
+
5
+ export class AcceptInvitationDto extends InvitationTokenDto {
6
+ @ApiPropertyOptional({
7
+ description:
8
+ "Required only when the invitation target is an email with no existing user.",
9
+ example: "dev-password-123",
10
+ minLength: 8,
11
+ maxLength: 128,
12
+ })
13
+ @IsOptional()
14
+ @IsString()
15
+ @MinLength(8)
16
+ @MaxLength(128)
17
+ password?: string;
18
+
19
+ @ApiPropertyOptional({ example: "New Member", maxLength: 120 })
20
+ @IsOptional()
21
+ @IsString()
22
+ @MaxLength(120)
23
+ displayName?: string;
24
+ }
@@ -0,0 +1,100 @@
1
+ import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
2
+ import { InvitationTargetType } from "@prisma/client";
3
+ import { Type } from "class-transformer";
4
+ import {
5
+ isEmail,
6
+ IsEnum,
7
+ IsInt,
8
+ IsOptional,
9
+ IsString,
10
+ IsUUID,
11
+ Max,
12
+ MaxLength,
13
+ Min,
14
+ MinLength,
15
+ Validate,
16
+ ValidationArguments,
17
+ ValidatorConstraint,
18
+ ValidatorConstraintInterface,
19
+ } from "class-validator";
20
+
21
+ const mobileTargetPattern = /^\+?[1-9]\d{6,14}$/;
22
+
23
+ type InvitationTargetValueObject = {
24
+ targetType?: InvitationTargetType;
25
+ };
26
+
27
+ @ValidatorConstraint({ name: "InvitationTargetValue", async: false })
28
+ class InvitationTargetValueConstraint implements ValidatorConstraintInterface {
29
+ validate(value: unknown, args: ValidationArguments) {
30
+ if (typeof value !== "string") {
31
+ return false;
32
+ }
33
+
34
+ const targetType = (args.object as InvitationTargetValueObject).targetType;
35
+ if (targetType === InvitationTargetType.EMAIL) {
36
+ return isEmail(value.trim());
37
+ }
38
+
39
+ if (targetType === InvitationTargetType.MOBILE) {
40
+ return mobileTargetPattern.test(value.trim());
41
+ }
42
+
43
+ return false;
44
+ }
45
+
46
+ defaultMessage(args: ValidationArguments) {
47
+ const targetType = (args.object as InvitationTargetValueObject).targetType;
48
+ if (targetType === InvitationTargetType.EMAIL) {
49
+ return "targetValue must be a valid email address when targetType is EMAIL";
50
+ }
51
+
52
+ if (targetType === InvitationTargetType.MOBILE) {
53
+ return "targetValue must be an E.164-style mobile number when targetType is MOBILE";
54
+ }
55
+
56
+ return "targetValue must match targetType";
57
+ }
58
+ }
59
+
60
+ export class CreateInvitationDto {
61
+ @ApiProperty({
62
+ enum: InvitationTargetType,
63
+ example: InvitationTargetType.EMAIL,
64
+ })
65
+ @IsEnum(InvitationTargetType)
66
+ targetType!: InvitationTargetType;
67
+
68
+ @ApiProperty({
69
+ description:
70
+ "Email address or E.164-style mobile number matching targetType.",
71
+ example: "new.member@example.com",
72
+ minLength: 3,
73
+ maxLength: 320,
74
+ })
75
+ @IsString()
76
+ @MinLength(3)
77
+ @MaxLength(320)
78
+ @Validate(InvitationTargetValueConstraint)
79
+ targetValue!: string;
80
+
81
+ @ApiProperty({
82
+ example: "f602c057-04f4-4ef8-8c84-1b7c62fbf8c5",
83
+ format: "uuid",
84
+ })
85
+ @IsUUID()
86
+ roleId!: string;
87
+
88
+ @ApiPropertyOptional({
89
+ description: "Invitation lifetime in days.",
90
+ example: 7,
91
+ minimum: 1,
92
+ maximum: 30,
93
+ })
94
+ @IsOptional()
95
+ @Type(() => Number)
96
+ @IsInt()
97
+ @Min(1)
98
+ @Max(30)
99
+ expiresInDays?: number;
100
+ }
@@ -0,0 +1,108 @@
1
+ import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
2
+ import { InvitationStatus, InvitationTargetType } from "@prisma/client";
3
+ import { MembershipResponseDto } from "../../../common/dto/membership-response.dto";
4
+ import { RoleSummaryDto } from "../../../common/dto/role-summary.dto";
5
+ import {
6
+ ActiveUserSummaryDto,
7
+ UserSummaryDto,
8
+ } from "../../../common/dto/user-summary.dto";
9
+
10
+ export class InvitationResponseDto {
11
+ @ApiProperty({
12
+ example: "17a21ad7-bd1b-42d8-b809-0a3892bb60c3",
13
+ format: "uuid",
14
+ })
15
+ id!: string;
16
+
17
+ @ApiProperty({
18
+ example: "2c67399d-670c-4025-a5fd-1ea9a211891e",
19
+ format: "uuid",
20
+ })
21
+ orgId!: string;
22
+
23
+ @ApiProperty({
24
+ enum: InvitationTargetType,
25
+ example: InvitationTargetType.EMAIL,
26
+ })
27
+ targetType!: InvitationTargetType;
28
+
29
+ @ApiProperty({ example: "new.member@example.com" })
30
+ targetValue!: string;
31
+
32
+ @ApiProperty({ example: "new.member@example.com" })
33
+ normalizedTargetValue!: string;
34
+
35
+ @ApiProperty({
36
+ example: "f602c057-04f4-4ef8-8c84-1b7c62fbf8c5",
37
+ format: "uuid",
38
+ })
39
+ roleId!: string;
40
+
41
+ @ApiProperty({ enum: InvitationStatus, example: InvitationStatus.PENDING })
42
+ status!: InvitationStatus;
43
+
44
+ @ApiProperty({ example: "2026-06-08T10:30:00.000Z", format: "date-time" })
45
+ expiresAt!: string;
46
+
47
+ @ApiProperty({
48
+ example: "4a4f0d8a-4bd2-469f-a6a9-3e1cb6a2b456",
49
+ format: "uuid",
50
+ })
51
+ invitedByUserId!: string;
52
+
53
+ @ApiPropertyOptional({
54
+ example: "7efd9a26-fbec-4511-ae37-7fb1c35e5215",
55
+ format: "uuid",
56
+ nullable: true,
57
+ })
58
+ acceptedByUserId?: string | null;
59
+
60
+ @ApiProperty({ type: RoleSummaryDto })
61
+ role!: RoleSummaryDto;
62
+
63
+ @ApiProperty({ type: UserSummaryDto })
64
+ invitedByUser!: UserSummaryDto;
65
+
66
+ @ApiPropertyOptional({ type: UserSummaryDto, nullable: true })
67
+ acceptedByUser?: UserSummaryDto | null;
68
+
69
+ @ApiProperty({ example: "2026-06-01T10:30:00.000Z", format: "date-time" })
70
+ createdAt!: string;
71
+
72
+ @ApiPropertyOptional({
73
+ example: "2026-06-01T10:35:00.000Z",
74
+ format: "date-time",
75
+ nullable: true,
76
+ })
77
+ acceptedAt?: string | null;
78
+
79
+ @ApiPropertyOptional({
80
+ example: "2026-06-01T10:40:00.000Z",
81
+ format: "date-time",
82
+ nullable: true,
83
+ })
84
+ revokedAt?: string | null;
85
+ }
86
+
87
+ export class InvitationWithTokenResponseDto {
88
+ @ApiProperty({ type: InvitationResponseDto })
89
+ invitation!: InvitationResponseDto;
90
+
91
+ @ApiProperty({
92
+ description:
93
+ "One-time invitation token. This is returned only at create/resend time.",
94
+ example: "k0Y7QJr7pC1r7GJrFXdN2vzmw1lYkT5YhJdORQb4Pp4",
95
+ })
96
+ inviteToken!: string;
97
+ }
98
+
99
+ export class AcceptInvitationResponseDto {
100
+ @ApiProperty({ type: InvitationResponseDto })
101
+ invitation!: InvitationResponseDto;
102
+
103
+ @ApiProperty({ type: MembershipResponseDto })
104
+ membership!: MembershipResponseDto;
105
+
106
+ @ApiProperty({ type: ActiveUserSummaryDto })
107
+ user!: ActiveUserSummaryDto;
108
+ }
@@ -0,0 +1,15 @@
1
+ import { ApiProperty } from "@nestjs/swagger";
2
+ import { IsString, MaxLength, MinLength } from "class-validator";
3
+
4
+ export class InvitationTokenDto {
5
+ @ApiProperty({
6
+ description: "One-time invitation token from create/resend invitation.",
7
+ example: "k0Y7QJr7pC1r7GJrFXdN2vzmw1lYkT5YhJdORQb4Pp4",
8
+ minLength: 20,
9
+ maxLength: 256,
10
+ })
11
+ @IsString()
12
+ @MinLength(20)
13
+ @MaxLength(256)
14
+ token!: string;
15
+ }
@@ -0,0 +1,12 @@
1
+ import { Module } from "@nestjs/common";
2
+ import { AuthModule } from "../auth/auth.module";
3
+ import { MembershipsModule } from "../memberships/memberships.module";
4
+ import { InvitationsService } from "./application/services/invitations.service";
5
+ import { InvitationsController } from "./presentation/invitations.controller";
6
+
7
+ @Module({
8
+ imports: [AuthModule, MembershipsModule],
9
+ controllers: [InvitationsController],
10
+ providers: [InvitationsService],
11
+ })
12
+ export class InvitationsModule {}
@@ -0,0 +1,149 @@
1
+ import {
2
+ Body,
3
+ Controller,
4
+ Get,
5
+ HttpCode,
6
+ Param,
7
+ Post,
8
+ UseGuards,
9
+ } from "@nestjs/common";
10
+ import {
11
+ ApiBearerAuth,
12
+ ApiCreatedResponse,
13
+ ApiOkResponse,
14
+ ApiOperation,
15
+ ApiParam,
16
+ ApiTags,
17
+ } from "@nestjs/swagger";
18
+ import { ApiErrorResponses } from "../../../common/swagger/api-error-responses";
19
+ import { PermissionGuard } from "../../access-control/application/services/permission.guard";
20
+ import { RequirePermissions } from "../../access-control/presentation/permissions.decorator";
21
+ import { JwtAuthGuard } from "../../auth/infrastructure/passport/jwt-auth.guard";
22
+ import { CurrentUser } from "../../auth/presentation/current-user.decorator";
23
+ import { AuthenticatedUser } from "../../auth/types/authenticated-user";
24
+ import { OrgScopeGuard } from "../../request-context/presentation/org-scope.guard";
25
+ import { InvitationsService } from "../application/services/invitations.service";
26
+ import { AcceptInvitationDto } from "../dto/accept-invitation.dto";
27
+ import { CreateInvitationDto } from "../dto/create-invitation.dto";
28
+ import { InvitationTokenDto } from "../dto/invitation-token.dto";
29
+ import {
30
+ AcceptInvitationResponseDto,
31
+ InvitationResponseDto,
32
+ InvitationWithTokenResponseDto,
33
+ } from "../dto/invitation-response.dto";
34
+
35
+ @ApiTags("Invitations")
36
+ @Controller()
37
+ export class InvitationsController {
38
+ constructor(private readonly invitationsService: InvitationsService) {}
39
+
40
+ @Post("organisations/:orgId/invitations")
41
+ @UseGuards(JwtAuthGuard, OrgScopeGuard, PermissionGuard)
42
+ @RequirePermissions("memberships.invite")
43
+ @ApiBearerAuth()
44
+ @ApiParam({ name: "orgId", description: "Organisation ID.", format: "uuid" })
45
+ @ApiOperation({
46
+ summary: "Create an invitation for an email or mobile target.",
47
+ })
48
+ @ApiCreatedResponse({
49
+ description: "Invitation created. The inviteToken is shown once.",
50
+ type: InvitationWithTokenResponseDto,
51
+ })
52
+ @ApiErrorResponses(400, 401, 403, 404, 409)
53
+ create(
54
+ @CurrentUser() user: AuthenticatedUser,
55
+ @Param("orgId") orgId: string,
56
+ @Body() dto: CreateInvitationDto,
57
+ ) {
58
+ return this.invitationsService.createInvitation(user, orgId, dto);
59
+ }
60
+
61
+ @Get("organisations/:orgId/invitations")
62
+ @UseGuards(JwtAuthGuard, OrgScopeGuard, PermissionGuard)
63
+ @RequirePermissions("memberships.read")
64
+ @ApiBearerAuth()
65
+ @ApiParam({ name: "orgId", description: "Organisation ID.", format: "uuid" })
66
+ @ApiOperation({ summary: "List invitations for an organisation." })
67
+ @ApiOkResponse({
68
+ description: "Organisation invitations.",
69
+ type: [InvitationResponseDto],
70
+ })
71
+ @ApiErrorResponses(400, 401, 403)
72
+ list(@CurrentUser() user: AuthenticatedUser, @Param("orgId") orgId: string) {
73
+ return this.invitationsService.listInvitations(user, orgId);
74
+ }
75
+
76
+ @Post("organisations/:orgId/invitations/:invitationId/revoke")
77
+ @HttpCode(200)
78
+ @UseGuards(JwtAuthGuard, OrgScopeGuard, PermissionGuard)
79
+ @RequirePermissions("memberships.revoke")
80
+ @ApiBearerAuth()
81
+ @ApiParam({ name: "orgId", description: "Organisation ID.", format: "uuid" })
82
+ @ApiParam({
83
+ name: "invitationId",
84
+ description: "Invitation ID.",
85
+ format: "uuid",
86
+ })
87
+ @ApiOperation({ summary: "Revoke a pending invitation." })
88
+ @ApiOkResponse({
89
+ description: "Revoked invitation.",
90
+ type: InvitationResponseDto,
91
+ })
92
+ @ApiErrorResponses(400, 401, 403, 404, 409, 410)
93
+ revoke(
94
+ @CurrentUser() user: AuthenticatedUser,
95
+ @Param("orgId") orgId: string,
96
+ @Param("invitationId") invitationId: string,
97
+ ) {
98
+ return this.invitationsService.revokeInvitation(user, orgId, invitationId);
99
+ }
100
+
101
+ @Post("organisations/:orgId/invitations/:invitationId/resend")
102
+ @HttpCode(200)
103
+ @UseGuards(JwtAuthGuard, OrgScopeGuard, PermissionGuard)
104
+ @RequirePermissions("memberships.invite")
105
+ @ApiBearerAuth()
106
+ @ApiParam({ name: "orgId", description: "Organisation ID.", format: "uuid" })
107
+ @ApiParam({
108
+ name: "invitationId",
109
+ description: "Invitation ID.",
110
+ format: "uuid",
111
+ })
112
+ @ApiOperation({ summary: "Resend a pending or expired invitation." })
113
+ @ApiOkResponse({
114
+ description: "Invitation resent. The new inviteToken is shown once.",
115
+ type: InvitationWithTokenResponseDto,
116
+ })
117
+ @ApiErrorResponses(400, 401, 403, 404, 409)
118
+ resend(
119
+ @CurrentUser() user: AuthenticatedUser,
120
+ @Param("orgId") orgId: string,
121
+ @Param("invitationId") invitationId: string,
122
+ ) {
123
+ return this.invitationsService.resendInvitation(user, orgId, invitationId);
124
+ }
125
+
126
+ @Post("invitations/accept")
127
+ @HttpCode(200)
128
+ @ApiOperation({ summary: "Accept an invitation token." })
129
+ @ApiOkResponse({
130
+ description: "Invitation accepted and membership created.",
131
+ type: AcceptInvitationResponseDto,
132
+ })
133
+ @ApiErrorResponses(400, 401, 409, 410)
134
+ accept(@Body() dto: AcceptInvitationDto) {
135
+ return this.invitationsService.acceptInvitation(dto);
136
+ }
137
+
138
+ @Post("invitations/decline")
139
+ @HttpCode(200)
140
+ @ApiOperation({ summary: "Decline an invitation token." })
141
+ @ApiOkResponse({
142
+ description: "Declined invitation.",
143
+ type: InvitationResponseDto,
144
+ })
145
+ @ApiErrorResponses(400, 401, 409, 410)
146
+ decline(@Body() dto: InvitationTokenDto) {
147
+ return this.invitationsService.declineInvitation(dto);
148
+ }
149
+ }