Skip to content

Feature/userinfo - #273

Open
JasonRobertFrancis wants to merge 32 commits into
mainfrom
feature/userinfo
Open

Feature/userinfo#273
JasonRobertFrancis wants to merge 32 commits into
mainfrom
feature/userinfo

Conversation

@JasonRobertFrancis

Copy link
Copy Markdown
Contributor

No description provided.

@codecov-commenter

codecov-commenter commented Jul 28, 2026

Copy link
Copy Markdown

Bundle Report

Bundle size has no change ✅

@codecov-commenter

codecov-commenter commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 27.71962% with 6352 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.19%. Comparing base (dd7f02c) to head (5a8fdb3).
⚠️ Report is 44 commits behind head on main.

Files with missing lines Patch % Lines
web/Areas/Directory/Services/UserInfoService.cs 41.45% 764 Missing and 38 partials ⚠️
web/Areas/Directory/Views/UserInfo.cshtml 0.00% 386 Missing ⚠️
web/Models/PPS/VwUserinfoUser.cs 0.00% 149 Missing ⚠️
web/Models/PPS/PsJobV.cs 0.00% 125 Missing ⚠️
web/Models/PPS/JobDV.cs 0.00% 121 Missing ⚠️
web/Models/PPS/JpmJpItemDV.cs 0.00% 121 Missing ⚠️
web/Models/PPS/PositionDV.cs 0.00% 118 Missing ⚠️
web/Models/PPS/PsJpmJpItemsV.cs 0.00% 116 Missing ⚠️
web/Models/PPS/EdbperVc.cs 0.00% 104 Missing ⚠️
web/Models/PPS/VwAllJobPosOrg.cs 0.00% 102 Missing ⚠️
... and 196 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #273      +/-   ##
==========================================
+ Coverage   50.07%   56.19%   +6.11%     
==========================================
  Files         998     1196     +198     
  Lines       58354    80434   +22080     
  Branches     5853     6185     +332     
