Skip to content

Commit db96aec

Browse files
Merge pull request #154 from Hardhat-Enterprises/dashboard-api-lachlan-v2
Add GetUserDashboard endpoint routed through user service
2 parents 8c77143 + b9c117c commit db96aec

14 files changed

Lines changed: 750 additions & 47 deletions

File tree

backend/.tsbuildinfo/common.tsbuildinfo

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

backend/api-gateway/src/app.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
// app.ts
2+
23
import express from "express";
34
import cors from "cors";
45
import dotenv from "dotenv";
56
import { config, connectRabbitMQ, logger } from "@phoenix/common";
7+
68
import userRoutes from "./routes/user.routes";
79
import ingestionRoutes from "./routes/ingestion.routes";
810
import notificationRoutes from "./routes/notification.routes";
11+
912
import swaggerUi from "swagger-ui-express";
1013
import { swaggerSpec } from "@phoenix/common";
14+
1115
// import authRoutes from "./routes/auth.routes";
1216

1317
dotenv.config();
@@ -31,14 +35,18 @@ app.use("/api/ingestion", ingestionRoutes);
3135
app.use("/api/notifications", notificationRoutes);
3236

3337
const startServer = async () => {
34-
await connectRabbitMQ(process.env.RABBITMQ_URL!);
3538
try {
36-
(app.listen(config.PORT),
37-
() => {
38-
logger.info(`${config.SERVICE_NAME} running on port ${config.PORT}`);
39-
});
39+
// Connect to RabbitMQ first
40+
await connectRabbitMQ(process.env.RABBITMQ_URL!);
41+
42+
// Start the Express server
43+
app.listen(config.PORT, () => {
44+
logger.info(
45+
`${config.SERVICE_NAME} running on port ${config.PORT}`,
46+
);
47+
});
4048
} catch (error) {
41-
logger.error("Error starting server:", error);
49+
logger.error(`Error starting server: ${error}`);
4250
process.exit(1);
4351
}
4452
};

backend/api-gateway/src/controllers/user.controller.ts

