Skip to content

Commit 71552d2

Browse files
authored
Merge pull request #771 from bcgov/SRS-721
feat: SRS-721 Task Assignment For Approving Authority Users
2 parents 5f59dcf + 1a4cefa commit 71552d2

File tree

12 files changed

+1764
-1416
lines changed

12 files changed

+1764
-1416
lines changed

backend/users/src/app/controllers/user.controller.ts

Lines changed: 127 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -11,74 +11,146 @@ import {
1111
Roles,
1212
Unprotected,
1313
} from 'nest-keycloak-connect';
14+
import { AddUserToGroupDto } from '../dto/addUserToGroup';
15+
import { Key } from 'readline';
16+
import { KeycloakService } from '../services/keycloak.service';
17+
import { ConfigService } from '@nestjs/config';
1418
// import { KeycloakService } from 'src/app/services/keycloak.service';
1519
// import { AddUserToGroupDto } from 'src/app/dto/addUserToGroup';
1620

1721
@Controller('users')
1822
@Resource('user-service')
1923
export class UserController {
20-
constructor() {}
24+
constructor(
25+
private readonly keyCloakService: KeycloakService,
26+
private readonly configService: ConfigService,
27+
) {}
2128

2229
/**
2330
* Add user to a group in Keycloak.
2431
* @param addUserToGroupDto - Object containing userId.
2532
* @returns Object indicating success status and message.
2633
*/
27-
// @Post('/addGroup')
28-
// @Roles({ roles: ['user-admin'], mode: RoleMatchingMode.ANY })
29-
// async addUserToGroup(
30-
// @Body() addUserToGroupDto: AddUserToGroupDto,
31-
// ): Promise<any> {
32-
// try {
33-
// const { userId } = addUserToGroupDto;
34+
@Post('/addGroup')
35+
@Roles({ roles: ['user-admin'], mode: RoleMatchingMode.ANY })
36+
async addUserToGroup(
37+
@Body() addUserToGroupDto: AddUserToGroupDto,
38+
): Promise<any> {
39+
try {
40+
const { userId } = addUserToGroupDto;
3441

35-
// // Get access token from Keycloak
36-
// const accessToken = await this.keyCloakService.getToken();
37-
// if (!accessToken) {
38-
// throw new HttpException(
39-
// 'Failed to get access token',
40-
// HttpStatus.INTERNAL_SERVER_ERROR,
41-
// );
42-
// }
42+
// Get access token from Keycloak
43+
const accessToken = await this.keyCloakService.getToken();
44+
if (!accessToken) {
45+
throw new HttpException(
46+
'Failed to get access token',
47+
HttpStatus.INTERNAL_SERVER_ERROR,
48+
);
49+
}
4350

44-
// // Find group ID by name
45-
// const groupName = 'formsflow-client'; // Assuming 'formflow-client' is the group name
46-
// const groupId = await this.keyCloakService.getGroupIdByName(
47-
// groupName,
48-
// accessToken,
49-
// );
50-
// if (!groupId) {
51-
// throw new HttpException(
52-
// `Group '${groupName}' not found`,
53-
// HttpStatus.NOT_FOUND,
54-
// );
55-
// }
51+
// Find group ID by name
52+
const groupName = 'formsflow-client'; // Assuming 'formflow-client' is the group name
53+
const groupId = await this.keyCloakService.getGroupIdByName(
54+
groupName,
55+
accessToken,
56+
);
57+
if (!groupId) {
58+
throw new HttpException(
59+
`Group '${groupName}' not found`,
60+
HttpStatus.NOT_FOUND,
61+
);
62+
}
5663

57-
// // Add user to group
58-
// const result = await this.keyCloakService.addUserToGroup(
59-
// userId,
60-
// groupId,
61-
// accessToken,
62-
// );
63-
// if (result.success) {
64-
// return result;
65-
// }
66-
// } catch (error) {
67-
// console.log('addUserToGroup error', error);
68-
// // Handle errors
69-
// if (error.response && error.response.data && error.response.data.error) {
70-
// // If Keycloak returns an error message, throw a Bad Request exception with the error message
71-
// throw new HttpException(
72-
// error.response.data.error,
73-
// HttpStatus.BAD_REQUEST,
74-
// );
75-
// } else {
76-
// // If any other error occurs, throw an Internal Server Error exception
77-
// throw new HttpException(
78-
// 'Internal server error',
79-
// HttpStatus.INTERNAL_SERVER_ERROR,
80-
// );
81-
// }
82-
// }
83-
// }
64+
// Add user to group
65+
const result = await this.keyCloakService.addUserToGroup(
66+
userId,
67+
groupId,
68+
accessToken,
69+
);
70+
if (result.success) {
71+
return result;
72+
}
73+
} catch (error) {
74+
console.log('addUserToGroup error', error);
75+
// Handle errors
76+
if (error.response && error.response.data && error.response.data.error) {
77+
// If Keycloak returns an error message, throw a Bad Request exception with the error message
78+
throw new HttpException(
79+
error.response.data.error,
80+
HttpStatus.BAD_REQUEST,
81+
);
82+
} else {
83+
// If any other error occurs, throw an Internal Server Error exception
84+
throw new HttpException(
85+
'Internal server error',
86+
HttpStatus.INTERNAL_SERVER_ERROR,
87+
);
88+
}
89+
}
90+
}
91+
92+
/**
93+
* Add user to a specific approving authority group in Keycloak.
94+
* @param addUserToGroupDto - Object containing userId.
95+
* @returns Object indicating success status and message.
96+
*/
97+
@Post('/addUserToGroupForMuncipalUsers')
98+
@Roles({ roles: ['user-admin'], mode: RoleMatchingMode.ANY })
99+
async addUserToGroupForMuncipalUsers(
100+
@Body() addUserToGroupDto: AddUserToGroupDto,
101+
): Promise<any> {
102+
try {
103+
const { userId } = addUserToGroupDto;
104+
105+
// Get access token from Keycloak
106+
const accessToken = await this.keyCloakService.getToken();
107+
if (!accessToken) {
108+
throw new HttpException(
109+
'Failed to get access token',
110+
HttpStatus.INTERNAL_SERVER_ERROR,
111+
);
112+
}
113+
114+
// Find group ID by name
115+
const groupName = this.configService.get<string>(
116+
'LRS_APPROVING_AUTHORITY_GROUP_NAME',
117+
); // 'lrs-approving-authority'
118+
const groupId = await this.keyCloakService.getGroupIdByName(
119+
groupName,
120+
accessToken,
121+
);
122+
if (!groupId) {
123+
throw new HttpException(
124+
`Group '${groupName}' not found`,
125+
HttpStatus.NOT_FOUND,
126+
);
127+
}
128+
129+
// Add user to group
130+
const result = await this.keyCloakService.addUserToGroup(
131+
userId,
132+
groupId,
133+
accessToken,
134+
);
135+
if (result.success) {
136+
return result;
137+
}
138+
} catch (error) {
139+
console.log('addUserToGroupForMuncipalUsers error', error);
140+
// Handle errors
141+
if (error.response && error.response.data && error.response.data.error) {
142+
// If Keycloak returns an error message, throw a Bad Request exception with the error message
143+
throw new HttpException(
144+
error.response.data.error,
145+
HttpStatus.BAD_REQUEST,
146+
);
147+
} else {
148+
// If any other error occurs, throw an Internal Server Error exception
149+
throw new HttpException(
150+
'Internal server error',
151+
HttpStatus.INTERNAL_SERVER_ERROR,
152+
);
153+
}
154+
}
155+
}
84156
}