==========================================
+ Hits        29221    45199   +15978     
- Misses      28228    34260    +6032     
- Partials      905      975      +70     
Flag Coverage Δ
backend 56.02% <27.71%> (+6.77%) ⬆️
frontend 58.63% <ø> (+0.17%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

Comment thread test/Services/UserInfoServiceUnitTests.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Classes/Utilities/IamApi.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Views/UserInfo.cshtml Fixed

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Classes/Utilities/IamApi.cs Fixed
@rlorenzo

This comment was marked as resolved.

Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
Comment thread web/Areas/Directory/Services/UserInfoService.cs Fixed
@rlorenzo

This comment was marked as resolved.

@rlorenzo

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands the Directory/UserInfo functionality and supporting infrastructure in the VIPER web app by adding new UI styling, new/adjusted endpoints for directory search and session timeout, and a large set of scaffolded EF model types + DbContext registrations for additional data domains (PPS, Keys, IDCards, EquipmentLoan).

Changes:

  • Add Directory “userinfo” styling and wire it into the shared layout.
  • Add a new /GetSessionTimeout JSON endpoint and adjust the SessionTimeout view component behavior in development.
  • Introduce new Directory controller APIs and a large set of new EF entity classes, plus DbContext registrations for additional schemas/apps; update LDAP/IAM utilities and tests/docs accordingly.

Reviewed changes

Copilot reviewed 218 out of 220 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
web/wwwroot/css/userinfo.css Adds styling for the Directory “userinfo” page.
web/Viper.csproj Adjusts build warning suppression configuration.
web/Views/Shared/Components/SessionTimeout/SessionTimeout.cs Updates session timeout refresh URL behavior.
web/Views/Shared/_VIPERLayout.cshtml Loads directory/userinfo CSS conditionally; normalizes helper variable naming.
web/Properties/launchSettings.json Changes local launch behavior (launchBrowser).
web/Program.cs Registers additional DbContexts and HTTP client services.
web/Models/PPS/VwStipend.cs Scaffolded PPS EF entity.
web/Models/PPS/VwRankStepEthnicityPayRate.cs Scaffolded PPS EF entity.
web/Models/PPS/VwPersonAccrual.cs Scaffolded PPS EF entity.
web/Models/PPS/VwPerson.cs Scaffolded PPS EF entity.
web/Models/PPS/VwLoa.cs Scaffolded PPS EF entity.
web/Models/PPS/VwJobCodeAndGroup.cs Scaffolded PPS EF entity.
web/Models/PPS/VwEmployee.cs Scaffolded PPS EF entity.
web/Models/PPS/VwAccrualsCdm.cs Scaffolded PPS EF entity.
web/Models/PPS/VwAccrual.cs Scaffolded PPS EF entity.
web/Models/PPS/VisaPermitDataDV.cs Scaffolded PPS EF entity.
web/Models/PPS/UpdateLog.cs Scaffolded PPS EF entity.
web/Models/PPS/UnionDV.cs Scaffolded PPS EF entity.
web/Models/PPS/UcpathVerificationItem.cs Scaffolded PPS EF entity.
web/Models/PPS/UcpathOverride.cs Scaffolded PPS EF entity.
web/Models/PPS/UcpathmissingpersonBk.cs Scaffolded PPS EF entity.
web/Models/PPS/UcpathMissingPerson20190821.cs Scaffolded PPS EF entity.
web/Models/PPS/UcpathMissingPerson.cs Scaffolded PPS EF entity.
web/Models/PPS/UcpathItemNote.cs Scaffolded PPS EF entity.
web/Models/PPS/UcdOrganizationDV.cs Scaffolded PPS EF entity.
web/Models/PPS/UcdFauDV.cs Scaffolded PPS EF entity.
web/Models/PPS/UcdEmployeeFlagsDV.cs Scaffolded PPS EF entity.
web/Models/PPS/UcdEmployeeFlagsDOverride.cs Scaffolded PPS EF entity.
web/Models/PPS/TitlecodeGroup.cs Scaffolded PPS EF entity.
web/Models/PPS/TimeDailyDV.cs Scaffolded PPS EF entity.
web/Models/PPS/ServiceCreditUnit.cs Scaffolded PPS EF entity.
web/Models/PPS/ServiceCredit.cs Scaffolded PPS EF entity.
web/Models/PPS/PsxlatitemV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsVisaPmtDataV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsUnionTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsUcSsDisclosurV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsUcJobGrpDescV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsUcJobCodeTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsUcJobCodesV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsUcFundAttribV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsUcExtSystemV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsUcdDmPsNamesPrefVnamesV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsUcCtoOscV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsUcAmSsTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsUcAmSsRcdV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsPrimaryJobsV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsPersonV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsPersonalPhoneV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsPersDataEffdtV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsPerOrgInstV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsJpmProfileV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsJpmCatTypesV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsJpmCatItemsV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsGpRsltAcumV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsGpAbsReasonV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsGpAbsEaV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsGpAbsEaStaV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsEthnicGrpTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsErnProgramTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsEmplClassTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsEmailAddressesV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsEarningsBalV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsDiversEthnicV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsDeptTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsDeptBudgetErnV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsDeptBudgetDtV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsCountryTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsCompRatecdTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsCompensationV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsCitizenStsTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsCitizenshipV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsAddressTypTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsAddressesV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsAddlPayDataV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsActnReasonTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsActionTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/PsAcctCdTblV.cs Scaffolded PPS EF entity.
web/Models/PPS/Prj2EmpidToPpsid.cs Scaffolded PPS EF entity.
web/Models/PPS/PrimaryJobsDV.cs Scaffolded PPS EF entity.
web/Models/PPS/OrganizationDV.cs Scaffolded PPS EF entity.
web/Models/PPS/OdsEmployeeFlagsDV.cs Scaffolded PPS EF entity.
web/Models/PPS/JpmFV.cs Scaffolded PPS EF entity.
web/Models/PPS/JobStatusDV.cs Scaffolded PPS EF entity.
web/Models/PPS/JobOverride.cs Scaffolded PPS EF entity.
web/Models/PPS/JobHistoryDetail.cs Scaffolded PPS EF entity.
web/Models/PPS/JobHistory.cs Scaffolded PPS EF entity.
web/Models/PPS/JobActionDV.cs Scaffolded PPS EF entity.
web/Models/PPS/HistServiceCredit.cs Scaffolded PPS EF entity.
web/Models/PPS/HistloaV.cs Scaffolded PPS EF entity.
web/Models/PPS/GoAnywhereLog.cs Scaffolded PPS EF entity.
web/Models/PPS/FurloughTarget.cs Scaffolded PPS EF entity.
web/Models/PPS/Export.cs Scaffolded PPS EF entity.
web/Models/PPS/EthnicityGender20210201.cs Scaffolded PPS EF entity.
web/Models/PPS/EthnicityGender.cs Scaffolded PPS EF entity.
web/Models/PPS/EmployeeHistory.cs Scaffolded PPS EF entity.
web/Models/PPS/EdbeffrptLog.cs Scaffolded PPS EF entity.
web/Models/PPS/Edbeffrpt.cs Scaffolded PPS EF entity.
web/Models/PPS/Dvtloa.cs Scaffolded PPS EF entity.
web/Models/PPS/DiversEthnicityDV.cs Scaffolded PPS EF entity.
web/Models/PPS/DepartmentDV.cs Scaffolded PPS EF entity.
web/Models/PPS/DepartmentBudgetEarnFV.cs Scaffolded PPS EF entity.
web/Models/PPS/Ctvhme.cs Scaffolded PPS EF entity.
web/Models/PPS/Ctltci.cs Scaffolded PPS EF entity.
web/Models/PPS/Ctlcad.cs Scaffolded PPS EF entity.
web/Models/PPS/CompensationFV.cs Scaffolded PPS EF entity.
web/Models/PPS/CompensationDV.cs Scaffolded PPS EF entity.
web/Models/PPS/CompensationDRateV.cs Scaffolded PPS EF entity.
web/Models/PPS/AuditOverride.cs Scaffolded PPS EF entity.
web/Models/PPS/AccountCodeDV.cs Scaffolded PPS EF entity.
web/Models/PPS/AbsenceResultFV.cs Scaffolded PPS EF entity.
web/Models/PPS/AbsenceResultDV.cs Scaffolded PPS EF entity.
web/Models/PPS/AbsenceEventFV.cs Scaffolded PPS EF entity.
web/Models/PPS/AbsenceEventDV.cs Scaffolded PPS EF entity.
web/Models/PPS/AbsenceCalendarDV.cs Scaffolded PPS EF entity.
web/Models/Keys/VwUserinfo.cs Scaffolded Keys EF entity/view model.
web/Models/Keys/KeyManager.cs Scaffolded Keys EF entity.
web/Models/Keys/KeyBuilding.cs Scaffolded Keys EF entity.
web/Models/Keys/KeyAssignment.cs Scaffolded Keys EF entity.
web/Models/Keys/Key.cs Scaffolded Keys EF entity.
web/Models/Keys/Import3.cs Scaffolded Keys import EF entity.
web/Models/Keys/Import2.cs Scaffolded Keys import EF entity.
web/Models/Keys/Import.cs Scaffolded Keys import EF entity.
web/Models/Keys/Disposition.cs Scaffolded Keys EF entity.
web/Models/Keys/Building.cs Scaffolded Keys EF entity.
web/Models/IDCards/VwLatestIdcard.cs Scaffolded IDCards EF view entity.
web/Models/IDCards/VwDelimitedSpecialApprover.cs Scaffolded IDCards EF view entity.
web/Models/IDCards/VwApproverMothraId.cs Scaffolded IDCards EF view entity.
web/Models/IDCards/PrintQueue.cs Scaffolded IDCards EF entity (with navigation).
web/Models/IDCards/PhotoExport.cs Scaffolded IDCards EF entity.
web/Models/IDCards/LenelBadge.cs Scaffolded IDCards EF entity.
web/Models/IDCards/IgnoreList.cs Scaffolded IDCards EF entity.
web/Models/IDCards/IdCardToPrintQueue.cs Scaffolded join entity.
web/Models/IDCards/IdCard.cs Scaffolded IDCards EF entity.
web/Models/IDCards/ExtVisit.cs Scaffolded IDCards EF entity.
web/Models/IDCards/EcoTimeBadgeExclusion.cs Scaffolded IDCards EF entity.
web/Models/IDCards/DvtSvmUnit.cs Scaffolded IDCards lookup entity.
web/Models/IDCards/DvtSpecialty.cs Scaffolded IDCards lookup entity.
web/Models/IDCards/DvtSpecialApprover.cs Scaffolded IDCards lookup entity.
web/Models/IDCards/DvtReason.cs Scaffolded IDCards lookup entity.
web/Models/IDCards/DvtOverseer.cs Scaffolded IDCards lookup entity.
web/Models/IDCards/DvtClient.cs Scaffolded IDCards lookup entity.
web/Models/IDCards/DvtCardStatus.cs Scaffolded IDCards lookup entity.
web/Models/IDCards/DvtApprover.cs Scaffolded IDCards lookup entity.
web/Models/IDCards/Defuncted.cs Scaffolded IDCards EF entity.
web/Models/IDCards/DbIdCard.cs Scaffolded IDCards EF entity.
web/Models/IDCards/BulkLoadResult.cs Scaffolded IDCards EF entity.
web/Models/IDCards/Audit.cs Scaffolded IDCards audit EF entity.
web/Models/IDCards/AccessLevel.cs Scaffolded IDCards lookup entity.
web/Models/IDCards/AccessExpiration.cs Scaffolded IDCards EF entity.
web/Models/EquipmentLoan/VwLoan.cs Scaffolded EquipmentLoan EF view entity.
web/Models/EquipmentLoan/Reason.cs Scaffolded EquipmentLoan EF entity.
web/Models/EquipmentLoan/O.cs Scaffolded EquipmentLoan EF entity (OS lookup).
web/Models/EquipmentLoan/LoanNote.cs Scaffolded EquipmentLoan EF entity.
web/Models/EquipmentLoan/LoanItem.cs Scaffolded EquipmentLoan EF entity.
web/Models/EquipmentLoan/Loan.cs Scaffolded EquipmentLoan EF entity.
web/Models/EquipmentLoan/EmailTemplate.cs Scaffolded EquipmentLoan EF entity.
web/Models/EquipmentLoan/EmailSent.cs Scaffolded EquipmentLoan EF entity.
web/Models/EquipmentLoan/Audit.cs Scaffolded EquipmentLoan audit EF entity.
web/Models/EquipmentLoan/AssetType.cs Scaffolded EquipmentLoan lookup entity.
web/Models/EquipmentLoan/AssetNote.cs Scaffolded EquipmentLoan EF entity.
web/Models/EquipmentLoan/Asset.cs Scaffolded EquipmentLoan EF entity.
web/Models/EquipmentLoan/AppSetting.cs Scaffolded EquipmentLoan EF entity.
web/Controllers/HomeController.cs Adds a GetSessionTimeout endpoint.
web/Classes/Utilities/LdapService.cs Adds MothraID lookup and improves sorting; extends LDAP helpers.
web/Classes/Utilities/IamApi.cs Adds custom DateTime parsing for IAM API responses.
web/Classes/AreaController.cs Adds PopulateLeftNav helper and adjusts dev nav link conversion.
web/Areas/Directory/Models/UCPathResult.cs Adds Directory UCPath DTO.
web/Areas/Directory/Models/LoanResult.cs Adds Directory loan DTO.
web/Areas/Directory/Models/LdapUserContact.cs Adjusts LDAP contact model (MothraId nullable).
web/Areas/Directory/Models/KeyResult.cs Adds Directory key DTO.
web/Areas/Directory/Models/InstinctResult.cs Adds Directory instinct DTO.
web/Areas/Directory/Models/IndividualSearchResultWithIDs.cs Adjusts Directory search result mapping.
web/Areas/Directory/Models/IndividualSearchResult.cs Adjusts Directory search result mapping.
web/Areas/Directory/Models/IDCardResult.cs Adds Directory ID card DTO.
web/Areas/Directory/Models/DirectoryUser.cs Adds view model for Directory permissions/features.
web/Areas/Directory/Controllers/DirectoryController.cs Adds query-based search endpoint and left-nav population.
Viper.sln.DotSettings Updates ReSharper inspection severities.
test/Usings.cs Disables xUnit test parallelization globally.
test/Areas/Directory/VMACSServiceTest.cs Updates VMACS URL validation test cases.
CLAUDE.md Updates repo contribution/testing guidance.
.gitignore Updates ignore patterns (currently includes conflict marker and broad ignores).

Comment thread web/Views/Shared/Components/SessionTimeout/SessionTimeout.cs
Comment thread web/Controllers/HomeController.cs
Comment thread web/Classes/Utilities/LdapService.cs Outdated
Comment on lines +127 to +129
if (id == null) return null;
string filter = string.Format("(ucdpersonuuid = {0})", id);
var results = SearchLdap(filter);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JasonRobertFrancis Yes, this was flagged in the previous PR and still an issue

Comment thread web/Areas/Directory/Models/IndividualSearchResult.cs Outdated
Comment thread web/Areas/Directory/Models/IndividualSearchResultWithIDs.cs
Comment thread web/Viper.csproj
<ImplicitUsings>enable</ImplicitUsings>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<PublishDir>bin\Release\net10.0\publish\</PublishDir>
<NoWarn>$(NoWarn);NU1902;NU1608</NoWarn>
Comment thread web/wwwroot/css/userinfo.css Outdated

@bsedwards bsedwards left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address the student information in the user info page - we need to remove sensitive information.

Other things I've noticed:

  • I was using the directory on secure-test earlier, but now when I search I'm getting an HTML page saying my session has timed out.
Image
  • I was missing the AAUD Check, ID Check, and UC Path info links on directory entries.
  • Missing AD information from user info page.
  • Student information on the user info page only shows 5 flags for me. Please validate the permissions being checked.
Image Image

return null;
}