Lines changed: 141 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ export const getHealth = (req: Request, res: Response) => {
66
userGrpcClient.GetUserHealth({}, (error, response) => {
77
if (error) {
88
logger.error(`Error calling GetUserHealth: ${error}`);
9-
res
9+
10+
return res
1011
.status(
11-
response.status || HttpStatusCode.HTTP_STATUS_INTERNAL_SERVER_ERROR,
12+
response?.status || HttpStatusCode.HTTP_STATUS_INTERNAL_SERVER_ERROR,
1213
)
1314
.json({ message: "Error fetching user health" });
1415
}
16+
1517
return res
1618
.status(response.status || HttpStatusCode.HTTP_STATUS_OK)
1719
.json({ message: response?.message });
@@ -23,17 +25,152 @@ export const getUser = (req: Request, res: Response) => {
2325
if (error) {
2426
logger.error(`Error calling GetUsers: ${error}`);
2527

26-
res
28+
return res
2729
.status(
28-
response.status || HttpStatusCode.HTTP_STATUS_INTERNAL_SERVER_ERROR,
30+
response?.status || HttpStatusCode.HTTP_STATUS_INTERNAL_SERVER_ERROR,
2931
)
3032
.json({ message: "Error fetching users" });
3133
}
34+
3235
logger.info(`GetUsers response from gRPC: ${JSON.stringify(response)}`);
36+
3337
return res.status(response.status || HttpStatusCode.HTTP_STATUS_OK).json({
3438
status: response?.status,
3539
message: response?.message,
3640
user: response?.users,
3741
});
3842
});
3943
};
44+
45+
export const getUserDashboard = (req: Request, res: Response) => {
46+
userGrpcClient.GetUserDashboard({}, (error, response) => {
47+
if (error) {
48+
logger.error(`Error calling GetUserDashboard: ${error}`);
49+
50+
return res
51+
.status(
52+
response?.status || HttpStatusCode.HTTP_STATUS_INTERNAL_SERVER_ERROR,
53+
)
54+
.json({
55+
status:
56+
response?.status || HttpStatusCode.HTTP_STATUS_INTERNAL_SERVER_ERROR,
57+
message: "Error fetching dashboard overview",
58+
data: [],
59+
});
60+
}
61+
62+
logger.info(
63+
`GetUserDashboard response from gRPC: ${JSON.stringify(response)}`,
64+
);
65+
66+
return res.status(response.status || HttpStatusCode.HTTP_STATUS_OK).json({
67+
status: response?.status || HttpStatusCode.HTTP_STATUS_OK,
68+
message:
69+
response?.message || "Dashboard overview retrieved successfully",
70+
71+
data: [
72+
{
73+
total_hazards: response?.total_hazards,
74+
active_hazards: response?.active_hazards,
75+
total_threats: response?.total_threats,
76+
active_threats: response?.active_threats,
77+
total_risk_assessments: response?.total_risk_assessments,
78+
critical_risks: response?.critical_risks,
79+
last_updated: response?.last_updated || new Date().toISOString(),
80+
},
81+
],
82+
});
83+
});
84+
};
85+
86+
export const getUserDashboardCharts = (
87+
req: Request,
88+
res: Response,
89+
) => {
90+
userGrpcClient.GetUserDashboardCharts({}, (error, response) => {
91+
if (error) {
92+
logger.error(`Error calling GetUserDashboardCharts: ${error}`);
93+
94+
return res
95+
.status(
96+
response?.status || HttpStatusCode.HTTP_STATUS_INTERNAL_SERVER_ERROR,
97+
)
98+
.json({
99+
status:
100+
response?.status || HttpStatusCode.HTTP_STATUS_INTERNAL_SERVER_ERROR,
101+
message: "Error fetching dashboard charts",
102+
data: [],
103+
});
104+
}
105+
106+
logger.info(
107+
`GetUserDashboardCharts response from gRPC: ${JSON.stringify(response)}`,
108+
);
109+
110+
return res.status(response.status || HttpStatusCode.HTTP_STATUS_OK).json({
111+
status: response?.status || HttpStatusCode.HTTP_STATUS_OK,
112+
message:
113+
response?.message || "Dashboard charts retrieved successfully",
114+
115+
data: {
116+
hazards_by_severity: JSON.parse(
117+
response?.hazards_by_severity || "{}",
118+
),
119+
120+
threats_by_risk_level: JSON.parse(
121+
response?.threats_by_risk_level || "{}",
122+
),
123+
124+
risks_by_level: JSON.parse(response?.risks_by_level || "{}"),
125+
126+
last_updated:
127+
response?.last_updated || new Date().toISOString(),
128+
},
129+
});
130+
});
131+
};
132+
133+
export const getUserDashboardActivity = (
134+
req: Request,
135+
res: Response,
136+
) => {
137+
userGrpcClient.GetUserDashboardActivity({}, (error, response) => {
138+
if (error) {
139+
logger.error(`Error calling GetUserDashboardActivity: ${error}`);
140+
141+
return res
142+
.status(
143+
response?.status || HttpStatusCode.HTTP_STATUS_INTERNAL_SERVER_ERROR,
144+
)
145+
.json({
146+
status:
147+
response?.status || HttpStatusCode.HTTP_STATUS_INTERNAL_SERVER_ERROR,
148+
message: "Error fetching dashboard activity",
149+
data: [],
150+
});
151+
}
152+
153+
logger.info(
154+
`GetUserDashboardActivity response from gRPC: ${JSON.stringify(response)}`,
155+
);
156+
157+
return res.status(response.status || HttpStatusCode.HTTP_STATUS_OK).json({
158+
status: response?.status || HttpStatusCode.HTTP_STATUS_OK,
159+
message:
160+
response?.message || "Dashboard activity retrieved successfully",
161+
162+
data: {
163+
recent_hazards: JSON.parse(
164+
response?.recent_hazards || "[]",
165+
),
166+
167+
recent_threats: JSON.parse(
168+
response?.recent_threats || "[]",
169+
),
170+
171+
last_updated:
172+
response?.last_updated || new Date().toISOString(),
173+
},
174+
});
175+
});
176+
};

backend/api-gateway/src/grpc/user.grpc.ts

Lines changed: 100 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ dotenv.config();
88

99
const PROTO_PATH = path.resolve(`${process.env.USER_PROTO_PATH}`);
1010
logger.info(`Loading gRPC proto file from: ${PROTO_PATH}`);
11+
1112
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
1213
keepCase: true,
1314
longs: String,
@@ -26,16 +27,57 @@ const grpcObject = grpc.loadPackageDefinition(packageDefinition) as unknown as {
2627
};
2728

2829
export interface GetUserHealthRequest {}
30+
2931
export interface GetUserHealthResponse {
3032
status: number;
3133
message: string;
3234
}
3335

3436
export interface GetUsersRequest {}
37+
3538
export interface GetUsersResponse {
3639
status: number;
3740
message: string;
38-
users: [{ user_id: string; username: string; role: string }];
41+
users: {
42+
user_id: string;
43+
username: string;
44+
role: string;
45+
}[];
46+
}
47+
48+
export interface GetUserDashboardRequest {}
49+
50+
export interface GetUserDashboardResponse {
51+
status: number;
52+
message: string;
53+
total_hazards: number;
54+
active_hazards: number;
55+
total_threats: number;
56+
active_threats: number;
57+
total_risk_assessments: number;
58+
critical_risks: number;
59+
last_updated: string;
60+
}
61+
62+
export interface GetUserDashboardChartsRequest {}
63+
64+
export interface GetUserDashboardChartsResponse {
65+
status: number;
66+
message: string;
67+
hazards_by_severity: string;
68+
threats_by_risk_level: string;
69+
risks_by_level: string;
70+
last_updated: string;
71+
}
72+
73+
export interface GetUserDashboardActivityRequest {}
74+
75+
export interface GetUserDashboardActivityResponse {
76+
status: number;
77+
message: string;
78+
recent_hazards: string;
79+
recent_threats: string;
80+
last_updated: string;
3981
}
4082

4183
// ─── Threats ───────────────────────────────────────────────────────────────
@@ -61,6 +103,7 @@ export interface GetThreatsRequest {
61103
page?: number;
62104
limit?: number;
63105
}
106+
64107
export interface GetThreatsResponse {
65108
status: number;
66109
message: string;
@@ -73,6 +116,7 @@ export interface GetThreatsResponse {
73116
export interface GetThreatRequest {
74117
threat_id: string;
75118
}
119+
76120
export interface GetThreatResponse {
77121
status: number;
78122
message: string;
@@ -100,6 +144,7 @@ export interface GetHazardsRequest {
100144
page?: number;
101145
limit?: number;
102146
}
147+
103148
export interface GetHazardsResponse {
104149
status: number;
105150
message: string;
@@ -112,6 +157,7 @@ export interface GetHazardsResponse {
112157
export interface GetHazardRequest {
113158
hazard_event_id: string;
114159
}
160+
115161
export interface GetHazardResponse {
116162
status: number;
117163
message: string;
@@ -123,27 +169,74 @@ export interface GetHazardResponse {
123169
export interface UserServiceClient {
124170
GetUserHealth(
125171
request: GetUserHealthRequest,
126-
callback: (error: grpc.ServiceError | null, response: GetUserHealthResponse) => void,
172+
callback: (
173+
error: grpc.ServiceError | null,
174+
response: GetUserHealthResponse,
175+
) => void,
127176
): void;
177+
128178
GetUsers(
129179
request: GetUsersRequest,
130-
callback: (error: grpc.ServiceError | null, response: GetUsersResponse) => void,
180+
callback: (
181+
error: grpc.ServiceError | null,
182+
response: GetUsersResponse,
183+
) => void,
184+
): void;
185+
186+
GetUserDashboard(
187+
request: GetUserDashboardRequest,
188+
callback: (
189+
error: grpc.ServiceError | null,
190+
response: GetUserDashboardResponse,
191+
) => void,
131192
): void;
193+
194+
GetUserDashboardCharts(
195+
request: GetUserDashboardChartsRequest,
196+
callback: (
197+
error: grpc.ServiceError | null,
198+
response: GetUserDashboardChartsResponse,
199+
) => void,
200+
): void;
201+
202+
GetUserDashboardActivity(
203+
request: GetUserDashboardActivityRequest,
204+
callback: (
205+
error: grpc.ServiceError | null,
206+
response: GetUserDashboardActivityResponse,
207+
) => void,
208+
): void;
209+
132210
GetThreats(
133211
request: GetThreatsRequest,
134-
callback: (error: grpc.ServiceError | null, response: GetThreatsResponse) => void,
212+
callback: (
213+
error: grpc.ServiceError | null,
214+
response: GetThreatsResponse,
215+
) => void,
135216
): void;
217+
136218
GetThreat(
137219
request: GetThreatRequest,
138-
callback: (error: grpc.ServiceError | null, response: GetThreatResponse) => void,
220+
callback: (
221+
error: grpc.ServiceError | null,
222+
response: GetThreatResponse,
223+
) => void,
139224
): void;
225+
140226
GetHazards(
141227
request: GetHazardsRequest,
142-
callback: (error: grpc.ServiceError | null, response: GetHazardsResponse) => void,
228+
callback: (
229+
error: grpc.ServiceError | null,
230+
response: GetHazardsResponse,
231+
) => void,
143232
): void;
233+
144234
GetHazard(
145235
request: GetHazardRequest,
146-
callback: (error: grpc.ServiceError | null, response: GetHazardResponse) => void,
236+
callback: (
237+
error: grpc.ServiceError | null,
238+
response: GetHazardResponse,
239+
) => void,
147240
): void;
148241
}
149242

0 commit comments

Comments
 (0)