docker-compose.yml

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,37 @@ networks:
55
driver: bridge
66

77
services:
8+
frontend:
9+
container_name: frontend
10+
entrypoint:
11+
- "sh"
12+
- "-c"
13+
- "npm i && npm run start"
14+
environment:
15+
- WATCHPACK_POLLING=true
16+
- NODE_ENV=development
17+
- BACKEND_URL=backend
18+
healthcheck:
19+
test: [ "CMD", "curl", "-f", "http://localhost:4000" ]
20+
interval: 1m30s
21+
timeout: 10s
22+
retries: 3
23+
start_period: 40s
24+
hostname: frontend
25+
image: node:14
26+
links:
27+
- graphqlgateway
28+
ports:
29+
- "4000:3000"
30+
- "35729:35729"
31+
volumes:
32+
- ./frontend:/app:z
33+
- /app/node_modules
34+
working_dir: "/app"
835
database:
936
user: postgres
37+
ports:
38+
- "6000:5432"
1039
networks:
1140
- app-tier
1241
container_name: database
@@ -168,39 +197,13 @@ services:
168197
- /app/node_modules
169198
working_dir: "/app"
170199

171-
frontend:
172-
container_name: frontend
173-
entrypoint:
174-
- "sh"
175-
- "-c"
176-
- "npm i && npm run start"
177-
environment:
178-
- WATCHPACK_POLLING=true
179-
- NODE_ENV=development
180-
- BACKEND_URL=backend
181-
healthcheck:
182-
test: [ "CMD", "curl", "-f", "http://localhost:4000" ]
183-
interval: 1m30s
184-
timeout: 10s
185-
retries: 3
186-
start_period: 40s
187-
hostname: frontend
188-
image: node:14
189-
links:
190-
- graphqlgateway
191-
ports:
192-
- "4000:3000"
193-
- "35729:35729"
194-
volumes:
195-
- ./frontend:/app:z
196-
- /app/node_modules
197-
working_dir: "/app"
198200

199-
userapi_doc:
200-
container_name: userapi_doc
201-
build:
202-
context: ./backend/documentation/users
203-
dockerfile: ./Dockerfile
204-
restart: always
205-
ports:
206-
- "4001:4001"
201+
202+
userapi_doc:
203+
container_name: userapi_doc
204+
build:
205+
context: ./backend/documentation/users
206+
dockerfile: ./Dockerfile
207+
restart: always
208+
ports:
209+
- "4001:4001"

0 commit comments

Comments
 (0)