Console.WriteLine($"[INSTINCT SERVICE] mothraId: '{mothraId}', iamId: '{iamId}', result.MothraId: '{result.MothraId}'");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we should have console.writeline in production code

/// <summary>
/// Get cumulative GPA - equivalent to getCumulativeGPA in SIS.cfc
/// </summary>
private async Task<string?> GetStudentCumulativeGPAAsync(string pidm, string termCode, string majorCode)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this is reimplementing every function in SIS.cfc inside UserInfoService.cs. I'm not sure how many of these functions the user info page is actually using (ref previous comment on sensitivity of this info). I suggest implementing these functions in a separate class and having the UserInfoService only reference what is needed and approved for display on the UserInfoPage.

result.StudentBannerId = await GetStudentBannerIdAsync(result.Pidm);
result.StudentConfidential = await IsStudentConfidentialAsync(result.Pidm);
result.StudentConfidentialScope = await GetStudentConfidentialScopeAsync(result.Pidm);
result.StudentBirthDate = await GetStudentBirthDateAsync(result.Pidm);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these shown on the User Info page? Many of these fields are sensitive and should only be shown to a small number of users.

public static async Task<byte[]?> GetUserPhotoAsync(string mailId, bool useAltPhoto = false)
{
// stubbed
return null;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

??

var formContent = new FormUrlEncodedContent(formParams);
Console.WriteLine("[INSTINCT AUTH] Sending token POST request...");
var response = await httpClient.PostAsync(tokenUrl, formContent);
Console.WriteLine($"[INSTINCT AUTH] Response Status Code: {response.StatusCode}");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More Console.WriteLine

}
<li><strong>Dual Degree?:</strong> @(Model.StudentIsDualDegree ? "Yes" : "No")</li>

