diff --git a/src/actions/zoneProvision.js b/src/actions/zoneProvision.js index e2b4825..613c775 100644 --- a/src/actions/zoneProvision.js +++ b/src/actions/zoneProvision.js @@ -13,6 +13,7 @@ import * as ActionTypes from '../constants/ActionTypes'; import { asyncZoneSetActiveZone } from './activeZone'; import { normalizeZoneGetAll } from '../constants/Schemas'; import { zoneFetch, zoneFetchSuccess } from './zones'; +import { deduplicateOnActiveZones } from 'src/utils/utils'; /* * Zone Provision actions still use reducers/zones.js as the reducer @@ -136,7 +137,8 @@ function asyncSetHostAPIProvisionedDomainActive(domainName) { zoneGetAll(function(error, response) { if (response) { dispatch(zoneFetchSuccess(response.body.result)); - let normalizedZoneList = normalizeZoneGetAll(response.body.result); + const zoneList = deduplicateOnActiveZones(response.body.result); + let normalizedZoneList = normalizeZoneGetAll(zoneList); dispatch( asyncZoneSetActiveZone(normalizedZoneList.entities.zones[domainName]) ); diff --git a/src/actions/zones.js b/src/actions/zones.js index 1dc62f4..2a75298 100644 --- a/src/actions/zones.js +++ b/src/actions/zones.js @@ -70,7 +70,12 @@ export function asyncFetchZones() { zoneGetAll(function(error, response) { if (response) { dispatch(zoneFetchSuccess(response.body.result)); - if (response.body.result[0]) { + const activeZone = response.body.result.find( + zone => zone.status === 'active' + ); + if (activeZone) { + dispatch(zoneSetActiveZoneIfEmpty(activeZone)); + } else if (response.body.result[0]) { dispatch(zoneSetActiveZoneIfEmpty(response.body.result[0])); } } else { diff --git a/src/test/utils/deduplicateZonesTest.js b/src/test/utils/deduplicateZonesTest.js new file mode 100644 index 0000000..a564f59 --- /dev/null +++ b/src/test/utils/deduplicateZonesTest.js @@ -0,0 +1,56 @@ +import { deduplicateOnActiveZones } from '../../utils/utils'; +import expect from 'expect'; + +describe('deduplicateZones', () => { + it('should not change a list of zones without any duplicate', () => { + expect( + deduplicateOnActiveZones([ + { id: '1', name: 'cloudflare.com', status: 'active' }, + { id: '2', name: 'blog.cloudflare.com', status: 'active' } + ]) + ).toEqual([ + { id: '1', name: 'cloudflare.com', status: 'active' }, + { id: '2', name: 'blog.cloudflare.com', status: 'active' } + ]); + }); + + it('should remove non-active zone in case of duplicates', () => { + expect( + deduplicateOnActiveZones([ + { id: '1', name: 'cloudflare.com', status: 'active' }, + { id: '2', name: 'blog.cloudflare.com', status: 'active' }, + { id: '3', name: 'cloudflare.com', status: 'purged' } + ]) + ).toEqual([ + { id: '1', name: 'cloudflare.com', status: 'active' }, + { id: '2', name: 'blog.cloudflare.com', status: 'active' } + ]); + }); + + it('should not remove duplicates when there is no active zone', () => { + expect( + deduplicateOnActiveZones([ + { id: '1', name: 'cloudflare.com', status: 'pending' }, + { id: '2', name: 'blog.cloudflare.com', status: 'active' }, + { id: '3', name: 'cloudflare.com', status: 'purged' } + ]) + ).toEqual([ + { id: '1', name: 'cloudflare.com', status: 'pending' }, + { id: '2', name: 'blog.cloudflare.com', status: 'active' }, + { id: '3', name: 'cloudflare.com', status: 'purged' } + ]); + }); + + it('should remove multiple duplicates when there is one active zone', () => { + expect( + deduplicateOnActiveZones([ + { id: '1', name: 'cloudflare.com', status: 'pending' }, + { id: '2', name: 'cloudflare.com', status: 'purged' }, + { id: '3', name: 'cloudflare.com', status: 'active' }, + { id: '4', name: 'cloudflare.com', status: 'moved' } + ]) + ).toEqual([ + { id: '3', name: 'cloudflare.com', status: 'active' } + ]); + }); +}); diff --git a/src/utils/utils.js b/src/utils/utils.js index ee496b9..dc1bf61 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -70,3 +70,31 @@ export function formatMessageForIntegration( return formatMessage({ id: messageId }); } + +// deduplicateOnActiveZones was introduced as a potential fix for CUSTESC-36595. The goal of this function is to +// deduplicate the list of zones returned by the Cloudflare API based on the status of the zone. This way, we hope to +// guarantee that when normalizing the list of zones, only the active zone would show up in case of duplicates. For +// instance, in the mentioned tickets, two zones were potentially returned: a purged as well as an active zone. +export function deduplicateOnActiveZones(zones) { + let filteredZones = []; + const isActive = z => z.status === 'active'; + const isSameZone = (z1, z2) => z1.name === z2.name; + + zones.forEach(zone => { + if (isActive(zone)) { + // If the zone is active, we first remove all existing duplicates and then insert the active zone. + filteredZones = filteredZones.filter(fZone => !isSameZone(zone, fZone)); + filteredZones.push(zone); + } else { + // If the zone is not active, we only insert it if there is no existing active zone. + const alreadyHasActiveZone = filteredZones.some( + fZone => isSameZone(zone, fZone) && isActive(fZone) + ); + if (!alreadyHasActiveZone) { + filteredZones.push(zone); + } + } + }); + + return filteredZones; +}