Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1f422ec
Add custom DLS user auth class based off OAuthAuthorization
GrantDLS Apr 29, 2026
ef6f9c8
Add DLS configuration files
GrantDLS Apr 29, 2026
923e51f
Add DLS email handler.
GrantDLS Apr 29, 2026
07c5904
Add Diamond logo
GrantDLS Apr 29, 2026
43d9eba
Add DLS dependency config to switch statement
GrantDLS Apr 29, 2026
2d04712
Add new dependency mapping to DLS config
GrantDLS Apr 29, 2026
7d7a8db
Add Promise.all to asynchronously call configuration database calls.
GrantDLS Apr 29, 2026
f6ff971
Use proper casing for DLS in file/class names
GrantDLS Apr 30, 2026
21bf273
Clarify repeated use of given_name
GrantDLS Apr 30, 2026
deeeb8d
Remove unnecessary newlines
GrantDLS Apr 30, 2026
a865e76
Asynchronously run settings application functions
GrantDLS Apr 30, 2026
8e1441f
Refactor DSL email handler
GrantDLS May 11, 2026
ef474e9
Update to use live UOS fallback domain for email template
GrantDLS May 11, 2026
7adfb62
Add helper to get base url
GrantDLS May 11, 2026
191c39f
Throw error if no email handler for event type.
GrantDLS May 11, 2026
bb53a81
Add DLS email handler tests
GrantDLS May 11, 2026
9bfb61c
Remove unnecessary comment.
GrantDLS May 12, 2026
06b2f59
Remove more unnecessary comments
GrantDLS May 12, 2026
3eec14b
Refactors following PR comments
GrantDLS May 12, 2026
27ecb9b
Change upsert user to protected and override in DLSUserAuth class.
GrantDLS May 15, 2026
e545713
Merge branch 'develop' into dls-config
GrantDLS May 15, 2026
115ea34
Merge branch 'develop' into dls-config
bolmsten May 19, 2026
420012f
Merge branch 'develop' into dls-config
yoganandaness May 27, 2026
19c0834
Merge branch 'develop' into dls-config
yoganandaness Jun 1, 2026
1a0fe5f
Merge branch 'develop' into dls-config
yoganandaness Jun 3, 2026
a5b78fb
Use default logging handler
GrantDLS Jun 4, 2026
e85a603
Merge branch 'develop' into dls-config
yoganandaness Jun 4, 2026
98646e4
Merge branch 'develop' into dls-config
GrantDLS Jun 4, 2026
45598ca
Merge branch 'develop' into dls-config
zacharyjhankin Jun 5, 2026
7e615ea
Merge branch 'develop' into dls-config
yoganandaness Jun 8, 2026
41e4666
Remove dependency on new environment variable for UAS url
GrantDLS Jun 8, 2026
529bb3c
Merge branch 'develop' into dls-config
yoganandaness Jun 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions apps/backend/src/auth/DLSUserAuthorization.ts
Comment thread
GrantDLS marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import 'reflect-metadata';

import { logger } from '@user-office-software/duo-logger';
import { OpenIdClient } from '@user-office-software/openid';
import { ValidTokenSet } from '@user-office-software/openid/lib/model/ValidTokenSet';
import { ValidUserInfo } from '@user-office-software/openid/lib/model/ValidUserInfo';

import { OAuthAuthorization } from './OAuthAuthorization';
import { User, UserRole } from '../models/User';
import { GetOrCreateInstitutionInput } from '../resolvers/mutations/UpsertUserMutation';

