diff --git a/src/controllers/suggestions.js b/src/controllers/suggestions.js index ae61e4997..2683f81d0 100644 --- a/src/controllers/suggestions.js +++ b/src/controllers/suggestions.js @@ -1082,6 +1082,14 @@ function SuggestionsController(ctx, sqs, env) { return badRequest('variations must be an array'); } + // Block auto-deploy on non-granted suggestions for summit-plg users + if (await getIsSummitPlgEnabled(site, ctx, context)) { + const { notGrantedIds } = await SuggestionGrant.splitSuggestionsByGrantStatus(suggestionIds); + if (notGrantedIds.length > 0) { + return forbidden(`The following suggestions are not granted: ${notGrantedIds.join(', ')}`); + } + } + const configuration = await Configuration.findLatest(); if (!configuration.isHandlerEnabledForSite(`${opportunity.getType()}-auto-fix`, site)) { return badRequest(`Handler is not enabled for site ${site.getId()} autofix type ${opportunity.getType()}`); diff --git a/test/controllers/suggestions.test.js b/test/controllers/suggestions.test.js index 0c7ad07cd..d08795e1a 100644 --- a/test/controllers/suggestions.test.js +++ b/test/controllers/suggestions.test.js @@ -3584,6 +3584,66 @@ describe('Suggestions Controller', () => { sandbox.restore(); }); + it('proceeds with autofix when summit-plg is enabled and all suggestions are granted', async () => { + opportunity.getType = sandbox.stub().returns('meta-tags'); + mockSuggestionGrant.splitSuggestionsByGrantStatus.resolves({ + grantedIds: [SUGGESTION_IDS[0], SUGGESTION_IDS[2]], + notGrantedIds: [], + grantIds: [`grant-${SUGGESTION_IDS[0]}`, `grant-${SUGGESTION_IDS[2]}`], + }); + mockSuggestion.allByOpportunityId.resolves( + [mockSuggestionEntity(suggs[0]), mockSuggestionEntity(suggs[2])], + ); + mockSuggestion.bulkUpdateStatus.resolves([mockSuggestionEntity({ ...suggs[0], status: 'IN_PROGRESS' }), + mockSuggestionEntity({ ...suggs[2], status: 'IN_PROGRESS' }), + ]); + const response = await suggestionsControllerWithMock.autofixSuggestions({ + params: { + siteId: SITE_ID, + opportunityId: OPPORTUNITY_ID, + }, + data: { suggestionIds: [SUGGESTION_IDS[0], SUGGESTION_IDS[2]] }, + ...context, + }); + + expect(response.status).to.equal(207); + expect(mockSuggestionGrant.splitSuggestionsByGrantStatus).to.have.been.calledOnce; + }); + + it('does not check grant status when summit-plg is disabled for autofix', async () => { + const controllerPlgDisabled = await esmock('../../src/controllers/suggestions.js', { + '../../src/support/utils.js': { + getIMSPromiseToken: async () => ({ promise_token: 'token', expires_in: 14399, token_type: 'promise_token' }), + getIsSummitPlgEnabled: async () => false, + }, + }); + const ctrl = controllerPlgDisabled({ + dataAccess: mockSuggestionDataAccess, + pathInfo: { headers: { 'x-product': 'abcd' } }, + ...authContext, + }, mockSqs, { AUTOFIX_JOBS_QUEUE: 'https://autofix-jobs-queue' }); + + opportunity.getType = sandbox.stub().returns('meta-tags'); + mockSuggestionGrant.splitSuggestionsByGrantStatus.resetHistory(); + mockSuggestion.allByOpportunityId.resolves( + [mockSuggestionEntity(suggs[0]), mockSuggestionEntity(suggs[2])], + ); + mockSuggestion.bulkUpdateStatus.resolves([mockSuggestionEntity({ ...suggs[0], status: 'IN_PROGRESS' }), + mockSuggestionEntity({ ...suggs[2], status: 'IN_PROGRESS' }), + ]); + const response = await ctrl.autofixSuggestions({ + params: { + siteId: SITE_ID, + opportunityId: OPPORTUNITY_ID, + }, + data: { suggestionIds: [SUGGESTION_IDS[0], SUGGESTION_IDS[2]] }, + ...context, + }); + + expect(response.status).to.equal(207); + expect(mockSuggestionGrant.splitSuggestionsByGrantStatus).to.not.have.been.called; + }); + it('triggers autofixSuggestion and sets suggestions to in-progress', async () => { opportunity.getType = sandbox.stub().returns('meta-tags'); mockSuggestion.allByOpportunityId.resolves( @@ -3643,6 +3703,28 @@ describe('Suggestions Controller', () => { expect(bulkPatchResponse.suggestions[0].suggestion).to.have.property('status', 'IN_PROGRESS'); }); + it('returns forbidden when summit-plg is enabled and suggestions are not granted for autofix', async () => { + mockSuggestionGrant.splitSuggestionsByGrantStatus.resolves({ + grantedIds: [SUGGESTION_IDS[0]], + notGrantedIds: [SUGGESTION_IDS[2]], + grantIds: [`grant-${SUGGESTION_IDS[0]}`], + }); + const response = await suggestionsControllerWithMock.autofixSuggestions({ + params: { + siteId: SITE_ID, + opportunityId: OPPORTUNITY_ID, + }, + data: { suggestionIds: [SUGGESTION_IDS[0], SUGGESTION_IDS[2]] }, + ...context, + }); + + expect(response.status).to.equal(403); + const body = await response.json(); + expect(body.message).to.include('not granted'); + expect(body.message).to.include(SUGGESTION_IDS[2]); + expect(body.message).to.not.include(SUGGESTION_IDS[0]); + }); + it('triggers autofixSuggestion and sets suggestions to in-progress for alt-text', async () => { opportunity.getType = sandbox.stub().returns('alt-text'); mockSuggestion.allByOpportunityId.resolves(