diff --git a/src/support/slack/commands/identify-redirects.js b/src/support/slack/commands/identify-redirects.js index 53460b672..8d131b12a 100644 --- a/src/support/slack/commands/identify-redirects.js +++ b/src/support/slack/commands/identify-redirects.js @@ -9,15 +9,13 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ - -import { Site as SiteModel } from '@adobe/spacecat-shared-data-access'; -import { hasText } from '@adobe/spacecat-shared-utils'; +import { queueIdentifyRedirectsAudit } from '../../utils.js'; import BaseCommand from './base.js'; import { extractURLFromSlackInput, postErrorMessage } from '../../../utils/slack/base.js'; const PHRASES = ['identify-redirects']; -const DEFAULT_MINUTES = 3000; // 50 hours +const DEFAULT_MINUTES = 2500; // 41 hours, 40 minutes export default function IdentifyRedirectsCommand(context) { const baseCommand = BaseCommand({ @@ -30,15 +28,13 @@ export default function IdentifyRedirectsCommand(context) { const { dataAccess, - env, log, - sqs, updateRedirects = false, } = context; const { Site } = dataAccess; const handleExecution = async (args, slackContext) => { - const { say, channelId, threadTs } = slackContext; + const { say } = slackContext; try { const [baseURLInput, minutesInput] = args; @@ -58,53 +54,17 @@ export default function IdentifyRedirectsCommand(context) { return; } - const authoringType = site.getAuthoringType(); - const deliveryType = site.getDeliveryType(); - // check either authoringType or deliveryType is CS/CW - if (![ - SiteModel.AUTHORING_TYPES.CS, - SiteModel.AUTHORING_TYPES.CS_CW, - ].includes(authoringType) - && ![ - SiteModel.DELIVERY_TYPES.AEM_CS, - ].includes(deliveryType)) { - await say(`:warning: identify-redirects currently supports AEM CS/CW only. This site authoringType is \`${authoringType}\` and deliveryType is \`${deliveryType}\`.`); - return; - } - - const deliveryConfig = site.getDeliveryConfig?.() || {}; - const { programId, environmentId } = deliveryConfig; - - if (!hasText(programId) || !hasText(environmentId)) { - await say(':warning: This site is missing `deliveryConfig.programId` and/or `deliveryConfig.environmentId` required for Splunk queries.'); - return; - } - - if (!hasText(env?.AUDIT_JOBS_QUEUE_URL)) { - await say(':x: Server misconfiguration: missing `AUDIT_JOBS_QUEUE_URL`.'); - return; - } - - if (!sqs) { - await say(':x: Server misconfiguration: missing SQS client.'); - return; - } - - await say(`:mag: Queued redirect pattern detection for *${baseURL}* (last ${minutes}m). I’ll reply here when it’s ready.`); - - await sqs.sendMessage(env.AUDIT_JOBS_QUEUE_URL, { - type: 'identify-redirects', - siteId: site.getId(), + const result = await queueIdentifyRedirectsAudit({ + site, baseURL, - programId: String(programId), - environmentId: String(environmentId), minutes, updateRedirects, - slackContext: { - channelId, - threadTs, - }, - }); + slackContext, + }, context); + + if (!result.ok) { + await say(result.message || result.error); + } } catch (error) { log.error(error); await postErrorMessage(say, error); diff --git a/src/support/utils.js b/src/support/utils.js index c25428298..1bea3f945 100644 --- a/src/support/utils.js +++ b/src/support/utils.js @@ -1124,6 +1124,96 @@ export const createEntitlementAndEnrollment = async ( } }; +/* +* Queues an identify redirects audit for a site. +* @param {Object} site - The site to queue an identify redirects audit for. +* @param {string} baseURL? - The base URL of the site. +* @param {number} minutes? - The number of minutes to audit for. +* @param {boolean} updateRedirects? - Whether to update the redirects. +* @param {Object} slackContext - The Slack context object. +* @param {Object} context - The Lambda context containing dataAccess, log, etc. +* @returns {Promise<{ok: boolean, error?: string}>} - ok: true or { ok: false, error }. +*/ +export async function queueIdentifyRedirectsAudit( + { + site, baseURL, minutes = 2000, updateRedirects = false, slackContext, + }, + context, +) { + const { + env, + log, + sqs, + } = context; + + const { say, channelId, threadTs } = slackContext || {}; + try { + if (!site) { + return { ok: false, error: `:x: No site found with base URL '${baseURL}'.` }; + } + + const resolvedBaseURL = baseURL || site.getBaseURL(); + if (!resolvedBaseURL) { + return { ok: false, error: 'missing_base_url' }; + } + + // check for SQS client to talk to audit worker + if (!sqs) { + return { ok: false, error: ':x: Server misconfiguration: missing SQS client.' }; + } + + const authoringType = site.getAuthoringType(); + const deliveryType = site.getDeliveryType(); + // check either authoringType or deliveryType is CS/CW + if (![ + SiteModel.AUTHORING_TYPES.CS, // cs + SiteModel.AUTHORING_TYPES.CS_CW, // cs/crosswalk + ].includes(authoringType) + && ![ + SiteModel.DELIVERY_TYPES.AEM_CS, // aem_cs + ].includes(deliveryType)) { + return { + ok: false, + message: ':warning: identify-redirects currently supports AEM CS/CW only. ' + + `This site authoringType is \`${authoringType}\` and deliveryType is \`${deliveryType}\`.`, + }; + } + + const deliveryConfig = site.getDeliveryConfig?.() || {}; + const { programId, environmentId } = deliveryConfig; + if (!hasText(programId) || !hasText(environmentId)) { + return { ok: false, error: ':x: This site is missing `deliveryConfig.programId` and/or `deliveryConfig.environmentId` required for Splunk queries.' }; + } + + if (!hasText(env?.AUDIT_JOBS_QUEUE_URL)) { + return { ok: false, error: ':x: Server misconfiguration: missing `AUDIT_JOBS_QUEUE_URL`.' }; + } + if (!sqs) { + return { ok: false, error: ':x: Server misconfiguration: missing SQS client.' }; + } + if (say) { + await say(`:mag: Queued redirect pattern detection for *${resolvedBaseURL}* (last ${minutes}m). I’ll reply here when it’s ready.`); + } + + await sqs.sendMessage(env.AUDIT_JOBS_QUEUE_URL, { + type: 'identify-redirects', + siteId: site.getId(), + baseURL: resolvedBaseURL, + programId: String(programId), + environmentId: String(environmentId), + minutes, + updateRedirects, + slackContext: channelId != null && threadTs != null + ? { channelId, threadTs } + : undefined, + }); + return { ok: true }; + } catch (error) { + log.error(error); + throw error; + } +} + /** * Shared onboarding function used by both modal and command implementations. * @@ -1242,6 +1332,43 @@ export const onboardSingleSite = async ( additionalParams.deliveryConfig, ); + // configure redirectsmode and redirectssource + // check for valid authoringType and deliveryType + const authoringType = site.getAuthoringType(); + const deliveryType = site.getDeliveryType(); + let validForRedirects = true; + // check either authoringType or deliveryType is CS/CW + if (![ + SiteModel.AUTHORING_TYPES.CS, // cs + SiteModel.AUTHORING_TYPES.CS_CW, // cs/crosswalk + ].includes(authoringType) + && ![ + SiteModel.DELIVERY_TYPES.AEM_CS, // aem_cs + ].includes(deliveryType)) { + validForRedirects = false; + } + if (!validForRedirects) { + // skip update-redirects if invalid for redirects + log.info(`skipping update-redirects, as the site ${baseURL} is not valid for redirects because authoringType is \`${authoringType}\` and deliveryType is \`${deliveryType}\`.`); + } else { + const updateRedirectsResult = await queueIdentifyRedirectsAudit( + { + site, + baseURL, + minutes: 2000, + updateRedirects: true, + slackContext, + }, + context, + ); + if (!updateRedirectsResult.ok) { + reportLine.errors = updateRedirectsResult.error; + reportLine.status = 'Failed'; + await say(updateRedirectsResult.error); + return reportLine; + } + } + // Validate tier if (!Object.values(EntitlementModel.TIERS).includes(tier)) { reportLine.errors = `Invalid tier: ${tier}`; diff --git a/test/support/slack/commands/identify-redirects.test.js b/test/support/slack/commands/identify-redirects.test.js index 6e6470812..9cded25b4 100644 --- a/test/support/slack/commands/identify-redirects.test.js +++ b/test/support/slack/commands/identify-redirects.test.js @@ -22,11 +22,11 @@ use(sinonChai); describe('IdentifyRedirectsCommand', () => { const SiteModelStub = { AUTHORING_TYPES: { - CS: 'CS', - CS_CW: 'CS_CW', + CS: 'cs', + CS_CW: 'cs/crosswalk', }, DELIVERY_TYPES: { - AEM_CS: 'AEM_CS', + AEM_CS: 'aem_cs', }, }; @@ -223,7 +223,7 @@ describe('IdentifyRedirectsCommand', () => { baseURL: 'https://example.com', programId: 'p', environmentId: 'e', - minutes: 3000, + minutes: 2500, }); expect(sqsStub.sendMessage.firstCall.args[1]).to.deep.include({ slackContext: {