export class DLSUserAuthorization extends OAuthAuthorization {
constructor() {
super();
}

protected async upsertUser(
userInfo: ValidUserInfo,
tokenSet: ValidTokenSet
): Promise<User> {
const client = await OpenIdClient.getInstance();
let institutionInput: GetOrCreateInstitutionInput = null;
if (userInfo.institution_ror_id) {
institutionInput = userInfo.institution_ror_id as string;
} else if (userInfo.institution_name && userInfo.institution_country) {
institutionInput = {
country: userInfo.institution_country as string,
name: userInfo.institution_name as string,
};
}

const userId = this.getUniqueId(userInfo);
const userWithOAuthSubMatch =
await this.userDataSource.getByOIDCSub(userId);

const userWithEmailMatch = await this.userDataSource.getByEmail(
userInfo.email
);

const user = userWithOAuthSubMatch ?? userWithEmailMatch;

if (user) {
Comment thread
GrantDLS marked this conversation as resolved.
const updatedUser = await this.userDataSource.update({
...user,
email: userInfo.email,
oauthIssuer: client.issuer.metadata.issuer,
oauthRefreshToken: tokenSet.refresh_token ?? '',
oidcSub: userId,
});

return updatedUser;
} else {
const institution =
await this.getOrCreateUserInstitution(institutionInput);
const newUser = await this.userDataSource.create(
(userInfo.title as string) ?? 'unspecified',
userInfo.given_name,
userInfo.family_name,
userInfo.given_name ?? '', // Using given_name as preferred_name from the oauth provider is a federation id
userId,
tokenSet.refresh_token ?? '',
client.issuer.metadata.issuer,
institution?.id ?? 1,
userInfo.email
);

const roleID = this.getUserRole(newUser);

await this.userDataSource.addUserRole({
userID: newUser.id,
roleID,
});

if (roleID === UserRole.USER_OFFICER) {
logger.logInfo('Initial User Officer created', {
email: newUser.email,
});
}

return newUser;
}
}
}
4 changes: 2 additions & 2 deletions apps/backend/src/auth/OAuthAuthorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export class OAuthAuthorization extends UserAuthorization {
return institution;
}

