-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensure correct emails are sent for project status changes related to vouching #1853
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,7 @@ import { | |
addFeaturedProjectUpdate, | ||
exportProjectsWithFiltersToCsv, | ||
listDelist, | ||
revokeGivbacksEligibility, | ||
updateStatusOfProjects, | ||
verifyProjects, | ||
} from './projectsTab'; | ||
|
@@ -452,8 +453,20 @@ function verifyProjectsTestCases() { | |
recordIds: String(project.id), | ||
}, | ||
}, | ||
true, // give priority to revoke badge | ||
true, // revoke badge | ||
false, | ||
); | ||
await revokeGivbacksEligibility( | ||
{ | ||
currentAdmin: adminUser as User, | ||
h: {}, | ||
resource: {}, | ||
records: [], | ||
}, | ||
{ | ||
query: { | ||
recordIds: String(project.id), | ||
}, | ||
}, | ||
); | ||
|
||
const updatedProject = await findProjectById(project.id); | ||
|
@@ -527,15 +540,20 @@ function verifyProjectsTestCases() { | |
assert.isTrue(updatedProject?.listed); | ||
assert.equal(updatedProject?.reviewStatus, ReviewStatus.Listed); | ||
assert.isTrue(project!.verificationStatus === RevokeSteps.Revoked); | ||
assert.isTrue(updatedProject!.verificationStatus === null); | ||
assert.isTrue( | ||
updatedProject!.verificationStatus === project.verificationStatus, | ||
); | ||
Comment on lines
+543
to
+545
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assertion May Not Reflect Updated Verification Status The assertion checks if the updated project's assert.isTrue(
updatedProject!.verificationStatus === project.verificationStatus,
); Since the project's verification status might change after calling |
||
assert.equal( | ||
updatedVerificationForm!.status, | ||
PROJECT_VERIFICATION_STATUSES.VERIFIED, | ||
PROJECT_VERIFICATION_STATUSES.DRAFT, | ||
); | ||
Comment on lines
+548
to
+549
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential Mismatch in Verification Form Status After Verification You assert that the assert.equal(
updatedVerificationForm!.status,
PROJECT_VERIFICATION_STATUSES.DRAFT,
); However, after verification, shouldn't the status be |
||
assert.equal( | ||
updatedVerificationForm!.isTermAndConditionsAccepted, | ||
projectVerificationForm.isTermAndConditionsAccepted, | ||
); | ||
assert.equal(updatedVerificationForm!.isTermAndConditionsAccepted, true); | ||
assert.equal( | ||
updatedVerificationForm!.lastStep, | ||
PROJECT_VERIFICATION_STEPS.SUBMIT, | ||
projectVerificationForm.lastStep, | ||
); | ||
}); | ||
|
||
|
@@ -616,12 +634,15 @@ function verifyProjectsTestCases() { | |
assert.isTrue(updatedProject!.verificationStatus === RevokeSteps.Revoked); | ||
assert.equal( | ||
updatedVerificationForm!.status, | ||
PROJECT_VERIFICATION_STATUSES.DRAFT, | ||
PROJECT_VERIFICATION_STATUSES.VERIFIED, | ||
); | ||
Comment on lines
+637
to
+638
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Verification Form Status Should Reflect Unverification In the test case where a project is unverified, the assertion is: assert.equal(
updatedVerificationForm!.status,
PROJECT_VERIFICATION_STATUSES.VERIFIED,
); Since the project is unverified, the verification form status might need to be updated to |
||
assert.equal( | ||
updatedVerificationForm!.isTermAndConditionsAccepted, | ||
projectVerificationForm.isTermAndConditionsAccepted, | ||
); | ||
assert.equal(updatedVerificationForm!.isTermAndConditionsAccepted, false); | ||
assert.equal( | ||
updatedVerificationForm!.lastStep, | ||
PROJECT_VERIFICATION_STEPS.MANAGING_FUNDS, | ||
projectVerificationForm.lastStep, | ||
); | ||
}); | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -184,29 +184,72 @@ export const addFeaturedProjectUpdate = async ( | |||||||||
}; | ||||||||||
}; | ||||||||||
|
||||||||||
export const revokeGivbacksEligibility = async ( | ||||||||||
context: AdminJsContextInterface, | ||||||||||
request: AdminJsRequestInterface, | ||||||||||
) => { | ||||||||||
const { records, currentAdmin } = context; | ||||||||||
try { | ||||||||||
const projectIds = request?.query?.recordIds | ||||||||||
?.split(',') | ||||||||||
?.map(strId => Number(strId)) as number[]; | ||||||||||
const updateParams = { isGivbackEligible: false }; | ||||||||||
const projects = await Project.createQueryBuilder('project') | ||||||||||
.update<Project>(Project, updateParams) | ||||||||||
.where('project.id IN (:...ids)') | ||||||||||
.setParameter('ids', projectIds) | ||||||||||
.returning('*') | ||||||||||
.updateEntity(true) | ||||||||||
.execute(); | ||||||||||
|
||||||||||
for (const project of projects.raw) { | ||||||||||
const projectWithAdmin = (await findProjectById(project.id)) as Project; | ||||||||||
projectWithAdmin.verificationStatus = RevokeSteps.Revoked; | ||||||||||
await projectWithAdmin.save(); | ||||||||||
await getNotificationAdapter().projectBadgeRevoked({ | ||||||||||
project: projectWithAdmin, | ||||||||||
}); | ||||||||||
const verificationForm = await getVerificationFormByProjectId(project.id); | ||||||||||
if (verificationForm) { | ||||||||||
await makeFormDraft({ | ||||||||||
formId: verificationForm.id, | ||||||||||
adminId: currentAdmin.id, | ||||||||||
}); | ||||||||||
} | ||||||||||
} | ||||||||||
await Promise.all([ | ||||||||||
refreshUserProjectPowerView(), | ||||||||||
refreshProjectPowerView(), | ||||||||||
refreshProjectFuturePowerView(), | ||||||||||
]); | ||||||||||
} catch (error) { | ||||||||||
logger.error('revokeGivbacksEligibility() error', error); | ||||||||||
throw error; | ||||||||||
} | ||||||||||
return { | ||||||||||
redirectUrl: '/admin/resources/Project', | ||||||||||
records: records.map(record => { | ||||||||||
record.toJSON(context.currentAdmin); | ||||||||||
}), | ||||||||||
Comment on lines
+231
to
+233
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix mapping function to return values in 'records.map' In lines 231-233, the mapping function does not return any values, resulting in an array of undefined elements. To fix this, ensure that the callback returns the result of Apply this diff to correct the issue: records: records.map(record => {
- record.toJSON(context.currentAdmin);
+ return record.toJSON(context.currentAdmin);
}), Alternatively, simplify the code: - records: records.map(record => {
- record.toJSON(context.currentAdmin);
- }),
+ records: records.map(record => record.toJSON(context.currentAdmin)), 📝 Committable suggestion
Suggested change
|
||||||||||
notice: { | ||||||||||
message: 'Project(s) successfully revoked from Givbacks eligibility', | ||||||||||
type: 'success', | ||||||||||
}, | ||||||||||
}; | ||||||||||
}; | ||||||||||
|
||||||||||
export const verifyProjects = async ( | ||||||||||
context: AdminJsContextInterface, | ||||||||||
request: AdminJsRequestInterface, | ||||||||||
verified: boolean = true, | ||||||||||
revokeBadge: boolean = false, | ||||||||||
vouchedStatus: boolean = true, | ||||||||||
) => { | ||||||||||
const { records, currentAdmin } = context; | ||||||||||
// prioritize revokeBadge | ||||||||||
const verificationStatus = revokeBadge ? false : verified; | ||||||||||
try { | ||||||||||
const projectIds = request?.query?.recordIds | ||||||||||
?.split(',') | ||||||||||
?.map(strId => Number(strId)) as number[]; | ||||||||||
const projectsBeforeUpdating = await findProjectsByIdArray(projectIds); | ||||||||||
const updateParams = { verified: verificationStatus }; | ||||||||||
|
||||||||||
if (verificationStatus) { | ||||||||||
await Project.query(` | ||||||||||
UPDATE project | ||||||||||
SET "verificationStatus" = NULL | ||||||||||
WHERE id IN (${request?.query?.recordIds}) | ||||||||||
`); | ||||||||||
} | ||||||||||
const updateParams = { verified: vouchedStatus }; | ||||||||||
|
||||||||||
const projects = await Project.createQueryBuilder('project') | ||||||||||
.update<Project>(Project, updateParams) | ||||||||||
|
@@ -219,11 +262,11 @@ export const verifyProjects = async ( | |||||||||
for (const project of projects.raw) { | ||||||||||
if ( | ||||||||||
projectsBeforeUpdating.find(p => p.id === project.id)?.verified === | ||||||||||
verificationStatus | ||||||||||
vouchedStatus | ||||||||||
) { | ||||||||||
logger.debug('verifying/unVerifying project but no changes happened', { | ||||||||||
projectId: project.id, | ||||||||||
verificationStatus, | ||||||||||
verificationStatus: vouchedStatus, | ||||||||||
}); | ||||||||||
// if project.verified have not changed, so we should not execute rest of the codes | ||||||||||
continue; | ||||||||||
|
@@ -232,42 +275,10 @@ export const verifyProjects = async ( | |||||||||
project, | ||||||||||
status: project.status, | ||||||||||
userId: currentAdmin.id, | ||||||||||
description: verified | ||||||||||
description: vouchedStatus | ||||||||||
? HISTORY_DESCRIPTIONS.CHANGED_TO_VERIFIED | ||||||||||
: HISTORY_DESCRIPTIONS.CHANGED_TO_UNVERIFIED, | ||||||||||
}); | ||||||||||
const projectWithAdmin = (await findProjectById(project.id)) as Project; | ||||||||||
|
||||||||||
if (revokeBadge) { | ||||||||||
projectWithAdmin.verificationStatus = RevokeSteps.Revoked; | ||||||||||
await projectWithAdmin.save(); | ||||||||||
await getNotificationAdapter().projectBadgeRevoked({ | ||||||||||
project: projectWithAdmin, | ||||||||||
}); | ||||||||||
} else if (verificationStatus) { | ||||||||||
await getNotificationAdapter().projectVerified({ | ||||||||||
project: projectWithAdmin, | ||||||||||
}); | ||||||||||
} else { | ||||||||||
await getNotificationAdapter().projectUnVerified({ | ||||||||||
project: projectWithAdmin, | ||||||||||
}); | ||||||||||
} | ||||||||||
|
||||||||||
const verificationForm = await getVerificationFormByProjectId(project.id); | ||||||||||
if (verificationForm) { | ||||||||||
if (verificationStatus) { | ||||||||||
await makeFormVerified({ | ||||||||||
formId: verificationForm.id, | ||||||||||
adminId: currentAdmin.id, | ||||||||||
}); | ||||||||||
} else { | ||||||||||
await makeFormDraft({ | ||||||||||
formId: verificationForm.id, | ||||||||||
adminId: currentAdmin.id, | ||||||||||
}); | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
await Promise.all([ | ||||||||||
|
@@ -286,7 +297,7 @@ export const verifyProjects = async ( | |||||||||
}), | ||||||||||
notice: { | ||||||||||
message: `Project(s) successfully ${ | ||||||||||
verificationStatus ? 'verified' : 'unverified' | ||||||||||
vouchedStatus ? 'vouched' : 'unvouched' | ||||||||||
}`, | ||||||||||
type: 'success', | ||||||||||
}, | ||||||||||
|
@@ -1273,7 +1284,7 @@ export const projectsTab = { | |||||||||
}, | ||||||||||
component: false, | ||||||||||
}, | ||||||||||
verify: { | ||||||||||
approveVouched: { | ||||||||||
actionType: 'bulk', | ||||||||||
isVisible: true, | ||||||||||
isAccessible: ({ currentAdmin }) => | ||||||||||
|
@@ -1286,7 +1297,7 @@ export const projectsTab = { | |||||||||
}, | ||||||||||
component: false, | ||||||||||
}, | ||||||||||
reject: { | ||||||||||
removeVouched: { | ||||||||||
actionType: 'bulk', | ||||||||||
isVisible: true, | ||||||||||
isAccessible: ({ currentAdmin }) => | ||||||||||
|
@@ -1299,17 +1310,16 @@ export const projectsTab = { | |||||||||
}, | ||||||||||
component: false, | ||||||||||
}, | ||||||||||
// the difference is that it sends another segment event | ||||||||||
revokeBadge: { | ||||||||||
revokeGivbacksEligible: { | ||||||||||
actionType: 'bulk', | ||||||||||
isVisible: true, | ||||||||||
isAccessible: ({ currentAdmin }) => | ||||||||||
canAccessProjectAction( | ||||||||||
{ currentAdmin }, | ||||||||||
ResourceActions.REVOKE_BADGE, | ||||||||||
), | ||||||||||
handler: async (request, response, context) => { | ||||||||||
return verifyProjects(context, request, false, true); | ||||||||||
handler: async (request, _response, context) => { | ||||||||||
return revokeGivbacksEligibility(context, request); | ||||||||||
}, | ||||||||||
component: false, | ||||||||||
}, | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Potential Issue Detected with Project Eligibility Filtering
The replacement of
project.verified = true
withproject.isGivbackEligible = true
drastically reduces the number of eligible projects from multiple instances to just one. This significant change may inadvertently exclude many projects that were previously considered verified, potentially impacting email notifications and other dependent functionalities.🔗 Analysis chain
LGTM. Verify the impact on project selection.
The change from
project.verified = true
toproject.isGivbackEligible = true
aligns with the PR objective of ensuring correct emails for project status changes related to vouching. This modification shifts the focus from verified projects to Givback eligible projects, which is likely the intended behavior.To ensure this change doesn't unexpectedly alter the set of projects being processed, please run the following verification:
This script will help us understand the potential impact of this change on the number of projects being processed.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
Length of output: 502
Script:
Length of output: 70881