Skip to content

Commit

Permalink
feat: add co proposer claim to invite (#908)
Browse files Browse the repository at this point in the history
Co-authored-by: Jekabs Karklins <[email protected]>
Co-authored-by: Yoganandan Pandiyan <[email protected]>
  • Loading branch information
3 people authored Jan 30, 2025
1 parent 4bd7218 commit 9f5019b
Show file tree
Hide file tree
Showing 23 changed files with 487 additions and 34 deletions.
14 changes: 14 additions & 0 deletions apps/backend/db_patches/0168_AddCoProposerClaims.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
DO
$$
BEGIN
IF register_patch('0168_CreateCoProposerInvite', 'Jekabs Karklins', 'Adding co-proposer claims', '2025-01-10') THEN
BEGIN
CREATE TABLE IF NOT EXISTS co_proposer_invites (
invite_code_id INT NOT NULL REFERENCES invite_codes(invite_code_id) ON DELETE CASCADE,
proposal_pk INT NOT NULL REFERENCES proposals(proposal_pk) ON DELETE CASCADE,
PRIMARY KEY (invite_code_id, proposal_pk));
END;
END IF;
END;
$$
LANGUAGE plpgsql;
9 changes: 5 additions & 4 deletions apps/backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"@user-office-software/duo-localisation": "^1.2.0",
"@user-office-software/duo-logger": "^2.1.1",
"@user-office-software/duo-message-broker": "^1.6.0",
"@user-office-software/duo-validation": "^5.1.9",
"@user-office-software/duo-validation": "^5.1.11",
"@user-office-software/openid": "^1.4.0",
"await-to-js": "^2.1.1",
"bcryptjs": "^2.4.3",
Expand Down
26 changes: 26 additions & 0 deletions apps/backend/src/auth/InviteAuthorizer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { inject, injectable } from 'tsyringe';

import { Tokens } from '../config/Tokens';
import { UserRole, UserWithRole } from '../models/User';
import { UserAuthorization } from './UserAuthorization';

@injectable()
export class InviteAuthorization {
constructor(
@inject(Tokens.UserAuthorization) private userAuth: UserAuthorization
) {}

public isRoleInviteAuthorized = async (
agent: UserWithRole | null,
roleIds?: number[]
) => {
// If no roleIds are provided, the invite is considered as authorized
if (roleIds === undefined || roleIds.length === 0) return true;

if (this.userAuth.isUserOfficer(agent)) return true;

const onlyUserRole = roleIds.length === 1 && roleIds[0] === UserRole.USER;

return onlyUserRole;
};
}
2 changes: 2 additions & 0 deletions apps/backend/src/config/Tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const Tokens = {
CallDataSource: Symbol('CallDataSource'),
ConfigureEnvironment: Symbol('ConfigureEnvironment'),
ConfigureLogger: Symbol('ConfigureLogger'),
CoProposerInviteDataSource: Symbol('CoProposerInviteDataSource'),
EmailEventHandler: Symbol('EmailEventHandler'),
EventBus: Symbol('EventBus'),
EventLogsDataSource: Symbol('EventLogsDataSource'),
Expand All @@ -13,6 +14,7 @@ export const Tokens = {
GenericTemplateDataSource: Symbol('GenericTemplateDataSource'),
InstrumentDataSource: Symbol('InstrumentDataSource'),
InviteCodeDataSource: Symbol('InviteCodeDataSource'),
InviteAuthorization: Symbol('InviteAuthorization'),
TechniqueDataSource: Symbol('TechniqueDataSource'),
ListenToMessageQueue: Symbol('ListenToMessageQueue'),
MailService: Symbol('MailService'),
Expand Down
4 changes: 4 additions & 0 deletions apps/backend/src/config/dependencyConfigDefault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import {
} from '@user-office-software/duo-logger';

import 'reflect-metadata';
import { InviteAuthorization } from '../auth/InviteAuthorizer';
import { OAuthAuthorization } from '../auth/OAuthAuthorization';
import { ProposalAuthorization } from '../auth/ProposalAuthorization';
import { PostgresAdminDataSourceWithAutoUpgrade } from '../datasources/postgres/AdminDataSource';
import PostgresCallDataSource from '../datasources/postgres/CallDataSource';
import PostgresCoProposerInviteDataSource from '../datasources/postgres/CoProposerInviteDataSource';
import PostgresEventLogsDataSource from '../datasources/postgres/EventLogsDataSource';
import PostgresFapDataSource from '../datasources/postgres/FapDataSource';
import PostgresFeedbackDataSource from '../datasources/postgres/FeedbackDataSource';
Expand Down Expand Up @@ -63,6 +65,7 @@ async function skipEmailHandler(event: ApplicationEvent) {
}

mapClass(Tokens.AdminDataSource, PostgresAdminDataSourceWithAutoUpgrade);
mapClass(Tokens.CoProposerInviteDataSource, PostgresCoProposerInviteDataSource);
mapClass(Tokens.CallDataSource, PostgresCallDataSource);
mapClass(Tokens.EventLogsDataSource, PostgresEventLogsDataSource);
mapClass(Tokens.FeedbackDataSource, PostgresFeedbackDataSource);
Expand All @@ -71,6 +74,7 @@ mapClass(Tokens.GenericTemplateDataSource, PostgresGenericTemplateDataSource);
mapClass(Tokens.InstrumentDataSource, PostgresInstrumentDataSource);
mapClass(Tokens.InviteCodeDataSource, PostgresInviteCodesDataSource);
mapClass(Tokens.RoleInviteDataSource, PostgresRoleInviteDataSource);
mapClass(Tokens.InviteAuthorization, InviteAuthorization);
mapClass(Tokens.InternalReviewDataSource, PostgresInternalReviewDataSource);
mapClass(Tokens.PdfTemplateDataSource, PostgresPdfTemplateDataSource);
mapClass(Tokens.ProposalDataSource, PostgresProposalDataSource);
Expand Down
4 changes: 4 additions & 0 deletions apps/backend/src/config/dependencyConfigE2E.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { ConsoleLogger, setLogger } from '@user-office-software/duo-logger';

import 'reflect-metadata';
import { InviteAuthorization } from '../auth/InviteAuthorizer';
import { OAuthAuthorization } from '../auth/OAuthAuthorization';
import { ProposalAuthorization } from '../auth/ProposalAuthorization';
import PostgresAdminDataSource from '../datasources/postgres/AdminDataSource';
import PostgresCallDataSource from '../datasources/postgres/CallDataSource';
import PostgresCoProposerInviteDataSource from '../datasources/postgres/CoProposerInviteDataSource';
import PostgresEventLogsDataSource from '../datasources/postgres/EventLogsDataSource';
import PostgresFapDataSource from '../datasources/postgres/FapDataSource';
import PostgresFeedbackDataSource from '../datasources/postgres/FeedbackDataSource';
Expand Down Expand Up @@ -55,13 +57,15 @@ import { Tokens } from './Tokens';
import { mapClass, mapValue } from './utils';

mapClass(Tokens.AdminDataSource, PostgresAdminDataSource);
mapClass(Tokens.CoProposerInviteDataSource, PostgresCoProposerInviteDataSource);
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.InviteCodeDataSource, PostgresInviteCodesDataSource);
mapClass(Tokens.InviteAuthorization, InviteAuthorization);
mapClass(Tokens.RoleInviteDataSource, PostgresRoleInviteDataSource);
mapClass(Tokens.InternalReviewDataSource, PostgresInternalReviewDataSource);
mapClass(Tokens.PdfTemplateDataSource, PostgresPdfTemplateDataSource);
Expand Down
4 changes: 4 additions & 0 deletions apps/backend/src/config/dependencyConfigELI.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import 'reflect-metadata';

import { InviteAuthorization } from '../auth/InviteAuthorizer';
import { OAuthAuthorization } from '../auth/OAuthAuthorization';
import { ProposalAuthorization } from '../auth/ProposalAuthorization';
import { PostgresAdminDataSourceWithAutoUpgrade } from '../datasources/postgres/AdminDataSource';
import PostgresCallDataSource from '../datasources/postgres/CallDataSource';
import PostgresCoProposerInviteDataSource from '../datasources/postgres/CoProposerInviteDataSource';
import PostgresEventLogsDataSource from '../datasources/postgres/EventLogsDataSource';
import PostgresFapDataSource from '../datasources/postgres/FapDataSource';
import PostgresFeedbackDataSource from '../datasources/postgres/FeedbackDataSource';
Expand Down Expand Up @@ -57,6 +59,7 @@ import { mapClass, mapValue } from './utils';
const isProduction = process.env.NODE_ENV === 'production';

mapClass(Tokens.AdminDataSource, PostgresAdminDataSourceWithAutoUpgrade);
mapClass(Tokens.CoProposerInviteDataSource, PostgresCoProposerInviteDataSource);
mapClass(Tokens.CallDataSource, PostgresCallDataSource);
mapClass(Tokens.EventLogsDataSource, PostgresEventLogsDataSource);
mapClass(Tokens.FeedbackDataSource, PostgresFeedbackDataSource);
Expand All @@ -65,6 +68,7 @@ mapClass(Tokens.GenericTemplateDataSource, PostgresGenericTemplateDataSource);
mapClass(Tokens.InstrumentDataSource, PostgresInstrumentDataSource);
mapClass(Tokens.InviteCodeDataSource, PostgresInviteCodesDataSource);
mapClass(Tokens.RoleInviteDataSource, PostgresRoleInviteDataSource);
mapClass(Tokens.InviteAuthorization, InviteAuthorization);
mapClass(Tokens.PdfTemplateDataSource, PostgresPdfTemplateDataSource);
mapClass(Tokens.ProposalDataSource, PostgresProposalDataSource);
mapClass(Tokens.ProposalEsiDataSource, PostgresProposalEsiDataSource);
Expand Down
4 changes: 4 additions & 0 deletions apps/backend/src/config/dependencyConfigESS.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import 'reflect-metadata';

import { InviteAuthorization } from '../auth/InviteAuthorizer';
import { OAuthAuthorization } from '../auth/OAuthAuthorization';
import { ProposalAuthorization } from '../auth/ProposalAuthorization';
import { PostgresAdminDataSourceWithAutoUpgrade } from '../datasources/postgres/AdminDataSource';
import PostgresCallDataSource from '../datasources/postgres/CallDataSource';
import PostgresCoProposerInviteDataSource from '../datasources/postgres/CoProposerInviteDataSource';
import PostgresEventLogsDataSource from '../datasources/postgres/EventLogsDataSource';
import PostgresFapDataSource from '../datasources/postgres/FapDataSource';
import PostgresFeedbackDataSource from '../datasources/postgres/FeedbackDataSource';
Expand Down Expand Up @@ -57,6 +59,7 @@ import { Tokens } from './Tokens';
import { mapClass, mapValue } from './utils';

mapClass(Tokens.AdminDataSource, PostgresAdminDataSourceWithAutoUpgrade);
mapClass(Tokens.CoProposerInviteDataSource, PostgresCoProposerInviteDataSource);
mapClass(Tokens.CallDataSource, PostgresCallDataSource);
mapClass(Tokens.EventLogsDataSource, PostgresEventLogsDataSource);
mapClass(Tokens.FeedbackDataSource, PostgresFeedbackDataSource);
Expand All @@ -65,6 +68,7 @@ mapClass(Tokens.GenericTemplateDataSource, PostgresGenericTemplateDataSource);
mapClass(Tokens.InstrumentDataSource, PostgresInstrumentDataSource);
mapClass(Tokens.InviteCodeDataSource, PostgresInviteCodesDataSource);
mapClass(Tokens.RoleInviteDataSource, PostgresRoleInviteDataSource);
mapClass(Tokens.InviteAuthorization, InviteAuthorization);
mapClass(Tokens.PdfTemplateDataSource, PostgresPdfTemplateDataSource);
mapClass(Tokens.ProposalDataSource, PostgresProposalDataSource);
mapClass(Tokens.ProposalEsiDataSource, PostgresProposalEsiDataSource);
Expand Down
4 changes: 4 additions & 0 deletions apps/backend/src/config/dependencyConfigSTFC.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { setLogger, ConsoleLogger } from '@user-office-software/duo-logger';
import 'reflect-metadata';

import { InviteAuthorization } from '../auth/InviteAuthorizer';
import { StfcProposalAuthorization } from '../auth/StfcProposalAuthorization';
import { StfcUserAuthorization } from '../auth/StfcUserAuthorization';
import { PostgresAdminDataSourceWithAutoUpgrade } from '../datasources/postgres/AdminDataSource';
import PostgresCallDataSource from '../datasources/postgres/CallDataSource';
import PostgresCoProposerInviteDataSource from '../datasources/postgres/CoProposerInviteDataSource';
import PostgresEventLogsDataSource from '../datasources/postgres/EventLogsDataSource';
import PostgresFeedbackDataSource from '../datasources/postgres/FeedbackDataSource';
import PostgresFileDataSource from '../datasources/postgres/FileDataSource';
Expand Down Expand Up @@ -55,6 +57,7 @@ import { Tokens } from './Tokens';
import { mapClass, mapValue } from './utils';

mapClass(Tokens.AdminDataSource, PostgresAdminDataSourceWithAutoUpgrade);
mapClass(Tokens.CoProposerInviteDataSource, PostgresCoProposerInviteDataSource);
mapClass(Tokens.CallDataSource, PostgresCallDataSource);
mapClass(Tokens.EventLogsDataSource, PostgresEventLogsDataSource);
mapClass(Tokens.FeedbackDataSource, PostgresFeedbackDataSource);
Expand All @@ -63,6 +66,7 @@ mapClass(Tokens.GenericTemplateDataSource, PostgresGenericTemplateDataSource);
mapClass(Tokens.InstrumentDataSource, StfcInstrumentDataSource);
mapClass(Tokens.InviteCodeDataSource, PostgresInviteCodesDataSource);
mapClass(Tokens.RoleInviteDataSource, PostgresRoleInviteDataSource);
mapClass(Tokens.InviteAuthorization, InviteAuthorization);
mapClass(Tokens.PdfTemplateDataSource, PostgresPdfTemplateDataSource);
mapClass(Tokens.ProposalDataSource, StfcProposalDataSource);
mapClass(Tokens.ProposalEsiDataSource, PostgresProposalEsiDataSource);
Expand Down
8 changes: 6 additions & 2 deletions apps/backend/src/config/dependencyConfigTest.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import { setLogger, ConsoleLogger } from '@user-office-software/duo-logger';
import { ConsoleLogger, setLogger } from '@user-office-software/duo-logger';

import { UserAuthorizationMock } from '../auth/mockups/UserAuthorization';
import 'reflect-metadata';
import { InviteAuthorization } from '../auth/InviteAuthorizer';
import { UserAuthorizationMock } from '../auth/mockups/UserAuthorization';
import { ProposalAuthorization } from '../auth/ProposalAuthorization';
import { AdminDataSourceMock } from '../datasources/mockups/AdminDataSource';
import { CallDataSourceMock } from '../datasources/mockups/CallDataSource';
import { CoProposerInviteDataSourceMock } from '../datasources/mockups/CoProposerInviteDataSource';
import { EventLogsDataSourceMock } from '../datasources/mockups/EventLogsDataSource';
import { FapDataSourceMock } from '../datasources/mockups/FapDataSource';
import { FeedbackDataSourceMock } from '../datasources/mockups/FeedbackDataSource';
Expand Down Expand Up @@ -49,6 +51,7 @@ import { Tokens } from './Tokens';
import { mapClass, mapValue } from './utils';

mapClass(Tokens.AdminDataSource, AdminDataSourceMock);
mapClass(Tokens.CoProposerInviteDataSource, CoProposerInviteDataSourceMock);
mapClass(Tokens.CallDataSource, CallDataSourceMock);
mapClass(Tokens.EventLogsDataSource, EventLogsDataSourceMock);
mapClass(Tokens.FeedbackDataSource, FeedbackDataSourceMock);
Expand All @@ -57,6 +60,7 @@ mapClass(Tokens.GenericTemplateDataSource, GenericTemplateDataSourceMock);
mapClass(Tokens.InstrumentDataSource, InstrumentDataSourceMock);
mapClass(Tokens.InviteCodeDataSource, InviteCodesDataSourceMock);
mapClass(Tokens.RoleInviteDataSource, RoleInviteDataSourceMock);
mapClass(Tokens.InviteAuthorization, InviteAuthorization);
mapClass(Tokens.InternalReviewDataSource, InternalReviewDataSourceMock);
mapClass(Tokens.PdfTemplateDataSource, PdfTemplateDataSourceMock);
mapClass(Tokens.ProposalDataSource, ProposalDataSourceMock);
Expand Down
6 changes: 6 additions & 0 deletions apps/backend/src/datasources/CoProposerInviteDataSource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { CoProposerInvite } from '../models/CoProposerInvite';

export interface CoProposerInviteDataSource {
create(inviteCodeId: number, proposalPk: number): Promise<CoProposerInvite>;
findByInviteCodeId(inviteCodeId: number): Promise<CoProposerInvite | null>;
}
3 changes: 2 additions & 1 deletion apps/backend/src/datasources/ProposalDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ export interface ProposalDataSource {
updateProposalTechnicalReviewer(
args: UpdateTechnicalReviewAssigneeInput
): Promise<TechnicalReview[]>;
setProposalUsers(proposalPk: number, users: number[]): Promise<void>;
setProposalUsers(proposalPk: number, usersIds: number[]): Promise<void>;
addProposalUser(proposalPk: number, userId: number): Promise<void>;
submitProposal(
primaryKey: number,
referenceNumber?: string
Expand Down
36 changes: 36 additions & 0 deletions apps/backend/src/datasources/mockups/CoProposerInviteDataSource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { CoProposerInvite } from '../../models/CoProposerInvite';
import { CoProposerInviteDataSource } from '../CoProposerInviteDataSource';

export class CoProposerInviteDataSourceMock
implements CoProposerInviteDataSource
{
private invites: CoProposerInvite[] = [];

init() {
this.invites = [
new CoProposerInvite(1, 1),
new CoProposerInvite(2, 2),
new CoProposerInvite(3, 3),
];
}

async findByInviteCodeId(
inviteCodeId: number
): Promise<CoProposerInvite | null> {
return (
this.invites.find((invite) => invite.inviteCodeId === inviteCodeId) ||
null
);
}

async create(
inviteCodeId: number,
proposalPk: number
): Promise<CoProposerInvite> {
const newInvite = new CoProposerInvite(inviteCodeId, proposalPk);

this.invites.push(newInvite);

return newInvite;
}
}
9 changes: 8 additions & 1 deletion apps/backend/src/datasources/mockups/ProposalDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,14 @@ export class ProposalDataSourceMock implements ProposalDataSource {
return proposal;
}

async setProposalUsers(proposalPk: number, users: number[]): Promise<void> {
async setProposalUsers(
proposalPk: number,
usersIds: number[]
): Promise<void> {
throw new Error('Not implemented');
}

async addProposalUser(proposalPk: number, userId: number): Promise<void> {
throw new Error('Not implemented');
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { CoProposerInvite } from '../../models/CoProposerInvite';
import { CoProposerInviteDataSource } from '../CoProposerInviteDataSource';
import database from './database';

export default class PostgresCoProposerInviteDataSource
implements CoProposerInviteDataSource
{
async findByInviteCodeId(
inviteCodeId: number
): Promise<CoProposerInvite | null> {
return database('co_proposer_invites')
.where({ invite_code_id: inviteCodeId })
.select('*')
.first()
.then((row) => {
if (!row) {
return null;
}

return new CoProposerInvite(row.invite_code_id, row.proposal_pk);
});
}
async create(
inviteCodeId: number,
proposalPk: number
): Promise<CoProposerInvite> {
return database('co_proposer_invites')
.insert({ invite_code_id: inviteCodeId, proposal_pk: proposalPk })
.returning('*')
.then((rows) => {
const row = rows[0];

return new CoProposerInvite(row.invite_code_id, row.proposal_pk);
});
}
}
6 changes: 6 additions & 0 deletions apps/backend/src/datasources/postgres/ProposalDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,12 @@ export default class PostgresProposalDataSource implements ProposalDataSource {
});
}

async addProposalUser(proposalPk: number, userId: number): Promise<void> {
return database
.insert({ proposal_pk: proposalPk, user_id: userId })
.into('proposal_user');
}

async setProposalUsers(proposalPk: number, userIds: number[]): Promise<void> {
return database.transaction(async (trx) => {
return database
Expand Down
Loading

0 comments on commit 9f5019b

Please sign in to comment.