-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Pushh to brach for purpose of debugging code with wkubo. Not to be merged with main. * Branch update only, not for main. * My branch update for wkubo review of issues. Not for merge. * Tweaked menu and env header. * Latest updates for wkubo to review re: issues with TheHeader.vue state. * Header and router cleanup. * Removed comment. * Menu updates. * Sprint 1 updates: fixed getUserInfo to only call once, added conditions for unauth routing. * Header layout updates and cleanup. * Button fixes. * Updates to address code review. 1 outstanding issue remaining: hasUserRoles getter. * Fixed getter. * Confirmed getter for userHasRoles works, removed related/redundant setter code. * Updated unit tests. * Fixed image loading issues in prod build. * Fixed src. --------- Co-authored-by: weskubo-cgi <[email protected]>
- Loading branch information
Showing
26 changed files
with
749 additions
and
1,311 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,236 +1,138 @@ | ||
'use strict'; | ||
const {getSessionUser, getHttpHeader, minify, getUserGuid, getUserName, getLabelFromValue, postOperation, isIdirUser, getOperation} = require('./utils'); | ||
const config = require('../config/index'); | ||
const ApiError = require('./error'); | ||
const axios = require('axios'); | ||
const HttpStatus = require('http-status-codes'); | ||
const log = require('../components/logger'); | ||
const { APPLICATION_STATUS_CODES, CCFRI_STATUS_CODES, ECEWE_STATUS_CODES, CCOF_STATUS_CODES, CCOF_APPLICATION_TYPES, ORGANIZATION_PROVIDER_TYPES, CHANGE_REQUEST_TYPES} = require('../util/constants'); | ||
const { UserProfileFacilityMappings, UserProfileOrganizationMappings, UserProfileBaseFundingMappings, UserProfileApplicationMappings, UserProfileCCFRIMappings, UserProfileECEWEMappings /* lint error: , UserProfileChangeRequestNewFacilityMappings*/} = require('../util/mapping/Mappings'); | ||
|
||
const { MappableObjectForFront } = require('../util/mapping/MappableObject'); | ||
const _ = require ('lodash'); | ||
|
||
'use strict' | ||
const { getSessionUser, getUserName, getHttpHeader, minify, getUserGuid, isIdirUser } = require('./utils') | ||
const config = require('../config/index') | ||
const ApiError = require('./error') | ||
const axios = require('axios') | ||
const HttpStatus = require('http-status-codes') | ||
const log = require('../components/logger') | ||
// TODO... const { ORGANIZATION_PROVIDER_TYPES} = require('../util/constants') | ||
const { UserProfileMappings, UserProfileOrganizationMappings, UserProfileFacilityPermissionMappings, UserProfileFacilityMappings } = require('../util/mapping/Mappings') | ||
|
||
const { MappableObjectForFront } = require('../util/mapping/MappableObject') | ||
const _ = require('lodash') | ||
|
||
async function getUserInfo(req, res) { | ||
|
||
const userInfo = getSessionUser(req); | ||
const userInfo = getSessionUser(req) | ||
if (!userInfo || !userInfo.jwt || !userInfo._json) { | ||
return res.status(HttpStatus.UNAUTHORIZED).json({ | ||
message: 'No session data' | ||
}); | ||
message: 'No session data', | ||
}) | ||
} | ||
const isIdir = isIdirUser(req); | ||
const queryUserName = req.params?.queryUserName; | ||
const userName = getUserName(req); | ||
const isIdir = isIdirUser(req) | ||
const queryUserName = req.params?.queryUserName | ||
const userName = getUserName(req) | ||
|
||
// if is idir user (ministry user), make sure they are a user in dynamics | ||
// TODO commented out until we focus on IDIR login and weather this code is relevant | ||
if (isIdir) { | ||
let response = await getDynamicsUserByEmail(req); | ||
let response = await getDynamicsUserByEmail(req) | ||
if (response.value?.length > 0 && response.value[0].systemuserid) { | ||
log.verbose(`Ministry user: [${req.session.passport.user._json.display_name}] logged in.`); | ||
log.verbose(`Ministry user: [${req.session.passport.user._json.display_name}] logged in.`) | ||
} else { | ||
log.info(`Ministry user: [${req.session.passport.user._json.display_name}] attempted to log in but is not part of Dynamics.`); | ||
log.info(`Ministry user: [${req.session.passport.user._json.display_name}] attempted to log in but is not part of Dynamics.`) | ||
return res.status(HttpStatus.UNAUTHORIZED).json({ | ||
message: 'Not Authorized' | ||
}); | ||
message: 'Not Authorized', | ||
}) | ||
} | ||
} | ||
let resData = { | ||
displayName: (queryUserName)? userName + '-' + queryUserName : userName, | ||
// TODO i thing this has to do with impersonate... displayName: (queryUserName)? userName + '-' + queryUserName : userName, | ||
userName: userName, | ||
email: req.session.passport.user._json.email, | ||
isMinistryUser: isIdir, | ||
serverTime: new Date(), | ||
//TODO: unreadMessages is hardcoded. Remove this with API values when built out! | ||
unreadMessages: false, | ||
}; | ||
let userResponse = undefined; | ||
} | ||
let userResponse = undefined | ||
if (isIdir) { | ||
if (queryUserName) { | ||
try { | ||
log.info(`Ministry user [${userName}] is impersonating with username: [${queryUserName}].`); | ||
log.info(`Ministry user [${userName}] is impersonating with username: [${queryUserName}].`) | ||
// dynamics api requires a userID. if userID not found then it wil use the query name | ||
// put a random userID so that we only search by queryname | ||
userResponse = await getUserProfile(null, queryUserName); | ||
userResponse = await getUserProfile(null, queryUserName) | ||
if (userResponse === null) { | ||
return res.status(HttpStatus.NOT_FOUND).json({message: 'No user found with that BCeID UserName'}); | ||
return res.status(HttpStatus.NOT_FOUND).json({ message: 'No user found with that BCeID UserName' }) | ||
} | ||
} catch (e) { | ||
log.error('getUserProfile Error', e.response ? e.response.status : e.message); | ||
throw new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, {message: 'API Get error'}, e); | ||
log.error('getUserProfile Error', e.response ? e.response.status : e.message) | ||
throw new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, { message: 'API Get error' }, e) | ||
} | ||
} else { | ||
//If not looking for a username, return from here since ministry staff should not have an account | ||
return res.status(HttpStatus.OK).json(resData); | ||
return res.status(HttpStatus.OK).json(resData) | ||
} | ||
} else { | ||
//Not an idir user, so just get the guid from the header | ||
const userGuid = getUserGuid(req); | ||
log.verbose('User Guid is: ', userGuid); | ||
userResponse = await getUserProfile(userGuid, userName ); | ||
const userGuid = getUserGuid(req) | ||
log.verbose('User Guid is: ', userGuid) | ||
userResponse = await getUserProfile(userGuid) | ||
} | ||
|
||
if (log.isVerboseEnabled) { | ||
log.verbose('getUserProfile response:',minify(userResponse)); | ||
log.verbose('getUserProfile response:', minify(userResponse)) | ||
} | ||
|
||
if (userResponse === null) { | ||
creatUser(req); | ||
return res.status(HttpStatus.OK).json(resData); | ||
} | ||
if (userResponse === {}){ | ||
// If no data back, then no associated Organization/Facilities, return empty orgination data | ||
return res.status(HttpStatus.OK).json(resData); | ||
// If no data back, then no associated User Roles/Organization/Facilities/ | ||
return res.status(HttpStatus.UNAUTHORIZED).json(resData) | ||
} | ||
|
||
let organization = new MappableObjectForFront(userResponse, UserProfileOrganizationMappings).data; | ||
let user = new MappableObjectForFront(userResponse, UserProfileMappings).data | ||
let organization = new MappableObjectForFront(userResponse.organization, UserProfileOrganizationMappings).data | ||
resData.facilityPermission = parseFacilityPermissions(userResponse) | ||
|
||
let application = new MappableObjectForFront(userResponse.application, UserProfileApplicationMappings).data; | ||
application.organizationProviderType = getLabelFromValue(application.organizationProviderType, ORGANIZATION_PROVIDER_TYPES); | ||
application.applicationStatus = getLabelFromValue(application.applicationStatus, APPLICATION_STATUS_CODES, 'NEW'); | ||
application.applicationType = getLabelFromValue(application.applicationType, CCOF_APPLICATION_TYPES); | ||
application.ccofProgramYearId = userResponse.application?.ccof_ProgramYear?.ccof_program_yearid; | ||
application.ccofProgramYearName = userResponse.application?.ccof_ProgramYear?.ccof_name; | ||
application.ccofApplicationStatus = getLabelFromValue(application.ccofStatus, CCOF_STATUS_CODES, 'NEW'); | ||
|
||
|
||
resData.facilityList = parseFacilityData(userResponse); | ||
let results = { | ||
...resData, | ||
...user, | ||
...organization, | ||
...application, | ||
}; | ||
return res.status(HttpStatus.OK).json(results); | ||
} | ||
log.verbose('getUserInfo response:', results) | ||
return res.status(HttpStatus.OK).json(results) | ||
} | ||
|
||
async function getUserProfile(userGuid, userName) { | ||
async function getUserProfile(userGuid) { | ||
try { | ||
let url = undefined; | ||
let url = undefined | ||
if (userGuid) { | ||
url = config.get('dynamicsApi:apiEndpoint') + `/api/ProviderProfile?userId=${userGuid}&userName=${userName}`; | ||
} else { | ||
url = config.get('dynamicsApi:apiEndpoint') + `/api/ProviderProfile?userName=${userName}`; | ||
url = config.get('dynamicsApi:apiEndpoint') + `/api/ProviderProfile?userId=${userGuid}` | ||
} | ||
|
||
log.verbose('UserProfile Url is', url); | ||
const response = await axios.get(url, getHttpHeader()); | ||
return response.data; | ||
log.verbose('UserProfile Url is', url) | ||
let response = undefined | ||
response = await axios.get(url, getHttpHeader()) | ||
log.verbose('getUserProfile response:', response.data) | ||
return response.data | ||
} catch (e) { | ||
if (e.response?.status == '404') { | ||
log.verbose('response ', e.response.data); | ||
log.verbose('response ', e.response.data) | ||
if (e.response?.data?.startsWith('User not found')) { | ||
return null; | ||
return null | ||
} | ||
return {}; | ||
return {} | ||
} | ||
log.error('getUserProfile Error', e.response ? e.response.status : e.message); | ||
throw e; | ||
log.error('getUserProfile Error', e.response ? e.response.status : e.message) | ||
throw e | ||
} | ||
} | ||
|
||
function updateFacilityWithChangeRequestDetails(changeRequestList, returnValue, facilityId) { | ||
for (const changeRequest of changeRequestList) { | ||
//todo -mk check statuscode | ||
let changeActionNewFacilityList = changeRequest?.ccof_change_action_change_request?.filter(item =>item.ccof_changetype === CHANGE_REQUEST_TYPES.NEW_FACILITY); | ||
for (const changeActionNewFacility of changeActionNewFacilityList) { | ||
let result = changeActionNewFacility?.ccof_change_request_new_facility_change_act.find(item => item['_ccof_facility_value'] === facilityId); | ||
if (result) { | ||
returnValue.changeRequestId = changeRequest?.ccof_change_requestid; | ||
returnValue.unlockCcfri = result?.ccof_unlock_ccfri; | ||
returnValue.unlockNmf = result?.ccof_unlock_nmf_rfi; | ||
returnValue.unlockRfi = result?.ccof_unlock_rfi; | ||
|
||
function parseFacilityPermissions(userResponse) { | ||
const facilityList = Object.entries(userResponse.facility_permission) | ||
.map(([key, value]) => { | ||
// Only add facilities that have portal access | ||
if (value.ofm_portal_access === true) { | ||
const facilityPermission = new MappableObjectForFront(value, UserProfileFacilityPermissionMappings).data | ||
const facility = new MappableObjectForFront(value.facility, UserProfileFacilityMappings).data | ||
const combinedData = { ...facilityPermission, ...facility } | ||
if (!_.isEmpty(combinedData)) { | ||
return combinedData | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
function parseFacilityData(userResponse) { | ||
let facilityMap = new Map(userResponse.facilities?.map((m) => [m['accountid'], new MappableObjectForFront(m, UserProfileFacilityMappings).data])); | ||
|
||
if (userResponse.application) { | ||
facilityMap.forEach((value, key, map) => { | ||
let ccfriInfo = userResponse.application.ccof_applicationccfri_Application_ccof_ap?.find(item => item['_ccof_facility_value'] === key); | ||
ccfriInfo = new MappableObjectForFront(ccfriInfo, UserProfileCCFRIMappings).data; | ||
let eceweInfo = userResponse.application.ccof_ccof_application_ccof_applicationecewe_application?.find(item => item['_ccof_facility_value'] === key); | ||
eceweInfo = new MappableObjectForFront(eceweInfo, UserProfileECEWEMappings).data; | ||
let baseFunding = userResponse.application.ccof_application_basefunding_Application?.find(item => item['_ccof_facility_value'] === key); | ||
baseFunding = new MappableObjectForFront(baseFunding, UserProfileBaseFundingMappings).data; | ||
let changeRequestList = userResponse.application.ccof_ccof_change_request_Application_ccof_appl; | ||
let returnValue = { | ||
...value, | ||
...ccfriInfo, | ||
...eceweInfo, | ||
...baseFunding, | ||
}; | ||
updateFacilityWithChangeRequestDetails(changeRequestList, returnValue, key); | ||
map.set(key, returnValue); | ||
}); | ||
} | ||
let facilityList = []; | ||
facilityMap.forEach((facility) => { | ||
if (!_.isEmpty(facility)) { | ||
facility.ccofBaseFundingStatus = getLabelFromValue(facility.ccofBaseFundingStatus, CCOF_STATUS_CODES); | ||
facility.ccfriStatus = getLabelFromValue(facility.ccfriStatus, CCFRI_STATUS_CODES, 'NOT STARTED'); | ||
facility.eceweStatus = getLabelFromValue(facility.eceweStatus, ECEWE_STATUS_CODES, 'NOT STARTED'); | ||
facilityList.push(facility); | ||
} | ||
}); | ||
return facilityList; | ||
} | ||
|
||
async function getDynamicsUserByEmail(req) { | ||
let email = req.session.passport.user._json.email; | ||
if (!email) { | ||
//If for some reason, an email is not associated with the IDIR, just use [email protected] | ||
email = `${req.session.passport.user._json.idir_username}@gov.bc.ca`; | ||
} | ||
// eslint-disable-next-line quotes, | ||
email.includes("'") ? email = email.replace("'", "''") : email; | ||
try { | ||
let response = await getOperation(`systemusers?$select=firstname,domainname,lastname&$filter=internalemailaddress eq '${email}'`); | ||
return response; | ||
} catch (e) { | ||
log.error('getDynamicsUserByEmail Error', e.response ? e.response.status : e.message); | ||
throw new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, {message: 'API Get error'}, e); | ||
} | ||
} | ||
|
||
async function creatUser(req) { | ||
log.info('No user found, creating BCeID User: ', getUserName(req)); | ||
let given_name = req.session.passport.user._json.given_name; | ||
let family_name = req.session.passport.user._json.family_name; | ||
let firstname = undefined; | ||
let lastname = undefined; | ||
try { | ||
if (!family_name && given_name && given_name.split(' ').length > 1) { | ||
//If for some reason we don't have a last name from SSO, see if firstname has 2 words | ||
firstname = given_name.split(' ').slice(0, -1).join(' '); | ||
lastname = given_name.split(' ').slice(-1).join(' '); | ||
} else if (!given_name && family_name && family_name.split(' ').length > 1) { | ||
//If for some reason we don't have a firstname name from SSO, see if lastname has 2 words | ||
firstname = family_name.split(' ').slice(0, -1).join(' '); | ||
lastname = family_name.split(' ').slice(-1).join(' '); | ||
} else { | ||
firstname = given_name; | ||
lastname = family_name; | ||
} | ||
|
||
let payload = { | ||
ccof_userid: getUserGuid(req), | ||
firstname: firstname, | ||
lastname: lastname, | ||
emailaddress1: req.session.passport.user._json.email, | ||
ccof_username: getUserName(req) | ||
}; | ||
postOperation('contacts', payload); | ||
} catch (e) { | ||
log.error('Error when creating user: ', e); | ||
throw new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, {message: 'Error while creating a new BCeID User'}, e); | ||
} | ||
return null | ||
}) | ||
.filter((facility) => facility !== null) | ||
return facilityList | ||
} | ||
|
||
module.exports = { | ||
getUserInfo, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,39 @@ | ||
const OrganizationMappings = [ | ||
{ back: 'ccof_facilitystartdate', front: 'yearBeganOperation' }, | ||
{ back: 'name', front: 'legalName' }, | ||
{ back: 'address1_name', front: 'address1' }, //Address | ||
{ back: 'address1_city', front: 'city1' }, | ||
{ back: 'address1_postalcode', front: 'postalCode1' }, | ||
{ back: 'address2_name', front: 'address2' }, //Mailing Address | ||
{ back: 'address2_city', front: 'city2' }, | ||
{ back: 'address2_postalcode', front: 'postalCode2' }, | ||
{ back: 'address1_primarycontactname', front: 'contactName' }, | ||
{ back: 'ccof_position', front: 'position' }, | ||
{ back: 'telephone1', front: 'phone' }, | ||
const UserProfileMappings = [ | ||
{ back: 'contactid', front: 'contactId' }, | ||
{ back: 'ccof_userid', front: 'userId' }, | ||
{ back: 'ccof_username', front: 'username' }, | ||
{ back: 'emailaddress1', front: 'email' }, | ||
{ back: 'ccof_instructionnumber', front: 'incNumber' },//incorporation number | ||
{ back: 'ccof_typeoforganization', front: 'organizationType' }, | ||
{ back: 'ccof_formcomplete', front: 'isOrganizationComplete' }, | ||
{ back: 'ccof_is_mailing_address_same', front: 'isSameAsMailing'} | ||
]; | ||
{ back: 'ofm_first_name', front: 'firstName' }, | ||
{ back: 'ofm_last_name', front: 'lastName' }, | ||
{ back: 'ofm_portal_role', front: 'roles' }, | ||
] | ||
|
||
const ProgramYearMappings = [ | ||
{ back: 'ccof_program_yearid', front: 'programYearId' }, | ||
{ back: 'ccof_name', front: 'name' }, | ||
{ back: 'statuscode', front: 'status' }, | ||
{ back: 'ccof_programyearnumber', front: 'order' }, | ||
{ back: '_ccof_previousyear_value', front: 'previousYearId' }, | ||
{ back: 'ccof_intakeperiodstart', front: 'intakeStart' }, | ||
{ back: 'ccof_intakeperiodend', front: 'intakeEnd' }, | ||
{ back: 'ccof_declarationbstart', front: 'declarationbStart' }, | ||
]; | ||
const UserProfileOrganizationMappings = [ | ||
{ back: 'accountid', front: 'organizationId' }, | ||
{ back: 'accountnumber', front: 'organizationAccountNumber' }, | ||
{ back: 'ccof_accounttype', front: 'organizationAccountType' }, | ||
{ back: 'name', front: 'organizationName' }, | ||
{ back: 'statecode', front: 'organizationStateCode' }, | ||
{ back: 'statuscode', front: 'organizationStatus' }, | ||
] | ||
|
||
const UserProfileFacilityPermissionMappings = [ | ||
{ back: 'statecode', front: 'stateCode' }, | ||
{ back: 'statuscode', front: 'statusCode' }, | ||
] | ||
|
||
const UserProfileFacilityMappings = [ | ||
{ back: 'accountid', front: 'facilityId' }, | ||
{ back: 'accountnumber', front: 'facilityAccountNumber' }, | ||
{ back: 'name', front: 'facilityName' }, | ||
{ back: 'ccof_accounttype', front: 'facilityType' }, | ||
{ back: 'statecode', front: 'facilityStateCode' }, | ||
{ back: 'statuscode', front: 'facilityStatusCode' }, | ||
] | ||
|
||
module.exports = { | ||
OrganizationMappings, | ||
ProgramYearMappings | ||
}; | ||
UserProfileMappings, | ||
UserProfileOrganizationMappings, | ||
UserProfileFacilityPermissionMappings, | ||
UserProfileFacilityMappings, | ||
} |
Oops, something went wrong.