@if (Model.CanViewStudentID)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure being able to view the student ID is sufficient permission to view this detail. I would suggest leaving out things like GPA, residency and citizenship, ethnicity, age, etc. off the UserInfo page entirely.

<li><strong>Student Employer:</strong> @Model.StudentEmployer</li>
}
}
@if (!string.IsNullOrEmpty(Model.StudentPermanentAddress))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also leave addresses out of this page

Comment thread web/Viper.csproj
<ImplicitUsings>enable</ImplicitUsings>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<PublishDir>bin\Release\net10.0\publish\</PublishDir>
<NoWarn>$(NoWarn);NU1902;NU1608</NoWarn>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to disable warnings on these issues?

Comment thread .gitignore Outdated
# Used to reduce unnecessary dotnet builds
.build-cache/

<<<<<<< HEAD

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line created during a merge?

Comment thread .gitignore Outdated

# Agent folders
.claude
CLAUDE.md

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to exclude the .md files? I think Rex committed some.

userInfo.CanViewInstinct = ownPage || _userHelper.HasPermission(_rapsContext, currentUser, "SVMSecure.userinfo.instinct");
userInfo.CanViewADGroups = _userHelper.HasPermission(_rapsContext, currentUser, "SVMSecure.UserInfo.ADGroups");

