diff --git a/env_ai b/env_ai index 688f17e..e588604 100644 --- a/env_ai +++ b/env_ai @@ -10,7 +10,7 @@ VITE_OPB_SERVER_SESSION_PASSWORD=asidudhiuh33875 VITE_OBP_REDIS_URL=redis://127.0.0.1:6379 ### Opey Configuration ### -VITE_CHATBOT_ENABLED=true +VITE_CHATBOT_ENABLED=false VITE_CHATBOT_URL=http://localhost:5000 ### OAuth2/OIDC Configuration ### diff --git a/server/controllers/UserController.ts b/server/controllers/UserController.ts index 80c26fb..2373494 100644 --- a/server/controllers/UserController.ts +++ b/server/controllers/UserController.ts @@ -30,6 +30,7 @@ import { Request, Response } from 'express' import OBPClientService from '../services/OBPClientService' import { Service, Container } from 'typedi' import { OAuth2Service } from '../services/OAuth2Service' +import { DEFAULT_OBP_API_VERSION } from '../../shared-constants' @Service() @Controller('/user') @@ -129,9 +130,25 @@ export class UserController { } } + // Get actual user ID from OBP-API + let obpUserId = oauth2User.sub // Default to sub if OBP call fails + try { + const version = process.env.VITE_OBP_API_VERSION ?? DEFAULT_OBP_API_VERSION + const obpUser = await this.obpClientService.get( + `/obp/${version}/users/current`, + session['clientConfig'] + ) + if (obpUser && obpUser.user_id) { + obpUserId = obpUser.user_id + console.log('UserController: Got OBP user ID:', obpUserId) + } + } catch (error) { + console.warn('UserController: Could not fetch OBP user ID, using token sub:', error) + } + // Return user info in format compatible with frontend return response.json({ - user_id: oauth2User.sub, + user_id: obpUserId, username: oauth2User.username, email: oauth2User.email, email_verified: oauth2User.email_verified, diff --git a/server/services/OBPClientService.ts b/server/services/OBPClientService.ts index b9b34dd..e5b8188 100644 --- a/server/services/OBPClientService.ts +++ b/server/services/OBPClientService.ts @@ -28,6 +28,16 @@ import { Service } from 'typedi' import { DEFAULT_OBP_API_VERSION } from '../../shared-constants' +// Custom error class to preserve HTTP status codes +class OBPAPIError extends Error { + status: number + constructor(status: number, message: string) { + super(message) + this.status = status + this.name = 'OBPAPIError' + } +} + // OAuth2 Bearer token configuration interface OAuth2Config { accessToken: string @@ -140,7 +150,7 @@ export default class OBPClientService { if (!response.ok) { const errorText = await response.text() console.error('OBPClientService: GET request failed:', response.status, errorText) - throw new Error(`HTTP ${response.status}: ${errorText}`) + throw new OBPAPIError(response.status, errorText) } return await response.json() @@ -170,7 +180,7 @@ export default class OBPClientService { if (!response.ok) { const errorText = await response.text() console.error('OBPClientService: POST request failed:', response.status, errorText) - throw new Error(`HTTP ${response.status}: ${errorText}`) + throw new OBPAPIError(response.status, errorText) } return await response.json() @@ -200,7 +210,7 @@ export default class OBPClientService { if (!response.ok) { const errorText = await response.text() console.error('OBPClientService: PUT request failed:', response.status, errorText) - throw new Error(`HTTP ${response.status}: ${errorText}`) + throw new OBPAPIError(response.status, errorText) } return await response.json() @@ -228,7 +238,7 @@ export default class OBPClientService { if (!response.ok) { const errorText = await response.text() console.error('OBPClientService: DELETE request failed:', response.status, errorText) - throw new Error(`HTTP ${response.status}: ${errorText}`) + throw new OBPAPIError(response.status, errorText) } return await response.json() diff --git a/src/components/Preview.vue b/src/components/Preview.vue index 643c87c..ccae9dd 100644 --- a/src/components/Preview.vue +++ b/src/components/Preview.vue @@ -184,32 +184,156 @@ const highlightCode = (json) => { } } const submitEntitlement = async () => { - requiredRoles.value.forEach(async (formRole, idx) => { + for (const [idx, formRole] of requiredRoles.value.entries()) { + const role = roleForm[`role${formRole.role}${idx}`] + if (formRole.requires_bank_id) { - const role = roleForm[`role${formRole.role}${idx}`] + // Bank-level entitlement const bankId = roleForm[`bankId${formRole.role}${idx}`] - if (role && bankId && isUserLogon) { - const response = await createEntitlement(bankId, role) - let type = 'success' - if ('code' in response && response['code'] >= 400) { - type = 'error' - } + + if (!role || !bankId) { ElNotification({ duration: elMessageDuration, - message: response.message, + title: 'Missing Information', + message: 'Bank ID is required for this role.', position: 'bottom-right', - type + type: 'error' }) - } else { + continue + } + + if (!isUserLogon) { ElNotification({ duration: elMessageDuration, - message: 'Bank Id is required.', + title: 'Not Authenticated', + message: 'Please login to request this role.', + position: 'bottom-right', + type: 'error' + }) + continue + } + + try { + const response = await createEntitlement(bankId, role) + + // Check if response is an error object (from superagent) + const isError = response && response.error && response.error.response + const errorBody = isError ? response.error.response.body : null + const statusCode = isError ? response.error.status : null + + if (isError && errorBody && errorBody.code >= 400) { + // Parse error message from body + let errorMessage = 'Failed to create entitlement' + if (errorBody.message) { + // Message might be double-encoded JSON string + try { + const parsedMessage = JSON.parse(errorBody.message) + errorMessage = parsedMessage.message || errorBody.message + } catch { + errorMessage = errorBody.message + } + } + + ElNotification({ + duration: elMessageDuration, + title: `Error (${errorBody.code})`, + message: errorMessage, + position: 'bottom-right', + type: 'error' + }) + } else { + // Success + ElNotification({ + duration: elMessageDuration, + title: 'Success', + message: `Entitlement "${role}" requested successfully for bank "${bankId}"`, + position: 'bottom-right', + type: 'success' + }) + } + } catch (error: any) { + ElNotification({ + duration: elMessageDuration, + title: 'Request Failed', + message: error.message || 'An error occurred while requesting the entitlement', + position: 'bottom-right', + type: 'error' + }) + } + } else { + // System-wide entitlement (no bank_id required) + if (!role) { + ElNotification({ + duration: elMessageDuration, + title: 'Missing Information', + message: 'Role name is required.', + position: 'bottom-right', + type: 'error' + }) + continue + } + + if (!isUserLogon) { + ElNotification({ + duration: elMessageDuration, + title: 'Not Authenticated', + message: 'Please login to request this role.', + position: 'bottom-right', + type: 'error' + }) + continue + } + + try { + // System-wide entitlement uses empty string for bank_id + const response = await createEntitlement('', role) + + // Check if response is an error object (from superagent) + const isError = response && response.error && response.error.response + const errorBody = isError ? response.error.response.body : null + const statusCode = isError ? response.error.status : null + + if (isError && errorBody && errorBody.code >= 400) { + // Parse error message from body + let errorMessage = 'Failed to create entitlement' + if (errorBody.message) { + // Message might be double-encoded JSON string + try { + const parsedMessage = JSON.parse(errorBody.message) + errorMessage = parsedMessage.message || errorBody.message + } catch { + errorMessage = errorBody.message + } + } + + ElNotification({ + duration: elMessageDuration, + title: `Error (${errorBody.code})`, + message: errorMessage, + position: 'bottom-right', + type: 'error' + }) + } else { + // Success + ElNotification({ + duration: elMessageDuration, + title: 'Success', + message: `System-wide entitlement "${role}" requested successfully`, + position: 'bottom-right', + type: 'success' + }) + } + } catch (error: any) { + ElNotification({ + duration: elMessageDuration, + title: 'Request Failed', + message: error.message || 'An error occurred while requesting the entitlement', position: 'bottom-right', type: 'error' }) } } - }) + } } onBeforeMount(async () => { const route = useRoute()