From d4ed2a6cefbe3674b93c2c594a4aa8eac614cd12 Mon Sep 17 00:00:00 2001 From: alinarublea Date: Fri, 24 Jan 2025 10:54:49 +0100 Subject: [PATCH] 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 d599dfcc..e09dd8d1 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 8be22ea0..61115c20 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 44745966..c5ff2662 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 723e50ce..10b0e435 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 2e083414..e0db92f6 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 69398239..4c9f69de 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`); + }); + }); });