diff --git a/src/entities/Coauthor/model.ts b/src/entities/Coauthor/model.ts index 95c0dab1d..0b052e8bb 100644 --- a/src/entities/Coauthor/model.ts +++ b/src/entities/Coauthor/model.ts @@ -45,6 +45,8 @@ export default class CoauthorModel extends Model { } static async findAllByProposals(proposals: ProposalAttributes[], status?: CoauthorStatus): Promise { + if (proposals.length === 0) return [] + const query = SQL` SELECT address FROM ${table(this)} diff --git a/src/entities/Proposal/jobs.ts b/src/entities/Proposal/jobs.ts index 5a492a6ef..ffaae710a 100644 --- a/src/entities/Proposal/jobs.ts +++ b/src/entities/Proposal/jobs.ts @@ -40,7 +40,15 @@ async function updateAcceptedProposals(acceptedProposals: ProposalWithOutcome[], ProposalStatus.Passed ) - await BadgesService.giveLegislatorBadges(acceptedProposals) + try { + await BadgesService.giveLegislatorBadges(acceptedProposals) + } catch (error) { + ErrorService.report('Error while attempting to give badges', { + error, + category: ErrorCategory.Badges, + acceptedProposals, + }) + } } } @@ -195,35 +203,39 @@ async function categorizeProposals( } export async function finishProposal(context: JobContext) { - const finishableProposals = await ProposalModel.getFinishableProposals() - if (finishableProposals.length === 0) { - return - } + try { + const finishableProposals = await ProposalModel.getFinishableProposals() + if (finishableProposals.length === 0) { + return + } - const currentBudgets = await BudgetService.getBudgetsForProposals(finishableProposals) - - context.log(`Updating ${finishableProposals.length} proposals...`) - const { finishedProposals, acceptedProposals, outOfBudgetProposals, rejectedProposals, updatedBudgets } = - await categorizeProposals(finishableProposals, currentBudgets, context) - - await updateFinishedProposals(finishedProposals, context) - await updateAcceptedProposals(acceptedProposals, context) - await updateOutOfBudgetProposals(outOfBudgetProposals, context) - await updateRejectedProposals(rejectedProposals, context) - await BudgetService.updateBudgets(updatedBudgets) - - const proposals = [...finishedProposals, ...acceptedProposals, ...rejectedProposals] - context.log(`Updating ${proposals.length} proposals in discourse... \n\n`) - for (const { id, title, winnerChoice, outcomeStatus } of proposals) { - ProposalService.commentProposalUpdateInDiscourse(id) - if (outcomeStatus) { - DiscordService.finishProposal( - id, - title, - outcomeStatus, - outcomeStatus === ProposalOutcome.FINISHED ? winnerChoice : undefined - ) + const currentBudgets = await BudgetService.getBudgetsForProposals(finishableProposals) + + context.log(`Updating ${finishableProposals.length} proposals...`) + const { finishedProposals, acceptedProposals, outOfBudgetProposals, rejectedProposals, updatedBudgets } = + await categorizeProposals(finishableProposals, currentBudgets, context) + + await updateFinishedProposals(finishedProposals, context) + await updateAcceptedProposals(acceptedProposals, context) + await updateOutOfBudgetProposals(outOfBudgetProposals, context) + await updateRejectedProposals(rejectedProposals, context) + await BudgetService.updateBudgets(updatedBudgets) + + const proposals = [...finishedProposals, ...acceptedProposals, ...rejectedProposals] + context.log(`Updating ${proposals.length} proposals in discourse... \n\n`) + for (const { id, title, winnerChoice, outcomeStatus } of proposals) { + ProposalService.commentProposalUpdateInDiscourse(id) + if (outcomeStatus) { + DiscordService.finishProposal( + id, + title, + outcomeStatus, + outcomeStatus === ProposalOutcome.FINISHED ? winnerChoice : undefined + ) + } } + } catch (error) { + ErrorService.report('Error finishing proposals', { error, category: ErrorCategory.Job }) } } diff --git a/src/services/BadgesService.test.ts b/src/services/BadgesService.test.ts index 212450810..f659b11d0 100644 --- a/src/services/BadgesService.test.ts +++ b/src/services/BadgesService.test.ts @@ -12,13 +12,9 @@ jest.mock('../constants', () => ({ const COAUTHORS = ['0x56d0b5ed3d525332f00c9bc938f93598ab16aaa7', '0x49e4dbff86a2e5da27c540c9a9e8d2c3726e278f'] describe('giveLegislatorBadges', () => { - beforeAll(() => { - // eslint-disable-next-line @typescript-eslint/no-empty-function + it('should call queueAirdropJob with correct arguments for governance proposals', async () => { jest.spyOn(AirdropJobModel, 'create').mockResolvedValue(async () => {}) jest.spyOn(CoauthorModel, 'findAllByProposals').mockResolvedValue(COAUTHORS) - }) - - it('should call queueAirdropJob with correct arguments for governance proposals', async () => { const proposal = createTestProposal(ProposalType.Governance, ProposalStatus.Passed) proposal.user = '0x4757ce43dc5429b8f1a132dc29ef970e55ae722b' const expectedAuthorsAndCoauthors = [proposal.user, ...COAUTHORS].map(getChecksumAddress) @@ -29,4 +25,11 @@ describe('giveLegislatorBadges', () => { recipients: expectedAuthorsAndCoauthors, }) }) + + it('does not try to airdrop any badge when there are no governance proposals', async () => { + jest.clearAllMocks() + const proposal = createTestProposal(ProposalType.Draft, ProposalStatus.Passed) + await BadgesService.giveLegislatorBadges([proposal]) + expect(AirdropJobModel.create).not.toHaveBeenCalled() + }) }) diff --git a/src/services/BadgesService.ts b/src/services/BadgesService.ts index 226aac21a..bbece0027 100644 --- a/src/services/BadgesService.ts +++ b/src/services/BadgesService.ts @@ -95,6 +95,9 @@ export class BadgesService { static async giveLegislatorBadges(acceptedProposals: ProposalAttributes[]) { const governanceProposals = acceptedProposals.filter((proposal) => proposal.type === ProposalType.Governance) + if (governanceProposals.length === 0) { + return + } const coauthors = await CoauthorModel.findAllByProposals(governanceProposals, CoauthorStatus.APPROVED) const authors = governanceProposals.map((proposal) => proposal.user) const authorsAndCoauthors = new Set([...authors.map(getChecksumAddress), ...coauthors.map(getChecksumAddress)])