userInfo.CanViewDirectoryDetail = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JasonRobertFrancis The permission overrides are still in place. This has got to be debugging code, right?

Comment thread web/Classes/Utilities/LdapService.cs Outdated
Comment on lines +127 to +129
if (id == null) return null;
string filter = string.Format("(ucdpersonuuid = {0})", id);
var results = SearchLdap(filter);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JasonRobertFrancis Yes, this was flagged in the previous PR and still an issue

return NotFound();
}

[Route("/[area]/nav")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JasonRobertFrancis This will conflict with the /nav route for the Directory. Go to https://secure-test.vetmed.ucdavis.edu/2/Directory/nav and it will give an error that it doesn't on main/PROD.

<img src="https://viper.vetmed.ucdavis.edu/public/utilities/getbase64image.cfm?mailid=@Model.MailId" width="87" height="111" alt="User Photo" />
</span>
<span class="photo2">
<img src="https://viper.vetmed.ucdavis.edu/public/utilities/getbase64image.cfm?mailid=@Model.MailId&amp;altphoto=1" width="87" height="111" alt="Alternative Photo" />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be hardcoded to prod VIPER1, right?

<div class="direct">
<h2>User Information Page</h2>
<span class="photo">
<img src="https://viper.vetmed.ucdavis.edu/public/utilities/getbase64image.cfm?mailid=@Model.MailId" width="87" height="111" alt="User Photo" />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be hardcoded to prod VIPER1, right?

{
<li><strong>Banner ID:</strong> @Model.StudentBannerId</li>
}
<li><strong>Confidential?:</strong> @(Model.StudentConfidential ? "Yes" : "No")</li>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The flag is fetched, but it does not appear to be used to suppress any data. Is that right?

Comment thread .gitignore Outdated
CLAUDE.md

# Temp Agent Files
DESIGN.md*

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should not be ignored either

"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"launchBrowser": true,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed. If you use npm run dev the browser will be opened for you

</article>

@section Scripts {
<script src="~/js/userinfo.js"></script>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This JS file does not exist

{
if (vm?.item != null)
{
if (vm.item.Nextel != null) result.Nextel = vm.item.Nextel[0];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An empty value for Nextel/LDPager/Unit can crash the search.

Suggested code:

private static void PopulateVmacsDetails(IndividualSearchResult result, VMACSQuery? vm)
{
    var item = vm?.item;
    if (item == null)
    {
        return;
    }
    if (item.Nextel is { Length: > 0 }) result.Nextel = item.Nextel[0];
    if (item.LDPager is { Length: > 0 }) result.LDPager = item.LDPager[0];
    if (item.Unit is { Length: > 0 }) result.Department = item.Unit[0];
}

.ThenByDescending(p => p.Effdt)
.ToListAsync();

foreach (var history in historyData)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a Claude code analysis:

N+1 with synchronous blocking EF calls in an async request
UserInfoService.cs:1333-1348 calls GetReportsToName(history) and GetReportsToPosition(history) per UCPath history row. Each helper (1359-1433) issues up to two FirstOrDefault() calls — synchronous, not FirstOrDefaultAsync — at lines 1367, 1377, 1405, 1416. And the two helpers query the identical rows independently, so it's up to 4 blocking round-trips per row where 1 async batch would do. A person with 30 job actions is 120 sequential blocking DB calls holding a thread-pool thread.

Also:

  • PopulateKeysAsync:1498 — one AAUD query per key assignment to resolve IssuedBy
  • GetUserPermissionsForSystemAsync — called 5× from 1126-1136, re-running the same two large RAPS joins each time; only the trailing StartsWith(systemPrefix) filter differs
  • No .AsNoTracking() anywhere in a 2,229-line entirely read-only service

Seems like a major performance concern.

[Route("")]
public ActionResult Index()
{
return Redirect("/Directory");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would go back to VIPER1, is that expected?

@if (Model.CanViewRoles && Model.SystemRoles.Any())
{
<div class="roles">
<h2><a href="/RAPS/" target="_blank">System Roles</a></h2>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would go back to VIPER1, is that expected?

}
if (!foundMatch)
{
result.ErrorMessage = $"User found in API but no name match. Variations tried: {string.Join(", ", nameVariations)}. API users: {string.Join(", ", graphqlResponse.Data.SearchUsers.Select(u => $"{u.NameFirst} {u.NameLast}"))}";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When this returns no matches, it returns a list of API users. This seems like it would leak user information.

// Create GraphQL query
var query = $@"
query {{
searchUsers(name: ""{lastName}"") {{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GraphQL query built by string interpolation

{
[ApiController]
[Route("public/utilities")]
public class PublicPhotoController : ControllerBase

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This already exists on main. CMSUserPhotoController serves the same ICmsUserPhotoService at /api/cms/photos/by-mail/{mailId}?altPhoto=true, with the same cache headers and 304 handling (5633bedd, VPR-59). UserInfoController is [Permission(Allow = "SVMSecure")], so the <img> requests carry the auth cookie and it would work here as-is.

Worth a deliberate call either way: this controller has no [Permission] or [Authorize], and Program.cs sets a DefaultPolicy but no FallbackPolicy, so photo lookup by mailId, mothraId, iamId, and mivId is open to unauthenticated callers. The CMS one is deliberately gated.

Suggest pointing the view at @HttpHelper.GetRootURL()/api/cms/photos/by-mail/@Model.MailId?altPhoto=true and dropping this. If it stays, the cache/304 block and the mivId resolution both belong in the shared service rather than copied here.

/// <param name="mailID">Mail ID</param>
/// <param name="altphoto">Use alternative photo</param>
/// <returns></returns>
[Route("/userPhoto")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This returns NotFound() for every request, and with PublicPhotoController there are now three photo routes in play alongside the existing /api/cms/photos/by-mail/{mailId}. Worth deleting.

new("scope", "api_access")
};

var formContent = new FormUrlEncodedContent(formParams);
Comment on lines +404 to +410
foreach (var name in nameList)
{
if (!string.IsNullOrEmpty(name.StudentName) && name.ActivityDate.HasValue)
{
names.Add($"{name.StudentName} ({name.ActivityDate:MM/dd/yyyy})");
}
}
Comment on lines +1724 to +1734
foreach (var middlePart in middleParts)
{
if (middlePart.Length > 0)
{
var variation = $"{name} {middlePart[0]}";
if (!nameVariations.Contains(variation))
{
nameVariations.Add(variation);
}
}
}
Comment on lines +1110 to +1118
foreach (var role in filteredRoles)
{
string displayName = role.DisplayName ?? role.Role;
result.SystemRoles.Add(new SystemRole
{
System = system,
DisplayName = FormatPermissionName(displayName)
});
}
Comment on lines +1327 to +1342
foreach (var history in historyData)
{
var ucpathResult = new UCPathResult
{
JobCode = history.Jobcode,
JobCodeDescription = history.JobcodeDesc,
DepartmentId = history.Deptid,
DepartmentDescription = history.DeptDesc,
ActionDescription = history.ActionDescr,
PositionEffectiveDate = history.PositionEffdt.HasValue ? DateOnly.FromDateTime(history.PositionEffdt.Value) : null,
ReportsTo = GetReportsToName(history),
ReportsToPosition = GetReportsToPosition(history)
};

result.UCPathHistory.Add(ucpathResult);
}
Comment on lines +1645 to +1652
foreach (var groupDn in allGroups)
{
var formattedGroup = AdFormat(groupDn, domains);
if (!string.IsNullOrEmpty(formattedGroup))
{
result.ADMemberOf.Add(formattedGroup);
}
}
Comment on lines +683 to +712
foreach (var perm in permissions)
{
var parts = perm.Split('.');
var partsToProcess = parts.Skip(1).ToList();
if (!partsToProcess.Any())
{
continue;
}

var currentList = roots;
for (int i = 0; i < partsToProcess.Count; i++)
{
var part = partsToProcess[i];
var node = currentList.FirstOrDefault(n => n.Name == part);
if (node == null)
{
node = new PermissionNode
{
Name = part,
FullPath = string.Join('.', parts.Take(i + 2))
};
currentList.Add(node);
}
if (i == partsToProcess.Count - 1)
{
node.IsPermission = true;
}
currentList = node.Children;
}
}
Comment on lines +171 to +174
catch
{
return new List<string>();
}
Comment on lines +229 to +232
catch (Exception ex)
{
Console.WriteLine($"Warning: PopulateDirectoryInfoAsync LDAP failed: {ex.Message}");
}
Comment on lines +245 to +248
catch (Exception ex)
{
Console.WriteLine($"Warning: PopulateDirectoryInfoAsync VMACS failed: {ex.Message}");
}
@rlorenzo

rlorenzo commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

@JasonRobertFrancis "3165238 Merge branch 'Development' into feature/userinfo"

That is not good. That will merge in a bunch of unreleased features.

@JasonRobertFrancis

Copy link
Copy Markdown
Contributor Author

@JasonRobertFrancis "3165238 Merge branch 'Development' into feature/userinfo"

That is not good. That will merge in a bunch of unreleased features.

Thanks for catching that. It has been rolled back

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants