1313import { ok , notFound } from '@adobe/spacecat-shared-http-utils' ;
1414import { Audit } from '@adobe/spacecat-shared-data-access' ;
1515import { FORM_OPPORTUNITY_TYPES , formOpportunitiesMap } from '../constants.js' ;
16- import {
17- getSuccessCriteriaDetails ,
18- sendMessageToFormsQualityAgent ,
19- sendMessageToMystiqueForGuidance ,
20- } from '../utils.js' ;
16+ import { getSuccessCriteriaDetails } from '../utils.js' ;
2117import { updateStatusToIgnored } from '../../accessibility/utils/scrape-utils.js' ;
2218import {
2319 aggregateA11yIssuesByOppType ,
@@ -86,8 +82,10 @@ export async function createFormAccessibilitySuggestionsFromMystique(
8682 url : pageUrl ,
8783 ...( source && { source } ) ,
8884 issues : [ formattedIssue ] ,
89- aiGenerated : issue . aiGenerated || false ,
9085 } ;
86+ if ( 'aiGenerated' in issue ) {
87+ urlObject . aiGenerated = issue . aiGenerated ;
88+ }
9189
9290 formAccessibilityData . push ( urlObject ) ;
9391 } ) ;
@@ -123,162 +121,44 @@ export async function createFormAccessibilitySuggestionsFromMystique(
123121 * Create a11y opportunity for the given siteId and auditId
124122 * @param {string } auditId - The auditId of the audit
125123 * @param {string } siteId - The siteId of the site
126- * @param {object } a11yData - The a11y data
127124 * @param {object } context - The context object
128125 * @returns {Promise<void> }
129126 */
130- async function createOrUpdateOpportunity ( auditId , siteId , a11yData , context , opportunityId = null ) {
127+ async function createOpportunity ( auditId , siteId , context ) {
131128 const {
132129 dataAccess, log,
133130 } = context ;
134131 const { Opportunity } = dataAccess ;
135132 let opportunity = null ;
136133
137134 try {
138- if ( opportunityId ) {
139- opportunity = await Opportunity . findById ( opportunityId ) ;
140- }
141-
142- if ( a11yData ?. length === 0 ) {
143- log . debug ( `[Form Opportunity] [Site Id: ${ siteId } ] No a11y data found to create or update opportunity ` ) ;
144- return opportunity ;
145- }
146-
147- const filteredA11yData = a11yData . filter ( ( a11y ) => a11y . a11yIssues ?. length > 0 ) ;
148- if ( filteredA11yData . length === 0 ) {
149- log . debug ( `[Form Opportunity] [Site Id: ${ siteId } ] No a11y issues found to create or update opportunity` ) ;
150- return opportunity ;
151- }
152-
153- const a11yOpptyData = filteredA11yData . map ( ( a11yOpty ) => {
154- const a11yIssues = a11yOpty . a11yIssues . map ( ( issue ) => ( {
155- ...issue ,
156- successCriterias : Array . isArray ( issue . successCriterias ) && issue . successCriterias . length > 0
157- ? issue . successCriterias . map ( ( criteria ) => getSuccessCriteriaDetails ( criteria ) )
158- : [ ] ,
159- } ) ) ;
160- return {
161- form : a11yOpty . form ,
162- formSource : a11yOpty . formSource ,
163- a11yIssues,
164- } ;
165- } ) ;
166-
167- // Update existing opportunity
168- if ( opportunity ) {
169- const data = opportunity . getData ( ) ;
170- const existingA11yData = data . accessibility ;
171-
172- // Merge new data with existing data
173- const mergedData = [ ...existingA11yData ] ;
174- a11yOpptyData . forEach ( ( newForm ) => {
175- const existingFormIndex = mergedData . findIndex (
176- ( form ) => form . form === newForm . form && form . formSource === newForm . formSource ,
177- ) ;
178-
179- if ( existingFormIndex !== - 1 ) {
180- // Update existing form's a11yIssues
181- mergedData [ existingFormIndex ] . a11yIssues = [
182- ...mergedData [ existingFormIndex ] . a11yIssues ,
183- ...newForm . a11yIssues ,
184- ] ;
185- } else {
186- // Add new form data
187- mergedData . push ( {
188- form : newForm . form ,
189- formSource : newForm . formSource ,
190- a11yIssues : newForm . a11yIssues ,
191- } ) ;
192- }
193- } ) ;
194-
195- opportunity . setData ( {
196- ...data ,
197- accessibility : mergedData ,
198- } ) ;
199- opportunity = await opportunity . save ( ) ;
200- log . info ( `[Form Opportunity] [Site Id: ${ siteId } ] Updated existing a11y opportunity` ) ;
201- }
202-
203- // If no existing opportunity, create new opportunity
204- if ( ! opportunity ) {
205- // change status to IGNORED for older opportunities
206- await updateStatusToIgnored ( dataAccess , siteId , log , null , filterAccessibilityOpportunities ) ;
135+ // change status to IGNORED for older opportunities
136+ await updateStatusToIgnored ( dataAccess , siteId , log , null , filterAccessibilityOpportunities ) ;
207137
208- const opportunityData = {
209- siteId,
210- auditId,
211- runbook : 'https://adobe.sharepoint.com/:w:/s/AEM_Forms/Ebpoflp2gHFNl4w5-9C7dFEBBHHE4gTaRzHaofqSxJMuuQ?e=Ss6mep' ,
212- type : FORM_OPPORTUNITY_TYPES . FORM_A11Y ,
213- origin : 'AUTOMATION' ,
214- title : 'Accessibility - Assistive technology is incompatible on form' ,
215- description : '' ,
216- tags : [
217- 'Forms Accessibility' ,
218- ] ,
219- data : {
220- accessibility : a11yOpptyData ,
221- } ,
222- } ;
223- opportunity = await Opportunity . create ( opportunityData ) ;
224- log . debug ( `[Form Opportunity] [Site Id: ${ siteId } ] Created new a11y opportunity` ) ;
225- }
138+ const opportunityData = {
139+ siteId,
140+ auditId,
141+ runbook : 'https://adobe.sharepoint.com/:w:/s/AEM_Forms/Ebpoflp2gHFNl4w5-9C7dFEBBHHE4gTaRzHaofqSxJMuuQ?e=Ss6mep' ,
142+ type : FORM_OPPORTUNITY_TYPES . FORM_A11Y ,
143+ origin : 'AUTOMATION' ,
144+ title : 'Accessibility - Assistive technology is incompatible on form' ,
145+ description : '' ,
146+ tags : [
147+ 'Forms Accessibility' ,
148+ ] ,
149+ data : {
150+ dataSources : [ 'axe-core' ] ,
151+ } ,
152+ } ;
153+ opportunity = await Opportunity . create ( opportunityData ) ;
154+ log . debug ( `[Form Opportunity] [Site Id: ${ siteId } ] Created new a11y opportunity` ) ;
226155 } catch ( e ) {
227- log . error ( `[Form Opportunity] [Site Id: ${ siteId } ] Failed to create/update a11y opportunity with error: ${ e . message } ` ) ;
228- throw new Error ( `[Form Opportunity] [Site Id: ${ siteId } ] Failed to create/update a11y opportunity with error: ${ e . message } ` ) ;
156+ log . error ( `[Form Opportunity] [Site Id: ${ siteId } ] Failed to create a11y opportunity with error: ${ e . message } ` ) ;
157+ throw new Error ( `[Form Opportunity] [Site Id: ${ siteId } ] Failed to create a11y opportunity with error: ${ e . message } ` ) ;
229158 }
230159 return opportunity ;
231160}
232161
233- function getWCAGCriteriaString ( criteria ) {
234- const { name, criteriaNumber } = getSuccessCriteriaDetails ( criteria ) ;
235- return `${ criteriaNumber } ${ name } ` ;
236- }
237-
238- /**
239- * Transforms axe-core violation format to the expected output format
240- * This is a temporary function to transform sites' accessibility schema to forms' old schema
241- * to prevent impact on UI
242- * @param {Object } axeData - The axe-core violation data
243- * @returns {Object } Form with accessibility issues containing form, formSource, and a11yIssues
244- */
245- export function transformAxeViolationsToA11yData ( axeData ) {
246- const { violations, url, formSource } = axeData ;
247- const a11yIssues = [ ] ;
248-
249- // Process critical violations
250- if ( violations ?. critical ?. items ) {
251- Object . values ( violations . critical . items ) . forEach ( ( violation ) => {
252- a11yIssues . push ( {
253- issue : violation . description ,
254- level : violation . level ,
255- successCriterias : violation . successCriteriaTags . map ( getWCAGCriteriaString ) ,
256- htmlWithIssues : violation . htmlWithIssues ,
257- recommendation : violation . failureSummary ,
258- } ) ;
259- } ) ;
260- }
261-
262- // Process serious violations
263- if ( violations ?. serious ?. items ) {
264- Object . values ( violations . serious . items ) . forEach ( ( violation ) => {
265- a11yIssues . push ( {
266- issue : violation . description ,
267- level : violation . level ,
268- successCriterias : violation . successCriteriaTags . map ( getWCAGCriteriaString ) ,
269- htmlWithIssues : violation . htmlWithIssues ,
270- recommendation : violation . failureSummary ,
271- } ) ;
272- } ) ;
273- }
274-
275- return {
276- form : url ,
277- formSource,
278- a11yIssues,
279- } ;
280- }
281-
282162/**
283163 * Creates individual suggestions for form accessibility issues
284164 * This method processes the aggregated form data and creates individual suggestions
@@ -380,34 +260,37 @@ export async function createAccessibilityOpportunity(auditData, context) {
380260 const aggregatedData = aggregationResult . finalResultFiles . current ;
381261 const a11yData = [ ] ;
382262
263+ // Get total violations from overall data
264+ const totalViolations = aggregatedData . overall ?. violations ?. total || 0 ;
265+
383266 // Process each form identified by composite key (URL + formSource)
384- Object . entries ( aggregatedData ) . forEach ( ( [ key , data ] ) => {
267+ Object . entries ( aggregatedData ) . forEach ( ( [ key ] ) => {
385268 // Skip the 'overall' key as it contains summary data
386269 if ( key === 'overall' ) return ;
387270
388- const { violations } = data ;
389-
390271 // Extract URL and formSource from the composite key
391272 const [ url , formSource ] = key . includes ( URL_SOURCE_SEPARATOR )
392273 ? key . split ( URL_SOURCE_SEPARATOR )
393274 : [ key , null ] ;
394275
395- // Transform violations to the expected format
396- const transformedData = transformAxeViolationsToA11yData ( {
397- violations,
398- url,
276+ // Add all forms to a11yData
277+ a11yData . push ( {
278+ form : url ,
399279 formSource,
400280 } ) ;
401-
402- a11yData . push ( transformedData ) ;
403281 } ) ;
404282
405- // Create opportunity
406- const opportunity = await createOrUpdateOpportunity ( auditId , siteId , a11yData , context ) ;
283+ // Create opportunity only if there are violations
284+ let opportunity = null ;
285+ if ( totalViolations > 0 ) {
286+ opportunity = await createOpportunity ( auditId , siteId , context ) ;
407287
408- // Create individual suggestions for the opportunity (if opportunity was created/updated)
409- if ( opportunity ) {
410- await createFormAccessibilityIndividualSuggestions ( aggregatedData , opportunity , context ) ;
288+ // Create individual suggestions for the opportunity (if opportunity was created/updated)
289+ if ( opportunity ) {
290+ await createFormAccessibilityIndividualSuggestions ( aggregatedData , opportunity , context ) ;
291+ }
292+ } else {
293+ log . debug ( `[Form Opportunity] [Site Id: ${ siteId } ] No accessibility violations found, skipping opportunity creation` ) ;
411294 }
412295 // Send message to importer-worker to create/update a11y metrics
413296 log . debug ( `[FormA11yAudit] [Site Id: ${ siteId } ] Sending message to importer-worker to create/update a11y metrics` ) ;
@@ -449,7 +332,7 @@ export async function createAccessibilityOpportunity(auditData, context) {
449332
450333export default async function handler ( message , context ) {
451334 const { log, dataAccess } = context ;
452- const { Site } = dataAccess ;
335+ const { Site, Opportunity } = dataAccess ;
453336 const { auditId, siteId, data } = message ;
454337 const { opportunityId, a11y } = data ;
455338 log . debug ( `[Form Opportunity] [Site Id: ${ siteId } ] Received message in accessibility handler: ${ JSON . stringify ( message , null , 2 ) } ` ) ;
@@ -461,13 +344,16 @@ export default async function handler(message, context) {
461344 }
462345
463346 try {
464- const opportunity = await createOrUpdateOpportunity (
465- auditId ,
466- siteId ,
467- a11y ,
468- context ,
469- opportunityId ,
470- ) ;
347+ let opportunity = null ;
348+ if ( opportunityId ) {
349+ opportunity = await Opportunity . findById ( opportunityId ) ;
350+ if ( ! opportunity ) {
351+ log . error ( `[Form Opportunity] [Site Id: ${ siteId } ] A11y opportunity not found` ) ;
352+ return notFound ( 'A11y opportunity not found' ) ;
353+ }
354+ } else {
355+ opportunity = await createOpportunity ( auditId , siteId , context ) ;
356+ }
471357 if ( ! opportunity ) {
472358 log . info ( `[Form Opportunity] [Site Id: ${ siteId } ] A11y opportunity not detected, skipping guidance` ) ;
473359 return ok ( ) ;
@@ -488,16 +374,7 @@ export default async function handler(message, context) {
488374 } else {
489375 log . info ( `[Form Opportunity] [Site Id: ${ siteId } ] ${ opportunity . getType ( ) } -auto-fix is disabled for site, skipping code-fix generation` ) ;
490376 }
491-
492- log . info ( `[Form Opportunity] [Site Id: ${ siteId } ] a11y opportunity: ${ JSON . stringify ( opportunity , null , 2 ) } ` ) ;
493- const opportunityData = opportunity . getData ( ) ;
494- const a11yData = opportunityData . accessibility ;
495- // eslint-disable-next-line max-len
496- const formsList = a11yData . filter ( ( item ) => ! item . formDetails ) . map ( ( item ) => ( { form : item . form , formSource : item . formSource } ) ) ;
497- log . info ( `[Form Opportunity] [Site Id: ${ siteId } ] formsList: ${ JSON . stringify ( formsList , null , 2 ) } ` ) ;
498- await ( formsList . length === 0
499- ? sendMessageToMystiqueForGuidance ( context , opportunity )
500- : sendMessageToFormsQualityAgent ( context , opportunity , formsList ) ) ;
377+ // TODO: Send message to mystique for guidance
501378 } catch ( error ) {
502379 log . error ( `[Form Opportunity] [Site Id: ${ siteId } ] Failed to process a11y opportunity from mystique: ${ error . message } ` ) ;
503380 }
0 commit comments