private async upsertUser(
protected async upsertUser(
userInfo: ValidUserInfo,
tokenSet: ValidTokenSet
): Promise<User> {
Expand Down Expand Up @@ -233,7 +233,7 @@ export class OAuthAuthorization extends UserAuthorization {
}
}

private getUserRole(newUser: { id: number; email: string }): UserRole {
protected getUserRole(newUser: { id: number; email: string }): UserRole {
const roleID =
env.INITIAL_USER_OFFICER_EMAIL &&
newUser.email === env.INITIAL_USER_OFFICER_EMAIL
Expand Down
145 changes: 145 additions & 0 deletions apps/backend/src/config/dependencyConfigDLS.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { ConsoleLogger, setLogger } from '@user-office-software/duo-logger';

import 'reflect-metadata';
import { Tokens } from './Tokens';
import { DataAccessUsersAuthorization } from '../auth/DataAccessUsersAuthorization';
import { DLSUserAuthorization } from '../auth/DLSUserAuthorization';
import { ProposalAuthorization } from '../auth/ProposalAuthorization';
import { VisitAuthorization } from '../auth/VisitAuthorization';
import { VisitRegistrationAuthorization } from '../auth/VisitRegistrationAuthorization';
import { configureDLSEnvironment } from './dls/configureDLSEnvironment';
import { mapClass, mapValue } from './utils';
import { PostgresAdminDataSourceWithAutoUpgrade } from '../datasources/postgres/AdminDataSource';
import PostgresCallDataSource from '../datasources/postgres/CallDataSource';
import PostgresCoProposerClaimDataSource from '../datasources/postgres/CoProposerClaimDataSource';
import PostgresDataAccessUsersDataSource from '../datasources/postgres/DataAccessUsersDataSource';
import PostgresEmailTemplateDataSource from '../datasources/postgres/EmailTemplateDataSource';
import PostgresEventLogsDataSource from '../datasources/postgres/EventLogsDataSource';
import PostgresExperimentDataSource from '../datasources/postgres/ExperimentDataSource';
import PostgresExperimentSafetyPdfTemplateDataSource from '../datasources/postgres/ExperimentSafetyPdfTemplateDataSource';
import PostgresFapDataSource from '../datasources/postgres/FapDataSource';
import PostgresFeedbackDataSource from '../datasources/postgres/FeedbackDataSource';
import PostgresFileDataSource from '../datasources/postgres/FileDataSource';
import PostgresGenericTemplateDataSource from '../datasources/postgres/GenericTemplateDataSource';
import PostgresInstrumentDataSource from '../datasources/postgres/InstrumentDataSource';
import PostgresInternalReviewDataSource from '../datasources/postgres/InternalReviewDataSource';
import PostgresInviteDataSource from '../datasources/postgres/InviteDataSource';
import PostgresPredefinedMessageDataSource from '../datasources/postgres/PredefinedMessageDataSource';
import PostgresProposalDataSource from '../datasources/postgres/ProposalDataSource';
import PostgresProposalInternalCommentsDataSource from '../datasources/postgres/ProposalInternalCommentsDataSource';
import PostgresProposalPdfTemplateDataSource from '../datasources/postgres/ProposalPdfTemplateDataSource';
import PostgresQuestionaryDataSource from '../datasources/postgres/QuestionaryDataSource';
import PostgresReviewDataSource from '../datasources/postgres/ReviewDataSource';
import PostgresRoleClaimDataSource from '../datasources/postgres/RoleClaimsDataSource';
import PostgresRoleDataSource from '../datasources/postgres/RoleDataSource';
import PostgresSampleDataSource from '../datasources/postgres/SampleDataSource';
import PostgresShipmentDataSource from '../datasources/postgres/ShipmentDataSource';
import PostgresStatusActionsDataSource from '../datasources/postgres/StatusActionsDataSource';
import StatusActionsLogsDataSource from '../datasources/postgres/StatusActionsLogsDataSource';
import PostgresStatusDataSource from '../datasources/postgres/StatusDataSource';
import PostgresSystemDataSource from '../datasources/postgres/SystemDataSource';
import PostgresTagDataSource from '../datasources/postgres/TagDataSource';
import PostgresTechniqueDataSource from '../datasources/postgres/TechniqueDataSource';
import PostgresTemplateDataSource from '../datasources/postgres/TemplateDataSource';
import PostgresUnitDataSource from '../datasources/postgres/UnitDataSource';
import PostgresUserDataSource from '../datasources/postgres/UserDataSource';
import PostgresVisitDataSource from '../datasources/postgres/VisitDataSource';
import PostgresVisitRegistrationClaimDataSource from '../datasources/postgres/VisitRegistrationClaimDataSource';
import PostgresWorkflowDataSource from '../datasources/postgres/WorkflowDataSource';
import { DLSEmailHandler } from '../eventHandlers/email/DLS/DLSEmailHandler';
import createLoggingHandler from '../eventHandlers/logging';
import { SMTPMailService } from '../eventHandlers/MailService/SMTP/SMTPMailService';
import {
createListenToRabbitMQHandler,
createPostToRabbitMQHandler,
} from '../eventHandlers/messageBroker';
import { createApplicationEventBus } from '../events';
import { FapDataColumns } from '../factory/xlsx/FapDataColumns';
import {
callFapPopulateRow,
getDataRow,
populateRow,
} from '../factory/xlsx/FapDataRow';
import BasicUserDetailsLoader from '../loaders/BasicUserDetailsLoader';
import { SkipAssetRegistrar } from '../services/assetRegistrar/skip/SkipAssetRegistrar';

mapClass(Tokens.AdminDataSource, PostgresAdminDataSourceWithAutoUpgrade);
mapClass(Tokens.CoProposerClaimDataSource, PostgresCoProposerClaimDataSource);
mapClass(Tokens.DataAccessUsersDataSource, PostgresDataAccessUsersDataSource);
mapClass(Tokens.CallDataSource, PostgresCallDataSource);
mapClass(Tokens.EventLogsDataSource, PostgresEventLogsDataSource);
mapClass(Tokens.FeedbackDataSource, PostgresFeedbackDataSource);
mapClass(Tokens.FileDataSource, PostgresFileDataSource);
mapClass(Tokens.GenericTemplateDataSource, PostgresGenericTemplateDataSource);
mapClass(Tokens.InstrumentDataSource, PostgresInstrumentDataSource);
mapClass(Tokens.InviteDataSource, PostgresInviteDataSource);
mapClass(Tokens.RoleDataSource, PostgresRoleDataSource);
mapClass(Tokens.RoleClaimDataSource, PostgresRoleClaimDataSource);
mapClass(Tokens.InternalReviewDataSource, PostgresInternalReviewDataSource);
mapClass(
Tokens.ProposalPdfTemplateDataSource,
PostgresProposalPdfTemplateDataSource
);

mapClass(
Tokens.ExperimentSafetyPdfTemplateDataSource,
PostgresExperimentSafetyPdfTemplateDataSource
);
mapClass(Tokens.ProposalDataSource, PostgresProposalDataSource);
mapClass(
Tokens.ProposalInternalCommentsDataSource,
PostgresProposalInternalCommentsDataSource
);
mapClass(Tokens.StatusActionsDataSource, PostgresStatusActionsDataSource);
mapClass(Tokens.QuestionaryDataSource, PostgresQuestionaryDataSource);
mapClass(Tokens.ReviewDataSource, PostgresReviewDataSource);
mapClass(Tokens.FapDataSource, PostgresFapDataSource);
mapClass(Tokens.SampleDataSource, PostgresSampleDataSource);
mapClass(Tokens.ShipmentDataSource, PostgresShipmentDataSource);
mapClass(Tokens.SystemDataSource, PostgresSystemDataSource);
mapClass(Tokens.TemplateDataSource, PostgresTemplateDataSource);
mapClass(Tokens.UnitDataSource, PostgresUnitDataSource);
mapClass(Tokens.UserDataSource, PostgresUserDataSource);
mapClass(Tokens.VisitDataSource, PostgresVisitDataSource);
mapClass(
Tokens.VisitRegistrationClaimDataSource,
PostgresVisitRegistrationClaimDataSource
);
mapClass(Tokens.VisitAuthorization, VisitAuthorization);
mapClass(Tokens.VisitRegistrationAuthorization, VisitRegistrationAuthorization);
mapClass(Tokens.TechniqueDataSource, PostgresTechniqueDataSource);
mapClass(
Tokens.PredefinedMessageDataSource,
PostgresPredefinedMessageDataSource
);
mapClass(Tokens.StatusActionsLogsDataSource, StatusActionsLogsDataSource);
mapClass(Tokens.WorkflowDataSource, PostgresWorkflowDataSource);
mapClass(Tokens.StatusDataSource, PostgresStatusDataSource);
mapClass(Tokens.ExperimentDataSource, PostgresExperimentDataSource);
mapClass(Tokens.TagDataSource, PostgresTagDataSource);

mapClass(Tokens.UserAuthorization, DLSUserAuthorization);
mapClass(Tokens.ProposalAuthorization, ProposalAuthorization);
mapClass(Tokens.DataAccessUsersAuthorization, DataAccessUsersAuthorization);

mapClass(Tokens.AssetRegistrar, SkipAssetRegistrar);

mapClass(Tokens.MailService, SMTPMailService);

mapValue(Tokens.FapDataColumns, FapDataColumns);
mapValue(Tokens.FapDataRow, getDataRow);
mapValue(Tokens.PopulateRow, populateRow);
mapValue(Tokens.PopulateCallRow, callFapPopulateRow);

mapValue(Tokens.EmailEventHandler, DLSEmailHandler);
mapClass(Tokens.EmailTemplateDataSource, PostgresEmailTemplateDataSource);

mapValue(Tokens.PostToMessageQueue, createPostToRabbitMQHandler());
mapValue(Tokens.LoggingHandler, createLoggingHandler());
mapValue(Tokens.EventBus, createApplicationEventBus());
mapValue(Tokens.ListenToMessageQueue, createListenToRabbitMQHandler());

mapValue(Tokens.ConfigureEnvironment, configureDLSEnvironment);
Comment thread
GrantDLS marked this conversation as resolved.
mapValue(Tokens.ConfigureLogger, () => setLogger(new ConsoleLogger()));

mapClass(Tokens.BasicUserDetailsLoader, BasicUserDetailsLoader);
Loading
Loading