From 317ca32148d266415dbfdceaf35c3630db73f5b8 Mon Sep 17 00:00:00 2001 From: alinarublea Date: Wed, 13 Dec 2023 14:37:16 +0100 Subject: [PATCH 1/2] feat: add rum api calls to shared --- .../src/index.js | 16 +++++++++++++ .../test/rum-api-client.test.js | 24 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/packages/spacecat-shared-rum-api-client/src/index.js b/packages/spacecat-shared-rum-api-client/src/index.js index 195fd2a74..fda9255ca 100644 --- a/packages/spacecat-shared-rum-api-client/src/index.js +++ b/packages/spacecat-shared-rum-api-client/src/index.js @@ -18,6 +18,8 @@ import { fetch } from './utils.js'; const APIS = { ROTATE_DOMAINKEYS: 'https://helix-pages.anywhere.run/helix-services/run-query@v3/rotate-domainkeys', RUM_DASHBOARD: 'https://main--franklin-dashboard--adobe.hlx.live/views/rum-dashboard', + DOMAIN_LIST: 'https://helix-pages.anywhere.run/helix-services/run-query@v3/rum-dashboard', + NOT_FOUND_CHECKPOINTS: 'https://helix-pages.anywhere.run/helix-services/run-query@v3/rum-checkpoint-urls', }; export async function sendRequest(url, opts) { @@ -85,6 +87,20 @@ export default class RUMAPIClient { this.domainkey = domainkey; } + async getRUMDashboard(params) { + return sendRequest(createUrl( + APIS.DOMAIN_LIST, + { domainkey: this.domainkey, ...params }, + )); + } + + async get404Checkpoints(params) { + return sendRequest(createUrl( + APIS.NOT_FOUND_CHECKPOINTS, + { domainkey: this.domainkey, ...params }, + )); + } + async createBacklink(url, expiry) { const scopedDomainKey = await generateDomainKey(this.domainkey, url, expiry); return `${APIS.RUM_DASHBOARD}?interval=${expiry}&offset=0&limit=100&url=${url}&domainkey=${scopedDomainKey}`; diff --git a/packages/spacecat-shared-rum-api-client/test/rum-api-client.test.js b/packages/spacecat-shared-rum-api-client/test/rum-api-client.test.js index fad0eb76d..9418a51c7 100644 --- a/packages/spacecat-shared-rum-api-client/test/rum-api-client.test.js +++ b/packages/spacecat-shared-rum-api-client/test/rum-api-client.test.js @@ -59,4 +59,28 @@ describe('rum api client', () => { await expect(sendRequest('https://space.cat/dummy-page')) .to.be.rejectedWith('Unexpected response from rum api. $.results.data is not array'); }); + + it('returns data when getRUMDashboard api is successful', async () => { + nock('https://helix-pages.anywhere.run/helix-services') + .get('/run-query@v3/rum-dashboard') + .query({ + domainkey: 'hebele', + }) + .reply(200, JSON.stringify({ results: { data: [] } })); + const rumApiClient = RUMAPIClient.createFrom({ env: { RUM_API_KEY: 'hebele' } }); + await expect(rumApiClient.getRUMDashboard()) + .to.be.fulfilled; + }); + + it('returns data when get404Checkpoints api is successful', async () => { + nock('https://helix-pages.anywhere.run/helix-services') + .get('/run-query@v3/rum-checkpoint-urls') + .query({ + domainkey: 'hebele', + }) + .reply(200, JSON.stringify({ results: { data: [] } })); + const rumApiClient = RUMAPIClient.createFrom({ env: { RUM_API_KEY: 'hebele' } }); + await expect(rumApiClient.get404Checkpoints()) + .to.be.fulfilled; + }); }); From d4ed2a6cefbe3674b93c2c594a4aa8eac614cd12 Mon Sep 17 00:00:00 2001 From: alinarublea Date: Fri, 24 Jan 2025 10:54:49 +0100 Subject: [PATCH 2/2] feat: add site competitors entity --- package-lock.json | 2 +- .../src/models/site/index.d.ts | 4 ++ .../src/models/site/site.collection.js | 27 ++++++++ .../src/models/site/site.schema.js | 5 ++ .../test/it/site/site.test.js | 3 + .../unit/models/site/site.collection.test.js | 63 +++++++++++++++++++ 6 files changed, 103 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index d599dfcc6..e09dd8d17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20085,7 +20085,7 @@ }, "packages/spacecat-shared-content-client": { "name": "@adobe/spacecat-shared-content-client", - "version": "1.3.9", + "version": "1.3.10", "license": "Apache-2.0", "dependencies": { "@adobe/helix-universal": "5.0.8", diff --git a/packages/spacecat-shared-data-access/src/models/site/index.d.ts b/packages/spacecat-shared-data-access/src/models/site/index.d.ts index 8be22ea08..61115c206 100644 --- a/packages/spacecat-shared-data-access/src/models/site/index.d.ts +++ b/packages/spacecat-shared-data-access/src/models/site/index.d.ts @@ -51,6 +51,7 @@ export interface Site extends BaseModel { getOrganization(): Promise; getOrganizationId(): string; getSiteCandidates(): Promise; + getSiteCompetitors(): Promise; getSiteTopPages(): Promise; getSiteTopPagesBySource(source: string): Promise; getSiteTopPagesBySourceAndGeo(source: string, geo: string): Promise; @@ -65,6 +66,7 @@ export interface Site extends BaseModel { setIsLive(isLive: boolean): Site; setIsLiveToggledAt(isLiveToggledAt: string): Site; setOrganizationId(organizationId: string): Site; + setSiteCompetitors(siteCompetitors: object): Site; toggleLive(): Site; } @@ -77,4 +79,6 @@ export interface SiteCollection extends BaseCollection { findByBaseURL(baseURL: string): Promise; findByDeliveryType(deliveryType: string): Promise; findByOrganizationId(organizationId: string): Promise; + addSiteCompetitorBySiteId(siteId: string, siteCompetitorBaseUrl: string): Promise; + removeSiteCompetitorBySiteId(siteId: string, siteCompetitorBaseUrl: string): Promise; } diff --git a/packages/spacecat-shared-data-access/src/models/site/site.collection.js b/packages/spacecat-shared-data-access/src/models/site/site.collection.js index 44745966e..c5ff2662a 100755 --- a/packages/spacecat-shared-data-access/src/models/site/site.collection.js +++ b/packages/spacecat-shared-data-access/src/models/site/site.collection.js @@ -71,6 +71,33 @@ class SiteCollection extends BaseCollection { return orderedSites; } + + async addSiteCompetitorBySiteId(siteId, siteCompetitorBaseURL) { + const site = await this.findById(siteId); + if (!site) { + throw new DataAccessError(`Site with id ${siteId} not found`, this); + } + const currentSiteCompetitors = site.getSiteCompetitors(); + if (!currentSiteCompetitors.includes(siteCompetitorBaseURL)) { + currentSiteCompetitors.push(siteCompetitorBaseURL); + await site.save(); + } + return site; + } + + async removeSiteCompetitorBySiteId(siteId, siteCompetitorBaseURL) { + const site = await this.findById(siteId); + if (!site) { + throw new DataAccessError(`Site with id ${siteId} not found`, this); + } + const currentSiteCompetitors = site.getSiteCompetitors(); + const indexOfSiteCompetitor = currentSiteCompetitors.indexOf(siteCompetitorBaseURL); + if (indexOfSiteCompetitor !== -1) { + currentSiteCompetitors.splice(indexOfSiteCompetitor, 1); + await site.save(); + } + return site; + } } export default SiteCollection; diff --git a/packages/spacecat-shared-data-access/src/models/site/site.schema.js b/packages/spacecat-shared-data-access/src/models/site/site.schema.js index 723e50ce7..10b0e435f 100755 --- a/packages/spacecat-shared-data-access/src/models/site/site.schema.js +++ b/packages/spacecat-shared-data-access/src/models/site/site.schema.js @@ -69,6 +69,11 @@ const schema = new SchemaBuilder(Site, SiteCollection) default: {}, validate: (value) => isObject(value), }) + .addAttribute('siteCompetitors', { + type: 'list', + default: [], + validate: (value) => Array.isArray(value), + }) .addAttribute('isLive', { type: 'boolean', required: true, diff --git a/packages/spacecat-shared-data-access/test/it/site/site.test.js b/packages/spacecat-shared-data-access/test/it/site/site.test.js index 2e083414b..e0db92f6c 100644 --- a/packages/spacecat-shared-data-access/test/it/site/site.test.js +++ b/packages/spacecat-shared-data-access/test/it/site/site.test.js @@ -32,6 +32,7 @@ async function checkSite(site) { expect(site.getGitHubURL()).to.be.a('string'); expect(site.getHlxConfig()).to.be.an('object'); expect(site.getOrganizationId()).to.be.a('string'); + expect(site.getSiteCompetitors()).to.be.an('array'); expect(isIsoDate(site.getCreatedAt())).to.be.true; expect(isIsoDate(site.getUpdatedAt())).to.be.true; @@ -287,6 +288,7 @@ describe('Site IT', async () => { }, hlxVersion: 5, }, + siteCompetitors: ['https://competitor1.com', 'https://competitor2.com'], organizationId: sampleData.organizations[0].getId(), isLive: true, isLiveToggledAt: '2024-12-06T08:35:24.125Z', @@ -304,6 +306,7 @@ describe('Site IT', async () => { await checkSite(newSite); expect(newSite.getBaseURL()).to.equal(newSiteData.baseURL); + expect(newSite.getSiteCompetitors()).to.deep.equal(newSiteData.siteCompetitors); }); it('updates a site', async () => { diff --git a/packages/spacecat-shared-data-access/test/unit/models/site/site.collection.test.js b/packages/spacecat-shared-data-access/test/unit/models/site/site.collection.test.js index 69398239f..4c9f69dec 100755 --- a/packages/spacecat-shared-data-access/test/unit/models/site/site.collection.test.js +++ b/packages/spacecat-shared-data-access/test/unit/models/site/site.collection.test.js @@ -113,4 +113,67 @@ describe('SiteCollection', () => { expect(instance.allByDeliveryType).to.have.been.calledOnce; }); }); + describe('addSiteCompetitorBySiteId', () => { + it('adds a site competitor by site ID', async () => { + const siteId = 's12345'; + const siteCompetitorBaseURL = 'https://competitor.com'; + const siteCompetitors = []; + const mockSite = { + siteCompetitors: {}, + getId: () => siteId, + getSiteCompetitors: () => (siteCompetitors), + save: stub().resolves(), + }; + + instance.findById = stub().resolves(mockSite); + + const result = await instance.addSiteCompetitorBySiteId(siteId, siteCompetitorBaseURL); + + expect(result).to.equal(mockSite); + expect(mockSite.getSiteCompetitors()).to.have.deep.equal([siteCompetitorBaseURL]); + expect(mockSite.save).to.have.been.calledOnce; + }); + + it('throws an error if site is not found', async () => { + const siteId = 's12345'; + const siteCompetitorBaseURL = 'https://competitor.com'; + + instance.findById = stub().resolves(null); + + await expect(instance.addSiteCompetitorBySiteId(siteId, siteCompetitorBaseURL)) + .to.be.rejectedWith(`Site with id ${siteId} not found`); + }); + }); + + describe('removeSiteCompetitorBySiteId', () => { + it('removes a site competitor by site ID', async () => { + const siteId = 's12345'; + const siteCompetitorBaseURL1 = 'https://competitor1.com'; + const siteCompetitorBaseURL2 = 'https://competitor2.com'; + const siteCompetitors = [siteCompetitorBaseURL1, siteCompetitorBaseURL2]; + const mockSite = { + getId: () => siteId, + getSiteCompetitors: () => (siteCompetitors), + save: stub().resolves(), + }; + + instance.findById = stub().resolves(mockSite); + + const result = await instance.removeSiteCompetitorBySiteId(siteId, siteCompetitorBaseURL1); + + expect(result).to.equal(mockSite); + expect(mockSite.getSiteCompetitors()).to.deep.equal([siteCompetitorBaseURL2]); + expect(mockSite.save).to.have.been.calledOnce; + }); + + it('throws an error if site is not found', async () => { + const siteId = 's12345'; + const siteCompetitorBaseURL = 'https://competitor.com'; + + instance.findById = stub().resolves(null); + + await expect(instance.removeSiteCompetitorBySiteId(siteId, siteCompetitorBaseURL)) + .to.be.rejectedWith(`Site with id ${siteId} not found`); + }); + }); });