Skip to content

Commit

Permalink
Merge pull request #437 from bcgov/feat/admin-edit-proposal
Browse files Browse the repository at this point in the history
Feat/admin edit proposal
  • Loading branch information
IanFonzie authored Nov 29, 2023
2 parents 1b65720 + 9d1c428 commit ba36c8c
Show file tree
Hide file tree
Showing 15 changed files with 308 additions and 117 deletions.
2 changes: 1 addition & 1 deletion src/back-end/lib/db/affiliation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ export const deleteAffiliation = tryDb<[Id], Affiliation>(

function makeIsUserTypeChecker(
membershipType: MembershipType
): (connection: Connection, user: User, ordId: Id) => Promise<boolean> {
): (connection: Connection, user: User, orgId: Id) => Promise<boolean> {
return async (connection: Connection, user: User, orgId: Id) => {
if (!user) {
return false;
Expand Down
86 changes: 57 additions & 29 deletions src/back-end/lib/db/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,7 @@ async function rawOrganizationSlimToOrganizationSlim(
possessOneServiceArea,
numTeamMembers,
active,
serviceAreas,
viewerIsOrgAdmin
serviceAreas
} = raw;
let fetchedLogoImageFile: FileRecord | undefined;
if (logoImageFile) {
Expand All @@ -147,8 +146,7 @@ async function rawOrganizationSlimToOrganizationSlim(
active,
numTeamMembers:
numTeamMembers === undefined ? undefined : parseInt(numTeamMembers, 10),
serviceAreas,
...(viewerIsOrgAdmin ? { viewerIsOrgAdmin } : {})
serviceAreas
};
}

Expand Down Expand Up @@ -250,6 +248,40 @@ function generateOrganizationQuery(connection: Connection) {
);
}

function viewerIsOrgAdminQuery(
session: Session | undefined,
connection: Connection,
query: ReturnType<typeof generateOrganizationQuery>
) {
return session
? query.select<RawOrganization>(
connection.raw('exists(?) as "viewerIsOrgAdmin"', [
connection
.select("user")
.from("affiliations")
.where({
organization: connection.ref("organizations.id"),
membershipStatus: MembershipStatus.Active,
membershipType: MembershipType.Admin,
user: session.user.id
})
.first()
])
)
: query;
}

function generateOrganizationQueryWithViewerIsOrgAdminInfo(
connection: Connection,
session: Session | undefined
) {
return viewerIsOrgAdminQuery(
session,
connection,
generateOrganizationQuery(connection)
);
}

/**
* Return a single slimmed-down organization.
* Only return ownership/RFQ data if admin/gov user, or if an owner of the organization.
Expand Down Expand Up @@ -322,17 +354,27 @@ export const readOneOrganization = tryDb<
[Id, boolean?, Session?],
Organization | null
>(async (connection, id, allowInactive = false, session) => {
let query = generateOrganizationQuery(connection).where({
let query = generateOrganizationQueryWithViewerIsOrgAdminInfo(
connection,
session
).where({
"organizations.id": id
});

if (!allowInactive) {
query = query.andWhere({ "organizations.active": true });
}

const result = await query.first<RawOrganization>();
const resultWithViewerIsOrgAdmin = await query.first<
RawOrganization & { viewerIsOrgAdmin: boolean }
>();
const { viewerIsOrgAdmin, ...result } = resultWithViewerIsOrgAdmin;
if (result) {
if (!session || (isVendor(session) && result.owner !== session.user?.id)) {
if (
!session ||
(isVendor(session) &&
!(result.owner === session.user?.id || viewerIsOrgAdmin))
) {
delete result.owner;
delete result.numTeamMembers;
delete result.acceptedTWUTerms;
Expand Down Expand Up @@ -407,30 +449,15 @@ export const readManyOrganizations = tryDb<
[Session, boolean?, number?, number?],
ReadManyResponseBody
>(async (connection, session, allowInactive = false, page, pageSize) => {
let query = generateOrganizationQuery(connection);
let query = generateOrganizationQueryWithViewerIsOrgAdminInfo(
connection,
session
);

if (!allowInactive) {
query = query.andWhere({ "organizations.active": true });
}

// Used to render links for viewing organizations.
if (session) {
query = query.select(
connection.raw('exists(?) as "viewerIsOrgAdmin"', [
connection
.select("user")
.from("affiliations")
.where({
organization: connection.ref("organizations.id"),
membershipStatus: MembershipStatus.Active,
membershipType: MembershipType.Admin,
user: session.user.id
})
.first()
])
);
}

// Default is to only have one page because we are requesting everything.
let numPages = 1;

Expand All @@ -455,7 +482,9 @@ export const readManyOrganizations = tryDb<

// Execute query, and the destructure results to only choose 'slim' fields that user has access to
// Admin/owners get additional fields related to ownership/rfq status
const results = ((await query) as RawOrganization[]) || [];
const results =
((await query) as (RawOrganization & { viewerIsOrgAdmin: boolean })[]) ||
[];
const items = await Promise.all(
results.map(async (raw) => {
const {
Expand Down Expand Up @@ -496,8 +525,7 @@ export const readManyOrganizations = tryDb<
possessOneServiceArea: serviceAreas.length > 0,
acceptedTWUTerms,
acceptedSWUTerms,
serviceAreas,
viewerIsOrgAdmin
serviceAreas
});
}
})
Expand Down
27 changes: 23 additions & 4 deletions src/back-end/lib/db/proposal/code-with-us.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { generateUuid } from "back-end/lib";
import { Connection, Transaction, tryDb } from "back-end/lib/db";
import {
Connection,
Transaction,
isUserOwnerOrAdminOfOrg,
tryDb
} from "back-end/lib/db";
import { readOneFileById } from "back-end/lib/db/file";
import {
generateCWUOpportunityQuery,
Expand Down Expand Up @@ -373,7 +378,8 @@ export const readOneCWUProposal = tryDb<[Id, Session], CWUProposal | null>(
session,
result.opportunity,
result.id,
result.status
result.status,
result.proponentOrganization
)
) {
// Add score to proposal
Expand Down Expand Up @@ -582,7 +588,7 @@ export const readOneProposalByOpportunityAndAuthor = tryDb<
);
});

export async function isCWUProposalAuthor(
async function isCWUProposalAuthor(
connection: Connection,
user: User,
id: Id
Expand All @@ -597,6 +603,18 @@ export async function isCWUProposalAuthor(
}
}

export async function isCWUProposalAuthorOrIsUserOwnerOrAdminOfOrg(
connection: Connection,
user: User,
proposalId: Id,
orgId: Id | null
) {
return (
(await isCWUProposalAuthor(connection, user, proposalId)) ||
(!!orgId && (await isUserOwnerOrAdminOfOrg(connection, user, orgId)))
);
}

export const createCWUProposal = tryDb<
[CreateCWUProposalParams, AuthenticatedSession],
CWUProposal
Expand Down Expand Up @@ -1065,7 +1083,8 @@ export const readOneCWUAwardedProposal = tryDb<
session,
opportunity,
result.id,
result.status
result.status,
result.proponentOrganization
)
) {
// Add score to proposal
Expand Down
30 changes: 25 additions & 5 deletions src/back-end/lib/db/proposal/sprint-with-us.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { generateUuid } from "back-end/lib";
import { Connection, Transaction, tryDb } from "back-end/lib/db";
import {
Connection,
Transaction,
isUserOwnerOrAdminOfOrg,
tryDb
} from "back-end/lib/db";
import { readOneFileById } from "back-end/lib/db/file";
import {
generateSWUOpportunityQuery,
Expand Down Expand Up @@ -636,7 +641,7 @@ export const readOneSWUProposalByOpportunityAndAuthor = tryDb<
return valid(result ? result : null);
});

export async function isSWUProposalAuthor(
async function isSWUProposalAuthor(
connection: Connection,
user: User,
id: Id
Expand All @@ -651,6 +656,18 @@ export async function isSWUProposalAuthor(
}
}

export async function isSWUProposalAuthorOrIsUserOwnerOrAdminOfOrg(
connection: Connection,
user: User,
proposalId: Id,
orgId: Id | null
) {
return (
(await isSWUProposalAuthor(connection, user, proposalId)) ||
(!!orgId && (await isUserOwnerOrAdminOfOrg(connection, user, orgId)))
);
}

export const readManyProposalReferences = tryDb<[Id], SWUProposalReference[]>(
async (connection, proposalId) => {
const results = await connection<SWUProposalReference>(
Expand Down Expand Up @@ -710,7 +727,8 @@ export const readOneSWUProposal = tryDb<
connection,
session,
result.opportunity,
result.id
result.id,
result.organization
)
) {
const rawProposalStatuses = await connection<RawHistoryRecord>(
Expand All @@ -735,7 +753,8 @@ export const readOneSWUProposal = tryDb<
session,
result.opportunity,
result.id,
result.status
result.status,
result.organization
);
result.teamQuestionResponses =
getValidValue(
Expand Down Expand Up @@ -1720,7 +1739,8 @@ export const readOneSWUAwardedProposal = tryDb<
session,
opportunity,
result.id,
result.status
result.status,
result.organization
))
) {
await calculateScores(connection, session, opportunity, [result]);
Expand Down
30 changes: 25 additions & 5 deletions src/back-end/lib/db/proposal/team-with-us.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { generateUuid } from "back-end/lib";
import { Connection, Transaction, tryDb } from "back-end/lib/db";
import {
Connection,
Transaction,
isUserOwnerOrAdminOfOrg,
tryDb
} from "back-end/lib/db";
import { readOneFileById } from "back-end/lib/db/file";
import {
generateTWUOpportunityQuery,
Expand Down Expand Up @@ -515,7 +520,7 @@ export const readOneTWUProposalByOpportunityAndAuthor = tryDb<
return valid(result ? result : null);
});

export async function isTWUProposalAuthor(
async function isTWUProposalAuthor(
connection: Connection,
user: User,
id: Id
Expand All @@ -530,6 +535,18 @@ export async function isTWUProposalAuthor(
}
}

export async function isTWUProposalAuthorOrIsUserOwnerOrAdminOfOrg(
connection: Connection,
user: User,
proposalId: Id,
orgId: Id | null
) {
return (
(await isTWUProposalAuthor(connection, user, proposalId)) ||
(!!orgId && (await isUserOwnerOrAdminOfOrg(connection, user, orgId)))
);
}

export const readManyProposalResourceQuestionResponses = tryDb<
[Id, boolean?],
RawTWUProposalResourceQuestionResponse[]
Expand Down Expand Up @@ -603,7 +620,8 @@ export const readOneTWUProposal = tryDb<
connection,
session,
result.opportunity,
result.id
result.id,
result.organization
)
) {
const rawProposalStatuses = await connection<RawHistoryRecord>(
Expand All @@ -628,7 +646,8 @@ export const readOneTWUProposal = tryDb<
session,
result.opportunity,
result.id,
result.status
result.status,
result.organization
);
result.resourceQuestionResponses =
getValidValue(
Expand Down Expand Up @@ -1368,7 +1387,8 @@ export const readOneTWUAwardedProposal = tryDb<
session,
opportunity,
result.id,
result.status
result.status,
result.organization
))
) {
await calculateScores(connection, session, opportunity, [result]);
Expand Down
Loading

0 comments on commit ba36c8c

Please sign in to comment.