Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/geo-brand-presence/detect-geo-brand-presence-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default async function handler(message, context) {
return notFound();
}

const configVersion = data.config_version;
const sheetUrl = URL.parse(data.presigned_url);
if (!sheetUrl || !sheetUrl.href) {
log.error(`GEO BRAND PRESENCE: Invalid presigned URL: ${data.presigned_url}`);
Expand All @@ -48,7 +49,10 @@ export default async function handler(message, context) {

// upload to sharepoint & publish via hlx admin api
const sharepointClient = await createLLMOSharepointClient(context);
const outputLocation = `${site.getConfig().getLlmoDataFolder()}/brand-presence`;
let outputLocation = `${site.getConfig().getLlmoDataFolder()}/brand-presence`;
if (configVersion != null && configVersion !== '') {
outputLocation = `${outputLocation}/config_${configVersion}`;
}
const xlsxName = (
/;\s*content=(brandpresence-.*$)/.exec(sheetUrl.searchParams.get('response-content-disposition') ?? '')?.[1]
?? sheetUrl.pathname.replace(/.*[/]/, '')
Expand Down
4 changes: 4 additions & 0 deletions src/geo-brand-presence/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { parquetReadObjects } from 'hyparquet';
import { GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { randomUUID } from 'node:crypto';
import { llmoConfig } from '@adobe/spacecat-shared-utils';
import { AuditBuilder } from '../common/audit-builder.js';
import { wwwUrlResolver } from '../common/index.js';

Expand Down Expand Up @@ -79,6 +80,8 @@ export async function sendToMystique(context, getPresignedUrl = getSignedUrl) {
return;
}

const config = await llmoConfig.readConfig(siteId, s3Client, { s3Bucket: bucket });

const url = await asPresignedJsonUrl(prompts, bucket, { ...context, getPresignedUrl });
log.info('GEO BRAND PRESENCE: Presigned URL for prompts for site id %s (%s): %s', siteId, baseURL, url);
await Promise.all(OPPTY_TYPES.map(async (opptyType) => {
Expand All @@ -92,6 +95,7 @@ export async function sendToMystique(context, getPresignedUrl = getSignedUrl) {
week: calendarWeek.week,
year: calendarWeek.year,
data: {
config_version: config.version,
url,
},
};
Expand Down
39 changes: 35 additions & 4 deletions test/audits/geo-brand-presence.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import { parquetWriteBuffer } from 'hyparquet-writer';
import { keywordPromptsImportStep, sendToMystique } from '../../src/geo-brand-presence/handler.js';
import { llmoConfig } from '@adobe/spacecat-shared-utils';

use(sinonChai);

Expand Down Expand Up @@ -56,6 +57,7 @@ describe('Geo Brand Presence Handler', () => {
s3Client = {
send: sinon.stub().throws(new Error('no stubbed response')),
};
s3Client.send.withArgs(matchS3Cmd('PutObjectCommand')).resolves({});
getPresignedUrl = sandbox.stub();
context = {
log,
Expand Down Expand Up @@ -160,7 +162,8 @@ describe('Geo Brand Presence Handler', () => {

it('should send message to Mystique for all opportunity types when keywordQuestions are found', async () => {
// Mock S3 client method used by getStoredMetrics (AWS SDK v3 style)
fakeS3Response(fakeData());
fakeS3ParquetResponse(fakeData());
fakeS3ConfigResponse('v12345');

getPresignedUrl.resolves('https://example.com/presigned-url');

Expand All @@ -183,6 +186,7 @@ describe('Geo Brand Presence Handler', () => {
deliveryType: site.getDeliveryType(),
});
expect(brandPresenceMessage.data).deep.equal({
config_version: 'v12345',
web_search_provider: 'chatgpt',
url: 'https://example.com/presigned-url',
});
Expand All @@ -203,7 +207,7 @@ describe('Geo Brand Presence Handler', () => {
});

it('should skip sending message to Mystique when no keywordQuestions', async () => {
fakeS3Response([]);
fakeS3ParquetResponse([]);
await sendToMystique({
...context,
auditContext: {
Expand All @@ -214,7 +218,7 @@ describe('Geo Brand Presence Handler', () => {
expect(sqs.sendMessage).to.not.have.been.called;
});

function fakeS3Response(response) {
function fakeS3ParquetResponse(response) {
const columnData = {
prompt: { data: [], name: 'prompt', type: 'STRING' },
region: { data: [], name: 'region', type: 'STRING' },
Expand All @@ -236,7 +240,9 @@ describe('Geo Brand Presence Handler', () => {

const buffer = parquetWriteBuffer({ columnData: Object.values(columnData) });

s3Client.send.resolves({
s3Client.send.withArgs(
matchS3Cmd('GetObjectCommand', { Key: sinon.match(/\/data\.parquet$/) })
).resolves({
Body: {
async transformToByteArray() {
return new Uint8Array(buffer);
Expand All @@ -245,6 +251,19 @@ describe('Geo Brand Presence Handler', () => {
});
}

function fakeS3ConfigResponse(version) {
s3Client.send.withArgs(
matchS3Cmd('GetObjectCommand', { Key: llmoConfig.llmoConfigPath(site.getId()) })
).resolves({
Body: {
async transformToString() {
return JSON.stringify(llmoConfig.defaultConfig());
},
},
VersionId: version,
});
}

function fakeData(mapFn) {
const data = [
{
Expand Down Expand Up @@ -312,3 +331,15 @@ describe('Geo Brand Presence Handler', () => {
return mapFn ? data.map(mapFn) : data;
}
});

/**
* @param {string} name - The name of the S3 command to match.
* @param {Record<string, unknown>} [input] - The partial input of the S3 command to match.
*/
function matchS3Cmd(name, input) {
const match = { constructor: sinon.match({ name }) };
if (input) {
match.input = sinon.match(input);
}
return sinon.match(match);
}