Skip to content

Commit

Permalink
feat: check for existing twu org proposals
Browse files Browse the repository at this point in the history
  • Loading branch information
IanFonzie committed Dec 1, 2023
1 parent 5ebeadf commit b55ef21
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 22 deletions.
52 changes: 37 additions & 15 deletions src/back-end/lib/db/proposal/team-with-us.ts
Original file line number Diff line number Diff line change
Expand Up @@ -499,26 +499,48 @@ export const readOwnTWUProposals = tryDb<
);
});

const readOneTWUProposalWithIdsQuery = (
query: (
connection: Connection,
...ids: Id[]
) => Promise<Pick<RawTWUProposal, "id"> | undefined>
) =>
tryDb<[Session, ...Id[]], Id | null>(async (connection, session, ...ids) => {
if (!session) {
return valid(null);
}

const result = (await query(connection, session.user.id, ...ids))?.id;

return valid(result ? result : null);
});

/**
* Used as confirmation that the person creating a proposal is not the same
* person as who created the opportunity. Returns `valid(null)` on success.
*/
export const readOneTWUProposalByOpportunityAndAuthor = tryDb<
[Id, Session],
Id | null
>(async (connection, opportunityId, session) => {
if (!session) {
return valid(null);
}
const result = (
await connection<{ id: Id }>("twuProposals")
.where({ opportunity: opportunityId, createdBy: session.user.id })
.select("id")
.first()
)?.id;
export const readOneTWUProposalByOpportunityAndAuthor =
readOneTWUProposalWithIdsQuery(
async (connection, userId, opportunityId) =>
await connection<RawTWUProposal, { id: Id }>("twuProposals")
.where({ opportunity: opportunityId, createdBy: userId })
.select("id")
.first()
);

return valid(result ? result : null);
});
/**
* Used as confirmation that the organization does not have more than one
* proposal associated with the opportunity. Returns `valid(null)` on success.
*/
export const readOneTWUProposalByOpportunityAndOrgAuthor =
readOneTWUProposalWithIdsQuery(
async (connection, userId, opportunityId, organizationId) =>
await connection<RawTWUProposal, { id: Id }>("twuProposals")
.where({ opportunity: opportunityId, organization: organizationId })
.andWhereNot({ createdBy: userId })
.select("id")
.first()
);

async function isTWUProposalAuthor(
connection: Connection,
Expand Down
65 changes: 58 additions & 7 deletions src/back-end/lib/resources/proposal/team-with-us.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,21 +297,46 @@ const create: crud.Create<
});
}

// Check for existing proposal on this opportunity, authored by this user
if (organization) {
const dbResultOrgProposal =
await db.readOneTWUProposalByOpportunityAndOrgAuthor(
connection,
request.session,
opportunity,
organization
);
if (isInvalid(dbResultOrgProposal)) {
return invalid({
database: [db.ERROR_MESSAGE]
});
}
if (dbResultOrgProposal.value) {
return invalid({
existingOrganizationProposal: {
proposalId: dbResultOrgProposal.value,
errors: ["Please select a different organization."]
}
});
}
}

/**
* Check for existing proposal on this opportunity, authored by this user
* If the person is not the author, dbResult will be valid(null)
*/
const dbResult = await db.readOneTWUProposalByOpportunityAndAuthor(
connection,
opportunity,
request.session
);
if (isInvalid(dbResult)) {
const dbResultProposal =
await db.readOneTWUProposalByOpportunityAndAuthor(
connection,
request.session,
opportunity
);
if (isInvalid(dbResultProposal)) {
return invalid({
database: [db.ERROR_MESSAGE]
});
}
if (dbResult.value) {
if (dbResultProposal.value) {
return invalid({
conflict: ["You already have a proposal for this opportunity."]
});
Expand Down Expand Up @@ -600,6 +625,32 @@ const update: crud.Update<
});
}

// Check for existing proposal on this opportunity, authored by this user
if (validatedOrganization.value) {
const dbResult =
await db.readOneTWUProposalByOpportunityAndOrgAuthor(
connection,
request.session,
twuOpportunity.id,
validatedOrganization.value.id
);
if (isInvalid(dbResult)) {
return invalid({
database: [db.ERROR_MESSAGE]
});
}
if (dbResult.value && dbResult.value !== request.params.id) {
return invalid({
proposal: adt("edit" as const, {
existingOrganizationProposal: {
proposalId: dbResult.value,
errors: ["Please select a different organization."]
}
})
});
}
}

// Attachments must be validated for both drafts and published opportunities
const validatedAttachments = await validateAttachments(
connection,
Expand Down

0 comments on commit b55ef21

Please sign in to comment.