diff --git a/api/src/__tests__/initialize-loaders.test.js b/api/src/__tests__/initialize-loaders.test.js deleted file mode 100644 index ed28b1dd44..0000000000 --- a/api/src/__tests__/initialize-loaders.test.js +++ /dev/null @@ -1,42 +0,0 @@ -import { initializeLoaders } from '../initialize-loaders' - -describe('initializeLoaders', () => { - it('returns a object with a key for each loader', () => { - const loaders = initializeLoaders({ - query: jest.fn(), - userKey: '1234', - i18n: jest.fn(), - language: 'en', - cleanseInput: jest.fn(), - loginRequiredBool: true, - moment: jest.fn(), // momentjs - }) - - expect(loaders).toHaveProperty( - 'loadDkimFailConnectionsBySumId', - 'loadDmarcFailConnectionsBySumId', - 'loadDmarcSummaryConnectionsByUserId', - 'loadDmarcSummaryEdgeByDomainIdAndPeriod', - 'loadDmarcSummaryByKey', - 'loadFullPassConnectionsBySumId', - 'loadSpfFailureConnectionsBySumId', - 'loadStartDateFromPeriod', - 'loadDmarcYearlySumEdge', - 'loadOrgByKey', - 'loadOrganizationNamesById', - 'loadUserByUserName', - 'loadUserConnectionsByUserId', - 'loadUserByKey', - 'loadMyTrackerByUserId', - 'loadVerifiedDomainsById', - 'loadVerifiedDomainByKey', - 'loadVerifiedDomainConnections', - 'loadVerifiedDomainConnectionsByOrgId', - 'loadVerifiedOrgByKey', - 'loadVerifiedOrgBySlug', - 'loadVerifiedOrgConnectionsByDomainId', - 'loadVerifiedOrgConnections', - 'loadAllVerifiedRuaDomains', - ) - }) -}) diff --git a/api/src/__tests__/server.test.js b/api/src/__tests__/server.test.js index 94f16e71d2..26e2471f80 100644 --- a/api/src/__tests__/server.test.js +++ b/api/src/__tests__/server.test.js @@ -133,7 +133,7 @@ describe('parse server', () => { .post('/graphql') .set('Accept', 'application/json') .send({ - query: '{findVerifiedDomains (first: 5) { edges { node { id }}}}', + query: '{findMyOrganizations (first: 5) { edges { node { id }}}}', }) expect(response.status).toEqual(400) diff --git a/api/src/affiliation/mutations/__tests__/invite-user-to-org.test.js b/api/src/affiliation/mutations/__tests__/invite-user-to-org.test.js index ed82606ae9..38eb7a4934 100644 --- a/api/src/affiliation/mutations/__tests__/invite-user-to-org.test.js +++ b/api/src/affiliation/mutations/__tests__/invite-user-to-org.test.js @@ -205,11 +205,15 @@ describe('invite user to org', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendOrgInviteEmail: sendOrgInviteEmail }, validators: { cleanseInput }, @@ -300,11 +304,15 @@ describe('invite user to org', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendOrgInviteEmail: sendOrgInviteEmail }, validators: { cleanseInput }, @@ -395,11 +403,15 @@ describe('invite user to org', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendOrgInviteEmail: sendOrgInviteEmail }, validators: { cleanseInput }, @@ -486,11 +498,15 @@ describe('invite user to org', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendOrgInviteCreateAccount }, validators: { cleanseInput }, @@ -581,11 +597,15 @@ describe('invite user to org', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendOrgInviteCreateAccount }, validators: { cleanseInput }, @@ -677,11 +697,15 @@ describe('invite user to org', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendOrgInviteCreateAccount }, validators: { cleanseInput }, @@ -789,11 +813,15 @@ describe('invite user to org', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendOrgInviteEmail: sendOrgInviteEmail }, validators: { cleanseInput }, @@ -884,11 +912,15 @@ describe('invite user to org', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendOrgInviteEmail: sendOrgInviteEmail }, validators: { cleanseInput }, @@ -976,11 +1008,15 @@ describe('invite user to org', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendOrgInviteCreateAccount }, validators: { cleanseInput }, @@ -1072,11 +1108,15 @@ describe('invite user to org', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendOrgInviteCreateAccount }, validators: { cleanseInput }, @@ -1250,18 +1290,22 @@ describe('invite user to org', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn(), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), + dataSources: { + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, - loadOrganizationNamesById: { - load: jest.fn(), + organization: { + byKey: { + load: jest.fn(), + }, + namesById: { + load: jest.fn(), + }, }, }, notify: { sendOrgInviteCreateAccount: jest.fn() }, @@ -1330,18 +1374,22 @@ describe('invite user to org', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), + dataSources: { + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, - loadOrganizationNamesById: { - load: jest.fn(), + organization: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, + namesById: { + load: jest.fn(), + }, }, }, notify: { sendOrgInviteCreateAccount: jest.fn() }, @@ -1412,18 +1460,22 @@ describe('invite user to org', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), + dataSources: { + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, - loadOrganizationNamesById: { - load: jest.fn(), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 123 }), + }, + namesById: { + load: jest.fn(), + }, }, }, notify: { sendOrgInviteCreateAccount: jest.fn() }, @@ -1494,18 +1546,22 @@ describe('invite user to org', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), + dataSources: { + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, - loadOrganizationNamesById: { - load: jest.fn(), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 123 }), + }, + namesById: { + load: jest.fn(), + }, }, }, notify: { sendOrgInviteCreateAccount: jest.fn() }, @@ -1576,18 +1632,22 @@ describe('invite user to org', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), + dataSources: { + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, - loadOrganizationNamesById: { - load: jest.fn(), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 123 }), + }, + namesById: { + load: jest.fn(), + }, }, }, notify: { sendOrgInviteCreateAccount: jest.fn() }, @@ -1662,11 +1722,15 @@ describe('invite user to org', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: i18n.locale }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendOrgInviteCreateAccount: jest.fn() }, validators: { cleanseInput }, @@ -1740,11 +1804,15 @@ describe('invite user to org', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: i18n.locale }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendOrgInviteCreateAccount: jest.fn(), diff --git a/api/src/affiliation/mutations/__tests__/leave-organization.test.js b/api/src/affiliation/mutations/__tests__/leave-organization.test.js index 7a34fa2fb1..6f1bf2e42c 100644 --- a/api/src/affiliation/mutations/__tests__/leave-organization.test.js +++ b/api/src/affiliation/mutations/__tests__/leave-organization.test.js @@ -230,13 +230,15 @@ describe('given a successful leave', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), + dataSources: { + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: user._key, + }), + }, }, validators: { cleanseInput }, }, @@ -317,13 +319,15 @@ describe('given a successful leave', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), + dataSources: { + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: user._key, + }), + }, }, validators: { cleanseInput }, }, @@ -438,13 +442,15 @@ describe('given a successful leave', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), + dataSources: { + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: user._key, + }), + }, }, validators: { cleanseInput }, }, @@ -525,13 +531,15 @@ describe('given a successful leave', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), + dataSources: { + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: user._key, + }), + }, }, validators: { cleanseInput }, }, @@ -627,9 +635,11 @@ describe('given an unsuccessful leave', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + organization: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, validators: { cleanseInput }, @@ -700,9 +710,11 @@ describe('given an unsuccessful leave', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), + dataSources: { + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 123 }), + }, }, }, validators: { cleanseInput }, @@ -769,9 +781,11 @@ describe('given an unsuccessful leave', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), + dataSources: { + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 123 }), + }, }, }, validators: { cleanseInput }, @@ -840,9 +854,11 @@ describe('given an unsuccessful leave', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + organization: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, validators: { cleanseInput }, @@ -913,9 +929,11 @@ describe('given an unsuccessful leave', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), + dataSources: { + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 123 }), + }, }, }, validators: { cleanseInput }, @@ -982,9 +1000,11 @@ describe('given an unsuccessful leave', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), + dataSources: { + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 123 }), + }, }, }, validators: { cleanseInput }, diff --git a/api/src/affiliation/mutations/__tests__/remove-user-from-org.test.js b/api/src/affiliation/mutations/__tests__/remove-user-from-org.test.js index ba45c2efea..7d0a9a3588 100644 --- a/api/src/affiliation/mutations/__tests__/remove-user-from-org.test.js +++ b/api/src/affiliation/mutations/__tests__/remove-user-from-org.test.js @@ -247,18 +247,22 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - userKey: admin._key, - i18n, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: admin._key, - i18n, - }), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: admin._key, + i18n, + }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + userKey: admin._key, + i18n, + }), + }, }, validators: { cleanseInput }, }, @@ -346,18 +350,22 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - userKey: admin._key, - i18n, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: admin._key, - i18n, - }), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: admin._key, + i18n, + }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + userKey: admin._key, + i18n, + }), + }, }, validators: { cleanseInput }, }, @@ -451,18 +459,22 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - userKey: admin._key, - i18n, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: admin._key, - i18n, - }), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: admin._key, + i18n, + }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + userKey: admin._key, + i18n, + }), + }, }, validators: { cleanseInput }, }, @@ -543,18 +555,22 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - userKey: admin._key, - i18n, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: admin._key, - i18n, - }), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: admin._key, + i18n, + }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + userKey: admin._key, + i18n, + }), + }, }, validators: { cleanseInput }, }, @@ -642,18 +658,22 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - userKey: admin._key, - i18n, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: admin._key, - i18n, - }), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: admin._key, + i18n, + }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + userKey: admin._key, + i18n, + }), + }, }, validators: { cleanseInput }, }, @@ -747,18 +767,22 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - userKey: admin._key, - i18n, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: admin._key, - i18n, - }), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: admin._key, + i18n, + }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + userKey: admin._key, + i18n, + }), + }, }, validators: { cleanseInput }, }, @@ -857,18 +881,22 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - userKey: admin._key, - i18n, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: admin._key, - i18n, - }), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: admin._key, + i18n, + }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + userKey: admin._key, + i18n, + }), + }, }, validators: { cleanseInput }, }, @@ -956,18 +984,22 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - userKey: admin._key, - i18n, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: admin._key, - i18n, - }), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: admin._key, + i18n, + }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + userKey: admin._key, + i18n, + }), + }, }, validators: { cleanseInput }, }, @@ -1061,18 +1093,22 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - userKey: admin._key, - i18n, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: admin._key, - i18n, - }), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: admin._key, + i18n, + }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + userKey: admin._key, + i18n, + }), + }, }, validators: { cleanseInput }, }, @@ -1161,12 +1197,16 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byKey: { + load: jest.fn(), + }, }, - loadUserByKey: { - load: jest.fn(), + organization: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, validators: { cleanseInput }, @@ -1242,14 +1282,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -1325,14 +1369,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -1408,12 +1456,16 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -1486,14 +1538,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -1565,14 +1621,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -1639,14 +1699,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -1718,14 +1782,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -1797,14 +1865,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -1880,12 +1952,16 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byKey: { + load: jest.fn(), + }, }, - loadUserByKey: { - load: jest.fn(), + organization: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, validators: { cleanseInput }, @@ -1961,14 +2037,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -2045,14 +2125,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -2129,12 +2213,16 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -2207,14 +2295,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -2287,14 +2379,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -2363,14 +2459,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -2444,14 +2544,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, @@ -2525,14 +2629,18 @@ describe('given the removeUserFromOrg mutation', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 12345 }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _key: 12345 }), + }, }, }, validators: { cleanseInput }, diff --git a/api/src/affiliation/mutations/__tests__/request-org-affiliation.test.js b/api/src/affiliation/mutations/__tests__/request-org-affiliation.test.js index 5016beaee0..4451c72c3c 100644 --- a/api/src/affiliation/mutations/__tests__/request-org-affiliation.test.js +++ b/api/src/affiliation/mutations/__tests__/request-org-affiliation.test.js @@ -196,10 +196,14 @@ describe('invite user to org', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendInviteRequestEmail: sendInviteRequestEmail }, validators: { cleanseInput }, @@ -353,15 +357,19 @@ describe('invite user to org', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - loadUserByKey: { - load: jest.fn(), + dataSources: { + user: { + byKey: { + load: jest.fn(), + }, }, - loadOrganizationNamesById: { - load: jest.fn(), + organization: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, + namesById: { + load: jest.fn(), + }, }, }, notify: { sendInviteRequestEmail: jest.fn() }, @@ -430,15 +438,19 @@ describe('invite user to org', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _id: org._id }), - }, - loadUserByKey: { - load: jest.fn(), + dataSources: { + user: { + byKey: { + load: jest.fn(), + }, }, - loadOrganizationNamesById: { - load: jest.fn(), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _id: org._id }), + }, + namesById: { + load: jest.fn(), + }, }, }, notify: { sendInviteRequestEmail: jest.fn() }, @@ -508,15 +520,19 @@ describe('invite user to org', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _id: org._id }), - }, - loadUserByKey: { - load: jest.fn(), + dataSources: { + user: { + byKey: { + load: jest.fn(), + }, }, - loadOrganizationNamesById: { - load: jest.fn(), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ _id: org._id }), + }, + namesById: { + load: jest.fn(), + }, }, }, notify: { sendInviteRequestEmail: jest.fn() }, @@ -584,10 +600,14 @@ describe('invite user to org', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), - loadUserByKey: loadUserByKey({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: i18n.locale }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendInviteRequestEmail: jest.fn() }, validators: { cleanseInput }, @@ -639,10 +659,14 @@ describe('invite user to org', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), - loadUserByKey: loadUserByKey({ query }), - loadOrganizationNamesById: loadOrganizationNamesById({ query }), + dataSources: { + user: { + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: i18n.locale }), + namesById: loadOrganizationNamesById({ query }), + }, }, notify: { sendInviteRequestEmail: jest.fn() }, validators: { cleanseInput }, diff --git a/api/src/affiliation/mutations/__tests__/transfer-org-ownership.test.js b/api/src/affiliation/mutations/__tests__/transfer-org-ownership.test.js index 72a42e05ff..0fa83d3985 100644 --- a/api/src/affiliation/mutations/__tests__/transfer-org-ownership.test.js +++ b/api/src/affiliation/mutations/__tests__/transfer-org-ownership.test.js @@ -185,14 +185,18 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), - loadUserByKey: loadUserByKey({ query, userKey: user._key, i18n }), + dataSources: { + user: { + byKey: loadUserByKey({ query, userKey: user._key, i18n }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: user._key, + }), + }, }, validators: { cleanseInput }, }, @@ -253,14 +257,18 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), - loadUserByKey: loadUserByKey({ query, userKey: user._key, i18n }), + dataSources: { + user: { + byKey: loadUserByKey({ query, userKey: user._key, i18n }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: user._key, + }), + }, }, validators: { cleanseInput }, }, @@ -334,18 +342,22 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: user._key, - i18n, - }), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: user._key, + i18n, + }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: user._key, + }), + }, }, validators: { cleanseInput }, }, @@ -428,18 +440,22 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: user._key, - i18n, - }), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: user._key, + i18n, + }), + }, + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: user._key, + }), + }, }, validators: { cleanseInput }, }, @@ -522,15 +538,19 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: user._key, + i18n, + }), + }, + organization: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, - loadUserByKey: loadUserByKey({ - query, - userKey: user._key, - i18n, - }), }, validators: { cleanseInput }, }, @@ -589,18 +609,22 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: user._key, + i18n, }), }, - loadUserByKey: loadUserByKey({ - query, - userKey: user._key, - i18n, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, + }, }, validators: { cleanseInput }, }, @@ -661,15 +685,19 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, }, }, validators: { cleanseInput }, @@ -731,17 +759,21 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, }, }, validators: { cleanseInput }, @@ -805,17 +837,21 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, }, }, validators: { cleanseInput }, @@ -878,17 +914,21 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, }, }, validators: { cleanseInput }, @@ -949,17 +989,21 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, }, }, validators: { cleanseInput }, @@ -1022,17 +1066,21 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, }, }, validators: { cleanseInput }, @@ -1105,15 +1153,19 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: user._key, + i18n, + }), + }, + organization: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, - loadUserByKey: loadUserByKey({ - query, - userKey: user._key, - i18n, - }), }, validators: { cleanseInput }, }, @@ -1172,18 +1224,22 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', + dataSources: { + user: { + byKey: loadUserByKey({ + query, + userKey: user._key, + i18n, }), }, - loadUserByKey: loadUserByKey({ - query, - userKey: user._key, - i18n, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, + }, }, validators: { cleanseInput }, }, @@ -1245,15 +1301,19 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, }, }, validators: { cleanseInput }, @@ -1315,17 +1375,21 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, }, }, validators: { cleanseInput }, @@ -1389,17 +1453,21 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, }, }, validators: { cleanseInput }, @@ -1464,17 +1532,21 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, }, }, validators: { cleanseInput }, @@ -1537,17 +1609,21 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, }, }, validators: { cleanseInput }, @@ -1612,17 +1688,21 @@ describe('given the transferOrgOwnership mutation', () => { }), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - slug: 'mocked-org', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + verified: false, + slug: 'mocked-org', + }), + }, }, }, validators: { cleanseInput }, diff --git a/api/src/affiliation/mutations/__tests__/update-user-role.test.js b/api/src/affiliation/mutations/__tests__/update-user-role.test.js index bac77c338d..bcc9d1a3c4 100644 --- a/api/src/affiliation/mutations/__tests__/update-user-role.test.js +++ b/api/src/affiliation/mutations/__tests__/update-user-role.test.js @@ -212,11 +212,15 @@ describe('update a users role', () => { tfaRequired: tfaRequired({ i18n }), }, notify: { sendRoleChangeEmail }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: { load: jest.fn().mockResolvedValue(orgNames) }, + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: { load: jest.fn().mockResolvedValue(orgNames) }, + }, }, validators: { cleanseInput, @@ -292,11 +296,15 @@ describe('update a users role', () => { tfaRequired: tfaRequired({ i18n }), }, notify: { sendRoleChangeEmail }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: { load: jest.fn().mockResolvedValue(orgNames) }, + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: { load: jest.fn().mockResolvedValue(orgNames) }, + }, }, validators: { cleanseInput, @@ -381,11 +389,15 @@ describe('update a users role', () => { tfaRequired: tfaRequired({ i18n }), }, notify: { sendRoleChangeEmail }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: { load: jest.fn().mockResolvedValue(orgNames) }, + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: { load: jest.fn().mockResolvedValue(orgNames) }, + }, }, validators: { cleanseInput, @@ -461,11 +473,15 @@ describe('update a users role', () => { tfaRequired: tfaRequired({ i18n }), }, notify: { sendRoleChangeEmail }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: { load: jest.fn().mockResolvedValue(orgNames) }, + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: { load: jest.fn().mockResolvedValue(orgNames) }, + }, }, validators: { cleanseInput, @@ -559,11 +575,15 @@ describe('update a users role', () => { tfaRequired: tfaRequired({ i18n }), }, notify: { sendRoleChangeEmail }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: { load: jest.fn().mockResolvedValue(orgNames) }, + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: { load: jest.fn().mockResolvedValue(orgNames) }, + }, }, validators: { cleanseInput, @@ -637,11 +657,15 @@ describe('update a users role', () => { tfaRequired: tfaRequired({ i18n }), }, notify: { sendRoleChangeEmail }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - loadOrganizationNamesById: { load: jest.fn().mockResolvedValue(orgNames) }, + dataSources: { + user: { + byUserName: loadUserByUserName({ query }), + byKey: loadUserByKey({ query }), + }, + organization: { + byKey: loadOrgByKey({ query, language: 'en' }), + namesById: { load: jest.fn().mockResolvedValue(orgNames) }, + }, }, validators: { cleanseInput, @@ -719,12 +743,16 @@ describe('update a users role', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn(), + dataSources: { + user: { + byUserName: { + load: jest.fn(), + }, }, - loadUserByUserName: { - load: jest.fn(), + organization: { + byKey: { + load: jest.fn(), + }, }, }, notify: { sendRoleChangeEmail }, @@ -791,12 +819,16 @@ describe('update a users role', () => { tfaRequired: jest.fn(), }, notify: { sendRoleChangeEmail }, - loaders: { - loadOrgByKey: { - load: jest.fn(), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue(undefined), + }, }, - loadUserByUserName: { - load: jest.fn().mockReturnValue(undefined), + organization: { + byKey: { + load: jest.fn(), + }, }, }, validators: { @@ -864,14 +896,18 @@ describe('update a users role', () => { tfaRequired: jest.fn(), }, notify: { sendRoleChangeEmail }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, validators: { @@ -938,16 +974,20 @@ describe('update a users role', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', + }), + }, }, }, notify: { sendRoleChangeEmail }, @@ -1016,16 +1056,20 @@ describe('update a users role', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', + }), + }, }, }, notify: { sendRoleChangeEmail }, @@ -1094,16 +1138,20 @@ describe('update a users role', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', + }), + }, }, }, notify: { sendRoleChangeEmail }, @@ -1175,16 +1223,20 @@ describe('update a users role', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', + }), + }, }, }, notify: { sendRoleChangeEmail }, @@ -1255,16 +1307,20 @@ describe('update a users role', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', + }), + }, }, }, notify: { sendRoleChangeEmail }, @@ -1328,16 +1384,20 @@ describe('update a users role', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', + }), + }, }, }, notify: { sendRoleChangeEmail }, @@ -1404,16 +1464,20 @@ describe('update a users role', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', + }), + }, }, }, notify: { sendRoleChangeEmail }, @@ -1479,16 +1543,20 @@ describe('update a users role', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 456, + }), + }, }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', + }), + }, }, }, notify: { sendRoleChangeEmail }, diff --git a/api/src/affiliation/mutations/invite-user-to-org.js b/api/src/affiliation/mutations/invite-user-to-org.js index aede988dc1..4bd7fdff7c 100644 --- a/api/src/affiliation/mutations/invite-user-to-org.js +++ b/api/src/affiliation/mutations/invite-user-to-org.js @@ -40,10 +40,14 @@ able to sign-up and be assigned to that organization in one mutation.`, i18n, request, userKey, - dataSources: { affiliation: affiliationDataSource, auditLogs: auditLogsDataSource }, + dataSources: { + affiliation: affiliationDataSource, + auditLogs: auditLogsDataSource, + user: userDataSource, + organization, + }, request: { ip }, auth: { checkPermission, tokenize, userRequired, verifiedRequired, tfaRequired }, - loaders: { loadOrgByKey, loadUserByUserName, loadOrganizationNamesById }, notify: { sendOrgInviteCreateAccount, sendOrgInviteEmail }, validators: { cleanseInput }, }, @@ -69,7 +73,7 @@ able to sign-up and be assigned to that organization in one mutation.`, } // Check to see if requested org exists - const org = await loadOrgByKey.load(orgId) + const org = await organization.byKey.load(orgId) if (typeof org === 'undefined') { console.warn( @@ -113,7 +117,7 @@ able to sign-up and be assigned to that organization in one mutation.`, // Get org names to use in email let orgNames try { - orgNames = await loadOrganizationNamesById.load(org._id) + orgNames = await organization.namesById.load(org._id) } catch (err) { console.error( `Error occurred when user: ${userKey} attempted to invite user: ${userName} to org: ${org._key}. Error while retrieving organization names. error: ${err}`, @@ -122,7 +126,7 @@ able to sign-up and be assigned to that organization in one mutation.`, } // Check to see if requested user exists - const requestedUser = await loadUserByUserName.load(userName) + const requestedUser = await userDataSource.byUserName.load(userName) // If there is not associated account with that username send invite to org with create account if (typeof requestedUser === 'undefined') { diff --git a/api/src/affiliation/mutations/leave-organization.js b/api/src/affiliation/mutations/leave-organization.js index 152854afef..3dea1a23ab 100644 --- a/api/src/affiliation/mutations/leave-organization.js +++ b/api/src/affiliation/mutations/leave-organization.js @@ -24,9 +24,8 @@ export const leaveOrganization = new mutationWithClientMutationId({ args, { i18n, - dataSources: { affiliation: affiliationDataSource }, + dataSources: { affiliation: affiliationDataSource, organization }, auth: { userRequired, verifiedRequired }, - loaders: { loadOrgByKey }, validators: { cleanseInput }, }, ) => { @@ -36,7 +35,7 @@ export const leaveOrganization = new mutationWithClientMutationId({ verifiedRequired({ user }) - const org = await loadOrgByKey.load(orgKey) + const org = await organization.byKey.load(orgKey) if (typeof org === 'undefined') { console.warn(`User ${user._key} attempted to leave undefined organization: ${orgKey}`) diff --git a/api/src/affiliation/mutations/remove-user-from-org.js b/api/src/affiliation/mutations/remove-user-from-org.js index 909399f5be..ca0286f807 100644 --- a/api/src/affiliation/mutations/remove-user-from-org.js +++ b/api/src/affiliation/mutations/remove-user-from-org.js @@ -31,10 +31,14 @@ export const removeUserFromOrg = new mutationWithClientMutationId({ { i18n, userKey, - dataSources: { affiliation: affiliationDataSource, auditLogs: auditLogsDataSource }, + dataSources: { + affiliation: affiliationDataSource, + auditLogs: auditLogsDataSource, + user: userDataSource, + organization, + }, request: { ip }, auth: { checkPermission, userRequired, verifiedRequired, tfaRequired }, - loaders: { loadOrgByKey, loadUserByKey }, validators: { cleanseInput }, }, ) => { @@ -49,7 +53,7 @@ export const removeUserFromOrg = new mutationWithClientMutationId({ tfaRequired({ user }) // Get requested org - const requestedOrg = await loadOrgByKey.load(requestedOrgKey) + const requestedOrg = await organization.byKey.load(requestedOrgKey) if (typeof requestedOrg === 'undefined') { console.warn( `User: ${userKey} attempted to remove user: ${requestedUserKey} from org: ${requestedOrgKey}, however no org with that id could be found.`, @@ -65,7 +69,7 @@ export const removeUserFromOrg = new mutationWithClientMutationId({ const permission = await checkPermission({ orgId: requestedOrg._id }) // Get requested user - const requestedUser = await loadUserByKey.load(requestedUserKey) + const requestedUser = await userDataSource.byKey.load(requestedUserKey) if (typeof requestedUser === 'undefined') { console.warn( `User: ${userKey} attempted to remove user: ${requestedUserKey} from org: ${requestedOrg._key}, however no user with that id could be found.`, diff --git a/api/src/affiliation/mutations/request-org-affiliation.js b/api/src/affiliation/mutations/request-org-affiliation.js index e4564aefb1..7ee22a040d 100644 --- a/api/src/affiliation/mutations/request-org-affiliation.js +++ b/api/src/affiliation/mutations/request-org-affiliation.js @@ -29,10 +29,14 @@ export const requestOrgAffiliation = new mutationWithClientMutationId({ i18n, request, userKey, - dataSources: { affiliation: affiliationDataSource, auditLogs: auditLogsDataSource }, + dataSources: { + affiliation: affiliationDataSource, + auditLogs: auditLogsDataSource, + user: userDataSource, + organization, + }, request: { ip }, auth: { userRequired, verifiedRequired }, - loaders: { loadOrgByKey, loadUserByKey, loadOrganizationNamesById }, notify: { sendInviteRequestEmail }, validators: { cleanseInput }, }, @@ -44,7 +48,7 @@ export const requestOrgAffiliation = new mutationWithClientMutationId({ verifiedRequired({ user }) // Check to see if requested org exists - const org = await loadOrgByKey.load(orgId) + const org = await organization.byKey.load(orgId) if (typeof org === 'undefined') { console.warn( @@ -131,7 +135,7 @@ export const requestOrgAffiliation = new mutationWithClientMutationId({ // Get org names to use in email let orgNames try { - orgNames = await loadOrganizationNamesById.load(org._id) + orgNames = await organization.namesById.load(org._id) } catch (err) { console.error( `Error occurred when user: ${userKey} attempted to request invite to org: ${org._key}. Error while retrieving organization names. error: ${err}`, @@ -148,7 +152,7 @@ export const requestOrgAffiliation = new mutationWithClientMutationId({ displayName: 'Service Account', _key: 'service-account', } - } else adminUser = await loadUserByKey.load(userKey) + } else adminUser = await userDataSource.byKey.load(userKey) await sendInviteRequestEmail({ user: adminUser, diff --git a/api/src/affiliation/mutations/transfer-org-ownership.js b/api/src/affiliation/mutations/transfer-org-ownership.js index d4ae317a38..b7f6d8fbad 100644 --- a/api/src/affiliation/mutations/transfer-org-ownership.js +++ b/api/src/affiliation/mutations/transfer-org-ownership.js @@ -29,9 +29,8 @@ export const transferOrgOwnership = new mutationWithClientMutationId({ args, { i18n, - dataSources: { affiliation: affiliationDataSource }, + dataSources: { affiliation: affiliationDataSource, user: userDataSource, organization }, auth: { checkOrgOwner, userRequired, verifiedRequired }, - loaders: { loadOrgByKey, loadUserByKey }, validators: { cleanseInput }, }, ) => { @@ -46,7 +45,7 @@ export const transferOrgOwnership = new mutationWithClientMutationId({ verifiedRequired({ user: requestingUser }) // load the requested org - const org = await loadOrgByKey.load(orgKey) + const org = await organization.byKey.load(orgKey) // ensure requested org is not undefined if (typeof org === 'undefined') { @@ -74,7 +73,7 @@ export const transferOrgOwnership = new mutationWithClientMutationId({ } // get the user that is org ownership is being transferred to - const requestedUser = await loadUserByKey.load(userTransferKey) + const requestedUser = await userDataSource.byKey.load(userTransferKey) // check to ensure requested user is not undefined if (typeof requestedUser === 'undefined') { diff --git a/api/src/affiliation/mutations/update-user-role.js b/api/src/affiliation/mutations/update-user-role.js index 1660b990f7..28ef5dbe98 100644 --- a/api/src/affiliation/mutations/update-user-role.js +++ b/api/src/affiliation/mutations/update-user-role.js @@ -38,10 +38,14 @@ given organization.`, { i18n, userKey, - dataSources: { affiliation: affiliationDataSource, auditLogs: auditLogsDataSource }, + dataSources: { + affiliation: affiliationDataSource, + auditLogs: auditLogsDataSource, + user: userDataSource, + organization, + }, request: { ip }, auth: { checkPermission, userRequired, verifiedRequired, tfaRequired }, - loaders: { loadOrgByKey, loadUserByUserName, loadOrganizationNamesById }, validators: { cleanseInput }, notify: { sendRoleChangeEmail }, }, @@ -68,7 +72,7 @@ given organization.`, } // Check to see if requested user exists - const requestedUser = await loadUserByUserName.load(userName) + const requestedUser = await userDataSource.byUserName.load(userName) if (typeof requestedUser === 'undefined') { console.warn( @@ -82,7 +86,7 @@ given organization.`, } // Check to see if org exists - const org = await loadOrgByKey.load(orgId) + const org = await organization.byKey.load(orgId) if (typeof org === 'undefined') { console.warn( @@ -178,7 +182,7 @@ given organization.`, // Get org names to use in email let orgNames try { - orgNames = await loadOrganizationNamesById.load(org._id) + orgNames = await organization.namesById.load(org._id) } catch (err) { console.error( `Error occurred when user: ${userKey} attempted to update a user's: ${userName} role. Error while retrieving organization names. error: ${err}`, diff --git a/api/src/affiliation/objects/__tests__/affiliation.test.js b/api/src/affiliation/objects/__tests__/affiliation.test.js index ea7daa0d19..ccfb08bb35 100644 --- a/api/src/affiliation/objects/__tests__/affiliation.test.js +++ b/api/src/affiliation/objects/__tests__/affiliation.test.js @@ -70,9 +70,11 @@ describe('given the user affiliation object', () => { { _to: 'users/1' }, {}, { - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue(expectedResult), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue(expectedResult), + }, }, }, }, @@ -119,9 +121,11 @@ describe('given the user affiliation object', () => { { _from: '1' }, {}, { - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(expectedResult), + dataSources: { + organization: { + byKey: { + load: jest.fn().mockReturnValue(expectedResult), + }, }, }, }, diff --git a/api/src/affiliation/objects/affiliation.js b/api/src/affiliation/objects/affiliation.js index e1b0f34f6c..c4d92c76b1 100644 --- a/api/src/affiliation/objects/affiliation.js +++ b/api/src/affiliation/objects/affiliation.js @@ -18,9 +18,9 @@ export const affiliationType = new GraphQLObjectType({ user: { type: userSharedType, description: 'The affiliated users information.', - resolve: async ({_to}, _args, {loaders: {loadUserByKey}}) => { + resolve: async ({_to}, _args, {dataSources: {user: userDataSource}}) => { const userKey = _to.split('/')[1] - const user = await loadUserByKey.load(userKey) + const user = await userDataSource.byKey.load(userKey) user.id = user._key return user }, @@ -28,9 +28,9 @@ export const affiliationType = new GraphQLObjectType({ organization: { type: organizationType, description: 'The affiliated organizations information.', - resolve: async ({_from}, _args, {loaders: {loadOrgByKey}}) => { + resolve: async ({_from}, _args, {dataSources: {organization}}) => { const orgKey = _from.split('/')[1] - const org = await loadOrgByKey.load(orgKey) + const org = await organization.byKey.load(orgKey) org.id = org._key return org }, diff --git a/api/src/audit-logs/objects/target-resource.js b/api/src/audit-logs/objects/target-resource.js index e89b43b328..791e7c7219 100644 --- a/api/src/audit-logs/objects/target-resource.js +++ b/api/src/audit-logs/objects/target-resource.js @@ -25,8 +25,8 @@ export const targetResourceType = new GraphQLObjectType({ name: { type: GraphQLString, description: 'Name of the affiliated organization.', - resolve: async ({ id, name }, _, { loaders: { loadOrgByKey } }) => { - const org = await loadOrgByKey.load(id) + resolve: async ({ id, name }, _, { dataSources: { organization } }) => { + const org = await organization.byKey.load(id) if (typeof org === 'undefined') { return name } diff --git a/api/src/audit-logs/queries/find-audit-logs.js b/api/src/audit-logs/queries/find-audit-logs.js index b10186c116..6fb9598211 100644 --- a/api/src/audit-logs/queries/find-audit-logs.js +++ b/api/src/audit-logs/queries/find-audit-logs.js @@ -35,8 +35,7 @@ export const findAuditLogs = { userKey, i18n, auth: { checkPermission, userRequired, verifiedRequired }, - loaders: { loadOrgByKey }, - dataSources: { auditLogs }, + dataSources: { auditLogs, organization }, validators: { cleanseInput }, }, ) => { @@ -45,7 +44,7 @@ export const findAuditLogs = { const { type: _orgType, id: orgId } = fromGlobalId(cleanseInput(args.orgId)) // Get Org from db - const org = await loadOrgByKey.load(orgId) + const org = await organization.byKey.load(orgId) // Check to see if user belongs to org const permission = await checkPermission({ orgId: org?._id }) diff --git a/api/src/create-context.js b/api/src/create-context.js index 4f66bc71cc..cbedc2eba9 100644 --- a/api/src/create-context.js +++ b/api/src/create-context.js @@ -4,9 +4,7 @@ import fetch from 'isomorphic-fetch' import { v4 as uuidv4 } from 'uuid' import jwt from 'jsonwebtoken' -import { loadUserByKey } from './user/loaders' import { cleanseInput, decryptPhoneNumber, slugify } from './validators' -import { initializeLoaders } from './initialize-loaders' import { SummariesDataSource } from './summaries' import { DnsScanDataSource } from './dns-scan' import { WebScanDataSource } from './web-scan' @@ -17,6 +15,8 @@ import { OrganizationDataSource } from './organization' import { TagsDataSource } from './tags' import { DomainDataSource } from './domain' import { AffiliationDataSource } from './affiliation' +import { UserDataSource } from './user' +import { DmarcSummariesDataSource } from './dmarc-summaries' import { AuthDataSource, checkDomainOwnership, @@ -71,6 +71,16 @@ export async function createContext({ userKey = 'NO_USER' } + const userDataSource = new UserDataSource({ + query, + userKey, + i18n, + language: request.language, + cleanseInput, + transaction, + collections, + }) + return { query, db, @@ -117,7 +127,7 @@ export async function createContext({ userRequired: userRequired({ i18n, userKey, - loadUserByKey: loadUserByKey({ query, userKey, i18n }), + loadUserByKey: userDataSource.byKey, }), verifiedRequired: verifiedRequired({ i18n }), verifyToken: verifyToken({ i18n }), @@ -182,15 +192,8 @@ export async function createContext({ transaction, collections, }), + user: userDataSource, + dmarcSummaries: new DmarcSummariesDataSource({ query, userKey, i18n, cleanseInput, moment, loginRequiredBool }), }, - loaders: initializeLoaders({ - query, - userKey, - i18n, - language: request.language, - cleanseInput, - loginRequiredBool, - moment, - }), } } diff --git a/api/src/dmarc-summaries/data-source.js b/api/src/dmarc-summaries/data-source.js new file mode 100644 index 0000000000..ab93aaad6c --- /dev/null +++ b/api/src/dmarc-summaries/data-source.js @@ -0,0 +1,34 @@ +import { + loadAllVerifiedRuaDomains, + loadDkimFailConnectionsBySumId, + loadDmarcFailConnectionsBySumId, + loadDmarcSummaryByKey, + loadDmarcSummaryConnectionsByUserId, + loadDmarcSummaryEdgeByDomainIdAndPeriod, + loadDmarcYearlySumEdge, + loadFullPassConnectionsBySumId, + loadSpfFailureConnectionsBySumId, + loadStartDateFromPeriod, +} from './loaders' + +export class DmarcSummariesDataSource { + constructor({ query, userKey, i18n, cleanseInput, moment, loginRequiredBool }) { + this.byKey = loadDmarcSummaryByKey({ query, userKey, i18n }) + this.startDateFromPeriod = loadStartDateFromPeriod({ moment, userKey, i18n }) + this.summaryEdgeByDomainIdAndPeriod = loadDmarcSummaryEdgeByDomainIdAndPeriod({ query, userKey, i18n }) + this.yearlySumEdges = loadDmarcYearlySumEdge({ query, userKey, i18n }) + this.connectionsByUserId = loadDmarcSummaryConnectionsByUserId({ + query, + userKey, + cleanseInput, + i18n, + auth: { loginRequiredBool }, + loadStartDateFromPeriod: this.startDateFromPeriod, + }) + this.dkimFailConnectionsBySumId = loadDkimFailConnectionsBySumId({ query, userKey, cleanseInput, i18n }) + this.dmarcFailConnectionsBySumId = loadDmarcFailConnectionsBySumId({ query, userKey, cleanseInput, i18n }) + this.fullPassConnectionsBySumId = loadFullPassConnectionsBySumId({ query, userKey, cleanseInput, i18n }) + this.spfFailureConnectionsBySumId = loadSpfFailureConnectionsBySumId({ query, userKey, cleanseInput, i18n }) + this.allVerifiedRuaDomains = loadAllVerifiedRuaDomains({ query, userKey, i18n }) + } +} diff --git a/api/src/dmarc-summaries/index.js b/api/src/dmarc-summaries/index.js index 7dab4e57a0..984784a815 100644 --- a/api/src/dmarc-summaries/index.js +++ b/api/src/dmarc-summaries/index.js @@ -1,3 +1,4 @@ +export * from './data-source' export * from './loaders' export * from './objects' export * from './queries' diff --git a/api/src/dmarc-summaries/objects/__tests__/detail-tables.test.js b/api/src/dmarc-summaries/objects/__tests__/detail-tables.test.js index 36b1ea5de2..63a2c47459 100644 --- a/api/src/dmarc-summaries/objects/__tests__/detail-tables.test.js +++ b/api/src/dmarc-summaries/objects/__tests__/detail-tables.test.js @@ -80,10 +80,12 @@ describe('testing the detailTables gql object', () => { { _id: '1' }, { first: 1 }, { - loaders: { - loadDkimFailConnectionsBySumId: jest - .fn() - .mockReturnValue(expectedResult), + dataSources: { + dmarcSummaries: { + dkimFailConnectionsBySumId: jest + .fn() + .mockReturnValue(expectedResult), + }, }, }, ), @@ -127,10 +129,12 @@ describe('testing the detailTables gql object', () => { { _id: '1' }, { first: 1 }, { - loaders: { - loadDmarcFailConnectionsBySumId: jest - .fn() - .mockReturnValue(expectedResult), + dataSources: { + dmarcSummaries: { + dmarcFailConnectionsBySumId: jest + .fn() + .mockReturnValue(expectedResult), + }, }, }, ), @@ -173,10 +177,12 @@ describe('testing the detailTables gql object', () => { { _id: '1' }, { first: 1 }, { - loaders: { - loadFullPassConnectionsBySumId: jest - .fn() - .mockReturnValue(expectedResult), + dataSources: { + dmarcSummaries: { + fullPassConnectionsBySumId: jest + .fn() + .mockReturnValue(expectedResult), + }, }, }, ), @@ -220,10 +226,12 @@ describe('testing the detailTables gql object', () => { { _id: '1' }, { first: 1 }, { - loaders: { - loadSpfFailureConnectionsBySumId: jest - .fn() - .mockReturnValue(expectedResult), + dataSources: { + dmarcSummaries: { + spfFailureConnectionsBySumId: jest + .fn() + .mockReturnValue(expectedResult), + }, }, }, ), diff --git a/api/src/dmarc-summaries/objects/__tests__/dmarc-summary.test.js b/api/src/dmarc-summaries/objects/__tests__/dmarc-summary.test.js index 16a781d3ab..18d232fb99 100644 --- a/api/src/dmarc-summaries/objects/__tests__/dmarc-summary.test.js +++ b/api/src/dmarc-summaries/objects/__tests__/dmarc-summary.test.js @@ -158,9 +158,11 @@ describe('testing the period gql object', () => { { _id: '1' }, {}, { - loaders: { - loadDmarcSummaryByKey: { - load: jest.fn().mockReturnValue(expectedResult), + dataSources: { + dmarcSummaries: { + byKey: { + load: jest.fn().mockReturnValue(expectedResult), + }, }, }, }, @@ -189,9 +191,11 @@ describe('testing the period gql object', () => { { _id: 'something/1' }, {}, { - loaders: { - loadDmarcSummaryByKey: { - load: jest.fn().mockReturnValue(expectedResult), + dataSources: { + dmarcSummaries: { + byKey: { + load: jest.fn().mockReturnValue(expectedResult), + }, }, }, }, diff --git a/api/src/dmarc-summaries/objects/detail-tables.js b/api/src/dmarc-summaries/objects/detail-tables.js index c4ae345aaf..31ee900d28 100644 --- a/api/src/dmarc-summaries/objects/detail-tables.js +++ b/api/src/dmarc-summaries/objects/detail-tables.js @@ -18,9 +18,9 @@ export const detailTablesType = new GraphQLObjectType({ resolve: async ( { _id }, args, - { loaders: { loadDkimFailConnectionsBySumId } }, + { dataSources: { dmarcSummaries: dmarcSummariesDataSource } }, ) => { - const dkimFailures = await loadDkimFailConnectionsBySumId({ + const dkimFailures = await dmarcSummariesDataSource.dkimFailConnectionsBySumId({ summaryId: _id, ...args, }) @@ -35,9 +35,9 @@ export const detailTablesType = new GraphQLObjectType({ resolve: async ( { _id }, args, - { loaders: { loadDmarcFailConnectionsBySumId } }, + { dataSources: { dmarcSummaries: dmarcSummariesDataSource } }, ) => { - const dmarcFailures = await loadDmarcFailConnectionsBySumId({ + const dmarcFailures = await dmarcSummariesDataSource.dmarcFailConnectionsBySumId({ summaryId: _id, ...args, }) @@ -52,9 +52,9 @@ export const detailTablesType = new GraphQLObjectType({ resolve: async ( { _id }, args, - { loaders: { loadFullPassConnectionsBySumId } }, + { dataSources: { dmarcSummaries: dmarcSummariesDataSource } }, ) => { - const fullPasses = await loadFullPassConnectionsBySumId({ + const fullPasses = await dmarcSummariesDataSource.fullPassConnectionsBySumId({ summaryId: _id, ...args, }) @@ -69,9 +69,9 @@ export const detailTablesType = new GraphQLObjectType({ resolve: async ( { _id }, args, - { loaders: { loadSpfFailureConnectionsBySumId } }, + { dataSources: { dmarcSummaries: dmarcSummariesDataSource } }, ) => { - const spfFailures = await loadSpfFailureConnectionsBySumId({ + const spfFailures = await dmarcSummariesDataSource.spfFailureConnectionsBySumId({ summaryId: _id, ...args, }) diff --git a/api/src/dmarc-summaries/objects/dmarc-summary.js b/api/src/dmarc-summaries/objects/dmarc-summary.js index 2da1e62316..f335c60ff8 100644 --- a/api/src/dmarc-summaries/objects/dmarc-summary.js +++ b/api/src/dmarc-summaries/objects/dmarc-summary.js @@ -55,9 +55,9 @@ export const dmarcSummaryType = new GraphQLObjectType({ categoryPercentages: { type: categoryPercentagesType, description: 'Category percentages based on the category totals.', - resolve: async ({ _id }, _, { loaders: { loadDmarcSummaryByKey } }) => { + resolve: async ({ _id }, _, { dataSources: { dmarcSummaries: dmarcSummariesDataSource } }) => { const dmarcSummaryKey = _id.split('/')[1] - const dmarcSummary = await loadDmarcSummaryByKey.load(dmarcSummaryKey) + const dmarcSummary = await dmarcSummariesDataSource.byKey.load(dmarcSummaryKey) return { totalMessages: dmarcSummary.totalMessages, ...dmarcSummary.categoryPercentages, @@ -67,9 +67,9 @@ export const dmarcSummaryType = new GraphQLObjectType({ categoryTotals: { type: categoryTotalsType, description: 'Category totals for quick viewing.', - resolve: async ({ _id }, _, { loaders: { loadDmarcSummaryByKey } }) => { + resolve: async ({ _id }, _, { dataSources: { dmarcSummaries: dmarcSummariesDataSource } }) => { const dmarcSummaryKey = _id.split('/')[1] - const dmarcSummary = await loadDmarcSummaryByKey.load(dmarcSummaryKey) + const dmarcSummary = await dmarcSummariesDataSource.byKey.load(dmarcSummaryKey) return dmarcSummary.categoryTotals }, }, diff --git a/api/src/dmarc-summaries/queries/__tests__/find-my-dmarc-summaries.test.js b/api/src/dmarc-summaries/queries/__tests__/find-my-dmarc-summaries.test.js index 9c837bbe8a..11abcbd851 100644 --- a/api/src/dmarc-summaries/queries/__tests__/find-my-dmarc-summaries.test.js +++ b/api/src/dmarc-summaries/queries/__tests__/find-my-dmarc-summaries.test.js @@ -192,15 +192,17 @@ describe('given the findMyDmarcSummaries query', () => { }), verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadDmarcSummaryConnectionsByUserId: loadDmarcSummaryConnectionsByUserId({ - query, - userKey: user._key, - cleanseInput, - auth: { loginRequired: true }, - i18n, - loadStartDateFromPeriod: mockedStartDateLoader, - }), + dataSources: { + dmarcSummaries: { + connectionsByUserId: loadDmarcSummaryConnectionsByUserId({ + query, + userKey: user._key, + cleanseInput, + auth: { loginRequired: true }, + i18n, + loadStartDateFromPeriod: mockedStartDateLoader, + }), + }, }, }, }) @@ -291,8 +293,8 @@ describe('given the findMyDmarcSummaries query', () => { verifiedRequired: verifiedRequired({ i18n }), loginRequiredBool: true, }, - loaders: { - loadDmarcSummaryConnectionsByUserId: jest.fn(), + dataSources: { + dmarcSummaries: { connectionsByUserId: jest.fn() }, }, }, }) @@ -337,15 +339,17 @@ describe('given the findMyDmarcSummaries query', () => { userRequired: jest.fn().mockReturnValue({}), verifiedRequired: jest.fn(), }, - loaders: { - loadDmarcSummaryConnectionsByUserId: loadDmarcSummaryConnectionsByUserId({ - query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), - userKey: user._key, - cleanseInput, - auth: { loginRequired: true }, - i18n, - loadStartDateFromPeriod: jest.fn(), - }), + dataSources: { + dmarcSummaries: { + connectionsByUserId: loadDmarcSummaryConnectionsByUserId({ + query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), + userKey: user._key, + cleanseInput, + auth: { loginRequired: true }, + i18n, + loadStartDateFromPeriod: jest.fn(), + }), + }, }, }, }) @@ -415,8 +419,8 @@ describe('given the findMyDmarcSummaries query', () => { loginRequiredBool: true, verifiedRequired: verifiedRequired({ i18n }), }, - loaders: { - loadDmarcSummaryConnectionsByUserId: jest.fn(), + dataSources: { + dmarcSummaries: { connectionsByUserId: jest.fn() }, }, }, }) @@ -461,15 +465,17 @@ describe('given the findMyDmarcSummaries query', () => { userRequired: jest.fn().mockReturnValue({}), verifiedRequired: jest.fn(), }, - loaders: { - loadDmarcSummaryConnectionsByUserId: loadDmarcSummaryConnectionsByUserId({ - query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), - userKey: user._key, - cleanseInput, - auth: { loginRequired: true }, - i18n, - loadStartDateFromPeriod: jest.fn(), - }), + dataSources: { + dmarcSummaries: { + connectionsByUserId: loadDmarcSummaryConnectionsByUserId({ + query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), + userKey: user._key, + cleanseInput, + auth: { loginRequired: true }, + i18n, + loadStartDateFromPeriod: jest.fn(), + }), + }, }, }, }) diff --git a/api/src/dmarc-summaries/queries/__tests__/get-all-verified-rua-domains.test.js b/api/src/dmarc-summaries/queries/__tests__/get-all-verified-rua-domains.test.js index 6633df0663..23330c9409 100644 --- a/api/src/dmarc-summaries/queries/__tests__/get-all-verified-rua-domains.test.js +++ b/api/src/dmarc-summaries/queries/__tests__/get-all-verified-rua-domains.test.js @@ -19,8 +19,10 @@ describe('getAllVerifiedRuaDomains', () => { verifiedRequired: mockVerifiedRequired, superAdminRequired: mockSuperAdminRequired, }, - loaders: { - loadAllVerifiedRuaDomains: mockLoadAllVerifiedRuaDomains, + dataSources: { + dmarcSummaries: { + allVerifiedRuaDomains: mockLoadAllVerifiedRuaDomains, + }, }, }, ) diff --git a/api/src/dmarc-summaries/queries/find-my-dmarc-summaries.js b/api/src/dmarc-summaries/queries/find-my-dmarc-summaries.js index cda2e995ae..900dac1b61 100644 --- a/api/src/dmarc-summaries/queries/find-my-dmarc-summaries.js +++ b/api/src/dmarc-summaries/queries/find-my-dmarc-summaries.js @@ -38,7 +38,7 @@ export const findMyDmarcSummaries = { { userKey, auth: { checkSuperAdmin, userRequired, verifiedRequired }, - loaders: { loadDmarcSummaryConnectionsByUserId }, + dataSources: { dmarcSummaries: dmarcSummariesDataSource }, }, ) => { const user = await userRequired() @@ -46,7 +46,7 @@ export const findMyDmarcSummaries = { const isSuperAdmin = await checkSuperAdmin() - const dmarcSummaries = await loadDmarcSummaryConnectionsByUserId({ + const dmarcSummaries = await dmarcSummariesDataSource.connectionsByUserId({ period: args.month, isSuperAdmin, ...args, diff --git a/api/src/dmarc-summaries/queries/get-all-verified-rua-domains.js b/api/src/dmarc-summaries/queries/get-all-verified-rua-domains.js index 1107d43c83..bf9a6bb3b2 100644 --- a/api/src/dmarc-summaries/queries/get-all-verified-rua-domains.js +++ b/api/src/dmarc-summaries/queries/get-all-verified-rua-domains.js @@ -9,7 +9,7 @@ export const getAllVerifiedRuaDomains = { { userKey, auth: { checkSuperAdmin, userRequired, verifiedRequired, superAdminRequired }, - loaders: { loadAllVerifiedRuaDomains }, + dataSources: { dmarcSummaries: dmarcSummariesDataSource }, }, ) => { const user = await userRequired() @@ -18,7 +18,7 @@ export const getAllVerifiedRuaDomains = { const isSuperAdmin = await checkSuperAdmin() superAdminRequired({ user, isSuperAdmin }) - const ruaDomains = await loadAllVerifiedRuaDomains({ ...args }) + const ruaDomains = await dmarcSummariesDataSource.allVerifiedRuaDomains({ ...args }) console.info(`User ${userKey} successfully retrieved all domains with DMARC reports.`) diff --git a/api/src/domain/objects/__tests__/domain.test.js b/api/src/domain/objects/__tests__/domain.test.js index 9e4f32ca8b..2cb8442af3 100644 --- a/api/src/domain/objects/__tests__/domain.test.js +++ b/api/src/domain/objects/__tests__/domain.test.js @@ -388,11 +388,13 @@ describe('given the domain object', () => { }, { userKey: '1', - loaders: { - loadDmarcSummaryEdgeByDomainIdAndPeriod: jest.fn().mockReturnValue({ - _to: 'dmarcSummaries/1', - }), - loadStartDateFromPeriod: jest.fn().mockReturnValue('2021-01-01'), + dataSources: { + dmarcSummaries: { + summaryEdgeByDomainIdAndPeriod: jest.fn().mockReturnValue({ + _to: 'dmarcSummaries/1', + }), + startDateFromPeriod: jest.fn().mockReturnValue('2021-01-01'), + }, }, auth: { checkDomainOwnership: jest.fn().mockReturnValue(true), @@ -440,9 +442,11 @@ describe('given the domain object', () => { { i18n, userKey: '1', - loaders: { - loadDmarcSummaryEdgeByDomainIdAndPeriod: jest.fn(), - loadStartDateFromPeriod: jest.fn().mockReturnValue('2021-01-01'), + dataSources: { + dmarcSummaries: { + summaryEdgeByDomainIdAndPeriod: jest.fn(), + startDateFromPeriod: jest.fn().mockReturnValue('2021-01-01'), + }, }, auth: { checkDomainOwnership: jest.fn().mockReturnValue(false), @@ -491,9 +495,11 @@ describe('given the domain object', () => { { i18n, userKey: '1', - loaders: { - loadDmarcSummaryEdgeByDomainIdAndPeriod: jest.fn(), - loadStartDateFromPeriod: jest.fn().mockReturnValue('2021-01-01'), + dataSources: { + dmarcSummaries: { + summaryEdgeByDomainIdAndPeriod: jest.fn(), + startDateFromPeriod: jest.fn().mockReturnValue('2021-01-01'), + }, }, auth: { checkDomainOwnership: jest.fn().mockReturnValue(false), @@ -528,14 +534,16 @@ describe('given the domain object', () => { {}, { userKey: '1', - loaders: { - loadDmarcYearlySumEdge: jest.fn().mockReturnValue([ - { - domainKey: '1', - _to: 'dmarcSummaries/1', - startDate: '2021-01-01', - }, - ]), + dataSources: { + dmarcSummaries: { + yearlySumEdges: jest.fn().mockReturnValue([ + { + domainKey: '1', + _to: 'dmarcSummaries/1', + startDate: '2021-01-01', + }, + ]), + }, }, auth: { checkDomainOwnership: jest.fn().mockReturnValue(true), @@ -587,8 +595,10 @@ describe('given the domain object', () => { language: 'fr', }, userKey: '1', - loaders: { - loadDmarcYearlySumEdge: jest.fn(), + dataSources: { + dmarcSummaries: { + yearlySumEdges: jest.fn(), + }, }, auth: { checkDomainOwnership: jest.fn().mockReturnValue(false), @@ -636,8 +646,10 @@ describe('given the domain object', () => { { i18n, userKey: '1', - loaders: { - loadDmarcYearlySumEdge: jest.fn(), + dataSources: { + dmarcSummaries: { + yearlySumEdges: jest.fn(), + }, }, auth: { checkDomainOwnership: jest.fn().mockReturnValue(false), diff --git a/api/src/domain/objects/domain.js b/api/src/domain/objects/domain.js index 4bc535174a..81e1a868d2 100644 --- a/api/src/domain/objects/domain.js +++ b/api/src/domain/objects/domain.js @@ -258,7 +258,7 @@ export const domainType = new GraphQLObjectType({ { i18n, userKey, - loaders: { loadDmarcSummaryEdgeByDomainIdAndPeriod, loadStartDateFromPeriod }, + dataSources: { dmarcSummaries: dmarcSummariesDataSource }, auth: { checkDomainOwnership, userRequired }, }, ) => { @@ -274,9 +274,9 @@ export const domainType = new GraphQLObjectType({ throw new Error(i18n._(t`Unable to retrieve DMARC report information for: ${domain}`)) } - const startDate = loadStartDateFromPeriod({ period: month, year }) + const startDate = dmarcSummariesDataSource.startDateFromPeriod({ period: month, year }) - const dmarcSummaryEdge = await loadDmarcSummaryEdgeByDomainIdAndPeriod({ + const dmarcSummaryEdge = await dmarcSummariesDataSource.summaryEdgeByDomainIdAndPeriod({ domainId: _id, startDate, }) @@ -294,7 +294,12 @@ export const domainType = new GraphQLObjectType({ resolve: async ( { _id, _key, domain }, __, - { i18n, userKey, loaders: { loadDmarcYearlySumEdge }, auth: { checkDomainOwnership, userRequired } }, + { + i18n, + userKey, + dataSources: { dmarcSummaries: dmarcSummariesDataSource }, + auth: { checkDomainOwnership, userRequired }, + }, ) => { await userRequired() @@ -309,7 +314,7 @@ export const domainType = new GraphQLObjectType({ throw new Error(i18n._(t`Unable to retrieve DMARC report information for: ${domain}`)) } - const dmarcSummaryEdges = await loadDmarcYearlySumEdge({ + const dmarcSummaryEdges = await dmarcSummariesDataSource.yearlySumEdges({ domainId: _id, }) diff --git a/api/src/enums/index.js b/api/src/enums/index.js index 89c87f1dad..317f4a933b 100644 --- a/api/src/enums/index.js +++ b/api/src/enums/index.js @@ -28,8 +28,6 @@ export * from './spf-order-field' export * from './ssl-order-field' export * from './status' export * from './tfa-send-method' -export * from './verified-domain-order-field' -export * from './verified-organization-order-field' export * from './web-order-field' export * from './tag-ownership' export * from './system-filter-value' diff --git a/api/src/enums/verified-domain-order-field.js b/api/src/enums/verified-domain-order-field.js deleted file mode 100644 index a0bcc20d2c..0000000000 --- a/api/src/enums/verified-domain-order-field.js +++ /dev/null @@ -1,37 +0,0 @@ -import {GraphQLEnumType} from 'graphql' - -export const VerifiedDomainOrderField = new GraphQLEnumType({ - name: 'VerifiedDomainOrderField', - description: - 'Properties by which verified domain connections can be ordered.', - values: { - DOMAIN: { - value: 'domain', - description: 'Order verified domain edges by domain.', - }, - LAST_RAN: { - value: 'last-ran', - description: 'Order verified domain edges by last ran.', - }, - DKIM_STATUS: { - value: 'dkim-status', - description: 'Order verified domain edges by dkim status.', - }, - DMARC_STATUS: { - value: 'dmarc-status', - description: 'Order verified domain edges by dmarc status.', - }, - HTTPS_STATUS: { - value: 'https-status', - description: 'Order verified domain edges by https status.', - }, - SPF_STATUS: { - value: 'spf-status', - description: 'Order verified domain edges by spf status.', - }, - SSL_STATUS: { - value: 'ssl-status', - description: 'Order verified domain edges by ssl status.', - }, - }, -}) diff --git a/api/src/enums/verified-organization-order-field.js b/api/src/enums/verified-organization-order-field.js deleted file mode 100644 index d358e64834..0000000000 --- a/api/src/enums/verified-organization-order-field.js +++ /dev/null @@ -1,57 +0,0 @@ -import {GraphQLEnumType} from 'graphql' - -export const VerifiedOrganizationOrderField = new GraphQLEnumType({ - name: 'VerifiedOrganizationOrderField', - description: - 'Properties by which verified organization connections can be ordered.', - values: { - ACRONYM: { - value: 'acronym', - description: 'Order verified organization edges by acronym.', - }, - NAME: { - value: 'name', - description: 'Order verified organization edges by name.', - }, - ZONE: { - value: 'zone', - description: 'Order verified organization edges by zone.', - }, - SECTOR: { - value: 'sector', - description: 'Order verified organization edges by sector.', - }, - COUNTRY: { - value: 'country', - description: 'Order verified organization edges by country.', - }, - SUMMARY_MAIL_PASS: { - value: 'summary-mail-pass', - description: 'Order verified organizations by summary mail pass count.', - }, - SUMMARY_MAIL_FAIL: { - value: 'summary-mail-fail', - description: 'Order verified organizations by summary mail fail count.', - }, - SUMMARY_MAIL_TOTAL: { - value: 'summary-mail-total', - description: 'Order verified organizations by summary mail total count.', - }, - SUMMARY_WEB_PASS: { - value: 'summary-web-pass', - description: 'Order verified organizations by summary web pass count.', - }, - SUMMARY_WEB_FAIL: { - value: 'summary-web-fail', - description: 'Order verified organizations by summary web fail count.', - }, - SUMMARY_WEB_TOTAL: { - value: 'summary-web-total', - description: 'Order verified organizations by summary web total count.', - }, - DOMAIN_COUNT: { - value: 'domain-count', - description: 'Order verified organizations by domain count.', - }, - }, -}) diff --git a/api/src/initialize-loaders.js b/api/src/initialize-loaders.js deleted file mode 100644 index 1abec1cd26..0000000000 --- a/api/src/initialize-loaders.js +++ /dev/null @@ -1,134 +0,0 @@ -import { - loadDkimFailConnectionsBySumId, - loadDmarcFailConnectionsBySumId, - loadDmarcSummaryConnectionsByUserId, - loadDmarcSummaryEdgeByDomainIdAndPeriod, - loadDmarcSummaryByKey, - loadFullPassConnectionsBySumId, - loadSpfFailureConnectionsBySumId, - loadStartDateFromPeriod, - loadDmarcYearlySumEdge, - loadAllVerifiedRuaDomains, -} from './dmarc-summaries/loaders' -import { loadOrgByKey, loadOrganizationNamesById } from './organization/loaders' -import { loadMyTrackerByUserId, loadUserByUserName, loadUserByKey, loadUserConnectionsByUserId } from './user/loaders' -import { - loadVerifiedDomainsById, - loadVerifiedDomainByKey, - loadVerifiedDomainConnections, - loadVerifiedDomainConnectionsByOrgId, -} from './verified-domains/loaders' -import { - loadVerifiedOrgByKey, - loadVerifiedOrgBySlug, - loadVerifiedOrgConnectionsByDomainId, - loadVerifiedOrgConnections, -} from './verified-organizations/loaders' - -export function initializeLoaders({ query, userKey, i18n, language, cleanseInput, loginRequiredBool, moment }) { - return { - loadDkimFailConnectionsBySumId: loadDkimFailConnectionsBySumId({ - query, - userKey, - cleanseInput, - i18n, - }), - loadDmarcFailConnectionsBySumId: loadDmarcFailConnectionsBySumId({ - query, - userKey, - cleanseInput, - i18n, - }), - loadDmarcSummaryConnectionsByUserId: loadDmarcSummaryConnectionsByUserId({ - query, - userKey, - cleanseInput, - i18n, - auth: { loginRequiredBool }, - loadStartDateFromPeriod: loadStartDateFromPeriod({ - moment, - userKey, - i18n, - }), - }), - loadDmarcSummaryEdgeByDomainIdAndPeriod: loadDmarcSummaryEdgeByDomainIdAndPeriod({ - query, - userKey, - i18n, - }), - loadDmarcSummaryByKey: loadDmarcSummaryByKey({ query, userKey, i18n }), - loadFullPassConnectionsBySumId: loadFullPassConnectionsBySumId({ - query, - userKey, - cleanseInput, - i18n, - }), - loadSpfFailureConnectionsBySumId: loadSpfFailureConnectionsBySumId({ - query, - userKey, - cleanseInput, - i18n, - }), - loadStartDateFromPeriod: loadStartDateFromPeriod({ - moment, - userKey, - i18n, - }), - loadDmarcYearlySumEdge: loadDmarcYearlySumEdge({ query, userKey, i18n }), - loadOrgByKey: loadOrgByKey({ query, language, userKey, i18n }), - loadOrganizationNamesById: loadOrganizationNamesById({ query, userKey, i18n }), - loadMyTrackerByUserId: loadMyTrackerByUserId({ - query, - language, - userKey, - i18n, - }), - loadUserByUserName: loadUserByUserName({ query, userKey, i18n }), - loadUserConnectionsByUserId: loadUserConnectionsByUserId({ - query, - userKey, - cleanseInput, - i18n, - }), - loadUserByKey: loadUserByKey({ query, userKey, i18n }), - loadVerifiedDomainsById: loadVerifiedDomainsById({ query, i18n }), - loadVerifiedDomainByKey: loadVerifiedDomainByKey({ query, i18n }), - loadVerifiedDomainConnections: loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }), - loadVerifiedDomainConnectionsByOrgId: loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }), - loadVerifiedOrgByKey: loadVerifiedOrgByKey({ - query, - language, - i18n, - }), - loadVerifiedOrgBySlug: loadVerifiedOrgBySlug({ - query, - language, - i18n, - }), - loadVerifiedOrgConnectionsByDomainId: loadVerifiedOrgConnectionsByDomainId({ - query, - language, - cleanseInput, - i18n, - }), - loadVerifiedOrgConnections: loadVerifiedOrgConnections({ - query, - language, - cleanseInput, - i18n, - }), - loadAllVerifiedRuaDomains: loadAllVerifiedRuaDomains({ - query, - userKey, - i18n, - }), - } -} diff --git a/api/src/locale/en/messages.po b/api/src/locale/en/messages.po index 4e7b025431..dd3dcddd11 100644 --- a/api/src/locale/en/messages.po +++ b/api/src/locale/en/messages.po @@ -123,7 +123,7 @@ msgstr "`{argSet}` on the `VerifiedDomain` connection cannot be less than zero." msgid "`{argSet}` on the `VerifiedOrganization` connection cannot be less than zero." msgstr "`{argSet}` on the `VerifiedOrganization` connection cannot be less than zero." -#: src/organization/objects/organization.js:246 +#: src/organization/objects/organization.js:256 #: src/organization/queries/get-all-organization-domain-statuses.js:69 msgid "Assess" msgstr "Assess" @@ -142,7 +142,7 @@ msgstr "Authentication error. Please sign in." msgid "Cannot query additional findings without permission." msgstr "Cannot query additional findings without permission." -#: src/organization/objects/organization.js:364 +#: src/organization/objects/organization.js:374 msgid "Cannot query affiliations on organization without admin permission or higher." msgstr "Cannot query affiliations on organization without admin permission or higher." @@ -171,16 +171,16 @@ msgstr "CVE is already ignored for this domain." msgid "CVE is not ignored for this domain." msgstr "CVE is not ignored for this domain." -#: src/organization/objects/organization.js:248 +#: src/organization/objects/organization.js:258 #: src/organization/queries/get-all-organization-domain-statuses.js:71 msgid "Deploy" msgstr "Deploy" -#: src/user/mutations/sign-up.js:111 +#: src/user/mutations/sign-up.js:112 msgid "Email already in use." msgstr "Email already in use." -#: src/organization/objects/organization.js:250 +#: src/organization/objects/organization.js:260 #: src/organization/queries/get-all-organization-domain-statuses.js:73 msgid "Enforce" msgstr "Enforce" @@ -198,18 +198,18 @@ msgstr "If an account with this username is found, a password reset link will be #~ msgid "If an account with this username is found, an email verification link will be found in your inbox." #~ msgstr "If an account with this username is found, an email verification link will be found in your inbox." -#: src/user/mutations/authenticate.js:221 -#: src/user/mutations/authenticate.js:229 -#: src/user/mutations/authenticate.js:231 +#: src/user/data-source.js:478 +#: src/user/data-source.js:486 +#: src/user/mutations/authenticate.js:149 msgid "Incorrect TFA code. Please sign in again." msgstr "Incorrect TFA code. Please sign in again." -#: src/user/mutations/reset-password.js:61 +#: src/user/mutations/reset-password.js:58 msgid "Incorrect token value. Please request a new email." msgstr "Incorrect token value. Please request a new email." -#: src/user/mutations/sign-in.js:68 -#: src/user/mutations/sign-in.js:285 +#: src/user/mutations/sign-in.js:65 +#: src/user/mutations/sign-in.js:193 msgid "Incorrect username or password. Please try again." msgstr "Incorrect username or password. Please try again." @@ -217,16 +217,16 @@ msgstr "Incorrect username or password. Please try again." msgid "Invalid token, please sign in." msgstr "Invalid token, please sign in." -#: src/organization/objects/organization.js:252 +#: src/organization/objects/organization.js:262 #: src/organization/queries/get-all-organization-domain-statuses.js:75 msgid "Maintain" msgstr "Maintain" -#: src/user/mutations/dismiss-message.js:75 +#: src/user/mutations/dismiss-message.js:52 msgid "Message dismissed successfully" msgstr "Message dismissed successfully" -#: src/user/mutations/reset-password.js:88 +#: src/user/mutations/reset-password.js:85 msgid "New passwords do not match." msgstr "New passwords do not match." @@ -349,20 +349,20 @@ msgstr "Passing both `first` and `last` to paginate the `VerifiedDomain` connect msgid "Passing both `first` and `last` to paginate the `VerifiedOrganization` connection is not supported." msgstr "Passing both `first` and `last` to paginate the `VerifiedOrganization` connection is not supported." -#: src/user/mutations/reset-password.js:100 -#: src/user/mutations/sign-up.js:89 +#: src/user/mutations/reset-password.js:97 +#: src/user/mutations/sign-up.js:90 msgid "Password does not meet requirements." msgstr "Password does not meet requirements." -#: src/user/mutations/reset-password.js:140 +#: src/user/mutations/reset-password.js:110 msgid "Password was successfully reset." msgstr "Password was successfully reset." -#: src/user/mutations/update-user-password.js:109 +#: src/user/mutations/update-user-password.js:86 msgid "Password was successfully updated." msgstr "Password was successfully updated." -#: src/user/mutations/sign-up.js:99 +#: src/user/mutations/sign-up.js:100 msgid "Passwords do not match." msgstr "Passwords do not match." @@ -380,7 +380,7 @@ msgstr "Permission check error. Unable to request domain information." msgid "Permission Denied: Could not retrieve specified organization." msgstr "Permission Denied: Could not retrieve specified organization." -#: src/user/mutations/update-user-profile.js:109 +#: src/user/mutations/update-user-profile.js:107 msgid "Permission Denied: Multi-factor authentication is required for admin accounts" msgstr "Permission Denied: Multi-factor authentication is required for admin accounts" @@ -454,7 +454,7 @@ msgstr "Permission Denied: Please contact organization user for help with creati #~ msgstr "Permission Denied: Please contact organization user for help with retrieving tags." #: src/domain/queries/find-domain-by-domain.js:51 -#: src/organization/objects/organization.js:201 +#: src/organization/objects/organization.js:211 msgid "Permission Denied: Please contact organization user for help with retrieving this domain." msgstr "Permission Denied: Please contact organization user for help with retrieving this domain." @@ -515,7 +515,7 @@ msgstr "Permission Denied: Please contact super admin for help with verifying th msgid "Permission error, not an admin for this user." msgstr "Permission error, not an admin for this user." -#: src/user/mutations/close-account.js:148 +#: src/user/mutations/close-account.js:106 msgid "Permission error: Unable to close other user's account." msgstr "Permission error: Unable to close other user's account." @@ -523,11 +523,11 @@ msgstr "Permission error: Unable to close other user's account." msgid "Permissions error. You do not have sufficient permissions to access this data." msgstr "Permissions error. You do not have sufficient permissions to access this data." -#: src/user/mutations/remove-phone-number.js:65 +#: src/user/mutations/remove-phone-number.js:32 msgid "Phone number has been successfully removed." msgstr "Phone number has been successfully removed." -#: src/user/mutations/set-phone-number.js:118 +#: src/user/mutations/set-phone-number.js:80 msgid "Phone number has been successfully set, you will receive a verification text message shortly." msgstr "Phone number has been successfully set, you will receive a verification text message shortly." @@ -536,7 +536,7 @@ msgstr "Phone number has been successfully set, you will receive a verification #~ msgid "Please provide a comment when adding an outside domain." #~ msgstr "Please provide a comment when adding an outside domain." -#: src/user/mutations/update-user-profile.js:188 +#: src/user/mutations/update-user-profile.js:161 msgid "Profile successfully updated." msgstr "Profile successfully updated." @@ -640,8 +640,8 @@ msgstr "Successfully added {domainCount} domain(s) to {0}." msgid "Successfully archived organization: {0}." msgstr "Successfully archived organization: {0}." -#: src/user/mutations/close-account.js:96 -#: src/user/mutations/close-account.js:230 +#: src/user/mutations/close-account.js:54 +#: src/user/mutations/close-account.js:146 msgid "Successfully closed account." msgstr "Successfully closed account." @@ -657,7 +657,7 @@ msgstr "Successfully dispatched subdomain discovery scan." #~ msgid "Successfully email verified account, and set TFA send method to email." #~ msgstr "Successfully email verified account, and set TFA send method to email." -#: src/user/mutations/verify-account.js:143 +#: src/user/mutations/verify-account.js:109 msgid "Successfully email verified account." msgstr "Successfully email verified account." @@ -729,7 +729,7 @@ msgstr "Successfully updated {domainCount} domain(s) in {0} with {1}." msgid "Successfully verified organization: {0}." msgstr "Successfully verified organization: {0}." -#: src/user/mutations/verify-phone-number.js:91 +#: src/user/mutations/verify-phone-number.js:65 msgid "Successfully verified phone number, and set TFA send method to text." msgstr "Successfully verified phone number, and set TFA send method to text." @@ -743,15 +743,15 @@ msgstr "Successfully verified phone number, and set TFA send method to text." msgid "Tag label already in use. Please try again with a different label." msgstr "Tag label already in use. Please try again with a different label." -#: src/user/mutations/authenticate.js:66 +#: src/user/mutations/authenticate.js:63 msgid "Token value incorrect, please sign in again." msgstr "Token value incorrect, please sign in again." -#: src/user/mutations/sign-in.js:78 +#: src/user/mutations/sign-in.js:75 msgid "Too many failed login attempts, please reset your password, and try again." msgstr "Too many failed login attempts, please reset your password, and try again." -#: src/user/mutations/complete-tour.js:73 +#: src/user/mutations/complete-tour.js:52 msgid "Tour completion confirmed successfully" msgstr "Tour completion confirmed successfully" @@ -782,10 +782,9 @@ msgstr "Unable to archive organization. Please try again." msgid "Unable to archive unknown organization." msgstr "Unable to archive unknown organization." -#: src/user/mutations/authenticate.js:79 -#: src/user/mutations/authenticate.js:121 -#: src/user/mutations/authenticate.js:146 -#: src/user/mutations/authenticate.js:155 +#: src/user/data-source.js:450 +#: src/user/data-source.js:458 +#: src/user/mutations/authenticate.js:76 msgid "Unable to authenticate. Please try again." msgstr "Unable to authenticate. Please try again." @@ -798,21 +797,18 @@ msgstr "Unable to authenticate. Please try again." msgid "Unable to check permission. Please try again." msgstr "Unable to check permission. Please try again." -#: src/user/mutations/close-account.js:160 +#: src/user/mutations/close-account.js:118 msgid "Unable to close account of an undefined user." msgstr "Unable to close account of an undefined user." -#: src/user/mutations/close-account.js:49 -#: src/user/mutations/close-account.js:65 -#: src/user/mutations/close-account.js:73 -#: src/user/mutations/close-account.js:183 -#: src/user/mutations/close-account.js:199 -#: src/user/mutations/close-account.js:207 +#: src/user/data-source.js:97 +#: src/user/data-source.js:111 +#: src/user/data-source.js:119 msgid "Unable to close account. Please try again." msgstr "Unable to close account. Please try again." +#: src/user/data-source.js:539 #: src/user/mutations/complete-tour.js:39 -#: src/user/mutations/complete-tour.js:64 msgid "Unable to confirm completion of the tour. Please try again." msgstr "Unable to confirm completion of the tour. Please try again." @@ -860,8 +856,8 @@ msgstr "Unable to create tag. Please try again." msgid "Unable to discover domains for unknown organization." msgstr "Unable to discover domains for unknown organization." +#: src/user/data-source.js:564 #: src/user/mutations/dismiss-message.js:39 -#: src/user/mutations/dismiss-message.js:66 msgid "Unable to dismiss message. Please try again." msgstr "Unable to dismiss message. Please try again." @@ -871,7 +867,7 @@ msgstr "Unable to dismiss message. Please try again." #~ msgid "Unable to dispatch one time scan. Please try again." #~ msgstr "Unable to dispatch one time scan. Please try again." -#: src/organization/objects/organization.js:271 +#: src/organization/objects/organization.js:281 msgid "Unable to export organization. Please try again." msgstr "Unable to export organization. Please try again." @@ -1041,8 +1037,8 @@ msgstr "Unable to load Aggregate guidance tag(s). Please try again." #~ msgid "Unable to load all organization domain statuses. Please try again." #~ msgstr "Unable to load all organization domain statuses. Please try again." -#: src/summaries/loaders/load-chart-summaries-by-period.js:56 -#: src/summaries/loaders/load-chart-summaries-by-period.js:66 +#: src/summaries/loaders/load-chart-summaries-by-period.js:58 +#: src/summaries/loaders/load-chart-summaries-by-period.js:68 msgid "Unable to load chart summary data. Please try again." msgstr "Unable to load chart summary data. Please try again." @@ -1178,8 +1174,8 @@ msgstr "Unable to load organization domain statuses. Please try again." msgid "Unable to load organization names. Please try again." msgstr "Unable to load organization names. Please try again." -#: src/organization/loaders/load-organization-summaries-by-period.js:50 -#: src/organization/loaders/load-organization-summaries-by-period.js:60 +#: src/organization/loaders/load-organization-summaries-by-period.js:52 +#: src/organization/loaders/load-organization-summaries-by-period.js:62 msgid "Unable to load organization summary data. Please try again." msgstr "Unable to load organization summary data. Please try again." @@ -1324,13 +1320,13 @@ msgstr "Unable to query log(s). Please try again." msgid "Unable to query user(s). Please try again." msgstr "Unable to query user(s). Please try again." -#: src/user/mutations/refresh-tokens.js:47 -#: src/user/mutations/refresh-tokens.js:59 -#: src/user/mutations/refresh-tokens.js:72 -#: src/user/mutations/refresh-tokens.js:85 -#: src/user/mutations/refresh-tokens.js:95 -#: src/user/mutations/refresh-tokens.js:123 -#: src/user/mutations/refresh-tokens.js:131 +#: src/user/data-source.js:506 +#: src/user/data-source.js:514 +#: src/user/mutations/refresh-tokens.js:44 +#: src/user/mutations/refresh-tokens.js:56 +#: src/user/mutations/refresh-tokens.js:69 +#: src/user/mutations/refresh-tokens.js:82 +#: src/user/mutations/refresh-tokens.js:92 msgid "Unable to refresh tokens, please sign in." msgstr "Unable to refresh tokens, please sign in." @@ -1381,8 +1377,8 @@ msgstr "Unable to remove domains from unknown organization." msgid "Unable to remove organization. Please try again." msgstr "Unable to remove organization. Please try again." -#: src/user/mutations/remove-phone-number.js:51 -#: src/user/mutations/remove-phone-number.js:59 +#: src/user/data-source.js:203 +#: src/user/data-source.js:211 msgid "Unable to remove phone number. Please try again." msgstr "Unable to remove phone number. Please try again." @@ -1454,9 +1450,9 @@ msgstr "Unable to request invite. Please try again." #~ msgid "Unable to reset password. Please request a new email." #~ msgstr "Unable to reset password. Please request a new email." -#: src/user/mutations/reset-password.js:76 -#: src/user/mutations/reset-password.js:125 -#: src/user/mutations/reset-password.js:133 +#: src/user/data-source.js:167 +#: src/user/data-source.js:175 +#: src/user/mutations/reset-password.js:73 msgid "Unable to reset password. Please try again." msgstr "Unable to reset password. Please try again." @@ -1500,7 +1496,7 @@ msgstr "Unable to send password reset email. Please try again." #~ msgstr "Unable to send two factor authentication message. Please try again." #: src/notify/notify-send-updated-username-email.js:18 -#: src/user/mutations/verify-account.js:102 +#: src/user/mutations/verify-account.js:99 msgid "Unable to send updated username email. Please try again." msgstr "Unable to send updated username email. Please try again." @@ -1508,30 +1504,31 @@ msgstr "Unable to send updated username email. Please try again." msgid "Unable to send verification email. Please try again." msgstr "Unable to send verification email. Please try again." -#: src/user/mutations/set-phone-number.js:97 -#: src/user/mutations/set-phone-number.js:105 +#: src/user/data-source.js:241 +#: src/user/data-source.js:249 msgid "Unable to set phone number, please try again." msgstr "Unable to set phone number, please try again." -#: src/user/mutations/sign-in.js:98 -#: src/user/mutations/sign-in.js:132 -#: src/user/mutations/sign-in.js:140 -#: src/user/mutations/sign-in.js:198 -#: src/user/mutations/sign-in.js:206 -#: src/user/mutations/sign-in.js:270 -#: src/user/mutations/sign-in.js:278 +#: src/user/data-source.js:323 +#: src/user/data-source.js:331 +#: src/user/data-source.js:357 +#: src/user/data-source.js:365 +#: src/user/data-source.js:385 +#: src/user/data-source.js:393 +#: src/user/data-source.js:413 +#: src/user/data-source.js:421 msgid "Unable to sign in, please try again." msgstr "Unable to sign in, please try again." -#: src/user/mutations/sign-up.js:197 -#: src/user/mutations/sign-up.js:208 +#: src/user/mutations/sign-up.js:163 +#: src/user/mutations/sign-up.js:173 msgid "Unable to sign up, please contact org admin for a new invite." msgstr "Unable to sign up, please contact org admin for a new invite." -#: src/user/mutations/sign-up.js:168 -#: src/user/mutations/sign-up.js:177 -#: src/user/mutations/sign-up.js:229 -#: src/user/mutations/sign-up.js:238 +#: src/user/data-source.js:40 +#: src/user/data-source.js:49 +#: src/user/data-source.js:67 +#: src/user/data-source.js:76 msgid "Unable to sign up. Please try again." msgstr "Unable to sign up. Please try again." @@ -1564,8 +1561,8 @@ msgstr "Unable to transfer ownership of undefined organization." msgid "Unable to transfer ownership to a user outside the org. Please invite the user and try again." msgstr "Unable to transfer ownership to a user outside the org. Please invite the user and try again." -#: src/user/mutations/verify-phone-number.js:72 -#: src/user/mutations/verify-phone-number.js:80 +#: src/user/data-source.js:269 +#: src/user/data-source.js:277 msgid "Unable to two factor authenticate. Please try again." msgstr "Unable to two factor authenticate. Please try again." @@ -1637,13 +1634,13 @@ msgstr "Unable to update password, new passwords do not match. Please try again. msgid "Unable to update password, passwords do not match requirements. Please try again." msgstr "Unable to update password, passwords do not match requirements. Please try again." -#: src/user/mutations/update-user-password.js:95 -#: src/user/mutations/update-user-password.js:103 +#: src/user/data-source.js:137 +#: src/user/data-source.js:145 msgid "Unable to update password. Please try again." msgstr "Unable to update password. Please try again." -#: src/user/mutations/update-user-profile.js:154 -#: src/user/mutations/update-user-profile.js:162 +#: src/user/data-source.js:297 +#: src/user/data-source.js:305 msgid "Unable to update profile. Please try again." msgstr "Unable to update profile. Please try again." @@ -1700,14 +1697,14 @@ msgstr "Unable to update user's role. Please try again." msgid "Unable to update your own role." msgstr "Unable to update your own role." -#: src/user/mutations/verify-account.js:51 -#: src/user/mutations/verify-account.js:63 -#: src/user/mutations/verify-account.js:77 +#: src/user/mutations/verify-account.js:48 +#: src/user/mutations/verify-account.js:60 +#: src/user/mutations/verify-account.js:74 msgid "Unable to verify account. Please request a new email." msgstr "Unable to verify account. Please request a new email." -#: src/user/mutations/verify-account.js:128 -#: src/user/mutations/verify-account.js:136 +#: src/user/data-source.js:590 +#: src/user/data-source.js:598 msgid "Unable to verify account. Please try again." msgstr "Unable to verify account. Please try again." @@ -1715,7 +1712,7 @@ msgstr "Unable to verify account. Please try again." msgid "Unable to verify if user is a super admin, please try again." msgstr "Unable to verify if user is a super admin, please try again." -#: src/user/mutations/update-user-profile.js:99 +#: src/user/mutations/update-user-profile.js:97 #: src/user/queries/is-user-admin.js:49 msgid "Unable to verify if user is an admin, please try again." msgstr "Unable to verify if user is an admin, please try again." @@ -1734,7 +1731,7 @@ msgstr "Unable to verify unknown organization." msgid "User could not be queried." msgstr "User could not be queried." -#: src/user/mutations/sign-up.js:79 +#: src/user/mutations/sign-up.js:80 msgid "User is trying to register for a non-production environment." msgstr "User is trying to register for a non-production environment." @@ -1742,8 +1739,8 @@ msgstr "User is trying to register for a non-production environment." msgid "User role was updated successfully." msgstr "User role was updated successfully." -#: src/user/mutations/update-user-profile.js:80 -#: src/user/mutations/verify-account.js:88 +#: src/user/mutations/update-user-profile.js:78 +#: src/user/mutations/verify-account.js:85 msgid "Username not available, please try another." msgstr "Username not available, please try another." diff --git a/api/src/locale/fr/messages.po b/api/src/locale/fr/messages.po index 95af02174b..4d0f2f806b 100644 --- a/api/src/locale/fr/messages.po +++ b/api/src/locale/fr/messages.po @@ -123,7 +123,7 @@ msgstr "`{argSet}` sur la connexion `VerifiedDomain` ne peut être inférieur à msgid "`{argSet}` on the `VerifiedOrganization` connection cannot be less than zero." msgstr "`{argSet}` sur la connexion `VerifiedOrganization` ne peut être inférieur à zéro." -#: src/organization/objects/organization.js:246 +#: src/organization/objects/organization.js:256 #: src/organization/queries/get-all-organization-domain-statuses.js:69 msgid "Assess" msgstr "Évaluez" @@ -142,7 +142,7 @@ msgstr "Erreur d'authentification. Veuillez vous connecter." msgid "Cannot query additional findings without permission." msgstr "Il n'est pas possible de demander des résultats supplémentaires sans autorisation." -#: src/organization/objects/organization.js:364 +#: src/organization/objects/organization.js:374 msgid "Cannot query affiliations on organization without admin permission or higher." msgstr "Impossible d'interroger les affiliations sur l'organisation sans l'autorisation de l'administrateur ou plus." @@ -171,16 +171,16 @@ msgstr "CVE est déjà ignoré pour ce domaine." msgid "CVE is not ignored for this domain." msgstr "Le CVE n'est pas ignoré dans ce domaine." -#: src/organization/objects/organization.js:248 +#: src/organization/objects/organization.js:258 #: src/organization/queries/get-all-organization-domain-statuses.js:71 msgid "Deploy" msgstr "msgstr Déployer" -#: src/user/mutations/sign-up.js:111 +#: src/user/mutations/sign-up.js:112 msgid "Email already in use." msgstr "Courriel déjà utilisé." -#: src/organization/objects/organization.js:250 +#: src/organization/objects/organization.js:260 #: src/organization/queries/get-all-organization-domain-statuses.js:73 msgid "Enforce" msgstr "Appliquer" @@ -198,18 +198,18 @@ msgstr "Si un compte avec ce nom d'utilisateur est trouvé, un lien de réinitia #~ msgid "If an account with this username is found, an email verification link will be found in your inbox." #~ msgstr "Si un compte avec ce nom d'utilisateur est trouvé, un lien de vérification par e-mail sera trouvé dans votre boîte de réception." -#: src/user/mutations/authenticate.js:221 -#: src/user/mutations/authenticate.js:229 -#: src/user/mutations/authenticate.js:231 +#: src/user/data-source.js:478 +#: src/user/data-source.js:486 +#: src/user/mutations/authenticate.js:149 msgid "Incorrect TFA code. Please sign in again." msgstr "Code TFA incorrect. Veuillez vous reconnecter." -#: src/user/mutations/reset-password.js:61 +#: src/user/mutations/reset-password.js:58 msgid "Incorrect token value. Please request a new email." msgstr "La valeur du jeton est incorrecte. Veuillez demander un nouvel e-mail." -#: src/user/mutations/sign-in.js:68 -#: src/user/mutations/sign-in.js:285 +#: src/user/mutations/sign-in.js:65 +#: src/user/mutations/sign-in.js:193 msgid "Incorrect username or password. Please try again." msgstr "Le nom d'utilisateur ou le mot de passe est incorrect. Veuillez réessayer." @@ -217,16 +217,16 @@ msgstr "Le nom d'utilisateur ou le mot de passe est incorrect. Veuillez réessay msgid "Invalid token, please sign in." msgstr "Jeton invalide, veuillez vous connecter." -#: src/organization/objects/organization.js:252 +#: src/organization/objects/organization.js:262 #: src/organization/queries/get-all-organization-domain-statuses.js:75 msgid "Maintain" msgstr "Maintenir" -#: src/user/mutations/dismiss-message.js:75 +#: src/user/mutations/dismiss-message.js:52 msgid "Message dismissed successfully" msgstr "Message rejeté avec succès" -#: src/user/mutations/reset-password.js:88 +#: src/user/mutations/reset-password.js:85 msgid "New passwords do not match." msgstr "Les nouveaux mots de passe ne correspondent pas." @@ -349,20 +349,20 @@ msgstr "Passer à la fois `first` et `last` pour paginer la connexion `VerifiedD msgid "Passing both `first` and `last` to paginate the `VerifiedOrganization` connection is not supported." msgstr "Passer à la fois `first` et `last` pour paginer la connexion `VerifiedOrganization` n'est pas supporté." -#: src/user/mutations/reset-password.js:100 -#: src/user/mutations/sign-up.js:89 +#: src/user/mutations/reset-password.js:97 +#: src/user/mutations/sign-up.js:90 msgid "Password does not meet requirements." msgstr "Le mot de passe ne répond pas aux exigences." -#: src/user/mutations/reset-password.js:140 +#: src/user/mutations/reset-password.js:110 msgid "Password was successfully reset." msgstr "Le mot de passe a été réinitialisé avec succès." -#: src/user/mutations/update-user-password.js:109 +#: src/user/mutations/update-user-password.js:86 msgid "Password was successfully updated." msgstr "Le mot de passe a été mis à jour avec succès." -#: src/user/mutations/sign-up.js:99 +#: src/user/mutations/sign-up.js:100 msgid "Passwords do not match." msgstr "Les mots de passe ne correspondent pas." @@ -380,7 +380,7 @@ msgstr "Erreur de vérification des permissions. Impossible de demander des info msgid "Permission Denied: Could not retrieve specified organization." msgstr "Permission refusée : Impossible de récupérer l'organisation spécifiée." -#: src/user/mutations/update-user-profile.js:109 +#: src/user/mutations/update-user-profile.js:107 msgid "Permission Denied: Multi-factor authentication is required for admin accounts" msgstr "Permission refusée : L'authentification multifactorielle est requise pour les comptes admin." @@ -454,7 +454,7 @@ msgstr "Permission refusée : Veuillez contacter l'utilisateur de l'organisation #~ msgstr "Permission refusée : Veuillez contacter l'utilisateur de l'organisation pour obtenir de l'aide afin de récupérer les étiquettes." #: src/domain/queries/find-domain-by-domain.js:51 -#: src/organization/objects/organization.js:201 +#: src/organization/objects/organization.js:211 msgid "Permission Denied: Please contact organization user for help with retrieving this domain." msgstr "Permission refusée : Veuillez contacter l'utilisateur de l'organisation pour obtenir de l'aide pour récupérer ce domaine." @@ -515,7 +515,7 @@ msgstr "Permission refusée : Veuillez contacter le super administrateur pour qu msgid "Permission error, not an admin for this user." msgstr "Erreur de permission, pas d'administrateur pour cet utilisateur." -#: src/user/mutations/close-account.js:148 +#: src/user/mutations/close-account.js:106 msgid "Permission error: Unable to close other user's account." msgstr "Erreur de permission: Impossible de fermer le compte d'un autre utilisateur." @@ -523,11 +523,11 @@ msgstr "Erreur de permission: Impossible de fermer le compte d'un autre utilisat msgid "Permissions error. You do not have sufficient permissions to access this data." msgstr "Erreur de permissions. Vous n'avez pas les autorisations suffisantes pour accéder à ces données." -#: src/user/mutations/remove-phone-number.js:65 +#: src/user/mutations/remove-phone-number.js:32 msgid "Phone number has been successfully removed." msgstr "Le numéro de téléphone a été supprimé avec succès." -#: src/user/mutations/set-phone-number.js:118 +#: src/user/mutations/set-phone-number.js:80 msgid "Phone number has been successfully set, you will receive a verification text message shortly." msgstr "Le numéro de téléphone a été configuré avec succès, vous recevrez bientôt un message de vérification." @@ -536,7 +536,7 @@ msgstr "Le numéro de téléphone a été configuré avec succès, vous recevrez #~ msgid "Please provide a comment when adding an outside domain." #~ msgstr "Veuillez fournir un commentaire lorsque vous ajoutez un domaine externe." -#: src/user/mutations/update-user-profile.js:188 +#: src/user/mutations/update-user-profile.js:161 msgid "Profile successfully updated." msgstr "Le profil a été mis à jour avec succès." @@ -640,8 +640,8 @@ msgstr "Ajouté avec succès le(s) domaine(s) {domainCount} à {0}." msgid "Successfully archived organization: {0}." msgstr "Organisation archivée avec succès : {0}." -#: src/user/mutations/close-account.js:96 -#: src/user/mutations/close-account.js:230 +#: src/user/mutations/close-account.js:54 +#: src/user/mutations/close-account.js:146 msgid "Successfully closed account." msgstr "Le compte a été fermé avec succès." @@ -657,7 +657,7 @@ msgstr "L'analyse de découverte du sous-domaine a été effectuée avec succès #~ msgid "Successfully email verified account, and set TFA send method to email." #~ msgstr "Réussir à envoyer un email au compte vérifié, et définir la méthode d'envoi de la TFA sur email." -#: src/user/mutations/verify-account.js:143 +#: src/user/mutations/verify-account.js:109 msgid "Successfully email verified account." msgstr "Envoi d'un courriel à un compte vérifié." @@ -729,7 +729,7 @@ msgstr "Mise à jour réussie de {domainCount} domaine(s) dans {0} avec {1}." msgid "Successfully verified organization: {0}." msgstr "Envoi réussi de l'invitation au service, et de l'email de l'organisation." -#: src/user/mutations/verify-phone-number.js:91 +#: src/user/mutations/verify-phone-number.js:65 msgid "Successfully verified phone number, and set TFA send method to text." msgstr "Le numéro de téléphone a été vérifié avec succès, et la méthode d'envoi de la TFA a été réglée sur le texte." @@ -743,15 +743,15 @@ msgstr "Le numéro de téléphone a été vérifié avec succès, et la méthode msgid "Tag label already in use. Please try again with a different label." msgstr "L'étiquette est déjà utilisée. Veuillez réessayer avec une autre étiquette." -#: src/user/mutations/authenticate.js:66 +#: src/user/mutations/authenticate.js:63 msgid "Token value incorrect, please sign in again." msgstr "La valeur du jeton est incorrecte, veuillez vous connecter à nouveau." -#: src/user/mutations/sign-in.js:78 +#: src/user/mutations/sign-in.js:75 msgid "Too many failed login attempts, please reset your password, and try again." msgstr "Trop de tentatives de connexion ont échoué, veuillez réinitialiser votre mot de passe et réessayer." -#: src/user/mutations/complete-tour.js:73 +#: src/user/mutations/complete-tour.js:52 msgid "Tour completion confirmed successfully" msgstr "Confirmation de l'achèvement du voyage" @@ -782,10 +782,9 @@ msgstr "Impossible d'archiver l'organisation. Veuillez réessayer." msgid "Unable to archive unknown organization." msgstr "Impossible d'archiver une organisation inconnue." -#: src/user/mutations/authenticate.js:79 -#: src/user/mutations/authenticate.js:121 -#: src/user/mutations/authenticate.js:146 -#: src/user/mutations/authenticate.js:155 +#: src/user/data-source.js:450 +#: src/user/data-source.js:458 +#: src/user/mutations/authenticate.js:76 msgid "Unable to authenticate. Please try again." msgstr "Impossible de s'authentifier. Veuillez réessayer." @@ -798,21 +797,18 @@ msgstr "Impossible de s'authentifier. Veuillez réessayer." msgid "Unable to check permission. Please try again." msgstr "Impossible de vérifier l'autorisation. Veuillez réessayer." -#: src/user/mutations/close-account.js:160 +#: src/user/mutations/close-account.js:118 msgid "Unable to close account of an undefined user." msgstr "Impossible de fermer le compte d'un utilisateur non défini." -#: src/user/mutations/close-account.js:49 -#: src/user/mutations/close-account.js:65 -#: src/user/mutations/close-account.js:73 -#: src/user/mutations/close-account.js:183 -#: src/user/mutations/close-account.js:199 -#: src/user/mutations/close-account.js:207 +#: src/user/data-source.js:97 +#: src/user/data-source.js:111 +#: src/user/data-source.js:119 msgid "Unable to close account. Please try again." msgstr "Impossible de fermer le compte. Veuillez réessayer." +#: src/user/data-source.js:539 #: src/user/mutations/complete-tour.js:39 -#: src/user/mutations/complete-tour.js:64 msgid "Unable to confirm completion of the tour. Please try again." msgstr "Impossible de confirmer l'achèvement de la visite. Veuillez réessayer." @@ -860,8 +856,8 @@ msgstr "Impossible de créer une balise. Veuillez réessayer." msgid "Unable to discover domains for unknown organization." msgstr "Impossible de découvrir les domaines d'une organisation inconnue." +#: src/user/data-source.js:564 #: src/user/mutations/dismiss-message.js:39 -#: src/user/mutations/dismiss-message.js:66 msgid "Unable to dismiss message. Please try again." msgstr "Impossible de rejeter le message. Veuillez réessayer." @@ -871,7 +867,7 @@ msgstr "Impossible de rejeter le message. Veuillez réessayer." #~ msgid "Unable to dispatch one time scan. Please try again." #~ msgstr "Impossible d'envoyer un scan unique. Veuillez réessayer." -#: src/organization/objects/organization.js:271 +#: src/organization/objects/organization.js:281 msgid "Unable to export organization. Please try again." msgstr "Impossible d'exporter l'organisation. Veuillez réessayer." @@ -1041,8 +1037,8 @@ msgstr "Impossible de charger le(s) tag(s) d'orientation des agrégats. Veuillez #~ msgid "Unable to load all organization domain statuses. Please try again." #~ msgstr "Impossible de charger tous les statuts de domaine d'organisation. Veuillez réessayer." -#: src/summaries/loaders/load-chart-summaries-by-period.js:56 -#: src/summaries/loaders/load-chart-summaries-by-period.js:66 +#: src/summaries/loaders/load-chart-summaries-by-period.js:58 +#: src/summaries/loaders/load-chart-summaries-by-period.js:68 msgid "Unable to load chart summary data. Please try again." msgstr "Impossible de charger les données du résumé du graphique. Veuillez réessayer." @@ -1178,8 +1174,8 @@ msgstr "Impossible de charger les statuts des domaines d'organisation. Veuillez msgid "Unable to load organization names. Please try again." msgstr "Impossible de charger les noms des organisations. Veuillez réessayer." -#: src/organization/loaders/load-organization-summaries-by-period.js:50 -#: src/organization/loaders/load-organization-summaries-by-period.js:60 +#: src/organization/loaders/load-organization-summaries-by-period.js:52 +#: src/organization/loaders/load-organization-summaries-by-period.js:62 msgid "Unable to load organization summary data. Please try again." msgstr "Impossible de charger les données de synthèse de l'organisation. Veuillez réessayer." @@ -1324,13 +1320,13 @@ msgstr "Impossible d'interroger le(s) journal(s). Veuillez réessayer." msgid "Unable to query user(s). Please try again." msgstr "Impossible d'interroger le(s) utilisateur(s). Veuillez réessayer." -#: src/user/mutations/refresh-tokens.js:47 -#: src/user/mutations/refresh-tokens.js:59 -#: src/user/mutations/refresh-tokens.js:72 -#: src/user/mutations/refresh-tokens.js:85 -#: src/user/mutations/refresh-tokens.js:95 -#: src/user/mutations/refresh-tokens.js:123 -#: src/user/mutations/refresh-tokens.js:131 +#: src/user/data-source.js:506 +#: src/user/data-source.js:514 +#: src/user/mutations/refresh-tokens.js:44 +#: src/user/mutations/refresh-tokens.js:56 +#: src/user/mutations/refresh-tokens.js:69 +#: src/user/mutations/refresh-tokens.js:82 +#: src/user/mutations/refresh-tokens.js:92 msgid "Unable to refresh tokens, please sign in." msgstr "Impossible de rafraîchir les jetons, veuillez vous connecter." @@ -1381,8 +1377,8 @@ msgstr "Impossible de supprimer les domaines d'une organisation inconnue." msgid "Unable to remove organization. Please try again." msgstr "Impossible de supprimer l'organisation. Veuillez réessayer." -#: src/user/mutations/remove-phone-number.js:51 -#: src/user/mutations/remove-phone-number.js:59 +#: src/user/data-source.js:203 +#: src/user/data-source.js:211 msgid "Unable to remove phone number. Please try again." msgstr "Impossible de supprimer le numéro de téléphone. Veuillez réessayer." @@ -1454,9 +1450,9 @@ msgstr "Impossible de demander une invitation. Veuillez réessayer." #~ msgid "Unable to reset password. Please request a new email." #~ msgstr "Impossible de réinitialiser le mot de passe. Veuillez demander un nouvel e-mail." -#: src/user/mutations/reset-password.js:76 -#: src/user/mutations/reset-password.js:125 -#: src/user/mutations/reset-password.js:133 +#: src/user/data-source.js:167 +#: src/user/data-source.js:175 +#: src/user/mutations/reset-password.js:73 msgid "Unable to reset password. Please try again." msgstr "Impossible de réinitialiser le mot de passe. Veuillez réessayer." @@ -1500,7 +1496,7 @@ msgstr "Impossible d'envoyer l'email de réinitialisation du mot de passe. Veuil #~ msgstr "Impossible d'envoyer le message d'authentification à deux facteurs. Veuillez réessayer." #: src/notify/notify-send-updated-username-email.js:18 -#: src/user/mutations/verify-account.js:102 +#: src/user/mutations/verify-account.js:99 msgid "Unable to send updated username email. Please try again." msgstr "Impossible d'envoyer l'email de mise à jour du nom d'utilisateur. Veuillez réessayer." @@ -1508,30 +1504,31 @@ msgstr "Impossible d'envoyer l'email de mise à jour du nom d'utilisateur. Veuil msgid "Unable to send verification email. Please try again." msgstr "Impossible d'envoyer l'email de vérification. Veuillez réessayer." -#: src/user/mutations/set-phone-number.js:97 -#: src/user/mutations/set-phone-number.js:105 +#: src/user/data-source.js:241 +#: src/user/data-source.js:249 msgid "Unable to set phone number, please try again." msgstr "Impossible de définir le numéro de téléphone, veuillez réessayer." -#: src/user/mutations/sign-in.js:98 -#: src/user/mutations/sign-in.js:132 -#: src/user/mutations/sign-in.js:140 -#: src/user/mutations/sign-in.js:198 -#: src/user/mutations/sign-in.js:206 -#: src/user/mutations/sign-in.js:270 -#: src/user/mutations/sign-in.js:278 +#: src/user/data-source.js:323 +#: src/user/data-source.js:331 +#: src/user/data-source.js:357 +#: src/user/data-source.js:365 +#: src/user/data-source.js:385 +#: src/user/data-source.js:393 +#: src/user/data-source.js:413 +#: src/user/data-source.js:421 msgid "Unable to sign in, please try again." msgstr "Impossible de se connecter, veuillez réessayer." -#: src/user/mutations/sign-up.js:197 -#: src/user/mutations/sign-up.js:208 +#: src/user/mutations/sign-up.js:163 +#: src/user/mutations/sign-up.js:173 msgid "Unable to sign up, please contact org admin for a new invite." msgstr "Impossible de s'inscrire, veuillez contacter l'administrateur de l'organisation pour obtenir une nouvelle invitation." -#: src/user/mutations/sign-up.js:168 -#: src/user/mutations/sign-up.js:177 -#: src/user/mutations/sign-up.js:229 -#: src/user/mutations/sign-up.js:238 +#: src/user/data-source.js:40 +#: src/user/data-source.js:49 +#: src/user/data-source.js:67 +#: src/user/data-source.js:76 msgid "Unable to sign up. Please try again." msgstr "Impossible de s'inscrire. Veuillez réessayer." @@ -1564,8 +1561,8 @@ msgstr "Impossible de transférer la propriété d'une organisation non définie msgid "Unable to transfer ownership to a user outside the org. Please invite the user and try again." msgstr "Impossible de transférer la propriété à un utilisateur extérieur à l'org. Veuillez inviter l'utilisateur et réessayer." -#: src/user/mutations/verify-phone-number.js:72 -#: src/user/mutations/verify-phone-number.js:80 +#: src/user/data-source.js:269 +#: src/user/data-source.js:277 msgid "Unable to two factor authenticate. Please try again." msgstr "Impossible de s'authentifier par deux facteurs. Veuillez réessayer." @@ -1631,13 +1628,13 @@ msgstr "Impossible de mettre à jour le mot de passe, les nouveaux mots de passe msgid "Unable to update password, passwords do not match requirements. Please try again." msgstr "Impossible de mettre à jour le mot de passe, les mots de passe ne correspondent pas aux exigences. Veuillez réessayer." -#: src/user/mutations/update-user-password.js:95 -#: src/user/mutations/update-user-password.js:103 +#: src/user/data-source.js:137 +#: src/user/data-source.js:145 msgid "Unable to update password. Please try again." msgstr "Impossible de mettre à jour le mot de passe. Veuillez réessayer." -#: src/user/mutations/update-user-profile.js:154 -#: src/user/mutations/update-user-profile.js:162 +#: src/user/data-source.js:297 +#: src/user/data-source.js:305 msgid "Unable to update profile. Please try again." msgstr "Impossible de mettre à jour le profil. Veuillez réessayer." @@ -1694,14 +1691,14 @@ msgstr "Impossible de mettre à jour le rôle de l'utilisateur. Veuillez réessa msgid "Unable to update your own role." msgstr "Impossible de mettre à jour votre propre rôle." -#: src/user/mutations/verify-account.js:51 -#: src/user/mutations/verify-account.js:63 -#: src/user/mutations/verify-account.js:77 +#: src/user/mutations/verify-account.js:48 +#: src/user/mutations/verify-account.js:60 +#: src/user/mutations/verify-account.js:74 msgid "Unable to verify account. Please request a new email." msgstr "Impossible de vérifier le compte. Veuillez demander un nouvel e-mail." -#: src/user/mutations/verify-account.js:128 -#: src/user/mutations/verify-account.js:136 +#: src/user/data-source.js:590 +#: src/user/data-source.js:598 msgid "Unable to verify account. Please try again." msgstr "Impossible de vérifier le compte. Veuillez réessayer." @@ -1709,7 +1706,7 @@ msgstr "Impossible de vérifier le compte. Veuillez réessayer." msgid "Unable to verify if user is a super admin, please try again." msgstr "Impossible de vérifier si l'utilisateur est un super administrateur, veuillez réessayer." -#: src/user/mutations/update-user-profile.js:99 +#: src/user/mutations/update-user-profile.js:97 #: src/user/queries/is-user-admin.js:49 msgid "Unable to verify if user is an admin, please try again." msgstr "Impossible de vérifier si l'utilisateur est un administrateur, veuillez réessayer." @@ -1728,7 +1725,7 @@ msgstr "Impossible de vérifier une organisation inconnue." msgid "User could not be queried." msgstr "L'utilisateur n'a pas pu être interrogé." -#: src/user/mutations/sign-up.js:79 +#: src/user/mutations/sign-up.js:80 msgid "User is trying to register for a non-production environment." msgstr "L'utilisateur essaie de s'enregistrer dans un environnement de non-production." @@ -1736,8 +1733,8 @@ msgstr "L'utilisateur essaie de s'enregistrer dans un environnement de non-produ msgid "User role was updated successfully." msgstr "Le rôle de l'utilisateur a été mis à jour avec succès." -#: src/user/mutations/update-user-profile.js:80 -#: src/user/mutations/verify-account.js:88 +#: src/user/mutations/update-user-profile.js:78 +#: src/user/mutations/verify-account.js:85 msgid "Username not available, please try another." msgstr "Le nom d'utilisateur n'est pas disponible, veuillez en essayer un autre." diff --git a/api/src/query.js b/api/src/query.js index 03430825eb..eb908907b7 100644 --- a/api/src/query.js +++ b/api/src/query.js @@ -6,8 +6,6 @@ import * as domainQueries from './domain/queries' import * as organizationQueries from './organization/queries' import * as summaryQueries from './summaries/queries' import * as userQueries from './user/queries' -import * as verifiedDomainQueries from './verified-domains/queries' -import * as verifiedOrgQueries from './verified-organizations/queries' import * as auditLogQueries from './audit-logs/queries' import * as additionalFindingsQueries from './additional-findings/queries' import * as tagsQueries from './tags/queries' @@ -30,10 +28,6 @@ export const createQuerySchema = () => { ...summaryQueries, // User Queries ...userQueries, - // Verified Domain Queries - ...verifiedDomainQueries, - // Verified Organization Queries - ...verifiedOrgQueries, ...additionalFindingsQueries, ...tagsQueries, }), diff --git a/api/src/tags/mutations/create-tag.js b/api/src/tags/mutations/create-tag.js index 293dbc2165..30b3149e55 100644 --- a/api/src/tags/mutations/create-tag.js +++ b/api/src/tags/mutations/create-tag.js @@ -52,8 +52,7 @@ export const createTag = new mutationWithClientMutationId({ request, userKey, auth: { userRequired, verifiedRequired, checkPermission, checkSuperAdmin, superAdminRequired }, - loaders: { loadOrgByKey }, - dataSources: { tags, auditLogs }, + dataSources: { tags, auditLogs, organization }, validators: { cleanseInput, slugify }, }, ) => { @@ -110,7 +109,7 @@ export const createTag = new mutationWithClientMutationId({ } // Check to see if org exists - org = await loadOrgByKey.load(orgId) + org = await organization.byKey.load(orgId) if (typeof org === 'undefined') { console.warn(`User: ${userKey} attempted to create a tag to an organization: ${orgId} that does not exist.`) return { diff --git a/api/src/tags/mutations/update-tag.js b/api/src/tags/mutations/update-tag.js index bf50c1b3bb..c2759a682f 100644 --- a/api/src/tags/mutations/update-tag.js +++ b/api/src/tags/mutations/update-tag.js @@ -57,8 +57,7 @@ export const updateTag = new mutationWithClientMutationId({ userKey, auth: { userRequired, verifiedRequired, checkSuperAdmin, superAdminRequired, checkPermission }, validators: { cleanseInput, slugify }, - loaders: { loadOrgByKey }, - dataSources: { tags, auditLogs }, + dataSources: { tags, auditLogs, organization }, }, ) => { // Get User @@ -104,7 +103,7 @@ export const updateTag = new mutationWithClientMutationId({ } } // Check to see if org exists - org = await loadOrgByKey.load(orgId) + org = await organization.byKey.load(orgId) if (typeof org === 'undefined') { console.warn(`User: ${userKey} attempted to update a tag to an organization: ${orgId} that does not exist.`) return { diff --git a/api/src/tags/objects/__tests__/tag.test.js b/api/src/tags/objects/__tests__/tag.test.js index f57630c826..2d9c41dd02 100644 --- a/api/src/tags/objects/__tests__/tag.test.js +++ b/api/src/tags/objects/__tests__/tag.test.js @@ -13,7 +13,7 @@ describe('Tag.organizations', () => { context = { userKey, auth: { userRequired, verifiedRequired, checkPermission }, - loaders: { loadOrgByKey }, + dataSources: { organization: { byKey: loadOrgByKey } }, } }) diff --git a/api/src/tags/objects/tag.js b/api/src/tags/objects/tag.js index f88c02986e..30383819c7 100644 --- a/api/src/tags/objects/tag.js +++ b/api/src/tags/objects/tag.js @@ -40,7 +40,7 @@ export const tagType = new GraphQLObjectType({ { userKey, auth: { userRequired, verifiedRequired, checkPermission }, - loaders: { loadOrgByKey }, + dataSources: { organization }, }, ) => { const user = await userRequired() @@ -50,7 +50,7 @@ export const tagType = new GraphQLObjectType({ const orgs = [] for (const orgId of organizations) { - const org = await loadOrgByKey.load(orgId) + const org = await organization.byKey.load(orgId) if (!org) continue const permission = await checkPermission({ orgId: org._id }) if (!ac.can(permission).readOwn('tag').granted) continue diff --git a/api/src/tags/queries/__tests__/find-all-tags.test.js b/api/src/tags/queries/__tests__/find-all-tags.test.js index 1673b6cbad..1d38fe6056 100644 --- a/api/src/tags/queries/__tests__/find-all-tags.test.js +++ b/api/src/tags/queries/__tests__/find-all-tags.test.js @@ -14,8 +14,7 @@ describe('findAllTags', () => { userKey = 'test-user' context = { userKey, - dataSources: { tags: { all: tagsAll } }, - loaders: { loadOrgByKey: jest.fn() }, + dataSources: { tags: { all: tagsAll }, organization: { byKey: jest.fn() } }, auth: { userRequired, verifiedRequired, checkSuperAdmin, superAdminRequired }, validators: { cleanseInput }, } diff --git a/api/src/tags/queries/find-all-tags.js b/api/src/tags/queries/find-all-tags.js index 31b58c411f..d87641df7a 100644 --- a/api/src/tags/queries/find-all-tags.js +++ b/api/src/tags/queries/find-all-tags.js @@ -21,8 +21,7 @@ export const findAllTags = { { userKey, auth: { userRequired, verifiedRequired, checkSuperAdmin, superAdminRequired }, - loaders: { loadOrgByKey }, - dataSources: { tags: tagsSource }, + dataSources: { tags: tagsSource, organization }, validators: { cleanseInput }, }, ) => { @@ -33,7 +32,7 @@ export const findAllTags = { if (args.orgId) { const { type: _orgType, id: orgId } = fromGlobalId(cleanseInput(args.orgId)) // Get Org from db - const org = await loadOrgByKey.load(orgId) + const org = await organization.byKey.load(orgId) orgKey = org?._key } else { const isSuperAdmin = await checkSuperAdmin() diff --git a/api/src/user/__tests__/data-source.test.js b/api/src/user/__tests__/data-source.test.js new file mode 100644 index 0000000000..310c2875e9 --- /dev/null +++ b/api/src/user/__tests__/data-source.test.js @@ -0,0 +1,202 @@ +import { dbNameFromFile } from 'arango-tools' +import { ensureDatabase as ensure } from '../../testUtilities' +import { setupI18n } from '@lingui/core' + +import englishMessages from '../../locale/en/messages' +import frenchMessages from '../../locale/fr/messages' +import { cleanseInput } from '../../validators' +import { collectionNames } from '../../collection-names' +import { UserDataSource } from '../data-source' +import dbschema from '../../../database.json' + +const { DB_PASS: rootPass, DB_URL: url } = process.env + +describe('given the UserDataSource', () => { + let query, drop, truncate, collections, transaction, i18n + + const consoleOutput = [] + const mockedInfo = (output) => consoleOutput.push(output) + const mockedWarn = (output) => consoleOutput.push(output) + const mockedError = (output) => consoleOutput.push(output) + + beforeAll(async () => { + console.info = mockedInfo + console.warn = mockedWarn + console.error = mockedError + i18n = setupI18n({ + locale: 'en', + localeData: { + en: { plurals: {} }, + fr: { plurals: {} }, + }, + locales: ['en', 'fr'], + messages: { + en: englishMessages.messages, + fr: frenchMessages.messages, + }, + }) + ;({ query, drop, truncate, collections, transaction } = await ensure({ + variables: { + dbname: dbNameFromFile(__filename), + username: 'root', + rootPassword: rootPass, + password: rootPass, + url, + }, + schema: dbschema, + })) + }) + afterEach(async () => { + consoleOutput.length = 0 + await truncate() + }) + afterAll(async () => { + await drop() + }) + + const makeDataSource = ({ userKey = 'NO_USER' } = {}) => + new UserDataSource({ + query, + userKey, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }) + + describe('loader properties', () => { + it('byKey loads a user by key', async () => { + const insertedUser = await collections.users.save({ + userName: 'test.account@istio.actually.exists', + displayName: 'Test Account', + }) + + const userDataSource = makeDataSource() + const user = await userDataSource.byKey.load(insertedUser._key) + + expect(user.userName).toEqual('test.account@istio.actually.exists') + }) + + it('byUserName loads a user by user name', async () => { + await collections.users.save({ + userName: 'test.account@istio.actually.exists', + displayName: 'Test Account', + }) + + const userDataSource = makeDataSource() + const user = await userDataSource.byUserName.load('test.account@istio.actually.exists') + + expect(user.displayName).toEqual('Test Account') + }) + }) + + describe('create', () => { + it('inserts a new user and returns it', async () => { + const userDataSource = makeDataSource() + + const insertedUser = await userDataSource.create({ + user: { + displayName: 'New User', + userName: 'new.user@istio.actually.exists', + password: 'hashed-password', + }, + }) + + expect(insertedUser.userName).toEqual('new.user@istio.actually.exists') + + const checkCursor = await query` + FOR user IN users + FILTER user.userName == "new.user@istio.actually.exists" + RETURN user + ` + const checkUser = await checkCursor.next() + expect(checkUser).toBeDefined() + }) + + it('inserts an affiliation edge when one is provided', async () => { + const org = await collections.organizations.save({ verified: false }) + const userDataSource = makeDataSource() + + const insertedUser = await userDataSource.create({ + user: { + displayName: 'New User', + userName: 'affiliated.user@istio.actually.exists', + password: 'hashed-password', + }, + affiliation: { orgId: org._id, permission: 'admin' }, + }) + + const affiliationCursor = await query` + FOR aff IN affiliations + FILTER aff._to == ${insertedUser._id} + RETURN aff + ` + const affiliation = await affiliationCursor.next() + expect(affiliation.permission).toEqual('admin') + }) + + describe('transaction step fails', () => { + it('throws an error', async () => { + const userDataSource = makeDataSource() + userDataSource._transaction = jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue(new Error('trx step error')), + abort: jest.fn(), + }) + + await expect(userDataSource.create({ user: { userName: 'fail@istio.actually.exists' } })).rejects.toEqual( + new Error('Unable to sign up. Please try again.'), + ) + }) + }) + }) + + describe('removeUserAndAffiliations', () => { + it('removes the user and their affiliations', async () => { + const insertedUser = await collections.users.save({ userName: 'remove.me@istio.actually.exists' }) + const org = await collections.organizations.save({ verified: false }) + await collections.affiliations.save({ + _from: org._id, + _to: insertedUser._id, + permission: 'admin', + }) + + const userDataSource = makeDataSource() + await userDataSource.removeUserAndAffiliations({ userId: insertedUser._id }) + + const userCursor = await query` + FOR user IN users + FILTER user._key == ${insertedUser._key} + RETURN user + ` + expect(await userCursor.hasNext).toBeDefined() + expect(await userCursor.all()).toEqual([]) + + const affCursor = await query` + FOR aff IN affiliations + FILTER aff._to == ${insertedUser._id} + RETURN aff + ` + expect(await affCursor.all()).toEqual([]) + }) + }) + + describe('updatePassword', () => { + it('updates the users password', async () => { + const insertedUser = await collections.users.save({ + userName: 'update.password@istio.actually.exists', + password: 'old-password', + }) + + const userDataSource = makeDataSource() + await userDataSource.updatePassword({ userKey: insertedUser._key, hashedPassword: 'new-password' }) + + const checkCursor = await query` + FOR user IN users + FILTER user._key == ${insertedUser._key} + RETURN user.password + ` + expect(await checkCursor.next()).toEqual('new-password') + }) + }) +}) diff --git a/api/src/user/data-source.js b/api/src/user/data-source.js new file mode 100644 index 0000000000..7936810db3 --- /dev/null +++ b/api/src/user/data-source.js @@ -0,0 +1,604 @@ +import { t } from '@lingui/macro' + +import { loadUserByKey, loadUserByUserName, loadUserConnectionsByUserId, loadMyTrackerByUserId } from './loaders' + +export class UserDataSource { + constructor({ query, userKey, i18n, language, cleanseInput, transaction, collections }) { + this._query = query + this._userKey = userKey + this._i18n = i18n + this._transaction = transaction + this._collections = collections + + this.byKey = loadUserByKey({ query, userKey, i18n }) + this.byUserName = loadUserByUserName({ query, userKey, i18n }) + this.connectionsByUserId = loadUserConnectionsByUserId({ query, userKey, cleanseInput, i18n }) + this.myTrackerByUserId = loadMyTrackerByUserId({ query, language, userKey, i18n }) + } + + async create({ user, affiliation }) { + const trx = await this._transaction(this._collections) + + let insertedUserCursor + try { + insertedUserCursor = await trx.step( + () => this._query` + WITH users + INSERT ${user} INTO users + RETURN MERGE( + { + id: NEW._key, + _type: "user" + }, + NEW + ) + `, + ) + } catch (err) { + console.error(`Transaction step error occurred while user: ${user.userName} attempted to sign up, creating user: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to sign up. Please try again.`)) + } + + let insertedUser + try { + insertedUser = await insertedUserCursor.next() + } catch (err) { + console.error(`Cursor error occurred while user: ${user.userName} attempted to sign up, creating user: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to sign up. Please try again.`)) + } + + if (affiliation) { + try { + await trx.step( + () => this._query` + WITH affiliations, organizations, users + INSERT { + _from: ${affiliation.orgId}, + _to: ${insertedUser._id}, + permission: ${affiliation.permission}, + } INTO affiliations + `, + ) + } catch (err) { + console.log(`DEBUG affiliation catch: this._i18n=${typeof this._i18n} err=${err} errStack=${err && err.stack}`) + console.error(`Transaction step error occurred while user: ${user.userName} attempted to sign up, assigning affiliation: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to sign up. Please try again.`)) + } + } + + try { + await trx.commit() + } catch (err) { + console.error(`Transaction commit error occurred while user: ${user.userName} attempted to sign up: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to sign up. Please try again.`)) + } + + return insertedUser + } + + async removeUserAndAffiliations({ userId }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH affiliations, organizations, users + FOR v, e IN 1..1 INBOUND ${userId} affiliations + REMOVE { _key: e._key } IN affiliations + OPTIONS { waitForSync: true } + `, + ) + } catch (err) { + console.error(`Trx step error occurred when removing users remaining affiliations when user: ${this._userKey} attempted to close account: ${userId}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to close account. Please try again.`)) + } + + try { + await trx.step( + () => this._query` + WITH users + REMOVE PARSE_IDENTIFIER(${userId}).key + IN users OPTIONS { waitForSync: true } + `, + ) + } catch (err) { + console.error(`Trx step error occurred when removing user: ${this._userKey} attempted to close account: ${userId}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to close account. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred when user: ${this._userKey} attempted to close account: ${userId}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to close account. Please try again.`)) + } + } + + async updatePassword({ userKey, hashedPassword }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH users + FOR user IN users + UPDATE ${userKey} WITH { password: ${hashedPassword} } IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when user: ${userKey} attempted to update their password: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to update password. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred when user: ${userKey} attempted to update their password: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to update password. Please try again.`)) + } + } + + async updatePasswordAndResetAttempts({ userKey, hashedPassword }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH users + FOR user IN users + UPDATE ${userKey} + WITH { + password: ${hashedPassword}, + failedLoginAttempts: 0 + } IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when user: ${userKey} attempted to reset their password: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to reset password. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred while user: ${userKey} attempted to authenticate: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to reset password. Please try again.`)) + } + } + + async removePhoneNumber({ userKey, tfaSendMethod }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH users + UPSERT { _key: ${userKey} } + INSERT { + phoneDetails: null, + phoneValidated: false, + tfaSendMethod: ${tfaSendMethod} + } + UPDATE { + phoneDetails: null, + phoneValidated: false, + tfaSendMethod: ${tfaSendMethod} + } + IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred well removing phone number for user: ${userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove phone number. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred well removing phone number for user: ${userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove phone number. Please try again.`)) + } + } + + async setPhoneNumber({ userKey, tfaCode, phoneDetails, tfaSendMethod }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH users + UPSERT { _key: ${userKey} } + INSERT { + tfaCode: ${tfaCode}, + phoneDetails: ${phoneDetails}, + phoneValidated: false, + tfaSendMethod: ${tfaSendMethod} + } + UPDATE { + tfaCode: ${tfaCode}, + phoneDetails: ${phoneDetails}, + phoneValidated: false, + tfaSendMethod: ${tfaSendMethod} + } + IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred for user: ${userKey} when upserting phone number information: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to set phone number, please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred for user: ${userKey} when upserting phone number information: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to set phone number, please try again.`)) + } + } + + async setPhoneValidated({ userKey }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH users + UPSERT { _key: ${userKey} } + INSERT { phoneValidated: true } + UPDATE { phoneValidated: true } + IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when upserting the tfaValidate field for ${userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to two factor authenticate. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred when upserting the tfaValidate field for ${userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to two factor authenticate. Please try again.`)) + } + } + + async updateProfile({ userKey, updatedUser }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH users + UPSERT { _key: ${userKey} } + INSERT ${updatedUser} + UPDATE ${updatedUser} + IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when user: ${userKey} attempted to update their profile: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to update profile. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred when user: ${userKey} attempted to update their profile: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to update profile. Please try again.`)) + } + } + + async resetFailedLoginAttemptsAndSetTfaCode({ userKey, tfaCode, refreshInfo }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH users + FOR u IN users + UPDATE ${userKey} WITH { failedLoginAttempts: 0 } IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when resetting failed login attempts for user: ${userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to sign in, please try again.`)) + } + + try { + await trx.step( + () => this._query` + WITH users + UPSERT { _key: ${userKey} } + INSERT { + tfaCode: ${tfaCode}, + refreshInfo: ${refreshInfo} + } + UPDATE { + tfaCode: ${tfaCode}, + refreshInfo: ${refreshInfo} + } + IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when inserting TFA code for user: ${userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to sign in, please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred while user: ${userKey} attempted to tfa sign in: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to sign in, please try again.`)) + } + } + + async resetFailedLoginAttemptsAndSetRefreshInfo({ userKey, refreshInfo, loginDate }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH users + FOR u IN users + UPDATE ${userKey} WITH { failedLoginAttempts: 0 } IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when resetting failed login attempts for user: ${userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to sign in, please try again.`)) + } + + try { + await trx.step( + () => this._query` + WITH users + UPSERT { _key: ${userKey} } + INSERT { refreshInfo: ${refreshInfo}, lastLogin: ${loginDate} } + UPDATE { refreshInfo: ${refreshInfo}, lastLogin: ${loginDate} } + IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when attempting to setting refresh tokens for user: ${userKey} during sign in: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to sign in, please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred while user: ${userKey} attempted a regular sign in: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to sign in, please try again.`)) + } + } + + async incrementFailedLoginAttempts({ userKey, failedLoginAttempts }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH users + FOR u IN users + UPDATE ${userKey} WITH { + failedLoginAttempts: ${failedLoginAttempts} + } IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when incrementing failed login attempts for user: ${userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to sign in, please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred while user: ${userKey} failed to sign in: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to sign in, please try again.`)) + } + } + + async authenticateSetSession({ userKey, refreshInfo, loginDate, emailValidated }) { + const trx = await this._transaction(this._collections) + + const fields = { + tfaCode: null, + refreshInfo, + lastLogin: loginDate, + } + if (emailValidated) { + fields.emailValidated = true + } + + try { + await trx.step( + () => this._query` + WITH users + UPSERT { _key: ${userKey} } + INSERT ${fields} + UPDATE ${fields} + IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when clearing tfa code and setting refresh id for user: ${userKey} during authentication: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to authenticate. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred while user: ${userKey} attempted to authenticate: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to authenticate. Please try again.`)) + } + } + + async resetTfaCode({ userKey }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH users + UPSERT { _key: ${userKey} } + INSERT { tfaCode: null } + UPDATE { tfaCode: null } + IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when clearing tfa code on attempt timeout for user: ${userKey} during authentication: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Incorrect TFA code. Please sign in again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred while user: ${userKey} attempted to authenticate: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Incorrect TFA code. Please sign in again.`)) + } + } + + async setRefreshInfo({ userKey, refreshInfo }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH users + UPSERT { _key: ${userKey} } + INSERT { refreshInfo: ${refreshInfo} } + UPDATE { refreshInfo: ${refreshInfo} } + IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when attempting to refresh tokens for user: ${userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to refresh tokens, please sign in.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred while user: ${userKey} attempted to refresh tokens: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to refresh tokens, please sign in.`)) + } + } + + async completeTour({ userKey, tourId }) { + try { + const completeTourCursor = await this._query` + LET userCompleteTours = FIRST( + FOR user IN users + FILTER user._key == ${userKey} + LIMIT 1 + RETURN user.completedTours + ) + UPDATE { _key: ${userKey} } + WITH { + completedTours: APPEND( + userCompleteTours[* FILTER CURRENT.tourId != ${tourId}], + { tourId: ${tourId}, completedAt: DATE_ISO8601(DATE_NOW()) } + ) + } + IN users + ` + await completeTourCursor.next() + } catch (err) { + console.error(`Database error occurred when user: ${userKey} attempted to complete tour: ${tourId}: ${err}`) + throw new Error(this._i18n._(t`Unable to confirm completion of the tour. Please try again.`)) + } + } + + async dismissMessage({ userKey, messageId }) { + try { + const dismissMessageCursor = await this._query` + LET userDismissedMessages = FIRST( + FOR user IN users + FILTER user._key == ${userKey} + LIMIT 1 + RETURN user.dismissedMessages + ) + UPDATE { _key: ${userKey} } + WITH { + dismissedMessages: APPEND( + userDismissedMessages[* FILTER CURRENT.messageId != ${messageId}], + { messageId: ${messageId}, dismissedAt: DATE_ISO8601(DATE_NOW()) } + ) + } + IN users + ` + await dismissMessageCursor.next() + } catch (err) { + console.error(`Database error occurred when user: ${userKey} attempted to dismiss message: ${messageId}: ${err}`) + throw new Error(this._i18n._(t`Unable to dismiss message. Please try again.`)) + } + } + + async verifyAccountUpdate({ userKey, newUserName }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH users + UPSERT { _key: ${userKey} } + INSERT { + emailValidated: true, + userName: ${newUserName}, + } + UPDATE { + emailValidated: true, + userName: ${newUserName}, + } + IN users + `, + ) + } catch (err) { + console.error(`Trx step error occurred when upserting email validation for user: ${userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to verify account. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Trx commit error occurred when upserting email validation for user: ${userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to verify account. Please try again.`)) + } + } +} diff --git a/api/src/user/index.js b/api/src/user/index.js index ee648b9915..f8897c6de9 100644 --- a/api/src/user/index.js +++ b/api/src/user/index.js @@ -1,3 +1,4 @@ +export * from './data-source' export * from './loaders' export * from './mutations' export * from './objects' diff --git a/api/src/user/mutations/__tests__/authenticate.test.js b/api/src/user/mutations/__tests__/authenticate.test.js index 94235d3ac7..5f951d0579 100644 --- a/api/src/user/mutations/__tests__/authenticate.test.js +++ b/api/src/user/mutations/__tests__/authenticate.test.js @@ -12,7 +12,7 @@ import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput } from '../../../validators' import { tokenize, verifyToken } from '../../../auth' -import { loadUserByKey } from '../../loaders' +import { UserDataSource } from '../../../user' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' import jwt from 'jsonwebtoken' @@ -100,6 +100,7 @@ describe('authenticate user account', () => { const mockedCookie = jest.fn() const mockedResponse = { cookie: mockedCookie } + const userDataSource = new UserDataSource({ query, userKey: user._key, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -145,8 +146,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, }, }) @@ -233,6 +234,7 @@ describe('authenticate user account', () => { const mockedTokenize = jest.fn().mockReturnValueOnce(authToken).mockReturnValueOnce(refreshToken) + const userDataSource = new UserDataSource({ query, userKey: user._key, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -279,8 +281,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, }, }) @@ -392,9 +394,7 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), - }, + dataSources: { user: {} }, }, }) @@ -464,9 +464,7 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), - }, + dataSources: { user: {} }, }, }) @@ -536,9 +534,11 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, }, @@ -630,12 +630,11 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 456, i18n, transaction, collections: collectionNames }), + { byKey: { load: jest.fn().mockReturnValue({ _key: 456 }) } }, + ), }, }, }) @@ -656,6 +655,10 @@ describe('authenticate user account', () => { secret: String(SIGN_IN_KEY), }) + const mockedTransaction = jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue(new Error('Transaction step error')), + abort: jest.fn(), + }) const response = await graphql({ schema, source: ` @@ -691,10 +694,7 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error')), - abort: jest.fn(), - }), + transaction: mockedTransaction, uuidv4, auth: { bcrypt, @@ -704,16 +704,21 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - tfaCode: 123456, - refreshInfo: { - remember: false, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 123, + tfaCode: 123456, + refreshInfo: { + remember: false, + }, + }), }, - }), - }, + }, + ), }, }, }) @@ -735,6 +740,11 @@ describe('authenticate user account', () => { secret: String(SIGN_IN_KEY), }) + const mockedTransaction = jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValue(), + commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), + abort: jest.fn(), + }) const response = await graphql({ schema, source: ` @@ -770,11 +780,7 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue(), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), - abort: jest.fn(), - }), + transaction: mockedTransaction, uuidv4, auth: { bcrypt, @@ -784,16 +790,21 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - tfaCode: 123456, - refreshInfo: { - remember: false, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 123, + tfaCode: 123456, + refreshInfo: { + remember: false, + }, + }), }, - }), - }, + }, + ), }, }, }) @@ -874,9 +885,7 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), - }, + dataSources: { user: {} }, }, }) @@ -946,9 +955,7 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), - }, + dataSources: { user: {} }, }, }) @@ -1018,9 +1025,11 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, }, @@ -1112,12 +1121,11 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 456, i18n, transaction, collections: collectionNames }), + { byKey: { load: jest.fn().mockReturnValue({ _key: 456 }) } }, + ), }, }, }) @@ -1130,165 +1138,6 @@ describe('authenticate user account', () => { ]) }) }) - describe('transaction step error occurs', () => { - describe('when clearing tfa code and setting refresh id', () => { - it('throws an error', async () => { - const token = tokenize({ - parameters: { userKey: 123 }, - secret: String(SIGN_IN_KEY), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - authenticate( - input: { - sendMethod: EMAIL - authenticationCode: 123456 - authenticateToken: "${token}" - } - ) { - result { - ... on AuthResult { - authToken - user { - id - userName - displayName - phoneValidated - emailValidated - } - } - ... on AuthenticateError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error')), - abort: jest.fn(), - }), - uuidv4, - auth: { - bcrypt, - tokenize, - verifyToken: verifyToken({}), - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - tfaCode: 123456, - refreshInfo: { - remember: false, - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError("Impossible de s'authentifier. Veuillez réessayer.")] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred when clearing tfa code and setting refresh id for user: 123 during authentication: Error: Transaction step error`, - ]) - }) - }) - }) - describe('transaction commit error occurs', () => { - describe('when user attempts to authenticate', () => { - it('throws an error', async () => { - const token = tokenize({ - parameters: { userKey: 123 }, - secret: String(SIGN_IN_KEY), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - authenticate( - input: { - sendMethod: EMAIL - authenticationCode: 123456 - authenticateToken: "${token}" - } - ) { - result { - ... on AuthResult { - authToken - user { - id - userName - displayName - phoneValidated - emailValidated - } - } - ... on AuthenticateError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue(), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), - abort: jest.fn(), - }), - uuidv4, - auth: { - bcrypt, - tokenize, - verifyToken: verifyToken({}), - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - tfaCode: 123456, - refreshInfo: { - remember: false, - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError("Impossible de s'authentifier. Veuillez réessayer.")] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred while user: 123 attempted to authenticate: Error: Transaction commit error`, - ]) - }) - }) - }) }) }) }) diff --git a/api/src/user/mutations/__tests__/close-account.test.js b/api/src/user/mutations/__tests__/close-account.test.js index 500f06a53e..4eafca37ac 100644 --- a/api/src/user/mutations/__tests__/close-account.test.js +++ b/api/src/user/mutations/__tests__/close-account.test.js @@ -8,7 +8,7 @@ import englishMessages from '../../../locale/en/messages' import frenchMessages from '../../../locale/fr/messages' import { checkSuperAdmin, userRequired } from '../../../auth' import { loadOrgByKey } from '../../../organization/loaders' -import { loadUserByKey } from '../../../user/loaders' +import { UserDataSource } from '../../../user' import { cleanseInput } from '../../../validators' import { createMutationSchema } from '../../../mutation' import { createQuerySchema } from '../../../query' @@ -140,6 +140,13 @@ describe('given the closeAccount mutation', () => { }) }) it('removes the users affiliations', async () => { + const userDataSource = new UserDataSource({ + query, + userKey: user._key, + i18n, + transaction, + collections: collectionNames, + }) await graphql({ schema, source: ` @@ -174,20 +181,19 @@ describe('given the closeAccount mutation', () => { userRequired: userRequired({ i18n, userKey: user._key, - loadUserByKey: loadUserByKey({ + loadUserByKey: userDataSource.byKey, + }), + }, + dataSources: { + organization: { + byKey: loadOrgByKey({ query, - userKey: user._key, + language: 'en', i18n, + userKey: user._key, }), - }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), + }, + user: userDataSource, }, validators: { cleanseInput }, }, @@ -219,6 +225,13 @@ describe('given the closeAccount mutation', () => { }) }) it('returns a status message', async () => { + const userDataSource = new UserDataSource({ + query, + userKey: user._key, + i18n, + transaction, + collections: collectionNames, + }) const response = await graphql({ schema, source: ` @@ -253,20 +266,19 @@ describe('given the closeAccount mutation', () => { userRequired: userRequired({ i18n, userKey: user._key, - loadUserByKey: loadUserByKey({ + loadUserByKey: userDataSource.byKey, + }), + }, + dataSources: { + organization: { + byKey: loadOrgByKey({ query, - userKey: user._key, + language: 'en', i18n, + userKey: user._key, }), - }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), + }, + user: userDataSource, }, validators: { cleanseInput }, }, @@ -302,6 +314,13 @@ describe('given the closeAccount mutation', () => { }) }) it('returns a status message', async () => { + const userDataSource = new UserDataSource({ + query, + userKey: user._key, + i18n, + transaction, + collections: collectionNames, + }) const response = await graphql({ schema, source: ` @@ -336,20 +355,19 @@ describe('given the closeAccount mutation', () => { userRequired: userRequired({ i18n, userKey: user._key, - loadUserByKey: loadUserByKey({ + loadUserByKey: userDataSource.byKey, + }), + }, + dataSources: { + organization: { + byKey: loadOrgByKey({ query, - userKey: user._key, + language: 'en', i18n, + userKey: user._key, }), - }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), + }, + user: userDataSource, }, validators: { cleanseInput }, }, @@ -370,6 +388,13 @@ describe('given the closeAccount mutation', () => { }) }) it('closes the users account', async () => { + const userDataSource = new UserDataSource({ + query, + userKey: user._key, + i18n, + transaction, + collections: collectionNames, + }) await graphql({ schema, source: ` @@ -404,20 +429,19 @@ describe('given the closeAccount mutation', () => { userRequired: userRequired({ i18n, userKey: user._key, - loadUserByKey: loadUserByKey({ + loadUserByKey: userDataSource.byKey, + }), + }, + dataSources: { + organization: { + byKey: loadOrgByKey({ query, - userKey: user._key, + language: 'en', i18n, + userKey: user._key, }), - }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), + }, + user: userDataSource, }, validators: { cleanseInput }, }, @@ -539,6 +563,13 @@ describe('given the closeAccount mutation', () => { }) }) it('removes the users affiliations', async () => { + const userDataSource = new UserDataSource({ + query, + userKey: user._key, + i18n, + transaction, + collections: collectionNames, + }) await graphql({ schema, source: ` @@ -573,25 +604,19 @@ describe('given the closeAccount mutation', () => { userRequired: userRequired({ i18n, userKey: user._key, - loadUserByKey: loadUserByKey({ + loadUserByKey: userDataSource.byKey, + }), + }, + dataSources: { + organization: { + byKey: loadOrgByKey({ query, - userKey: user._key, + language: 'en', i18n, + userKey: user._key, }), - }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: user._key, - i18n, - }), + }, + user: userDataSource, }, validators: { cleanseInput }, }, @@ -624,6 +649,13 @@ describe('given the closeAccount mutation', () => { }) }) it('returns a status message', async () => { + const userDataSource = new UserDataSource({ + query, + userKey: user._key, + i18n, + transaction, + collections: collectionNames, + }) const response = await graphql({ schema, source: ` @@ -658,25 +690,19 @@ describe('given the closeAccount mutation', () => { userRequired: userRequired({ i18n, userKey: user._key, - loadUserByKey: loadUserByKey({ + loadUserByKey: userDataSource.byKey, + }), + }, + dataSources: { + organization: { + byKey: loadOrgByKey({ query, - userKey: user._key, + language: 'en', i18n, + userKey: user._key, }), - }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: user._key, - i18n, - }), + }, + user: userDataSource, }, validators: { cleanseInput }, }, @@ -712,6 +738,13 @@ describe('given the closeAccount mutation', () => { }) }) it('returns a status message', async () => { + const userDataSource = new UserDataSource({ + query, + userKey: user._key, + i18n, + transaction, + collections: collectionNames, + }) const response = await graphql({ schema, source: ` @@ -746,25 +779,19 @@ describe('given the closeAccount mutation', () => { userRequired: userRequired({ i18n, userKey: user._key, - loadUserByKey: loadUserByKey({ + loadUserByKey: userDataSource.byKey, + }), + }, + dataSources: { + organization: { + byKey: loadOrgByKey({ query, - userKey: user._key, + language: 'en', i18n, + userKey: user._key, }), - }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: user._key, - }), - loadUserByKey: loadUserByKey({ - query, - userKey: user._key, - i18n, - }), + }, + user: userDataSource, }, validators: { cleanseInput }, }, @@ -785,6 +812,13 @@ describe('given the closeAccount mutation', () => { }) }) it('closes the users account', async () => { + const userDataSource = new UserDataSource({ + query, + userKey: superAdmin._key, + i18n, + transaction, + collections: collectionNames, + }) await graphql({ schema, source: ` @@ -821,20 +855,10 @@ describe('given the closeAccount mutation', () => { userRequired: userRequired({ i18n, userKey: superAdmin._key, - loadUserByKey: loadUserByKey({ - query, - userKey: superAdmin._key, - i18n, - }), - }), - }, - loaders: { - loadUserByKey: loadUserByKey({ - query, - userKey: superAdmin._key, - i18n, + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, validators: { cleanseInput }, }, }) @@ -903,13 +927,16 @@ describe('given the closeAccount mutation', () => { checkSuperAdmin: jest.fn().mockReturnValue(false), userRequired: jest.fn().mockReturnValue({ _key: '123' }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: '123', - }), + dataSources: { + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: '123', + }), + }, + user: {}, }, validators: { cleanseInput }, }, @@ -965,15 +992,19 @@ describe('given the closeAccount mutation', () => { checkSuperAdmin: jest.fn().mockReturnValue(true), userRequired: jest.fn().mockReturnValue({ _key: '123' }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: '123', - }), - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: '123', + }), + }, + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, validators: { cleanseInput }, @@ -1042,16 +1073,25 @@ describe('given the closeAccount mutation', () => { checkSuperAdmin: jest.fn().mockReturnValue(true), userRequired: jest.fn().mockReturnValue({ _key: '123', _id: 'users/123' }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: '123', - }), - loadUserByKey: { - load: jest.fn().mockReturnValue({ _key: '123' }), + dataSources: { + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: '123', + }), }, + user: Object.assign( + new UserDataSource({ + query: mockedQuery, + userKey: '123', + i18n, + transaction: mockedTransaction, + collections: collectionNames, + }), + { byKey: { load: jest.fn().mockReturnValue({ _key: '123' }) } }, + ), }, validators: { cleanseInput }, }, @@ -1108,16 +1148,25 @@ describe('given the closeAccount mutation', () => { checkSuperAdmin: jest.fn().mockReturnValue(true), userRequired: jest.fn().mockReturnValue({ _key: '123', _id: 'users/123' }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: '123', - }), - loadUserByKey: { - load: jest.fn().mockReturnValue({ _key: '123' }), + dataSources: { + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: '123', + }), }, + user: Object.assign( + new UserDataSource({ + query: mockedQuery, + userKey: '123', + i18n, + transaction: mockedTransaction, + collections: collectionNames, + }), + { byKey: { load: jest.fn().mockReturnValue({ _key: '123' }) } }, + ), }, validators: { cleanseInput }, }, @@ -1175,16 +1224,25 @@ describe('given the closeAccount mutation', () => { checkSuperAdmin: jest.fn().mockReturnValue(true), userRequired: jest.fn().mockReturnValue({ _key: '123', _id: 'users/123' }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: '123', - }), - loadUserByKey: { - load: jest.fn().mockReturnValue({ _key: '123' }), + dataSources: { + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: '123', + }), }, + user: Object.assign( + new UserDataSource({ + query: mockedQuery, + userKey: '123', + i18n, + transaction: mockedTransaction, + collections: collectionNames, + }), + { byKey: { load: jest.fn().mockReturnValue({ _key: '123' }) } }, + ), }, validators: { cleanseInput }, }, @@ -1248,13 +1306,16 @@ describe('given the closeAccount mutation', () => { checkSuperAdmin: jest.fn().mockReturnValue(false), userRequired: jest.fn().mockReturnValue({ _key: '123' }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: '123', - }), + dataSources: { + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: '123', + }), + }, + user: {}, }, validators: { cleanseInput }, }, @@ -1310,15 +1371,19 @@ describe('given the closeAccount mutation', () => { checkSuperAdmin: jest.fn().mockReturnValue(true), userRequired: jest.fn().mockReturnValue({ _key: '123' }), }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: '123', - }), - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + organization: { + byKey: loadOrgByKey({ + query, + language: 'en', + i18n, + userKey: '123', + }), + }, + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, validators: { cleanseInput }, @@ -1343,206 +1408,6 @@ describe('given the closeAccount mutation', () => { }) }) }) - describe('trx step error occurs', () => { - describe('when removing the users affiliations', () => { - it('throws an error', async () => { - const mockedCursor = { - all: jest.fn().mockReturnValue([{ count: 2 }]), - } - - const mockedQuery = jest.fn().mockReturnValue(mockedCursor) - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - commit: jest.fn(), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - closeAccountSelf(input: {}) { - result { - ... on CloseAccountResult { - status - } - ... on CloseAccountError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: mockedTransaction, - userKey: '123', - request: { ip: '127.0.0.1' }, - auth: { - checkSuperAdmin: jest.fn().mockReturnValue(true), - userRequired: jest.fn().mockReturnValue({ _key: '123', _id: 'users/123' }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: '123', - }), - loadUserByKey: { - load: jest.fn().mockReturnValue({ _key: '123' }), - }, - }, - validators: { cleanseInput }, - }, - }) - - const error = [new GraphQLError('Impossible de fermer le compte. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred when removing users remaining affiliations when user: 123 attempted to close account: users/123: Error: trx step error`, - ]) - }) - }) - describe('when removing the user', () => { - it('throws an error', async () => { - const mockedCursor = { - all: jest.fn().mockReturnValue([{ count: 2 }]), - } - - const mockedQuery = jest.fn().mockReturnValue(mockedCursor) - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValueOnce().mockRejectedValue(new Error('trx step error')), - commit: jest.fn(), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - closeAccountSelf(input: {}) { - result { - ... on CloseAccountResult { - status - } - ... on CloseAccountError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: mockedTransaction, - userKey: '123', - request: { ip: '127.0.0.1' }, - auth: { - checkSuperAdmin: jest.fn().mockReturnValue(true), - userRequired: jest.fn().mockReturnValue({ _key: '123', _id: 'users/123' }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: '123', - }), - loadUserByKey: { - load: jest.fn().mockReturnValue({ _key: '123' }), - }, - }, - validators: { cleanseInput }, - }, - }) - - const error = [new GraphQLError('Impossible de fermer le compte. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred when removing user: 123 attempted to close account: users/123: Error: trx step error`, - ]) - }) - }) - }) - describe('trx commit error occurs', () => { - it('throws an error', async () => { - const mockedCursor = { - all: jest.fn().mockReturnValue([{ count: 2 }]), - } - - const mockedQuery = jest.fn().mockReturnValue(mockedCursor) - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue(), - commit: jest.fn().mockRejectedValue(new Error('trx commit error')), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - closeAccountSelf(input: {}) { - result { - ... on CloseAccountResult { - status - } - ... on CloseAccountError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: mockedTransaction, - userKey: '123', - request: { ip: '127.0.0.1' }, - auth: { - checkSuperAdmin: jest.fn().mockReturnValue(true), - userRequired: jest.fn().mockReturnValue({ _key: '123', _id: 'users/123' }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ - query, - language: 'en', - i18n, - userKey: '123', - }), - loadUserByKey: { - load: jest.fn().mockReturnValue({ _key: '123' }), - }, - }, - validators: { cleanseInput }, - }, - }) - - const error = [new GraphQLError('Impossible de fermer le compte. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred when user: 123 attempted to close account: users/123: Error: trx commit error`, - ]) - }) - }) }) }) }) diff --git a/api/src/user/mutations/__tests__/refresh-tokens.test.js b/api/src/user/mutations/__tests__/refresh-tokens.test.js index c726fdb358..3c6333eab3 100644 --- a/api/src/user/mutations/__tests__/refresh-tokens.test.js +++ b/api/src/user/mutations/__tests__/refresh-tokens.test.js @@ -10,7 +10,7 @@ import frenchMessages from '../../../locale/fr/messages' import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput } from '../../../validators' -import { loadUserByKey } from '../../loaders' +import { UserDataSource } from '../../../user' import { tokenize } from '../../../auth' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -101,6 +101,7 @@ describe('refresh users tokens', () => { const mockedCookie = jest.fn() const mockedResponse = { cookie: mockedCookie } + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -137,8 +138,8 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, }, }) @@ -209,6 +210,7 @@ describe('refresh users tokens', () => { const mockedRequest = { cookies: { refresh_token: refreshToken } } + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -245,8 +247,8 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, }, }) @@ -341,9 +343,7 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), - }, + dataSources: { user: {} }, }, }) @@ -415,9 +415,7 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), - }, + dataSources: { user: {} }, }, }) @@ -491,9 +489,11 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, }, @@ -567,13 +567,15 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - refreshInfo: { - expiresAt: '', - }, - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + refreshInfo: { + expiresAt: '', + }, + }), + }, }, }, }, @@ -647,13 +649,15 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - refreshInfo: { - expiresAt: '', - }, - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + refreshInfo: { + expiresAt: '', + }, + }), + }, }, }, }, @@ -734,15 +738,20 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - refreshInfo: { - expiresAt: '', - refreshId: '1234', + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + { + byKey: { + load: jest.fn().mockReturnValue({ + refreshInfo: { + expiresAt: '', + refreshId: '1234', + }, + }), }, - }), - }, + }, + ), }, }, }) @@ -817,15 +826,20 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - refreshInfo: { - expiresAt: '', - refreshId: '1234', + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + { + byKey: { + load: jest.fn().mockReturnValue({ + refreshInfo: { + expiresAt: '', + refreshId: '1234', + }, + }), }, - }), - }, + }, + ), }, }, }) @@ -905,9 +919,7 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), - }, + dataSources: { user: {} }, }, }) @@ -979,9 +991,7 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), - }, + dataSources: { user: {} }, }, }) @@ -1055,9 +1065,11 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, }, @@ -1131,13 +1143,15 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - refreshInfo: { - expiresAt: '', - }, - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + refreshInfo: { + expiresAt: '', + }, + }), + }, }, }, }, @@ -1211,13 +1225,15 @@ describe('refresh users tokens', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - refreshInfo: { - expiresAt: '', - }, - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + refreshInfo: { + expiresAt: '', + }, + }), + }, }, }, }, @@ -1239,170 +1255,6 @@ describe('refresh users tokens', () => { }) }) }) - describe('transaction step error occurs', () => { - describe('when upserting new refreshId', () => { - it('throws an error', async () => { - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error')), - abort: jest.fn(), - }) - - const refreshToken = tokenize({ - parameters: { userKey: 123, uuid: '1234' }, - expPeriod: 168, - secret: String(REFRESH_KEY), - }) - const mockedRequest = { cookies: { refresh_token: refreshToken } } - const mockedFormat = jest - .fn() - .mockReturnValueOnce('2021-06-30T12:00:00') - .mockReturnValueOnce('2021-07-01T12:00:00') - const mockedMoment = jest.fn().mockReturnValue({ - format: mockedFormat, - isAfter: jest.fn().mockReturnValue(false), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - refreshTokens(input: {}) { - result { - ... on AuthResult { - authToken - user { - displayName - } - } - ... on AuthenticateError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: mockedTransaction, - uuidv4, - jwt, - moment: mockedMoment, - request: mockedRequest, - auth: { - tokenize: jest.fn().mockReturnValue('token'), - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - refreshInfo: { - expiresAt: '', - refreshId: '1234', - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Impossible de rafraîchir les jetons, veuillez vous connecter.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred when attempting to refresh tokens for user: 123: Error: Transaction step error`, - ]) - }) - }) - }) - describe('transaction commit error occurs', () => { - describe('when upserting new refreshId', () => { - it('throws an error', async () => { - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), - abort: jest.fn(), - }) - - const refreshToken = tokenize({ - parameters: { userKey: 123, uuid: '1234' }, - expPeriod: 168, - secret: String(REFRESH_KEY), - }) - const mockedRequest = { cookies: { refresh_token: refreshToken } } - - const mockedFormat = jest - .fn() - .mockReturnValueOnce('2021-06-30T12:00:00') - .mockReturnValueOnce('2021-07-01T12:00:00') - const mockedMoment = jest.fn().mockReturnValue({ - format: mockedFormat, - isAfter: jest.fn().mockReturnValue(false), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - refreshTokens(input: {}) { - result { - ... on AuthResult { - authToken - user { - displayName - } - } - ... on AuthenticateError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: mockedTransaction, - uuidv4, - jwt, - moment: mockedMoment, - request: mockedRequest, - auth: { - tokenize: jest.fn().mockReturnValue('token'), - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - refreshInfo: { - expiresAt: '', - refreshId: '1234', - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Impossible de rafraîchir les jetons, veuillez vous connecter.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred while user: 123 attempted to refresh tokens: Error: Transaction commit error`, - ]) - }) - }) - }) }) }) }) diff --git a/api/src/user/mutations/__tests__/remove-phone-number.test.js b/api/src/user/mutations/__tests__/remove-phone-number.test.js index ab123372a8..ee78800246 100644 --- a/api/src/user/mutations/__tests__/remove-phone-number.test.js +++ b/api/src/user/mutations/__tests__/remove-phone-number.test.js @@ -9,6 +9,7 @@ import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { userRequired } from '../../../auth' import { loadUserByKey } from '../../loaders' +import { UserDataSource } from '../../../user' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -87,6 +88,7 @@ describe('testing the removePhoneNumber mutation', () => { }) }) it('executes mutation successfully', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -113,9 +115,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -133,6 +136,7 @@ describe('testing the removePhoneNumber mutation', () => { expect(consoleOutput).toEqual([`User: ${user._key} successfully removed their phone number.`]) }) it('sets phoneDetails to null', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -159,9 +163,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -170,6 +175,7 @@ describe('testing the removePhoneNumber mutation', () => { expect(user.phoneDetails).toEqual(null) }) it('sets phoneValidated to false', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -196,9 +202,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -207,6 +214,7 @@ describe('testing the removePhoneNumber mutation', () => { expect(user.phoneValidated).toEqual(false) }) it('changes tfaSendMethod to email', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -233,9 +241,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -259,6 +268,7 @@ describe('testing the removePhoneNumber mutation', () => { }) }) it('executes mutation successfully', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -285,9 +295,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -305,6 +316,7 @@ describe('testing the removePhoneNumber mutation', () => { expect(consoleOutput).toEqual([`User: ${user._key} successfully removed their phone number.`]) }) it('sets phoneDetails to null', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -331,9 +343,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -342,6 +355,7 @@ describe('testing the removePhoneNumber mutation', () => { expect(user.phoneDetails).toEqual(null) }) it('sets phoneValidated to false', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -368,9 +382,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -379,6 +394,7 @@ describe('testing the removePhoneNumber mutation', () => { expect(user.phoneValidated).toEqual(false) }) it('changes tfaSendMethod to email', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -405,9 +421,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -447,6 +464,7 @@ describe('testing the removePhoneNumber mutation', () => { }) }) it('executes mutation successfully', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -473,9 +491,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -493,6 +512,7 @@ describe('testing the removePhoneNumber mutation', () => { expect(consoleOutput).toEqual([`User: ${user._key} successfully removed their phone number.`]) }) it('sets phoneDetails to null', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -519,9 +539,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -530,6 +551,7 @@ describe('testing the removePhoneNumber mutation', () => { expect(user.phoneDetails).toEqual(null) }) it('sets phoneValidated to false', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -556,9 +578,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -567,6 +590,7 @@ describe('testing the removePhoneNumber mutation', () => { expect(user.phoneValidated).toEqual(false) }) it('changes tfaSendMethod to email', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -593,9 +617,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -619,6 +644,7 @@ describe('testing the removePhoneNumber mutation', () => { }) }) it('executes mutation successfully', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -645,9 +671,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -665,6 +692,7 @@ describe('testing the removePhoneNumber mutation', () => { expect(consoleOutput).toEqual([`User: ${user._key} successfully removed their phone number.`]) }) it('sets phoneDetails to null', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -691,9 +719,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -702,6 +731,7 @@ describe('testing the removePhoneNumber mutation', () => { expect(user.phoneDetails).toEqual(null) }) it('sets phoneValidated to false', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -728,9 +758,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -739,6 +770,7 @@ describe('testing the removePhoneNumber mutation', () => { expect(user.phoneValidated).toEqual(false) }) it('changes tfaSendMethod to email', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -765,9 +797,10 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query, userKey: user._key }), + loadUserByKey: userDataSource.byKey, }), }, + dataSources: { user: userDataSource }, }, }) @@ -829,120 +862,14 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: jest.fn().mockReturnValue({ _key: 123 }), }, - }, - }) - - const error = [new GraphQLError('Unable to remove phone number. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred well removing phone number for user: 123: Error: transaction step error occurred.`, - ]) - }) - }) - }) - describe('commit error occurs', () => { - describe('when committing upsert', () => { - it('throws an error', async () => { - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn(), - commit: jest.fn().mockRejectedValue(new Error('transaction step error occurred.')), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - removePhoneNumber(input: {}) { - result { - ... on RemovePhoneNumberResult { - status - } - ... on RemovePhoneNumberError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - collections: collectionNames, - query, - transaction: mockedTransaction, - auth: { - userRequired: jest.fn().mockReturnValue({ _key: 123 }), + dataSources: { + user: new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), }, }, }) const error = [new GraphQLError('Unable to remove phone number. Please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred well removing phone number for user: 123: Error: transaction step error occurred.`, - ]) - }) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('step error occurs', () => { - describe('when running upsert', () => { - it('throws an error', async () => { - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('transaction step error occurred.')), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - removePhoneNumber(input: {}) { - result { - ... on RemovePhoneNumberResult { - status - } - ... on RemovePhoneNumberError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - collections: collectionNames, - query, - transaction: mockedTransaction, - auth: { - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - }, - }, - }) - - const error = [new GraphQLError('Impossible de supprimer le numéro de téléphone. Veuillez réessayer.')] - expect(response.errors).toEqual(error) expect(consoleOutput).toEqual([ `Trx step error occurred well removing phone number for user: 123: Error: transaction step error occurred.`, @@ -985,10 +912,13 @@ describe('testing the removePhoneNumber mutation', () => { auth: { userRequired: jest.fn().mockReturnValue({ _key: 123 }), }, + dataSources: { + user: new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + }, }, }) - const error = [new GraphQLError('Impossible de supprimer le numéro de téléphone. Veuillez réessayer.')] + const error = [new GraphQLError('Unable to remove phone number. Please try again.')] expect(response.errors).toEqual(error) expect(consoleOutput).toEqual([ diff --git a/api/src/user/mutations/__tests__/reset-password.test.js b/api/src/user/mutations/__tests__/reset-password.test.js index 366aa1b79b..742f46b303 100644 --- a/api/src/user/mutations/__tests__/reset-password.test.js +++ b/api/src/user/mutations/__tests__/reset-password.test.js @@ -12,7 +12,8 @@ import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput } from '../../../validators' import { tokenize, verifyToken } from '../../../auth' -import { loadUserByUserName, loadUserByKey } from '../../loaders' +import { UserDataSource } from '../../../user' +import { loadOrgByKey } from '../../../organization/loaders' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -56,6 +57,7 @@ describe('reset users password', () => { })) }) beforeEach(async () => { + const userDataSource = new UserDataSource({ query, userKey: undefined, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -91,8 +93,9 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, + organization: { byKey: loadOrgByKey({ query }) }, }, notify: { sendVerificationEmail: jest.fn(), @@ -138,6 +141,7 @@ describe('reset users password', () => { parameters: { userKey: user._key, currentPassword: user.password }, }) + const userDataSource = new UserDataSource({ query, userKey: undefined, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -175,9 +179,8 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, }, }) @@ -237,8 +240,8 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthEmail: mockNotify, @@ -273,6 +276,7 @@ describe('reset users password', () => { parameters: { userKey: user._key, currentPassword: user.password }, }) + const userDataSource = new UserDataSource({ query, userKey: undefined, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -311,9 +315,8 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, }, }) @@ -355,6 +358,7 @@ describe('reset users password', () => { parameters: { userKey: user._key, currentPassword: user.password }, }) + const userDataSource = new UserDataSource({ query, userKey: undefined, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -392,9 +396,8 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, }, }) @@ -454,8 +457,8 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthEmail: mockNotify, @@ -490,6 +493,7 @@ describe('reset users password', () => { parameters: { userKey: user._key, currentPassword: user.password }, }) + const userDataSource = new UserDataSource({ query, userKey: undefined, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -527,9 +531,8 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, }, }) @@ -604,9 +607,11 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn(), + dataSources: { + user: { + byKey: { + load: jest.fn(), + }, }, }, }, @@ -672,9 +677,11 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn(), + dataSources: { + user: { + byKey: { + load: jest.fn(), + }, }, }, }, @@ -740,9 +747,11 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, }, @@ -808,12 +817,14 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - password: 'currentPassword', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 123, + password: 'currentPassword', + }), + }, }, }, }, @@ -879,12 +890,14 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - password: 'currentPassword', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 123, + password: 'currentPassword', + }), + }, }, }, }, @@ -945,10 +958,6 @@ describe('reset users password', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error')), - abort: jest.fn(), - }), auth: { bcrypt, tokenize, @@ -957,13 +966,27 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - password: 'currentPassword', + dataSources: { + user: Object.assign( + new UserDataSource({ + query, + userKey: 123, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue(new Error('Transaction step error')), + abort: jest.fn(), + }), + collections: collectionNames, }), - }, + { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 123, + password: 'currentPassword', + }), + }, + }, + ), }, }, }) @@ -1015,11 +1038,6 @@ describe('reset users password', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), - abort: jest.fn(), - }), auth: { bcrypt, tokenize, @@ -1028,13 +1046,28 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - password: 'currentPassword', + dataSources: { + user: Object.assign( + new UserDataSource({ + query, + userKey: 123, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValue({}), + commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), + abort: jest.fn(), + }), + collections: collectionNames, }), - }, + { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 123, + password: 'currentPassword', + }), + }, + }, + ), }, }, }) @@ -1107,9 +1140,11 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn(), + dataSources: { + user: { + byKey: { + load: jest.fn(), + }, }, }, }, @@ -1175,9 +1210,11 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn(), + dataSources: { + user: { + byKey: { + load: jest.fn(), + }, }, }, }, @@ -1243,9 +1280,11 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, }, @@ -1311,12 +1350,14 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - password: 'currentPassword', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 123, + password: 'currentPassword', + }), + }, }, }, }, @@ -1382,12 +1423,14 @@ describe('reset users password', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - password: 'currentPassword', - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 123, + password: 'currentPassword', + }), + }, }, }, }, @@ -1410,147 +1453,6 @@ describe('reset users password', () => { ]) }) }) - describe('transaction step error occurs', () => { - describe('when updating users password', () => { - it('throws an error', async () => { - const resetToken = tokenize({ - parameters: { - userKey: 123, - currentPassword: 'currentPassword', - }, - }) - - const response = await graphql({ - schema, - source: ` - mutation { - resetPassword ( - input: { - password: "testpassword123" - confirmPassword: "testpassword123" - resetToken: "${resetToken}" - } - ) { - result { - ... on ResetPasswordError { - code - description - } - ... on ResetPasswordResult { - status - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error')), - abort: jest.fn(), - }), - auth: { - bcrypt, - tokenize, - verifyToken: verifyToken({ i18n }), - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - password: 'currentPassword', - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Impossible de réinitialiser le mot de passe. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred when user: 123 attempted to reset their password: Error: Transaction step error`, - ]) - }) - }) - }) - describe('transaction commit error occurs', () => { - describe('when updating users password', () => { - it('throws an error', async () => { - const resetToken = tokenize({ - parameters: { - userKey: 123, - currentPassword: 'currentPassword', - }, - }) - - const response = await graphql({ - schema, - source: ` - mutation { - resetPassword ( - input: { - password: "testpassword123" - confirmPassword: "testpassword123" - resetToken: "${resetToken}" - } - ) { - result { - ... on ResetPasswordError { - code - description - } - ... on ResetPasswordResult { - status - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), - abort: jest.fn(), - }), - auth: { - bcrypt, - tokenize, - verifyToken: verifyToken({ i18n }), - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - password: 'currentPassword', - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Impossible de réinitialiser le mot de passe. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred while user: 123 attempted to authenticate: Error: Transaction commit error`, - ]) - }) - }) - }) }) }) }) diff --git a/api/src/user/mutations/__tests__/send-password-reset.test.js b/api/src/user/mutations/__tests__/send-password-reset.test.js index 9fe11e1184..326262504b 100644 --- a/api/src/user/mutations/__tests__/send-password-reset.test.js +++ b/api/src/user/mutations/__tests__/send-password-reset.test.js @@ -107,8 +107,8 @@ describe('user send password reset email', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: { byUserName: loadUserByUserName({ query }) }, }, notify: { sendPasswordResetEmail: mockNotify, @@ -191,8 +191,8 @@ describe('user send password reset email', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: { byUserName: loadUserByUserName({ query }) }, }, notify: { sendPasswordResetEmail: mockNotify, @@ -271,9 +271,11 @@ describe('user send password reset email', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, notify: { @@ -338,9 +340,11 @@ describe('user send password reset email', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, notify: { diff --git a/api/src/user/mutations/__tests__/set-phone-number.test.js b/api/src/user/mutations/__tests__/set-phone-number.test.js index 2c4e154b9e..b581514929 100644 --- a/api/src/user/mutations/__tests__/set-phone-number.test.js +++ b/api/src/user/mutations/__tests__/set-phone-number.test.js @@ -10,7 +10,8 @@ import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput, decryptPhoneNumber } from '../../../validators' import { tokenize, userRequired } from '../../../auth' -import { loadUserByUserName, loadUserByKey } from '../../loaders' +import { loadUserByUserName } from '../../loaders' +import { UserDataSource } from '../../../user' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -87,6 +88,7 @@ describe('user sets a new phone number', () => { }) it('returns status text and updated user', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -120,15 +122,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -179,6 +181,7 @@ describe('user sets a new phone number', () => { }) it('returns status text and updated user', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -212,15 +215,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -257,6 +260,7 @@ describe('user sets a new phone number', () => { }) it('tfaSendMethod stays as none', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -290,15 +294,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -314,6 +318,7 @@ describe('user sets a new phone number', () => { }) it('sets phoneValidated to false', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -347,15 +352,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -384,6 +389,7 @@ describe('user sets a new phone number', () => { }) it('returns status text and update user', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -417,15 +423,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -462,6 +468,7 @@ describe('user sets a new phone number', () => { }) it('tfaSendMethod stays as email', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -495,15 +502,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -519,6 +526,7 @@ describe('user sets a new phone number', () => { }) it('sets phoneValidated to false', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -552,15 +560,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -589,6 +597,7 @@ describe('user sets a new phone number', () => { }) it('returns status text and updated user', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -622,15 +631,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -667,6 +676,7 @@ describe('user sets a new phone number', () => { }) it('sets tfaSendMethod to email', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -700,15 +710,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -724,6 +734,7 @@ describe('user sets a new phone number', () => { }) it('sets phoneValidated to false', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -757,15 +768,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -808,6 +819,7 @@ describe('user sets a new phone number', () => { }) it('returns status text and updated user', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -841,15 +853,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -900,6 +912,7 @@ describe('user sets a new phone number', () => { }) it('returns status text and updated user', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -933,15 +946,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -978,6 +991,7 @@ describe('user sets a new phone number', () => { }) it('tfaSendMethod stays as none', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -1011,15 +1025,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -1035,6 +1049,7 @@ describe('user sets a new phone number', () => { }) it('sets phoneValidated to false', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -1068,15 +1083,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -1105,6 +1120,7 @@ describe('user sets a new phone number', () => { }) it('returns status text', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -1138,15 +1154,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -1183,6 +1199,7 @@ describe('user sets a new phone number', () => { }) it('tfaSendMethod stays as email', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -1216,15 +1233,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -1240,6 +1257,7 @@ describe('user sets a new phone number', () => { }) it('sets phoneValidated to false', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -1273,15 +1291,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -1310,6 +1328,7 @@ describe('user sets a new phone number', () => { }) it('returns status text', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -1343,15 +1362,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -1388,6 +1407,7 @@ describe('user sets a new phone number', () => { }) it('sets tfaSendMethod to email', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -1421,15 +1441,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -1445,6 +1465,7 @@ describe('user sets a new phone number', () => { }) it('sets phoneValidated to false', async () => { const newPhoneNumber = '+12345678901' + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -1478,15 +1499,15 @@ describe('user sets a new phone number', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -1569,10 +1590,11 @@ describe('user sets a new phone number', () => { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: { - load: jest.fn(), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + { byKey: { load: jest.fn() } }, + ), }, notify: { sendAuthTextMsg: mockNotify, @@ -1637,10 +1659,11 @@ describe('user sets a new phone number', () => { cleanseInput, decryptPhoneNumber, }, - loaders: { - loadUserByKey: { - load: jest.fn(), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + { byKey: { load: jest.fn() } }, + ), }, notify: { sendAuthTextMsg: mockNotify, @@ -1650,159 +1673,6 @@ describe('user sets a new phone number', () => { const error = [new GraphQLError('Unable to set phone number, please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred for user: 123 when upserting phone number information: Error: Transaction commit error`, - ]) - }) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('transaction step error occurs', () => { - describe('when setting phone number', () => { - it('throws an error', async () => { - const newPhoneNumber = '+12345678901' - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error')), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - setPhoneNumber(input: { phoneNumber: "${newPhoneNumber}" }) { - result { - ... on SetPhoneNumberResult { - status - user { - phoneNumber - } - } - ... on SetPhoneNumberError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request, - userKey: 123, - query, - collections: collectionNames, - transaction: mockedTransaction, - auth: { - bcrypt, - tokenize, - userRequired: jest.fn().mockReturnValue({ - _key: 123, - }), - }, - validators: { - cleanseInput, - decryptPhoneNumber, - }, - loaders: { - loadUserByKey: { - load: jest.fn(), - }, - }, - notify: { - sendAuthTextMsg: mockNotify, - }, - }, - }) - - const error = [new GraphQLError('Impossible de définir le numéro de téléphone, veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred for user: 123 when upserting phone number information: Error: Transaction step error`, - ]) - }) - }) - }) - describe('transaction commit error occurs', () => { - describe('when setting phone number', () => { - it('throws an error', async () => { - const newPhoneNumber = '+12345678901' - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - setPhoneNumber(input: { phoneNumber: "${newPhoneNumber}" }) { - result { - ... on SetPhoneNumberResult { - status - user { - phoneNumber - } - } - ... on SetPhoneNumberError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request, - userKey: 123, - query, - collections: collectionNames, - transaction: mockedTransaction, - auth: { - bcrypt, - tokenize, - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - }, - validators: { - cleanseInput, - decryptPhoneNumber, - }, - loaders: { - loadUserByKey: { - load: jest.fn(), - }, - }, - notify: { - sendAuthTextMsg: mockNotify, - }, - }, - }) - - const error = [new GraphQLError('Impossible de définir le numéro de téléphone, veuillez réessayer.')] - expect(response.errors).toEqual(error) expect(consoleOutput).toEqual([ `Trx commit error occurred for user: 123 when upserting phone number information: Error: Transaction commit error`, diff --git a/api/src/user/mutations/__tests__/sign-in.test.js b/api/src/user/mutations/__tests__/sign-in.test.js index 933c264e7c..5fae7715f1 100644 --- a/api/src/user/mutations/__tests__/sign-in.test.js +++ b/api/src/user/mutations/__tests__/sign-in.test.js @@ -11,7 +11,8 @@ import frenchMessages from '../../../locale/fr/messages' import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput } from '../../../validators' -import { loadUserByUserName } from '../../loaders' +import { UserDataSource } from '../../../user' +import { loadOrgByKey } from '../../../organization/loaders' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' import { tokenize } from '../../../auth' @@ -64,6 +65,7 @@ describe('authenticate user account', () => { })) }) beforeEach(async () => { + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -99,8 +101,9 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, + organization: { byKey: loadOrgByKey({ query }) }, }, notify: { sendVerificationEmail: jest.fn(), @@ -158,6 +161,7 @@ describe('authenticate user account', () => { const mockedTokenize = jest.fn().mockReturnValueOnce(authToken) + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -195,8 +199,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthEmail: mockNotify, @@ -249,6 +253,7 @@ describe('authenticate user account', () => { const mockedTokenize = jest.fn().mockReturnValueOnce(authToken) + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -286,8 +291,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -342,6 +347,7 @@ describe('authenticate user account', () => { const mockedTokenize = jest.fn().mockReturnValueOnce(authToken) + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -379,8 +385,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthEmail: mockNotify, @@ -442,6 +448,7 @@ describe('authenticate user account', () => { const mockedTokenize = jest.fn().mockReturnValueOnce(authToken).mockReturnValueOnce(refreshToken) + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -481,8 +488,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthEmail: mockNotify, @@ -547,6 +554,7 @@ describe('authenticate user account', () => { const mockedTokenize = jest.fn().mockReturnValueOnce(authToken).mockReturnValueOnce(refreshToken) + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -587,8 +595,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthEmail: mockNotify, @@ -638,6 +646,7 @@ describe('authenticate user account', () => { UPDATE ${user._key} WITH { phoneValidated: false, failedLoginAttempts: 5 } IN users ` + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -675,8 +684,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthEmail: mockNotify, @@ -732,6 +741,7 @@ describe('authenticate user account', () => { const mockedTokenize = jest.fn().mockReturnValueOnce(authToken) + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -773,8 +783,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthTextMsg: mockNotify, @@ -827,6 +837,7 @@ describe('authenticate user account', () => { const mockedTokenize = jest.fn().mockReturnValueOnce(authToken) + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -868,8 +879,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthEmail: mockNotify, @@ -931,6 +942,7 @@ describe('authenticate user account', () => { const mockedTokenize = jest.fn().mockReturnValueOnce(authToken).mockReturnValueOnce(refreshToken) + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -969,8 +981,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthEmail: mockNotify, @@ -1035,6 +1047,7 @@ describe('authenticate user account', () => { const mockedTokenize = jest.fn().mockReturnValueOnce(authToken).mockReturnValueOnce(refreshToken) + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -1075,8 +1088,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthEmail: mockNotify, @@ -1126,6 +1139,7 @@ describe('authenticate user account', () => { UPDATE ${user._key} WITH { phoneValidated: false, failedLoginAttempts: 5 } IN users ` + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -1166,8 +1180,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendAuthEmail: mockNotify, @@ -1244,9 +1258,11 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, notify: { @@ -1316,14 +1332,19 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - }), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: jest.fn().mockReturnValue({ step: jest.fn(), commit: jest.fn() }), collections: collectionNames }), + { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'userName@email.ca', + password: 'password', + _key: 123, + }), + }, + }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -1395,10 +1416,11 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue(user), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query: jest.fn(), userKey: 123, i18n, transaction: jest.fn().mockReturnValue({ step: jest.fn(), commit: jest.fn() }), collections: collectionNames }), + { byUserName: { load: jest.fn().mockReturnValue(user) } }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -1453,15 +1475,20 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 10, - }), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: jest.fn().mockReturnValue({ step: jest.fn(), commit: jest.fn() }), collections: collectionNames }), + { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'userName@email.ca', + password: 'password', + _key: 123, + failedLoginAttempts: 10, + }), + }, + }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -1518,11 +1545,6 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction Step Error')), - commit: jest.fn(), - abort: jest.fn(), - }), uuidv4, auth: { bcrypt: { @@ -1533,15 +1555,30 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, + dataSources: { + user: Object.assign( + new UserDataSource({ + query, + userKey: 123, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue(new Error('Transaction Step Error')), + commit: jest.fn(), + abort: jest.fn(), + }), + collections: collectionNames, }), - }, + { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'userName@email.ca', + password: 'password', + _key: 123, + failedLoginAttempts: 1, + }), + }, + }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -1590,11 +1627,6 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValueOnce().mockRejectedValue(new Error('Transaction Step Error')), - commit: jest.fn(), - abort: jest.fn(), - }), uuidv4, auth: { bcrypt: { @@ -1605,15 +1637,30 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, + dataSources: { + user: Object.assign( + new UserDataSource({ + query, + userKey: 123, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValueOnce().mockRejectedValue(new Error('Transaction Step Error')), + commit: jest.fn(), + abort: jest.fn(), + }), + collections: collectionNames, }), - }, + { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'userName@email.ca', + password: 'password', + _key: 123, + failedLoginAttempts: 1, + }), + }, + }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -1662,11 +1709,6 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValueOnce().mockRejectedValue(new Error('Transaction Step Error')), - commit: jest.fn(), - abort: jest.fn(), - }), uuidv4, auth: { bcrypt: { @@ -1677,16 +1719,31 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, - tfaSendMethod: 'none', + dataSources: { + user: Object.assign( + new UserDataSource({ + query, + userKey: 123, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValueOnce().mockRejectedValue(new Error('Transaction Step Error')), + commit: jest.fn(), + abort: jest.fn(), + }), + collections: collectionNames, }), - }, + { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'userName@email.ca', + password: 'password', + _key: 123, + failedLoginAttempts: 1, + tfaSendMethod: 'none', + }), + }, + }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -1735,11 +1792,6 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction Step Error')), - commit: jest.fn(), - abort: jest.fn(), - }), uuidv4, auth: { bcrypt: { @@ -1750,16 +1802,31 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, - tfaSendMethod: 'none', + dataSources: { + user: Object.assign( + new UserDataSource({ + query, + userKey: 123, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue(new Error('Transaction Step Error')), + commit: jest.fn(), + abort: jest.fn(), + }), + collections: collectionNames, }), - }, + { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'userName@email.ca', + password: 'password', + _key: 123, + failedLoginAttempts: 1, + tfaSendMethod: 'none', + }), + }, + }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -1809,11 +1876,6 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn(), - commit: jest.fn().mockRejectedValue(new Error('Transaction Commit Error')), - abort: jest.fn(), - }), uuidv4, auth: { bcrypt: { @@ -1824,16 +1886,31 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, - tfaSendMethod: 'email', + dataSources: { + user: Object.assign( + new UserDataSource({ + query, + userKey: 123, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn(), + commit: jest.fn().mockRejectedValue(new Error('Transaction Commit Error')), + abort: jest.fn(), + }), + collections: collectionNames, }), - }, + { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'userName@email.ca', + password: 'password', + _key: 123, + failedLoginAttempts: 1, + tfaSendMethod: 'email', + }), + }, + }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -1882,11 +1959,6 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn(), - commit: jest.fn().mockRejectedValue(new Error('Transaction Commit Error')), - abort: jest.fn(), - }), uuidv4, auth: { bcrypt: { @@ -1897,16 +1969,31 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, - tfaSendMethod: 'none', + dataSources: { + user: Object.assign( + new UserDataSource({ + query, + userKey: 123, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn(), + commit: jest.fn().mockRejectedValue(new Error('Transaction Commit Error')), + abort: jest.fn(), + }), + collections: collectionNames, }), - }, + { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'userName@email.ca', + password: 'password', + _key: 123, + failedLoginAttempts: 1, + tfaSendMethod: 'none', + }), + }, + }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -1955,11 +2042,6 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn(), - commit: jest.fn().mockRejectedValue(new Error('Transaction Commit Error')), - abort: jest.fn(), - }), uuidv4, auth: { bcrypt: { @@ -1970,16 +2052,31 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, - tfaSendMethod: 'none', + dataSources: { + user: Object.assign( + new UserDataSource({ + query, + userKey: 123, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn(), + commit: jest.fn().mockRejectedValue(new Error('Transaction Commit Error')), + abort: jest.fn(), + }), + collections: collectionNames, }), - }, + { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'userName@email.ca', + password: 'password', + _key: 123, + failedLoginAttempts: 1, + tfaSendMethod: 'none', + }), + }, + }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -2052,9 +2149,11 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue(undefined), + }, }, }, notify: { @@ -2124,14 +2223,19 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - }), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: jest.fn().mockReturnValue({ step: jest.fn(), commit: jest.fn() }), collections: collectionNames }), + { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'userName@email.ca', + password: 'password', + _key: 123, + }), + }, + }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -2203,10 +2307,11 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue(user), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query: jest.fn(), userKey: 123, i18n, transaction: jest.fn().mockReturnValue({ step: jest.fn(), commit: jest.fn() }), collections: collectionNames }), + { byUserName: { load: jest.fn().mockReturnValue(user) } }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -2261,15 +2366,20 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 10, - }), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: jest.fn().mockReturnValue({ step: jest.fn(), commit: jest.fn() }), collections: collectionNames }), + { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'userName@email.ca', + password: 'password', + _key: 123, + failedLoginAttempts: 10, + }), + }, + }, + ), }, notify: { sendAuthEmail: mockNotify, @@ -2293,517 +2403,6 @@ describe('authenticate user account', () => { expect(consoleOutput).toEqual([`User: 123 tried to sign in, but has too many login attempts.`]) }) }) - describe('transaction step error occurs', () => { - describe('when resetting failed login attempts', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - signIn( - input: { - userName: "test.account@istio.actually.exists" - password: "testpassword123" - } - ) { - result { - ... on TFASignInResult { - authenticateToken - sendMethod - } - ... on AuthResult { - authToken - } - ... on SignInError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction Step Error')), - commit: jest.fn(), - abort: jest.fn(), - }), - uuidv4, - auth: { - bcrypt: { - compareSync: jest.fn().mockReturnValue(true), - }, - tokenize, - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, - }), - }, - }, - notify: { - sendAuthEmail: mockNotify, - }, - }, - }) - - const error = [new GraphQLError('Impossible de se connecter, veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred when resetting failed login attempts for user: 123: Error: Transaction Step Error`, - ]) - }) - }) - describe('when inserting tfa code', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - signIn( - input: { - userName: "test.account@istio.actually.exists" - password: "testpassword123" - } - ) { - result { - ... on TFASignInResult { - authenticateToken - sendMethod - } - ... on AuthResult { - authToken - } - ... on SignInError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValueOnce().mockRejectedValue(new Error('Transaction Step Error')), - commit: jest.fn(), - abort: jest.fn(), - }), - uuidv4, - auth: { - bcrypt: { - compareSync: jest.fn().mockReturnValue(true), - }, - tokenize, - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, - }), - }, - }, - notify: { - sendAuthEmail: mockNotify, - }, - }, - }) - - const error = [new GraphQLError('Impossible de se connecter, veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred when inserting TFA code for user: 123: Error: Transaction Step Error`, - ]) - }) - }) - describe('when setting refresh id', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - signIn( - input: { - userName: "test.account@istio.actually.exists" - password: "testpassword123" - } - ) { - result { - ... on TFASignInResult { - authenticateToken - sendMethod - } - ... on AuthResult { - authToken - } - ... on SignInError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValueOnce().mockRejectedValue(new Error('Transaction Step Error')), - commit: jest.fn(), - abort: jest.fn(), - }), - uuidv4, - auth: { - bcrypt: { - compareSync: jest.fn().mockReturnValue(true), - }, - tokenize, - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, - tfaSendMethod: 'none', - }), - }, - }, - notify: { - sendAuthEmail: mockNotify, - }, - }, - }) - - const error = [new GraphQLError('Impossible de se connecter, veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred when attempting to setting refresh tokens for user: 123 during sign in: Error: Transaction Step Error`, - ]) - }) - }) - describe('when incrementing failed login attempts', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - signIn( - input: { - userName: "test.account@istio.actually.exists" - password: "newpassword123" - } - ) { - result { - ... on TFASignInResult { - authenticateToken - sendMethod - } - ... on AuthResult { - authToken - } - ... on SignInError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction Step Error')), - commit: jest.fn(), - abort: jest.fn(), - }), - uuidv4, - auth: { - bcrypt: { - compareSync: jest.fn().mockReturnValue(false), - }, - tokenize, - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, - tfaSendMethod: 'none', - }), - }, - }, - notify: { - sendAuthEmail: mockNotify, - }, - }, - }) - const error = [new GraphQLError('Impossible de se connecter, veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred when incrementing failed login attempts for user: 123: Error: Transaction Step Error`, - ]) - }) - }) - }) - describe('transaction commit error occurs', () => { - describe('during tfa sign in', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - signIn( - input: { - userName: "test.account@istio.actually.exists" - password: "testpassword123" - } - ) { - result { - ... on TFASignInResult { - authenticateToken - sendMethod - } - ... on AuthResult { - authToken - } - ... on SignInError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn(), - commit: jest.fn().mockRejectedValue(new Error('Transaction Commit Error')), - abort: jest.fn(), - }), - uuidv4, - auth: { - bcrypt: { - compareSync: jest.fn().mockReturnValue(true), - }, - tokenize, - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, - tfaSendMethod: 'email', - }), - }, - }, - notify: { - sendAuthEmail: mockNotify, - }, - }, - }) - - const error = [new GraphQLError('Impossible de se connecter, veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred while user: 123 attempted to tfa sign in: Error: Transaction Commit Error`, - ]) - }) - }) - describe('during regular sign in', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - signIn( - input: { - userName: "test.account@istio.actually.exists" - password: "testpassword123" - } - ) { - result { - ... on TFASignInResult { - authenticateToken - sendMethod - } - ... on AuthResult { - authToken - } - ... on SignInError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn(), - commit: jest.fn().mockRejectedValue(new Error('Transaction Commit Error')), - abort: jest.fn(), - }), - uuidv4, - auth: { - bcrypt: { - compareSync: jest.fn().mockReturnValue(true), - }, - tokenize, - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, - tfaSendMethod: 'none', - }), - }, - }, - notify: { - sendAuthEmail: mockNotify, - }, - }, - }) - - const error = [new GraphQLError('Impossible de se connecter, veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred while user: 123 attempted a regular sign in: Error: Transaction Commit Error`, - ]) - }) - }) - describe('during failed login', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - signIn( - input: { - userName: "test.account@istio.actually.exists" - password: "newpassword123" - } - ) { - result { - ... on TFASignInResult { - authenticateToken - sendMethod - } - ... on AuthResult { - authToken - } - ... on SignInError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn(), - commit: jest.fn().mockRejectedValue(new Error('Transaction Commit Error')), - abort: jest.fn(), - }), - uuidv4, - auth: { - bcrypt: { - compareSync: jest.fn().mockReturnValue(false), - }, - tokenize, - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'userName@email.ca', - password: 'password', - _key: 123, - failedLoginAttempts: 1, - tfaSendMethod: 'none', - }), - }, - }, - notify: { - sendAuthEmail: mockNotify, - }, - }, - }) - const error = [new GraphQLError('Impossible de se connecter, veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred while user: 123 failed to sign in: Error: Transaction Commit Error`, - ]) - }) - }) - }) }) }) }) diff --git a/api/src/user/mutations/__tests__/sign-up.test.js b/api/src/user/mutations/__tests__/sign-up.test.js index 7dd4b0c961..e39ef1e986 100644 --- a/api/src/user/mutations/__tests__/sign-up.test.js +++ b/api/src/user/mutations/__tests__/sign-up.test.js @@ -11,7 +11,8 @@ import { tokenize, verifyToken } from '../../../auth' import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput } from '../../../validators' -import { loadUserByUserName, loadUserByKey } from '../../loaders' +import { loadUserByUserName } from '../../loaders' +import { UserDataSource } from '../../../user' import { loadOrgByKey } from '../../../organization/loaders' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -121,9 +122,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -195,9 +195,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -258,9 +257,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -333,9 +331,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -433,10 +430,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -510,10 +505,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -585,10 +578,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -651,10 +642,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -728,10 +717,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -803,10 +790,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -886,9 +871,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -959,9 +943,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -1022,9 +1005,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -1096,9 +1078,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -1197,10 +1178,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'fr' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -1274,10 +1253,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -1349,10 +1326,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'fr' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -1416,10 +1391,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'fr' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -1493,10 +1466,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -1568,10 +1539,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'fr' }) }, + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotify, @@ -1652,12 +1621,14 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadUserByKey: { - load: jest.fn(), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, }, notify: { @@ -1725,12 +1696,14 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadUserByKey: { - load: jest.fn(), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, }, notify: { @@ -1798,17 +1771,19 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - displayName: 'Test Account', - phoneValidated: false, - emailValidated: false, - }), - }, - loadUserByKey: { - load: jest.fn(), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'test.account@istio.actually.exists', + displayName: 'Test Account', + phoneValidated: false, + emailValidated: false, + }), + }, + byKey: { + load: jest.fn(), + }, }, }, notify: { @@ -1894,11 +1869,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadOrgByKey: { + loaders: { loadOrgByKey: loadOrgByKey({ query, language: 'en' }) }, + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _key: 123, orgDetails: { @@ -1924,9 +1896,14 @@ describe('testing user sign up', () => { }, }, }), - }, - loadUserByKey: { - load: jest.fn(), + } }, + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, }, notify: { @@ -2011,15 +1988,16 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue(undefined), - }, - loadUserByKey: { - load: jest.fn(), + } }, + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, }, notify: { @@ -2095,11 +2073,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadOrgByKey: { + loaders: { loadOrgByKey: loadOrgByKey({ query, language: 'en' }) }, + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _key: 123, orgDetails: { @@ -2125,10 +2100,19 @@ describe('testing user sign up', () => { }, }, }), - }, - loadUserByKey: { - load: jest.fn(), - }, + } }, + user: Object.assign(new UserDataSource({ + query, + userKey: undefined, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValue({ + next: jest.fn().mockRejectedValue('Cursor Error'), + }), + abort: jest.fn(), + }), + collections: collectionNames, + }), { byUserName: { load: jest.fn() } }), }, notify: { sendAuthEmail: mockNotify, @@ -2193,11 +2177,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadOrgByKey: { + loaders: { loadOrgByKey: loadOrgByKey({ query, language: 'en' }) }, + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _key: 123, orgDetails: { @@ -2223,10 +2204,17 @@ describe('testing user sign up', () => { }, }, }), - }, - loadUserByKey: { - load: jest.fn(), - }, + } }, + user: Object.assign(new UserDataSource({ + query, + userKey: undefined, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue('Transaction Step Error'), + abort: jest.fn(), + }), + collections: collectionNames, + }), { byUserName: { load: jest.fn() } }), }, notify: { sendAuthEmail: mockNotify, @@ -2300,11 +2288,7 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _key: 123, orgDetails: { @@ -2330,10 +2314,17 @@ describe('testing user sign up', () => { }, }, }), - }, - loadUserByKey: { - load: jest.fn(), - }, + } }, + user: Object.assign(new UserDataSource({ + query, + userKey: undefined, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValueOnce({ next: jest.fn() }).mockRejectedValue('Transaction Step Error'), + abort: jest.fn(), + }), + collections: collectionNames, + }), { byUserName: { load: jest.fn() } }), }, notify: { sendAuthEmail: mockNotify, @@ -2397,11 +2388,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadOrgByKey: { + loaders: { loadOrgByKey: loadOrgByKey({ query, language: 'en' }) }, + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _key: 123, orgDetails: { @@ -2427,10 +2415,18 @@ describe('testing user sign up', () => { }, }, }), - }, - loadUserByKey: { - load: jest.fn(), - }, + } }, + user: Object.assign(new UserDataSource({ + query, + userKey: undefined, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValue({ next: jest.fn() }), + commit: jest.fn().mockRejectedValue('Transaction Commit Error'), + abort: jest.fn(), + }), + collections: collectionNames, + }), { byUserName: { load: jest.fn() } }), }, notify: { sendAuthEmail: mockNotify, @@ -2506,12 +2502,14 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadUserByKey: { - load: jest.fn(), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, }, notify: { @@ -2579,12 +2577,14 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadUserByKey: { - load: jest.fn(), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, }, notify: { @@ -2652,17 +2652,19 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - displayName: 'Test Account', - phoneValidated: false, - emailValidated: false, - }), - }, - loadUserByKey: { - load: jest.fn(), + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) }, + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + userName: 'test.account@istio.actually.exists', + displayName: 'Test Account', + phoneValidated: false, + emailValidated: false, + }), + }, + byKey: { + load: jest.fn(), + }, }, }, notify: { @@ -2748,11 +2750,8 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadOrgByKey: { + loaders: { loadOrgByKey: loadOrgByKey({ query, language: 'en' }) }, + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _key: 123, orgDetails: { @@ -2778,9 +2777,14 @@ describe('testing user sign up', () => { }, }, }), - }, - loadUserByKey: { - load: jest.fn(), + } }, + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, }, notify: { @@ -2866,15 +2870,16 @@ describe('testing user sign up', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue(undefined), - }, - loadUserByKey: { - load: jest.fn(), + } }, + user: { + byUserName: { + load: jest.fn(), + }, + byKey: { + load: jest.fn(), + }, }, }, notify: { @@ -2902,408 +2907,6 @@ describe('testing user sign up', () => { }) }) }) - describe('given a cursor error', () => { - describe('when gathering inserted user', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - signUp( - input: { - displayName: "Test Account" - userName: "test.account@istio.actually.exists" - password: "testpassword123" - confirmPassword: "testpassword123" - } - ) { - result { - ... on TFASignInResult { - authenticateToken - sendMethod - } - ... on SignUpError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({ - next: jest.fn().mockRejectedValue('Cursor Error'), - }), - abort: jest.fn(), - }), - uuidv4, - request: { ip: '127.0.0.1' }, - auth: { - bcrypt, - tokenize: mockTokenize, - verifyToken: verifyToken({ i18n }), - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - notify: { - sendAuthEmail: mockNotify, - }, - }, - }) - - const error = [new GraphQLError("Impossible de s'inscrire. Veuillez réessayer.")] - - expect(response.errors).toEqual(error) - - expect(consoleOutput).toEqual([ - 'Cursor error occurred while user: test.account@istio.actually.exists attempted to sign up, creating user: Cursor Error', - ]) - }) - }) - }) - describe('given a transaction error', () => { - describe('when inserting user', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - signUp( - input: { - displayName: "Test Account" - userName: "test.account@istio.actually.exists" - password: "testpassword123" - confirmPassword: "testpassword123" - } - ) { - result { - ... on TFASignInResult { - authenticateToken - sendMethod - } - ... on SignUpError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue('Transaction Step Error'), - abort: jest.fn(), - }), - uuidv4, - request: { ip: '127.0.0.1' }, - auth: { - bcrypt, - tokenize: mockTokenize, - verifyToken: verifyToken({ i18n }), - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - notify: { - sendAuthEmail: mockNotify, - }, - }, - }) - - const error = [new GraphQLError("Impossible de s'inscrire. Veuillez réessayer.")] - - expect(response.errors).toEqual(error) - - expect(consoleOutput).toEqual([ - 'Transaction step error occurred while user: test.account@istio.actually.exists attempted to sign up, creating user: Transaction Step Error', - ]) - }) - }) - describe('when inserting affiliation', () => { - let token - beforeEach(() => { - token = tokenize({ - parameters: { - userName: 'test.account@istio.actually.exists', - orgKey: '123', - requestedRole: 'admin', - }, - }) - }) - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - signUp( - input: { - displayName: "Test Account" - userName: "test.account@istio.actually.exists" - password: "testpassword123" - confirmPassword: "testpassword123" - signUpToken: "${token}" - } - ) { - result { - ... on TFASignInResult { - authenticateToken - sendMethod - } - ... on SignUpError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValueOnce({ next: jest.fn() }).mockRejectedValue('Transaction Step Error'), - abort: jest.fn(), - }), - uuidv4, - request: { ip: '127.0.0.1' }, - auth: { - bcrypt, - tokenize: mockTokenize, - verifyToken: verifyToken({ i18n }), - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - notify: { - sendAuthEmail: mockNotify, - }, - }, - }) - - const error = [new GraphQLError("Impossible de s'inscrire. Veuillez réessayer.")] - - expect(response.errors).toEqual(error) - - expect(consoleOutput).toEqual([ - 'Transaction step error occurred while user: test.account@istio.actually.exists attempted to sign up, assigning affiliation: Transaction Step Error', - ]) - }) - }) - describe('when committing transaction', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - signUp( - input: { - displayName: "Test Account" - userName: "test.account@istio.actually.exists" - password: "testpassword123" - confirmPassword: "testpassword123" - } - ) { - result { - ... on TFASignInResult { - authenticateToken - sendMethod - } - ... on SignUpError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({ next: jest.fn() }), - commit: jest.fn().mockRejectedValue('Transaction Commit Error'), - abort: jest.fn(), - }), - uuidv4, - request: { ip: '127.0.0.1' }, - auth: { - bcrypt, - tokenize: mockTokenize, - verifyToken: verifyToken({ i18n }), - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - notify: { - sendAuthEmail: mockNotify, - }, - }, - }) - - const error = [new GraphQLError("Impossible de s'inscrire. Veuillez réessayer.")] - - expect(response.errors).toEqual(error) - - expect(consoleOutput).toEqual([ - 'Transaction commit error occurred while user: test.account@istio.actually.exists attempted to sign up: Transaction Commit Error', - ]) - }) - }) - }) }) }) }) diff --git a/api/src/user/mutations/__tests__/update-user-password.test.js b/api/src/user/mutations/__tests__/update-user-password.test.js index b3910e594f..c7298479c4 100644 --- a/api/src/user/mutations/__tests__/update-user-password.test.js +++ b/api/src/user/mutations/__tests__/update-user-password.test.js @@ -12,7 +12,8 @@ import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput } from '../../../validators' import { tokenize, userRequired } from '../../../auth' -import { loadUserByUserName, loadUserByKey } from '../../loaders' +import { UserDataSource } from '../../../user' +import { loadOrgByKey } from '../../../organization/loaders' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -57,6 +58,7 @@ describe('authenticate user account', () => { })) }) beforeEach(async () => { + const userDataSource = new UserDataSource({ query, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -92,8 +94,9 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, + organization: { byKey: loadOrgByKey({ query }) }, }, notify: { sendVerificationEmail: jest.fn(), @@ -134,6 +137,7 @@ describe('authenticate user account', () => { }) }) it('returns a successful status message', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -170,16 +174,13 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - }, + dataSources: { user: userDataSource }, }, }) @@ -230,8 +231,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotfiy, @@ -269,6 +270,7 @@ describe('authenticate user account', () => { }) }) it('returns a successful status message', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -305,16 +307,13 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), - }, + dataSources: { user: userDataSource }, }, }) @@ -365,8 +364,8 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: new UserDataSource({ query, transaction, collections: collectionNames }), }, notify: { sendAuthEmail: mockNotfiy, @@ -449,6 +448,7 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, + dataSources: { user: {} }, }, }) @@ -513,6 +513,7 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, + dataSources: { user: {} }, }, }) @@ -577,6 +578,7 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, + dataSources: { user: {} }, }, }) @@ -600,6 +602,10 @@ describe('authenticate user account', () => { describe('transaction step error occurs', () => { describe('when updating password', () => { it('returns an error message', async () => { + const mockedTransaction = jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue(new Error('Transaction step error')), + abort: jest.fn(), + }) const response = await graphql({ schema, source: ` @@ -628,10 +634,7 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error')), - abort: jest.fn(), - }), + transaction: mockedTransaction, userKey: 123, auth: { bcrypt: { @@ -646,6 +649,9 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, + dataSources: { + user: new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + }, }, }) @@ -661,6 +667,11 @@ describe('authenticate user account', () => { describe('transaction commit error occurs', () => { describe('when updating password', () => { it('returns an error message', async () => { + const mockedTransaction = jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValue({}), + commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), + abort: jest.fn(), + }) const response = await graphql({ schema, source: ` @@ -689,11 +700,7 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), - abort: jest.fn(), - }), + transaction: mockedTransaction, userKey: 123, auth: { bcrypt: { @@ -708,6 +715,9 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, + dataSources: { + user: new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + }, }, }) @@ -780,6 +790,7 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, + dataSources: { user: {} }, }, }) @@ -845,6 +856,7 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, + dataSources: { user: {} }, }, }) @@ -910,6 +922,7 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, + dataSources: { user: {} }, }, }) @@ -931,129 +944,6 @@ describe('authenticate user account', () => { ]) }) }) - describe('transaction step error occurs', () => { - describe('when updating password', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserPassword( - input: { - currentPassword: "testpassword123" - updatedPassword: "newtestpassword123" - updatedPasswordConfirm: "newtestpassword123" - } - ) { - result { - ... on UpdateUserPasswordResultType { - status - } - ... on UpdateUserPasswordError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - bcrypt: { - compareSync: jest.fn().mockReturnValue(true), - hashSync: jest.fn().mockReturnValue('password'), - }, - tokenize, - userRequired: jest.fn().mockReturnValue({ - _key: 123, - }), - }, - validators: { - cleanseInput, - }, - }, - }) - - const error = [new GraphQLError('Impossible de mettre à jour le mot de passe. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred when user: 123 attempted to update their password: Error: Transaction step error`, - ]) - }) - }) - }) - describe('transaction commit error occurs', () => { - describe('when updating password', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserPassword( - input: { - currentPassword: "testpassword123" - updatedPassword: "newtestpassword123" - updatedPasswordConfirm: "newtestpassword123" - } - ) { - result { - ... on UpdateUserPasswordResultType { - status - } - ... on UpdateUserPasswordError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - bcrypt: { - compareSync: jest.fn().mockReturnValue(true), - hashSync: jest.fn().mockReturnValue('password'), - }, - tokenize, - userRequired: jest.fn().mockReturnValue({ - _key: 123, - }), - }, - validators: { - cleanseInput, - }, - }, - }) - - const error = [new GraphQLError('Impossible de mettre à jour le mot de passe. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred when user: 123 attempted to update their password: Error: Transaction commit error`, - ]) - }) - }) - }) }) }) }) diff --git a/api/src/user/mutations/__tests__/update-user-profile.test.js b/api/src/user/mutations/__tests__/update-user-profile.test.js index ad8bfb23bf..700a6ea1f1 100644 --- a/api/src/user/mutations/__tests__/update-user-profile.test.js +++ b/api/src/user/mutations/__tests__/update-user-profile.test.js @@ -11,7 +11,7 @@ import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput } from '../../../validators' import { tokenize, userRequired } from '../../../auth' -import { loadUserByUserName, loadUserByKey } from '../../loaders' +import { UserDataSource } from '../../../user' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -91,6 +91,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -123,15 +124,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -172,6 +172,7 @@ describe('authenticate user account', () => { secret: String(AUTHENTICATED_KEY), })}` + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -210,15 +211,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail }, }, @@ -260,6 +260,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -297,15 +298,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -358,6 +358,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -390,15 +391,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -456,6 +456,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -488,15 +489,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -539,6 +539,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -571,15 +572,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -620,6 +620,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -652,15 +653,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -702,6 +702,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -734,15 +735,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -791,6 +791,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -823,15 +824,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -873,6 +873,7 @@ describe('authenticate user account', () => { secret: String(AUTHENTICATED_KEY), })}` + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -911,15 +912,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail }, }, @@ -961,6 +961,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -998,15 +999,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -1060,6 +1060,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -1092,15 +1093,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -1158,6 +1158,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -1190,15 +1191,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -1241,6 +1241,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -1273,15 +1274,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -1322,6 +1322,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -1354,15 +1355,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -1404,6 +1404,7 @@ describe('authenticate user account', () => { ` const user = await cursor.next() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -1436,15 +1437,14 @@ describe('authenticate user account', () => { tokenize, userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, validators: { cleanseInput, }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -1527,12 +1527,11 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({}), - }, - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({}), + }, }, }, notify: { sendVerificationEmail: jest.fn() }, @@ -1559,6 +1558,10 @@ describe('authenticate user account', () => { describe('given a transaction step error', () => { describe('when updating profile', () => { it('throws an error', async () => { + const mockedTransaction = jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue(new Error('Transaction step error')), + abort: jest.fn(), + }) const response = await graphql({ schema, source: ` @@ -1589,10 +1592,7 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error')), - abort: jest.fn(), - }), + transaction: mockedTransaction, userKey: 123, auth: { bcrypt, @@ -1604,13 +1604,11 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue(undefined), - }, - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + { byUserName: { load: jest.fn().mockReturnValue(undefined) } }, + ), }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -1628,6 +1626,11 @@ describe('authenticate user account', () => { describe('given a transaction step error', () => { describe('when updating profile', () => { it('throws an error', async () => { + const mockedTransaction = jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValue({}), + commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), + abort: jest.fn(), + }) const response = await graphql({ schema, source: ` @@ -1658,11 +1661,7 @@ describe('authenticate user account', () => { i18n, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), - abort: jest.fn(), - }), + transaction: mockedTransaction, userKey: 123, auth: { bcrypt, @@ -1674,13 +1673,11 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue(undefined), - }, - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + { byUserName: { load: jest.fn().mockReturnValue(undefined) } }, + ), }, notify: { sendVerificationEmail: jest.fn() }, }, @@ -1752,12 +1749,11 @@ describe('authenticate user account', () => { validators: { cleanseInput, }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({}), - }, - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({}), + }, }, }, notify: { sendVerificationEmail: jest.fn() }, @@ -1781,145 +1777,6 @@ describe('authenticate user account', () => { ]) }) }) - describe('given a transaction step error', () => { - describe('when updating profile', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserProfile( - input: { - displayName: "John Smith" - userName: "john.smith@istio.actually.works" - } - ) { - result { - ... on UpdateUserProfileResult { - status - user { - id - } - } - ... on UpdateUserProfileError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - bcrypt, - tokenize, - userRequired: jest.fn().mockReturnValue({ - tfaSendMethod: 'none', - }), - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue(undefined), - }, - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - notify: { sendVerificationEmail: jest.fn() }, - }, - }) - - const error = [new GraphQLError('Impossible de mettre à jour le profil. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred when user: 123 attempted to update their profile: Error: Transaction step error`, - ]) - }) - }) - }) - describe('given a transaction step error', () => { - describe('when updating profile', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserProfile( - input: { - displayName: "John Smith" - userName: "john.smith@istio.actually.works" - } - ) { - result { - ... on UpdateUserProfileResult { - status - user { - id - } - } - ... on UpdateUserProfileError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - bcrypt, - tokenize, - userRequired: jest.fn().mockReturnValue({ - tfaSendMethod: 'none', - }), - }, - validators: { - cleanseInput, - }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue(undefined), - }, - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - notify: { sendVerificationEmail: jest.fn() }, - }, - }) - - const error = [new GraphQLError('Impossible de mettre à jour le profil. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred when user: 123 attempted to update their profile: Error: Transaction commit error`, - ]) - }) - }) - }) }) }) }) diff --git a/api/src/user/mutations/__tests__/verify-account.test.js b/api/src/user/mutations/__tests__/verify-account.test.js index ec71acb6cd..9eb0e26cff 100644 --- a/api/src/user/mutations/__tests__/verify-account.test.js +++ b/api/src/user/mutations/__tests__/verify-account.test.js @@ -9,7 +9,7 @@ import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput } from '../../../validators' import { tokenize, verifyToken } from '../../../auth' -import { loadUserByKey, loadUserByUserName } from '../../loaders' +import { UserDataSource } from '../../../user' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -93,6 +93,7 @@ describe('user send password reset email', () => { const sendUpdatedUserNameEmail = jest.fn() + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -124,9 +125,8 @@ describe('user send password reset email', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: userDataSource, }, notify: { sendUpdatedUserNameEmail }, }, @@ -216,16 +216,17 @@ describe('user send password reset email', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - displayName: 'Test Account', - tfaValidated: false, - emailValidated: false, - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + userName: 'test.account@istio.actually.exists', + displayName: 'Test Account', + tfaValidated: false, + emailValidated: false, + }), + }, }, - loadUserByUserName: loadUserByUserName({ query }), }, notify: { sendUpdatedUserNameEmail: jest.fn() }, }, @@ -285,16 +286,17 @@ describe('user send password reset email', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - displayName: 'Test Account', - tfaValidated: false, - emailValidated: false, - }), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue({ + userName: 'test.account@istio.actually.exists', + displayName: 'Test Account', + tfaValidated: false, + emailValidated: false, + }), + }, }, - loadUserByUserName: loadUserByUserName({ query }), }, notify: { sendUpdatedUserNameEmail: jest.fn() }, }, @@ -353,11 +355,12 @@ describe('user send password reset email', () => { validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue(undefined), + dataSources: { + user: { + byKey: { + load: jest.fn().mockReturnValue(undefined), + }, }, - loadUserByUserName: loadUserByUserName({ query }), }, notify: { sendUpdatedUserNameEmail: jest.fn() }, }, @@ -411,27 +414,36 @@ describe('user send password reset email', () => { userKey: 123, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error occurred.')), - abort: jest.fn(), - }), auth: { verifyToken: verifyToken({}), }, validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - userName: 'test.account@istio.actually.exists', - displayName: 'Test Account', - tfaValidated: false, - emailValidated: false, + dataSources: { + user: Object.assign( + new UserDataSource({ + query, + userKey: 123, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue(new Error('Transaction step error occurred.')), + abort: jest.fn(), + }), + collections: collectionNames, }), - }, - loadUserByUserName: loadUserByUserName({ query, userKey: 123, i18n }), + { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 123, + userName: 'test.account@istio.actually.exists', + displayName: 'Test Account', + tfaValidated: false, + emailValidated: false, + }), + }, + }, + ), }, notify: { sendUpdatedUserNameEmail: jest.fn() }, }, @@ -477,28 +489,37 @@ describe('user send password reset email', () => { userKey: 123, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error occurred.')), - abort: jest.fn(), - }), auth: { verifyToken: verifyToken({}), }, validators: { cleanseInput, }, - loaders: { - loadUserByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - userName: 'test.account@istio.actually.exists', - displayName: 'Test Account', - tfaValidated: false, - emailValidated: false, + dataSources: { + user: Object.assign( + new UserDataSource({ + query, + userKey: 123, + i18n, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValue({}), + commit: jest.fn().mockRejectedValue(new Error('Transaction commit error occurred.')), + abort: jest.fn(), + }), + collections: collectionNames, }), - }, - loadUserByUserName: loadUserByUserName({ query, userKey: 123, i18n }), + { + byKey: { + load: jest.fn().mockReturnValue({ + _key: 123, + userName: 'test.account@istio.actually.exists', + displayName: 'Test Account', + tfaValidated: false, + emailValidated: false, + }), + }, + }, + ), }, notify: { sendUpdatedUserNameEmail: jest.fn() }, }, diff --git a/api/src/user/mutations/__tests__/verify-phone-number.test.js b/api/src/user/mutations/__tests__/verify-phone-number.test.js index 4da0f61bfc..95bf2f3793 100644 --- a/api/src/user/mutations/__tests__/verify-phone-number.test.js +++ b/api/src/user/mutations/__tests__/verify-phone-number.test.js @@ -7,7 +7,7 @@ import englishMessages from '../../../locale/en/messages' import frenchMessages from '../../../locale/fr/messages' import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' -import { loadUserByKey } from '../../loaders' +import { UserDataSource } from '../../../user' import { userRequired } from '../../../auth' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -79,6 +79,7 @@ describe('user send password reset email', () => { }) }) it('returns a successful status message', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -109,11 +110,11 @@ describe('user send password reset email', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, }, }) @@ -135,6 +136,7 @@ describe('user send password reset email', () => { expect(consoleOutput).toEqual([`User: ${user._key} successfully two factor authenticated their account.`]) }) it('updates the user phoneValidated to true', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -165,11 +167,11 @@ describe('user send password reset email', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, }, }) @@ -201,6 +203,7 @@ describe('user send password reset email', () => { }) }) it('returns a successful status message', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) const response = await graphql({ schema, source: ` @@ -231,11 +234,11 @@ describe('user send password reset email', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, }, }) @@ -258,6 +261,7 @@ describe('user send password reset email', () => { expect(consoleOutput).toEqual([`User: ${user._key} successfully two factor authenticated their account.`]) }) it('updates the user phoneValidated to true', async () => { + const userDataSource = new UserDataSource({ query, userKey: user._key, i18n, transaction, collections: collectionNames }) await graphql({ schema, source: ` @@ -288,11 +292,11 @@ describe('user send password reset email', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: userDataSource.byKey, }), }, - loaders: { - loadUserByKey: loadUserByKey({ query }), + dataSources: { + user: userDataSource, }, }, }) @@ -359,11 +363,7 @@ describe('user send password reset email', () => { _key: 123, }), }, - loaders: { - loadUserByKey: { - load: jest.fn(), - }, - }, + dataSources: { user: {} }, }, }) @@ -419,11 +419,7 @@ describe('user send password reset email', () => { tfaCode: 123456, }), }, - loaders: { - loadUserByKey: { - load: jest.fn(), - }, - }, + dataSources: { user: {} }, }, }) @@ -447,6 +443,10 @@ describe('user send password reset email', () => { describe('given a transaction step error', () => { describe('when upserting users phone validation status', () => { it('throws an error', async () => { + const mockedTransaction = jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue(new Error('Transaction step error')), + abort: jest.fn(), + }) const response = await graphql({ schema, source: ` @@ -473,20 +473,18 @@ describe('user send password reset email', () => { userKey: 123, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error')), - abort: jest.fn(), - }), + transaction: mockedTransaction, auth: { userRequired: jest.fn().mockReturnValue({ _key: 123, tfaCode: 123456, }), }, - loaders: { - loadUserByKey: { - load: jest.fn(), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + { byKey: { load: jest.fn() } }, + ), }, }, }) @@ -503,6 +501,11 @@ describe('user send password reset email', () => { describe('given a transaction commit error', () => { describe('when committing changes', () => { it('throws an error', async () => { + const mockedTransaction = jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValue({}), + commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), + abort: jest.fn(), + }) const response = await graphql({ schema, source: ` @@ -529,21 +532,18 @@ describe('user send password reset email', () => { userKey: 123, query, collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), - abort: jest.fn(), - }), + transaction: mockedTransaction, auth: { userRequired: jest.fn().mockReturnValue({ _key: 123, tfaCode: 123456, }), }, - loaders: { - loadUserByKey: { - load: jest.fn(), - }, + dataSources: { + user: Object.assign( + new UserDataSource({ query, userKey: 123, i18n, transaction: mockedTransaction, collections: collectionNames }), + { byKey: { load: jest.fn() } }, + ), }, }, }) @@ -607,11 +607,7 @@ describe('user send password reset email', () => { _key: 123, }), }, - loaders: { - loadUserByKey: { - load: jest.fn(), - }, - }, + dataSources: { user: {} }, }, }) @@ -667,11 +663,7 @@ describe('user send password reset email', () => { tfaCode: 123456, }), }, - loaders: { - loadUserByKey: { - load: jest.fn(), - }, - }, + dataSources: { user: {} }, }, }) @@ -692,119 +684,6 @@ describe('user send password reset email', () => { ]) }) }) - describe('given a transaction step error', () => { - describe('when upserting users phone validation status', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - verifyPhoneNumber(input: { twoFactorCode: 123456 }) { - result { - ... on VerifyPhoneNumberResult { - status - user { - displayName - } - } - ... on VerifyPhoneNumberError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - userKey: 123, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Transaction step error')), - abort: jest.fn(), - }), - auth: { - userRequired: jest.fn().mockReturnValue({ - _key: 123, - tfaCode: 123456, - }), - }, - loaders: { - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - - const error = [new GraphQLError("Impossible de s'authentifier par deux facteurs. Veuillez réessayer.")] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred when upserting the tfaValidate field for 123: Error: Transaction step error`, - ]) - }) - }) - }) - describe('given a transaction commit error', () => { - describe('when committing changes', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - verifyPhoneNumber(input: { twoFactorCode: 123456 }) { - result { - ... on VerifyPhoneNumberResult { - status - user { - displayName - } - } - ... on VerifyPhoneNumberError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - userKey: 123, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Transaction commit error')), - abort: jest.fn(), - }), - auth: { - userRequired: jest.fn().mockReturnValue({ - _key: 123, - tfaCode: 123456, - }), - }, - loaders: { - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - - const error = [new GraphQLError("Impossible de s'authentifier par deux facteurs. Veuillez réessayer.")] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred when upserting the tfaValidate field for 123: Error: Transaction commit error`, - ]) - }) - }) - }) }) }) }) diff --git a/api/src/user/mutations/authenticate.js b/api/src/user/mutations/authenticate.js index 1761186ffa..b11514d1e0 100644 --- a/api/src/user/mutations/authenticate.js +++ b/api/src/user/mutations/authenticate.js @@ -37,13 +37,10 @@ export const authenticate = new mutationWithClientMutationId({ { i18n, response, - query, - collections, - transaction, uuidv4, jwt, auth: { tokenize, verifyToken }, - loaders: { loadUserByKey }, + dataSources: { user: userDataSource }, validators: { cleanseInput }, }, ) => { @@ -68,7 +65,7 @@ export const authenticate = new mutationWithClientMutationId({ } // Gather sign in user - const user = await loadUserByKey.load(tokenParameters.userKey) + const user = await userDataSource.byKey.load(tokenParameters.userKey) // Replace with userRequired() if (typeof user === 'undefined') { @@ -91,68 +88,18 @@ export const authenticate = new mutationWithClientMutationId({ expiresAt: new Date(new Date().getTime() + ms(REFRESH_TOKEN_EXPIRY)), } - // Setup Transaction - const trx = await transaction(collections) - - // Reset tfa code attempts, and set refresh code - try { - await trx.step( - () => query` - WITH users - UPSERT { _key: ${user._key} } - INSERT { - tfaCode: null, - refreshInfo: ${refreshInfo}, - lastLogin: ${loginDate} - } - UPDATE { - tfaCode: null, - refreshInfo: ${refreshInfo}, - lastLogin: ${loginDate} - } - IN users - `, - ) - } catch (err) { - console.error( - `Trx step error occurred when clearing tfa code and setting refresh id for user: ${user._key} during authentication: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to authenticate. Please try again.`)) - } - // verify user email - if (sendMethod === 'email' && !user.emailValidated) { - try { - await trx.step( - () => query` - WITH users - UPSERT { _key: ${user._key} } - INSERT { - emailValidated: true, - } - UPDATE { - emailValidated: true, - } - IN users - `, - ) - user.emailValidated = true - } catch (err) { - console.error( - `Trx step error occurred when setting email validated to true for user: ${user._key} during authentication: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to authenticate. Please try again.`)) - } - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred while user: ${user._key} attempted to authenticate: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to authenticate. Please try again.`)) + const shouldValidateEmail = sendMethod === 'email' && !user.emailValidated + + // Reset tfa code attempts, set refresh code, and optionally validate email + await userDataSource.authenticateSetSession({ + userKey: user._key, + refreshInfo, + loginDate, + emailValidated: shouldValidateEmail, + }) + if (shouldValidateEmail) { + user.emailValidated = true } const token = tokenize({ @@ -198,36 +145,7 @@ export const authenticate = new mutationWithClientMutationId({ } else { console.warn(`User: ${user._key} attempted to authenticate their account, however the tfaCodes did not match.`) // reset tfa code - const trx = await transaction(collections) - try { - await trx.step( - () => query` - WITH users - UPSERT { _key: ${user._key} } - INSERT { - tfaCode: null, - } - UPDATE { - tfaCode: null, - } - IN users - `, - ) - } catch (err) { - console.error( - `Trx step error occurred when clearing tfa code on attempt timeout for user: ${user._key} during authentication: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Incorrect TFA code. Please sign in again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred while user: ${user._key} attempted to authenticate: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Incorrect TFA code. Please sign in again.`)) - } + await userDataSource.resetTfaCode({ userKey: user._key }) throw new Error(i18n._(t`Incorrect TFA code. Please sign in again.`)) } }, diff --git a/api/src/user/mutations/close-account.js b/api/src/user/mutations/close-account.js index 7a03baa586..8c5c84f77b 100644 --- a/api/src/user/mutations/close-account.js +++ b/api/src/user/mutations/close-account.js @@ -17,7 +17,7 @@ export const closeAccountSelf = new mutationWithClientMutationId({ }), mutateAndGetPayload: async ( args, - { i18n, query, collections, transaction, request: { ip }, auth: { userRequired }, validators: { cleanseInput } }, + { i18n, query, collections, transaction, request: { ip }, auth: { userRequired }, dataSources: { user: userDataSource }, validators: { cleanseInput } }, ) => { let submittedUserId if (args?.userId) { @@ -29,49 +29,7 @@ export const closeAccountSelf = new mutationWithClientMutationId({ const userId = user._id const targetUserName = user.userName - // Setup Trans action - const trx = await transaction(collections) - - try { - await trx.step( - () => query` - WITH affiliations, organizations, users - FOR v, e IN 1..1 INBOUND ${userId} affiliations - REMOVE { _key: e._key } IN affiliations - OPTIONS { waitForSync: true } - `, - ) - } catch (err) { - console.error( - `Trx step error occurred when removing users remaining affiliations when user: ${user._key} attempted to close account: ${userId}: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to close account. Please try again.`)) - } - - try { - await trx.step( - () => query` - WITH users - REMOVE PARSE_IDENTIFIER(${userId}).key - IN users OPTIONS { waitForSync: true } - `, - ) - } catch (err) { - console.error( - `Trx step error occurred when removing user: ${user._key} attempted to close account: ${userId}: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to close account. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred when user: ${user._key} attempted to close account: ${userId}: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to close account. Please try again.`)) - } + await userDataSource.removeUserAndAffiliations({ userId }) console.info(`User: ${user._key} successfully closed user: ${userId} account.`) await logActivity({ @@ -123,7 +81,7 @@ export const closeAccountOther = new mutationWithClientMutationId({ transaction, request: { ip }, auth: { checkSuperAdmin, userRequired }, - loaders: { loadUserByKey }, + dataSources: { user: userDataSource }, validators: { cleanseInput }, }, ) => { @@ -149,7 +107,7 @@ export const closeAccountOther = new mutationWithClientMutationId({ } } - const checkUser = await loadUserByKey.load(submittedUserId) + const checkUser = await userDataSource.byKey.load(submittedUserId) if (typeof checkUser === 'undefined') { console.warn( `User: ${user._key} attempted to close user: ${submittedUserId} account, but requested user is undefined.`, @@ -163,49 +121,7 @@ export const closeAccountOther = new mutationWithClientMutationId({ userId = checkUser._id targetUserName = checkUser.userName - // Setup Trans action - const trx = await transaction(collections) - - try { - await trx.step( - () => query` - WITH affiliations, organizations, users - FOR v, e IN 1..1 INBOUND ${userId} affiliations - REMOVE { _key: e._key } IN affiliations - OPTIONS { waitForSync: true } - `, - ) - } catch (err) { - console.error( - `Trx step error occurred when removing users remaining affiliations when user: ${user._key} attempted to close account: ${userId}: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to close account. Please try again.`)) - } - - try { - await trx.step( - () => query` - WITH users - REMOVE PARSE_IDENTIFIER(${userId}).key - IN users OPTIONS { waitForSync: true } - `, - ) - } catch (err) { - console.error( - `Trx step error occurred when removing user: ${user._key} attempted to close account: ${userId}: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to close account. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred when user: ${user._key} attempted to close account: ${userId}: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to close account. Please try again.`)) - } + await userDataSource.removeUserAndAffiliations({ userId }) console.info(`User: ${user._key} successfully closed user: ${userId} account.`) await logActivity({ diff --git a/api/src/user/mutations/complete-tour.js b/api/src/user/mutations/complete-tour.js index 8fff7a9458..fa9870e738 100644 --- a/api/src/user/mutations/complete-tour.js +++ b/api/src/user/mutations/complete-tour.js @@ -23,7 +23,7 @@ export const completeTour = new mutationWithClientMutationId({ }), mutateAndGetPayload: async ( args, - { i18n, query, auth: { userRequired }, loaders: { loadUserByKey }, validators: { cleanseInput } }, + { i18n, auth: { userRequired }, dataSources: { user: userDataSource }, validators: { cleanseInput } }, ) => { // Cleanse Input const tourId = cleanseInput(args.tourId) @@ -41,31 +41,10 @@ export const completeTour = new mutationWithClientMutationId({ } // Complete tour - try { - const completeTourCursor = await query` - LET userCompleteTours = FIRST( - FOR user IN users - FILTER user._key == ${user._key} - LIMIT 1 - RETURN user.completedTours - ) - UPDATE { _key: ${user._key} } - WITH { - completedTours: APPEND( - userCompleteTours[* FILTER CURRENT.tourId != ${tourId}], - { tourId: ${tourId}, completedAt: DATE_ISO8601(DATE_NOW()) } - ) - } - IN users - ` - await completeTourCursor.next() - } catch (err) { - console.error(`Database error occurred when user: ${user._key} attempted to complete tour: ${tourId}: ${err}`) - throw new Error(i18n._(t`Unable to confirm completion of the tour. Please try again.`)) - } + await userDataSource.completeTour({ userKey: user._key, tourId }) - await loadUserByKey.clear(user._key) - const returnUser = await loadUserByKey.load(user._key) + await userDataSource.byKey.clear(user._key) + const returnUser = await userDataSource.byKey.load(user._key) console.info(`User: ${user._key} has confirmed completion of tour: ${tourId}`) return { diff --git a/api/src/user/mutations/dismiss-message.js b/api/src/user/mutations/dismiss-message.js index a5bdbc3871..ed27a02eaa 100644 --- a/api/src/user/mutations/dismiss-message.js +++ b/api/src/user/mutations/dismiss-message.js @@ -23,7 +23,7 @@ export const dismissMessage = new mutationWithClientMutationId({ }), mutateAndGetPayload: async ( args, - { i18n, query, auth: { userRequired }, loaders: { loadUserByKey }, validators: { cleanseInput } }, + { i18n, auth: { userRequired }, dataSources: { user: userDataSource }, validators: { cleanseInput } }, ) => { // Cleanse Input const messageId = cleanseInput(args.messageId) @@ -41,33 +41,10 @@ export const dismissMessage = new mutationWithClientMutationId({ } // Dismiss message - try { - const dismissMessageCursor = await query` - LET userDismissedMessages = FIRST( - FOR user IN users - FILTER user._key == ${user._key} - LIMIT 1 - RETURN user.dismissedMessages - ) - UPDATE { _key: ${user._key} } - WITH { - dismissedMessages: APPEND( - userDismissedMessages[* FILTER CURRENT.messageId != ${messageId}], - { messageId: ${messageId}, dismissedAt: DATE_ISO8601(DATE_NOW()) } - ) - } - IN users - ` - await dismissMessageCursor.next() - } catch (err) { - console.error( - `Database error occurred when user: ${user._key} attempted to dismiss message: ${messageId}: ${err}`, - ) - throw new Error(i18n._(t`Unable to dismiss message. Please try again.`)) - } + await userDataSource.dismissMessage({ userKey: user._key, messageId }) - await loadUserByKey.clear(user._key) - const returnUser = await loadUserByKey.load(user._key) + await userDataSource.byKey.clear(user._key) + const returnUser = await userDataSource.byKey.load(user._key) console.info(`User: ${user._key} successfully dismissed message: ${messageId}`) return { diff --git a/api/src/user/mutations/refresh-tokens.js b/api/src/user/mutations/refresh-tokens.js index 0028b753e5..9eff3bcf33 100644 --- a/api/src/user/mutations/refresh-tokens.js +++ b/api/src/user/mutations/refresh-tokens.js @@ -23,14 +23,11 @@ export const refreshTokens = new mutationWithClientMutationId({ i18n, response, request, - query, - collections, - transaction, uuidv4, jwt, moment, auth: { tokenize }, - loaders: { loadUserByKey }, + dataSources: { user: userDataSource }, }, ) => { // check uuid matches @@ -62,7 +59,7 @@ export const refreshTokens = new mutationWithClientMutationId({ const { userKey, uuid } = decodedRefreshToken.parameters - const user = await loadUserByKey.load(userKey) + const user = await userDataSource.byKey.load(userKey) if (typeof user === 'undefined') { console.warn(`User: ${userKey} attempted to refresh tokens with an invalid user id.`) @@ -104,32 +101,7 @@ export const refreshTokens = new mutationWithClientMutationId({ expiresAt: new Date(new Date().getTime() + ms(String(REFRESH_TOKEN_EXPIRY))), } - // Setup Transaction - const trx = await transaction(collections) - - try { - await trx.step( - () => query` - WITH users - UPSERT { _key: ${user._key} } - INSERT { refreshInfo: ${refreshInfo} } - UPDATE { refreshInfo: ${refreshInfo} } - IN users - `, - ) - } catch (err) { - console.error(`Trx step error occurred when attempting to refresh tokens for user: ${userKey}: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to refresh tokens, please sign in.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred while user: ${userKey} attempted to refresh tokens: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to refresh tokens, please sign in.`)) - } + await userDataSource.setRefreshInfo({ userKey, refreshInfo }) const newAuthToken = tokenize({ expiresIn: AUTH_TOKEN_EXPIRY, diff --git a/api/src/user/mutations/remove-phone-number.js b/api/src/user/mutations/remove-phone-number.js index b1d449b1a0..5c7f3863b3 100644 --- a/api/src/user/mutations/remove-phone-number.js +++ b/api/src/user/mutations/remove-phone-number.js @@ -14,7 +14,7 @@ export const removePhoneNumber = new mutationWithClientMutationId({ resolve: (payload) => payload, }, }), - mutateAndGetPayload: async (_args, { i18n, collections, query, transaction, auth: { userRequired } }) => { + mutateAndGetPayload: async (_args, { i18n, auth: { userRequired }, dataSources: { user: userDataSource } }) => { // Get requesting user const user = await userRequired() @@ -24,40 +24,7 @@ export const removePhoneNumber = new mutationWithClientMutationId({ tfaSendMethod = 'email' } - // Setup Transaction - const trx = await transaction(collections) - - try { - await trx.step( - () => query` - WITH users - UPSERT { _key: ${user._key} } - INSERT { - phoneDetails: null, - phoneValidated: false, - tfaSendMethod: ${tfaSendMethod} - } - UPDATE { - phoneDetails: null, - phoneValidated: false, - tfaSendMethod: ${tfaSendMethod} - } - IN users - `, - ) - } catch (err) { - console.error(`Trx step error occurred well removing phone number for user: ${user._key}: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to remove phone number. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred well removing phone number for user: ${user._key}: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to remove phone number. Please try again.`)) - } + await userDataSource.removePhoneNumber({ userKey: user._key, tfaSendMethod }) console.info(`User: ${user._key} successfully removed their phone number.`) return { diff --git a/api/src/user/mutations/reset-password.js b/api/src/user/mutations/reset-password.js index 8deb0bbb7b..b7cfdd7e9b 100644 --- a/api/src/user/mutations/reset-password.js +++ b/api/src/user/mutations/reset-password.js @@ -34,11 +34,8 @@ export const resetPassword = new mutationWithClientMutationId({ args, { i18n, - query, - collections, - transaction, auth: { verifyToken, bcrypt }, - loaders: { loadUserByKey }, + dataSources: { user: userDataSource }, validators: { cleanseInput }, }, ) => { @@ -63,7 +60,7 @@ export const resetPassword = new mutationWithClientMutationId({ } // Check if user exists - const user = await loadUserByKey.load(tokenParameters.userKey) + const user = await userDataSource.byKey.load(tokenParameters.userKey) // Replace with userRequired() if (typeof user === 'undefined') { @@ -104,34 +101,7 @@ export const resetPassword = new mutationWithClientMutationId({ // Update users password in db const hashedPassword = bcrypt.hashSync(password, 10) - // Setup Transaction - const trx = await transaction(collections) - - try { - await trx.step( - () => query` - WITH users - FOR user IN users - UPDATE ${user._key} - WITH { - password: ${hashedPassword}, - failedLoginAttempts: 0 - } IN users - `, - ) - } catch (err) { - console.error(`Trx step error occurred when user: ${user._key} attempted to reset their password: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to reset password. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred while user: ${user._key} attempted to authenticate: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to reset password. Please try again.`)) - } + await userDataSource.updatePasswordAndResetAttempts({ userKey: user._key, hashedPassword }) console.info(`User: ${user._key} successfully reset their password.`) diff --git a/api/src/user/mutations/send-password-reset.js b/api/src/user/mutations/send-password-reset.js index 5578b94147..f85e30584d 100644 --- a/api/src/user/mutations/send-password-reset.js +++ b/api/src/user/mutations/send-password-reset.js @@ -31,14 +31,14 @@ export const sendPasswordResetLink = new mutationWithClientMutationId({ request, auth: { tokenize }, validators: { cleanseInput }, - loaders: { loadUserByUserName }, + dataSources: { user: userDataSource }, notify: { sendPasswordResetEmail }, }, ) => { // Cleanse Input const userName = cleanseInput(args.userName).toLowerCase() - const user = await loadUserByUserName.load(userName) + const user = await userDataSource.byUserName.load(userName) if (typeof user !== 'undefined') { const token = tokenize({ diff --git a/api/src/user/mutations/set-phone-number.js b/api/src/user/mutations/set-phone-number.js index 09f874d6e7..1dec0b7407 100644 --- a/api/src/user/mutations/set-phone-number.js +++ b/api/src/user/mutations/set-phone-number.js @@ -29,11 +29,8 @@ export const setPhoneNumber = new mutationWithClientMutationId({ args, { i18n, - query, - collections, - transaction, auth: { userRequired }, - loaders: { loadUserByKey }, + dataSources: { user: userDataSource }, validators: { cleanseInput }, notify: { sendAuthTextMsg }, }, @@ -67,47 +64,12 @@ export const setPhoneNumber = new mutationWithClientMutationId({ tfaSendMethod = 'email' } - // Setup Transaction - const trx = await transaction(collections) - // Insert TFA code into DB - try { - await trx.step( - () => query` - WITH users - UPSERT { _key: ${user._key} } - INSERT { - tfaCode: ${tfaCode}, - phoneDetails: ${phoneDetails}, - phoneValidated: false, - tfaSendMethod: ${tfaSendMethod} - } - UPDATE { - tfaCode: ${tfaCode}, - phoneDetails: ${phoneDetails}, - phoneValidated: false, - tfaSendMethod: ${tfaSendMethod} - } - IN users - `, - ) - } catch (err) { - console.error(`Trx step error occurred for user: ${user._key} when upserting phone number information: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to set phone number, please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred for user: ${user._key} when upserting phone number information: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to set phone number, please try again.`)) - } + await userDataSource.setPhoneNumber({ userKey: user._key, tfaCode, phoneDetails, tfaSendMethod }) // Get newly updated user - await loadUserByKey.clear(user._key) - user = await loadUserByKey.load(user._key) + await userDataSource.byKey.clear(user._key) + user = await userDataSource.byKey.load(user._key) await sendAuthTextMsg({ user }) diff --git a/api/src/user/mutations/sign-in.js b/api/src/user/mutations/sign-in.js index bf0efdcdda..693f04b464 100644 --- a/api/src/user/mutations/sign-in.js +++ b/api/src/user/mutations/sign-in.js @@ -39,14 +39,11 @@ export const signIn = new mutationWithClientMutationId({ args, { i18n, - query, - collections, - transaction, uuidv4, response, jwt, auth: { tokenize, bcrypt }, - loaders: { loadUserByUserName }, + dataSources: { user: userDataSource }, validators: { cleanseInput }, notify: { sendAuthEmail, sendAuthTextMsg }, }, @@ -57,7 +54,7 @@ export const signIn = new mutationWithClientMutationId({ const rememberMe = args.rememberMe // Gather user who just signed in - let user = await loadUserByUserName.load(userName) + let user = await userDataSource.byUserName.load(userName) // Replace with userRequired() if (typeof user === 'undefined') { @@ -78,26 +75,8 @@ export const signIn = new mutationWithClientMutationId({ description: i18n._(t`Too many failed login attempts, please reset your password, and try again.`), } } else { - // Setup Transaction - const trx = await transaction(collections) - // Check to see if passwords match if (bcrypt.compareSync(password, user.password)) { - // Reset Failed Login attempts - try { - await trx.step( - () => query` - WITH users - FOR u IN users - UPDATE ${user._key} WITH { failedLoginAttempts: 0 } IN users - `, - ) - } catch (err) { - console.error(`Trx step error occurred when resetting failed login attempts for user: ${user._key}: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to sign in, please try again.`)) - } - const refreshId = uuidv4() const refreshInfo = { refreshId, @@ -109,40 +88,12 @@ export const signIn = new mutationWithClientMutationId({ // Generate TFA code const tfaCode = Math.floor(100000 + Math.random() * 900000) - // Insert TFA code into DB - try { - await trx.step( - () => query` - WITH users - UPSERT { _key: ${user._key} } - INSERT { - tfaCode: ${tfaCode}, - refreshInfo: ${refreshInfo} - } - UPDATE { - tfaCode: ${tfaCode}, - refreshInfo: ${refreshInfo} - } - IN users - `, - ) - } catch (err) { - console.error(`Trx step error occurred when inserting TFA code for user: ${user._key}: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to sign in, please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred while user: ${user._key} attempted to tfa sign in: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to sign in, please try again.`)) - } + // Reset failed login attempts and insert TFA code into DB + await userDataSource.resetFailedLoginAttemptsAndSetTfaCode({ userKey: user._key, tfaCode, refreshInfo }) // Get newly updated user - await loadUserByUserName.clear(userName) - user = await loadUserByUserName.load(userName) + await userDataSource.byUserName.clear(userName) + user = await userDataSource.byUserName.load(userName) // Check if user's last successful login was over 30 days ago let lastLogin @@ -180,31 +131,7 @@ export const signIn = new mutationWithClientMutationId({ } } else { const loginDate = new Date().toISOString() - try { - await trx.step( - () => query` - WITH users - UPSERT { _key: ${user._key} } - INSERT { refreshInfo: ${refreshInfo}, lastLogin: ${loginDate} } - UPDATE { refreshInfo: ${refreshInfo}, lastLogin: ${loginDate} } - IN users - `, - ) - } catch (err) { - console.error( - `Trx step error occurred when attempting to setting refresh tokens for user: ${user._key} during sign in: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to sign in, please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred while user: ${user._key} attempted a regular sign in: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to sign in, please try again.`)) - } + await userDataSource.resetFailedLoginAttemptsAndSetRefreshInfo({ userKey: user._key, refreshInfo, loginDate }) const token = tokenize({ expiresIn: AUTH_TOKEN_EXPIRY, @@ -251,32 +178,10 @@ export const signIn = new mutationWithClientMutationId({ // increment failed login attempts user.failedLoginAttempts += 1 - try { - // Increase users failed login attempts - await trx.step( - () => query` - WITH users - FOR u IN users - UPDATE ${user._key} WITH { - failedLoginAttempts: ${user.failedLoginAttempts} - } IN users - `, - ) - } catch (err) { - console.error( - `Trx step error occurred when incrementing failed login attempts for user: ${user._key}: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to sign in, please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred while user: ${user._key} failed to sign in: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to sign in, please try again.`)) - } + await userDataSource.incrementFailedLoginAttempts({ + userKey: user._key, + failedLoginAttempts: user.failedLoginAttempts, + }) console.warn(`User attempted to authenticate: ${user._key} with invalid credentials.`) return { diff --git a/api/src/user/mutations/sign-up.js b/api/src/user/mutations/sign-up.js index 16dfb0eed7..57f5aa9f98 100644 --- a/api/src/user/mutations/sign-up.js +++ b/api/src/user/mutations/sign-up.js @@ -57,7 +57,7 @@ export const signUp = new mutationWithClientMutationId({ uuidv4, request: { ip }, auth: { bcrypt, tokenize, verifyToken }, - loaders: { loadOrgByKey, loadUserByUserName, loadUserByKey }, + dataSources: { user: userDataSource, organization }, notify: { sendAuthEmail }, validators: { cleanseInput }, }, @@ -101,7 +101,7 @@ export const signUp = new mutationWithClientMutationId({ } // Check to see if user already exists - const checkUser = await loadUserByUserName.load(userName) + const checkUser = await userDataSource.byUserName.load(userName) if (typeof checkUser !== 'undefined') { console.warn(`User: ${userName} tried to sign up, however there is already an account in use with that email.`) @@ -142,42 +142,8 @@ export const signUp = new mutationWithClientMutationId({ }, } - // Setup Transaction - const trx = await transaction(collections) - - let insertedUserCursor - try { - insertedUserCursor = await trx.step( - () => query` - WITH users - INSERT ${user} INTO users - RETURN MERGE( - { - id: NEW._key, - _type: "user" - }, - NEW - ) - `, - ) - } catch (err) { - console.error( - `Transaction step error occurred while user: ${userName} attempted to sign up, creating user: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to sign up. Please try again.`)) - } - - let insertedUser - try { - insertedUser = await insertedUserCursor.next() - } catch (err) { - console.error(`Cursor error occurred while user: ${userName} attempted to sign up, creating user: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to sign up. Please try again.`)) - } - // Assign user to org + let affiliation if (signUpToken !== '') { // Gather token parameters const tokenParameters = verifyToken({ @@ -190,7 +156,6 @@ export const signUp = new mutationWithClientMutationId({ if (userName !== tokenUserName) { console.warn(`User: ${userName} attempted to sign up with an invite token, however emails do not match.`) - await trx.abort() return { _type: 'error', code: 400, @@ -198,10 +163,9 @@ export const signUp = new mutationWithClientMutationId({ } } - const checkOrg = await loadOrgByKey.load(tokenOrgKey) + const checkOrg = await organization.byKey.load(tokenOrgKey) if (typeof checkOrg === 'undefined') { console.warn(`User: ${userName} attempted to sign up with an invite token, however the org could not be found.`) - await trx.abort() return { _type: 'error', code: 400, @@ -209,36 +173,12 @@ export const signUp = new mutationWithClientMutationId({ } } - try { - await trx.step( - () => - query` - WITH affiliations, organizations, users - INSERT { - _from: ${checkOrg._id}, - _to: ${insertedUser._id}, - permission: ${tokenRequestedRole}, - } INTO affiliations - `, - ) - } catch (err) { - console.error( - `Transaction step error occurred while user: ${userName} attempted to sign up, assigning affiliation: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to sign up. Please try again.`)) - } + affiliation = { orgId: checkOrg._id, permission: tokenRequestedRole } } - try { - await trx.commit() - } catch (err) { - console.error(`Transaction commit error occurred while user: ${userName} attempted to sign up: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to sign up. Please try again.`)) - } + const insertedUser = await userDataSource.create({ user, affiliation }) - const returnUser = await loadUserByKey.load(insertedUser._key) + const returnUser = await userDataSource.byKey.load(insertedUser._key) await sendAuthEmail({ user: returnUser }) const authenticateToken = tokenize({ diff --git a/api/src/user/mutations/update-user-password.js b/api/src/user/mutations/update-user-password.js index 78d07d6b6b..21e10e9323 100644 --- a/api/src/user/mutations/update-user-password.js +++ b/api/src/user/mutations/update-user-password.js @@ -31,7 +31,7 @@ export const updateUserPassword = new mutationWithClientMutationId({ }), mutateAndGetPayload: async ( args, - { i18n, query, collections, transaction, auth: { bcrypt, userRequired }, validators: { cleanseInput } }, + { i18n, auth: { bcrypt, userRequired }, dataSources: { user: userDataSource }, validators: { cleanseInput } }, ) => { // Cleanse Input const currentPassword = cleanseInput(args.currentPassword) @@ -78,30 +78,7 @@ export const updateUserPassword = new mutationWithClientMutationId({ // Update password in DB const hashedPassword = bcrypt.hashSync(updatedPassword, 10) - // Setup Transaction - const trx = await transaction(collections) - - try { - await trx.step( - () => query` - WITH users - FOR user IN users - UPDATE ${user._key} WITH { password: ${hashedPassword} } IN users - `, - ) - } catch (err) { - console.error(`Trx step error occurred when user: ${user._key} attempted to update their password: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to update password. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred when user: ${user._key} attempted to update their password: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to update password. Please try again.`)) - } + await userDataSource.updatePassword({ userKey: user._key, hashedPassword }) console.info(`User: ${user._key} successfully updated their password.`) return { diff --git a/api/src/user/mutations/update-user-profile.js b/api/src/user/mutations/update-user-profile.js index b7619fc81f..82dcf4b005 100644 --- a/api/src/user/mutations/update-user-profile.js +++ b/api/src/user/mutations/update-user-profile.js @@ -49,12 +49,10 @@ export const updateUserProfile = new mutationWithClientMutationId({ { i18n, query, - collections, - transaction, userKey, request, auth: { tokenize, userRequired }, - loaders: { loadUserByKey, loadUserByUserName }, + dataSources: { user: userDataSource }, notify: { sendVerificationEmail }, validators: { cleanseInput }, }, @@ -71,7 +69,7 @@ export const updateUserProfile = new mutationWithClientMutationId({ // Check to see if username is already in use if (userName !== '') { - const checkUser = await loadUserByUserName.load(userName) + const checkUser = await userDataSource.byUserName.load(userName) if (typeof checkUser !== 'undefined') { console.warn(`User: ${userKey} attempted to update their username, but the username is already in use.`) return { @@ -135,35 +133,10 @@ export const updateUserProfile = new mutationWithClientMutationId({ emailUpdateOptions: typeof emailUpdateOptions !== 'undefined' ? emailUpdateOptions : user?.emailUpdateOptions, } - // Setup Transaction - const trx = await transaction(collections) - - try { - await trx.step( - () => query` - WITH users - UPSERT { _key: ${user._key} } - INSERT ${updatedUser} - UPDATE ${updatedUser} - IN users - `, - ) - } catch (err) { - console.error(`Trx step error occurred when user: ${userKey} attempted to update their profile: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to update profile. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred when user: ${userKey} attempted to update their profile: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to update profile. Please try again.`)) - } + await userDataSource.updateProfile({ userKey, updatedUser }) - await loadUserByKey.clear(user._key) - const returnUser = await loadUserByKey.load(userKey) + await userDataSource.byKey.clear(user._key) + const returnUser = await userDataSource.byKey.load(userKey) if (changedUserName) { const token = tokenize({ diff --git a/api/src/user/mutations/verify-account.js b/api/src/user/mutations/verify-account.js index 19fa3a894c..92693e46f8 100644 --- a/api/src/user/mutations/verify-account.js +++ b/api/src/user/mutations/verify-account.js @@ -25,11 +25,8 @@ export const verifyAccount = new mutationWithClientMutationId({ args, { i18n, - query, - collections, - transaction, auth: { verifyToken }, - loaders: { loadUserByKey, loadUserByUserName }, + dataSources: { user: userDataSource }, notify: { sendUpdatedUserNameEmail }, validators: { cleanseInput }, }, @@ -67,7 +64,7 @@ export const verifyAccount = new mutationWithClientMutationId({ // Auth shouldn't be needed with this // Check if user exists const { userKey, userName: newUserName } = tokenParameters - const user = await loadUserByKey.load(userKey) + const user = await userDataSource.byKey.load(userKey) if (typeof user === 'undefined') { console.warn(`User: ${userKey} attempted to verify account, however no account is associated with this id.`) @@ -79,7 +76,7 @@ export const verifyAccount = new mutationWithClientMutationId({ } // Ensure newUserName is still not already in use - const checkUser = await loadUserByUserName.load(newUserName) + const checkUser = await userDataSource.byUserName.load(newUserName) if (typeof checkUser !== 'undefined') { console.warn(`User: ${userKey} attempted to update their username, but the username is already in use.`) return { @@ -102,39 +99,8 @@ export const verifyAccount = new mutationWithClientMutationId({ throw new Error(i18n._(t`Unable to send updated username email. Please try again.`)) } - // Setup Transaction - const trx = await transaction(collections) - // Verify users account - try { - await trx.step( - () => query` - WITH users - UPSERT { _key: ${user._key} } - INSERT { - emailValidated: true, - userName: ${newUserName}, - } - UPDATE { - emailValidated: true, - userName: ${newUserName}, - } - IN users - `, - ) - } catch (err) { - console.error(`Trx step error occurred when upserting email validation for user: ${user._key}: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to verify account. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred when upserting email validation for user: ${user._key}: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to verify account. Please try again.`)) - } + await userDataSource.verifyAccountUpdate({ userKey: user._key, newUserName }) console.info(`User: ${user._key} successfully email validated their account.`) diff --git a/api/src/user/mutations/verify-phone-number.js b/api/src/user/mutations/verify-phone-number.js index bcbf7d0fca..c15844438f 100644 --- a/api/src/user/mutations/verify-phone-number.js +++ b/api/src/user/mutations/verify-phone-number.js @@ -23,7 +23,7 @@ export const verifyPhoneNumber = new mutationWithClientMutationId({ }), mutateAndGetPayload: async ( args, - { i18n, userKey, query, collections, transaction, auth: { userRequired }, loaders: { loadUserByKey } }, + { i18n, userKey, auth: { userRequired }, dataSources: { user: userDataSource } }, ) => { // Cleanse Input const twoFactorCode = args.twoFactorCode @@ -52,36 +52,10 @@ export const verifyPhoneNumber = new mutationWithClientMutationId({ } } - // Setup Transaction - const trx = await transaction(collections) + await userDataSource.setPhoneValidated({ userKey: user._key }) - // Update phoneValidated to be true - try { - await trx.step( - () => query` - WITH users - UPSERT { _key: ${user._key} } - INSERT { phoneValidated: true } - UPDATE { phoneValidated: true } - IN users - `, - ) - } catch (err) { - console.error(`Trx step error occurred when upserting the tfaValidate field for ${user._key}: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to two factor authenticate. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Trx commit error occurred when upserting the tfaValidate field for ${user._key}: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to two factor authenticate. Please try again.`)) - } - - await loadUserByKey.clear(userKey) - const updatedUser = await loadUserByKey.load(userKey) + await userDataSource.byKey.clear(userKey) + const updatedUser = await userDataSource.byKey.load(userKey) console.info(`User: ${user._key} successfully two factor authenticated their account.`) diff --git a/api/src/user/queries/__tests__/find-my-tracker.test.js b/api/src/user/queries/__tests__/find-my-tracker.test.js index 27791a5993..91f9f4c84c 100644 --- a/api/src/user/queries/__tests__/find-my-tracker.test.js +++ b/api/src/user/queries/__tests__/find-my-tracker.test.js @@ -9,7 +9,7 @@ import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput } from '../../../validators' import { userRequired, verifiedRequired } from '../../../auth' -import { loadUserByKey, loadMyTrackerByUserId } from '../../loaders' +import { UserDataSource } from '../../data-source' import { DomainDataSource } from '../../../domain/data-source' import dbschema from '../../../../database.json' @@ -143,6 +143,13 @@ describe('given findMyTracker query', () => { describe('user queries for myTracker', () => { describe('in english', () => { it('returns myTracker results', async () => { + const userDataSource = new UserDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + }) const response = await graphql({ schema, source: ` @@ -207,22 +214,10 @@ describe('given findMyTracker query', () => { userRequired: userRequired({ i18n, userKey: user._key, - loadUserByKey: loadUserByKey({ - query, - userKey: user._key, - i18n, - }), + loadUserByKey: userDataSource.byKey, }), verifiedRequired: verifiedRequired({}), }, - loaders: { - loadMyTrackerByUserId: loadMyTrackerByUserId({ - query, - userKey: user._key, - cleanseInput, - language: 'en', - }), - }, dataSources: { domain: new DomainDataSource({ query, @@ -232,6 +227,7 @@ describe('given findMyTracker query', () => { loginRequiredBool: true, i18n, }), + user: userDataSource, }, }, }) @@ -388,13 +384,13 @@ describe('given findMyTracker query', () => { userRequired: jest.fn().mockReturnValue({}), verifiedRequired: jest.fn(), }, - loaders: { - loadMyTrackerByUserId: loadMyTrackerByUserId({ + dataSources: { + user: new UserDataSource({ query: mockedQuery, userKey: user._key, - cleanseInput, - language: 'en', i18n, + language: 'en', + cleanseInput, }), }, }, diff --git a/api/src/user/queries/__tests__/find-my-users.test.js b/api/src/user/queries/__tests__/find-my-users.test.js index f4a7bed846..5ad07855f2 100644 --- a/api/src/user/queries/__tests__/find-my-users.test.js +++ b/api/src/user/queries/__tests__/find-my-users.test.js @@ -10,7 +10,7 @@ import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput } from '../../../validators' import { checkSuperAdmin, superAdminRequired, userRequired, verifiedRequired } from '../../../auth' -import { loadUserByKey, loadUserConnectionsByUserId } from '../../loaders' +import { UserDataSource } from '../../data-source' import dbschema from '../../../../database.json' const { DB_PASS: rootPass, DB_URL: url } = process.env @@ -189,6 +189,13 @@ describe('given findMyUsersQuery', () => { describe('super admin queries for their users', () => { describe('in english', () => { it('returns users with affiliations', async () => { + const userDataSource = new UserDataSource({ + query, + userKey: superAdmin._key, + i18n, + language: 'en', + cleanseInput, + }) const response = await graphql({ schema, source: ` @@ -225,23 +232,13 @@ describe('given findMyUsersQuery', () => { userRequired: userRequired({ i18n, userKey: superAdmin._key, - loadUserByKey: loadUserByKey({ - query, - userKey: superAdmin._key, - i18n, - }), + loadUserByKey: userDataSource.byKey, }), verifiedRequired: verifiedRequired({}), superAdminRequired: superAdminRequired({}), }, - loaders: { - loadUserConnectionsByUserId: loadUserConnectionsByUserId({ - query, - userKey: superAdmin._key, - cleanseInput, - auth: { loginRequired: true }, - language: 'en', - }), + dataSources: { + user: userDataSource, }, }, }) @@ -348,14 +345,13 @@ describe('given findMyUsersQuery', () => { verifiedRequired: jest.fn(), superAdminRequired: jest.fn(), }, - loaders: { - loadUserConnectionsByUserId: loadUserConnectionsByUserId({ + dataSources: { + user: new UserDataSource({ query: mockedQuery, userKey: superAdmin._key, - cleanseInput, - auth: { loginRequired: true }, - language: 'en', i18n, + language: 'en', + cleanseInput, }), }, }, diff --git a/api/src/user/queries/__tests__/find-user-by-username.test.js b/api/src/user/queries/__tests__/find-user-by-username.test.js index 6006d15417..b7bf720e64 100644 --- a/api/src/user/queries/__tests__/find-user-by-username.test.js +++ b/api/src/user/queries/__tests__/find-user-by-username.test.js @@ -8,7 +8,7 @@ import { userRequired, checkUserIsAdminForUser } from '../../../auth' import { createQuerySchema } from '../../../query' import { cleanseInput } from '../../../validators' import { createMutationSchema } from '../../../mutation' -import { loadUserByKey, loadUserByUserName } from '../../loaders' +import { UserDataSource } from '../../data-source' import englishMessages from '../../../locale/en/messages' import frenchMessages from '../../../locale/fr/messages' import dbschema from '../../../../database.json' @@ -143,15 +143,15 @@ describe('given the findUserByUsername query', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: new UserDataSource({ query, userKey: user._key, i18n, cleanseInput }).byKey, }), checkUserIsAdminForUser: checkUserIsAdminForUser({ userKey: user._key, query, }), }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: new UserDataSource({ query, userKey: user._key, i18n, cleanseInput }), }, validators: { cleanseInput, @@ -204,15 +204,15 @@ describe('given the findUserByUsername query', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: new UserDataSource({ query, userKey: user._key, i18n, cleanseInput }).byKey, }), checkUserIsAdminForUser: checkUserIsAdminForUser({ userKey: user._key, query, }), }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: new UserDataSource({ query, userKey: user._key, i18n, cleanseInput }), }, validators: { cleanseInput, @@ -280,15 +280,15 @@ describe('given the findUserByUsername query', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: new UserDataSource({ query, userKey: user._key, i18n, cleanseInput }).byKey, }), checkUserIsAdminForUser: checkUserIsAdminForUser({ userKey: user._key, query, }), }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: new UserDataSource({ query, userKey: user._key, i18n, cleanseInput }), }, validators: { cleanseInput, @@ -341,15 +341,15 @@ describe('given the findUserByUsername query', () => { auth: { userRequired: userRequired({ userKey: user._key, - loadUserByKey: loadUserByKey({ query }), + loadUserByKey: new UserDataSource({ query, userKey: user._key, i18n, cleanseInput }).byKey, }), checkUserIsAdminForUser: checkUserIsAdminForUser({ userKey: user._key, query, }), }, - loaders: { - loadUserByUserName: loadUserByUserName({ query }), + dataSources: { + user: new UserDataSource({ query, userKey: user._key, i18n, cleanseInput }), }, validators: { cleanseInput, @@ -410,11 +410,13 @@ describe('given the findUserByUsername query', () => { userRequired: jest.fn(), checkUserIsAdminForUser: jest.fn().mockReturnValue(undefined), }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 123, - }), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 123, + }), + }, }, }, validators: { @@ -448,11 +450,13 @@ describe('given the findUserByUsername query', () => { userRequired: jest.fn(), checkUserIsAdminForUser: jest.fn().mockReturnValue(false), }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 123, - }), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 123, + }), + }, }, }, validators: { @@ -506,11 +510,13 @@ describe('given the findUserByUsername query', () => { userRequired: jest.fn(), checkUserIsAdminForUser: jest.fn().mockReturnValue(undefined), }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 123, - }), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 123, + }), + }, }, }, validators: { @@ -544,11 +550,13 @@ describe('given the findUserByUsername query', () => { userRequired: jest.fn(), checkUserIsAdminForUser: jest.fn().mockReturnValue(false), }, - loaders: { - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 123, - }), + dataSources: { + user: { + byUserName: { + load: jest.fn().mockReturnValue({ + _key: 123, + }), + }, }, }, validators: { diff --git a/api/src/user/queries/__tests__/is-user-admin.test.js b/api/src/user/queries/__tests__/is-user-admin.test.js index 3328d3ec5e..1e304d58c2 100644 --- a/api/src/user/queries/__tests__/is-user-admin.test.js +++ b/api/src/user/queries/__tests__/is-user-admin.test.js @@ -129,8 +129,8 @@ describe('given the isUserAdmin query', () => { }, loaders: { loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query }), }, + dataSources: { organization: { byKey: loadOrgByKey({ query }) } }, validators: { cleanseInput, }, @@ -176,8 +176,8 @@ describe('given the isUserAdmin query', () => { }, loaders: { loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query }), }, + dataSources: { organization: { byKey: loadOrgByKey({ query }) } }, validators: { cleanseInput, }, @@ -223,8 +223,8 @@ describe('given the isUserAdmin query', () => { }, loaders: { loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query }), }, + dataSources: { organization: { byKey: loadOrgByKey({ query }) } }, validators: { cleanseInput, }, @@ -272,8 +272,8 @@ describe('given the isUserAdmin query', () => { }, loaders: { loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), }, + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) } }, validators: { cleanseInput, }, @@ -319,8 +319,8 @@ describe('given the isUserAdmin query', () => { }, loaders: { loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), }, + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) } }, validators: { cleanseInput, }, @@ -366,8 +366,8 @@ describe('given the isUserAdmin query', () => { }, loaders: { loadUserByKey: loadUserByKey({ query }), - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), }, + dataSources: { organization: { byKey: loadOrgByKey({ query, language: 'en' }) } }, validators: { cleanseInput, }, @@ -421,11 +421,7 @@ describe('given the isUserAdmin query', () => { _key: 123, }), }, - loaders: { - loadOrgByKey: { - load: jest.fn(), - }, - }, + dataSources: { organization: { byKey: { load: jest.fn() } } }, validators: { cleanseInput, }, @@ -475,11 +471,7 @@ describe('given the isUserAdmin query', () => { _key: 123, }), }, - loaders: { - loadOrgByKey: { - load: jest.fn(), - }, - }, + dataSources: { organization: { byKey: { load: jest.fn() } } }, validators: { cleanseInput, }, diff --git a/api/src/user/queries/find-my-tracker.js b/api/src/user/queries/find-my-tracker.js index 0f73c9cb57..029e39bdfb 100644 --- a/api/src/user/queries/find-my-tracker.js +++ b/api/src/user/queries/find-my-tracker.js @@ -13,7 +13,7 @@ export const findMyTracker = { i18n, userKey, auth: { userRequired, verifiedRequired }, - loaders: { loadMyTrackerByUserId }, + dataSources: { user: userDataSource }, }, ) => { // Get User @@ -21,7 +21,7 @@ export const findMyTracker = { verifiedRequired({ user }) // Retrieve organization by slug - const myTracker = await loadMyTrackerByUserId() + const myTracker = await userDataSource.myTrackerByUserId() if (typeof myTracker === 'undefined') { console.warn(`User ${userKey} could not retrieve organization.`) diff --git a/api/src/user/queries/find-my-users.js b/api/src/user/queries/find-my-users.js index 38ae198971..982b60c61b 100644 --- a/api/src/user/queries/find-my-users.js +++ b/api/src/user/queries/find-my-users.js @@ -24,7 +24,7 @@ export const findMyUsers = { { userKey, auth: { checkSuperAdmin, userRequired, verifiedRequired, superAdminRequired }, - loaders: { loadUserConnectionsByUserId }, + dataSources: { user: userDataSource }, }, ) => { const user = await userRequired() @@ -33,7 +33,7 @@ export const findMyUsers = { const isSuperAdmin = await checkSuperAdmin() superAdminRequired({ user, isSuperAdmin }) - const userConnections = await loadUserConnectionsByUserId({ + const userConnections = await userDataSource.connectionsByUserId({ isSuperAdmin, ...args, }) diff --git a/api/src/user/queries/find-user-by-username.js b/api/src/user/queries/find-user-by-username.js index dcd8c3c986..ebc7adcf7a 100644 --- a/api/src/user/queries/find-user-by-username.js +++ b/api/src/user/queries/find-user-by-username.js @@ -20,7 +20,7 @@ export const findUserByUsername = { i18n, userKey, auth: { userRequired, checkUserIsAdminForUser }, - loaders: { loadUserByUserName }, + dataSources: { user: userDataSource }, validators: { cleanseInput }, }, ) => { @@ -33,7 +33,7 @@ export const findUserByUsername = { if (permission) { // Retrieve user by userName - const user = await loadUserByUserName.load(userName) + const user = await userDataSource.byUserName.load(userName) user.id = user._key return user } else { diff --git a/api/src/user/queries/is-user-admin.js b/api/src/user/queries/is-user-admin.js index 108947b7a2..afc8517780 100644 --- a/api/src/user/queries/is-user-admin.js +++ b/api/src/user/queries/is-user-admin.js @@ -19,7 +19,7 @@ export const isUserAdmin = { query, userKey, auth: { checkPermission, userRequired }, - loaders: { loadOrgByKey }, + dataSources: { organization }, validators: { cleanseInput }, }, ) => { @@ -28,7 +28,7 @@ export const isUserAdmin = { // check if for a specific org if (orgKey) { - const org = await loadOrgByKey.load(orgKey) + const org = await organization.byKey.load(orgKey) const permission = await checkPermission({ orgId: org._id }) return ['admin', 'owner', 'super_admin'].includes(permission) diff --git a/api/src/verified-domains/index.js b/api/src/verified-domains/index.js deleted file mode 100644 index 7dab4e57a0..0000000000 --- a/api/src/verified-domains/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './loaders' -export * from './objects' -export * from './queries' diff --git a/api/src/verified-domains/inputs/__tests__/verified-domain-order.test.js b/api/src/verified-domains/inputs/__tests__/verified-domain-order.test.js deleted file mode 100644 index a03bd7ef2e..0000000000 --- a/api/src/verified-domains/inputs/__tests__/verified-domain-order.test.js +++ /dev/null @@ -1,21 +0,0 @@ -import { GraphQLNonNull } from 'graphql' - -import { verifiedDomainOrder } from '../verified-domain-order' -import { OrderDirection, VerifiedDomainOrderField } from '../../../enums' - -describe('given the verifiedDomainOrder input object', () => { - describe('testing fields', () => { - it('has a direction field', () => { - const demoType = verifiedDomainOrder.getFields() - - expect(demoType).toHaveProperty('direction') - expect(demoType.direction.type).toMatchObject(new GraphQLNonNull(OrderDirection)) - }) - it('has a field field', () => { - const demoType = verifiedDomainOrder.getFields() - - expect(demoType).toHaveProperty('field') - expect(demoType.field.type).toMatchObject(new GraphQLNonNull(VerifiedDomainOrderField)) - }) - }) -}) diff --git a/api/src/verified-domains/inputs/index.js b/api/src/verified-domains/inputs/index.js deleted file mode 100644 index 29a575ab1e..0000000000 --- a/api/src/verified-domains/inputs/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './verified-domain-order' diff --git a/api/src/verified-domains/inputs/verified-domain-order.js b/api/src/verified-domains/inputs/verified-domain-order.js deleted file mode 100644 index d6d4d8851e..0000000000 --- a/api/src/verified-domains/inputs/verified-domain-order.js +++ /dev/null @@ -1,18 +0,0 @@ -import { GraphQLInputObjectType, GraphQLNonNull } from 'graphql' - -import { OrderDirection, VerifiedDomainOrderField } from '../../enums' - -export const verifiedDomainOrder = new GraphQLInputObjectType({ - name: 'VerifiedDomainOrder', - description: 'Ordering options for verified domain connections.', - fields: () => ({ - field: { - type: new GraphQLNonNull(VerifiedDomainOrderField), - description: 'The field to order verified domains by.', - }, - direction: { - type: new GraphQLNonNull(OrderDirection), - description: 'The ordering direction.', - }, - }), -}) diff --git a/api/src/verified-domains/loaders/__tests__/load-verified-domain-by-domain.test.js b/api/src/verified-domains/loaders/__tests__/load-verified-domain-by-domain.test.js deleted file mode 100644 index 55ea1176cf..0000000000 --- a/api/src/verified-domains/loaders/__tests__/load-verified-domain-by-domain.test.js +++ /dev/null @@ -1,229 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { loadVerifiedDomainsById } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given a loadVerifiedDomainsById dataloader', () => { - let query, drop, truncate, collections, i18n, domain1, domain2, org - const consoleOutput = [] - const mockedError = (output) => consoleOutput.push(output) - beforeAll(() => { - console.error = mockedError - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given a successful load', () => { - beforeAll(async () => { - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - org = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - domain1 = await collections.domains.save({ - domain: 'test.canada.ca', - }) - domain2 = await collections.domains.save({ - domain: 'test.gc.ca', - }) - await collections.claims.save({ - _from: org._id, - _to: domain1._id, - }) - await collections.claims.save({ - _from: org._id, - _to: domain2._id, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - describe('provided a single id', () => { - it('returns a single user', async () => { - // Get Domain From db - const expectedCursor = await query` - FOR domain IN domains - FILTER domain.domain == "test.canada.ca" - RETURN MERGE(domain, { id: domain._key, _type: "verifiedDomain" }) - ` - const expectedDomain = await expectedCursor.next() - - const loader = loadVerifiedDomainsById({ query }) - const user = await loader.load(expectedDomain.domain) - - expect(user).toEqual(expectedDomain) - }) - }) - describe('provided a list of ids', () => { - it('returns a list of users', async () => { - const domainDomains = [] - const expectedDomains = [] - const expectedCursor = await query` - FOR domain IN domains - RETURN MERGE(domain, { id: domain._key, _type: "verifiedDomain" }) - ` - - while (expectedCursor.hasMore) { - const tempUser = await expectedCursor.next() - domainDomains.push(tempUser.domain) - expectedDomains.push(tempUser) - } - - const loader = loadVerifiedDomainsById({ query }) - const users = await loader.loadMany(domainDomains) - expect(users).toEqual(expectedDomains) - }) - }) - }) - describe('given an unsuccessful load', () => { - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('database error is raised', () => { - it('returns an error', async () => { - const mockedQuery = jest.fn().mockRejectedValue(new Error('Database error occurred.')) - const loader = loadVerifiedDomainsById({ query: mockedQuery, i18n }) - - try { - await loader.load('domain.ca') - } catch (err) { - expect(err).toEqual(new Error('Unable to load verified domain(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Database error occurred when running loadVerifiedDomainsById: Error: Database error occurred.`, - ]) - }) - }) - describe('cursor error is raised', () => { - it('throws an error', async () => { - const cursor = { - forEach() { - throw new Error('Cursor error occurred.') - }, - } - const mockedQuery = jest.fn().mockReturnValue(cursor) - const loader = loadVerifiedDomainsById({ query: mockedQuery, i18n }) - - try { - await loader.load('domain.ca') - } catch (err) { - expect(err).toEqual(new Error('Unable to load verified domain(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Cursor error occurred during loadVerifiedDomainsById: Error: Cursor error occurred.`, - ]) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('database error is raised', () => { - it('returns an error', async () => { - const mockedQuery = jest.fn().mockRejectedValue(new Error('Database error occurred.')) - const loader = loadVerifiedDomainsById({ query: mockedQuery, i18n }) - - try { - await loader.load('domain.ca') - } catch (err) { - expect(err).toEqual(new Error('Impossible de charger le(s) domaine(s) vérifié(s). Veuillez réessayer.')) - } - - expect(consoleOutput).toEqual([ - `Database error occurred when running loadVerifiedDomainsById: Error: Database error occurred.`, - ]) - }) - }) - describe('cursor error is raised', () => { - it('throws an error', async () => { - const cursor = { - forEach() { - throw new Error('Cursor error occurred.') - }, - } - const mockedQuery = jest.fn().mockReturnValue(cursor) - const loader = loadVerifiedDomainsById({ query: mockedQuery, i18n }) - - try { - await loader.load('domain.ca') - } catch (err) { - expect(err).toEqual(new Error('Impossible de charger le(s) domaine(s) vérifié(s). Veuillez réessayer.')) - } - - expect(consoleOutput).toEqual([ - `Cursor error occurred during loadVerifiedDomainsById: Error: Cursor error occurred.`, - ]) - }) - }) - }) - }) -}) diff --git a/api/src/verified-domains/loaders/__tests__/load-verified-domain-by-key.test.js b/api/src/verified-domains/loaders/__tests__/load-verified-domain-by-key.test.js deleted file mode 100644 index 0fc8226a6c..0000000000 --- a/api/src/verified-domains/loaders/__tests__/load-verified-domain-by-key.test.js +++ /dev/null @@ -1,229 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { loadVerifiedDomainByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given a loadVerifiedDomainByKey dataloader', () => { - let query, drop, truncate, collections, i18n, domain1, domain2, org - const consoleOutput = [] - const mockedError = (output) => consoleOutput.push(output) - beforeAll(() => { - console.error = mockedError - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given a successful load', () => { - beforeAll(async () => { - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - org = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - domain1 = await collections.domains.save({ - domain: 'test.canada.ca', - }) - domain2 = await collections.domains.save({ - domain: 'test.gc.ca', - }) - await collections.claims.save({ - _from: org._id, - _to: domain1._id, - }) - await collections.claims.save({ - _from: org._id, - _to: domain2._id, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - describe('provided a single id', () => { - it('returns a single domain', async () => { - // Get Domain From db - const expectedCursor = await query` - FOR domain IN domains - FILTER domain.domain == "test.canada.ca" - RETURN MERGE(domain, { id: domain._key, _type: "verifiedDomain" }) - ` - const expectedDomain = await expectedCursor.next() - - const loader = loadVerifiedDomainByKey({ query }) - const user = await loader.load(expectedDomain._key) - - expect(user).toEqual(expectedDomain) - }) - }) - describe('provided a list of ids', () => { - it('returns a list of domains', async () => { - const domainIds = [] - const expectedDomains = [] - const expectedCursor = await query` - FOR domain IN domains - RETURN MERGE(domain, { id: domain._key, _type: "verifiedDomain" }) - ` - - while (expectedCursor.hasMore) { - const tempUser = await expectedCursor.next() - domainIds.push(tempUser._key) - expectedDomains.push(tempUser) - } - - const loader = loadVerifiedDomainByKey({ query }) - const users = await loader.loadMany(domainIds) - expect(users).toEqual(expectedDomains) - }) - }) - }) - describe('given an unsuccessful load', () => { - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('database error is raised', () => { - it('returns an error', async () => { - const mockedQuery = jest.fn().mockRejectedValue(new Error('Database error occurred.')) - const loader = loadVerifiedDomainByKey({ query: mockedQuery, i18n }) - - try { - await loader.load('1') - } catch (err) { - expect(err).toEqual(new Error('Unable to load verified domain(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Database error occurred when running loadVerifiedDomainByKey: Error: Database error occurred.`, - ]) - }) - }) - describe('cursor error is raised', () => { - it('throws an error', async () => { - const cursor = { - forEach() { - throw new Error('Cursor error occurred.') - }, - } - const mockedQuery = jest.fn().mockReturnValue(cursor) - const loader = loadVerifiedDomainByKey({ query: mockedQuery, i18n }) - - try { - await loader.load('1') - } catch (err) { - expect(err).toEqual(new Error('Unable to load verified domain(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Cursor error occurred during loadVerifiedDomainByKey: Error: Cursor error occurred.`, - ]) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('database error is raised', () => { - it('returns an error', async () => { - const mockedQuery = jest.fn().mockRejectedValue(new Error('Database error occurred.')) - const loader = loadVerifiedDomainByKey({ query: mockedQuery, i18n }) - - try { - await loader.load('1') - } catch (err) { - expect(err).toEqual(new Error('Impossible de charger le(s) domaine(s) vérifié(s). Veuillez réessayer.')) - } - - expect(consoleOutput).toEqual([ - `Database error occurred when running loadVerifiedDomainByKey: Error: Database error occurred.`, - ]) - }) - }) - describe('cursor error is raised', () => { - it('throws an error', async () => { - const cursor = { - forEach() { - throw new Error('Cursor error occurred.') - }, - } - const mockedQuery = jest.fn().mockReturnValue(cursor) - const loader = loadVerifiedDomainByKey({ query: mockedQuery, i18n }) - - try { - await loader.load('1') - } catch (err) { - expect(err).toEqual(new Error('Impossible de charger le(s) domaine(s) vérifié(s). Veuillez réessayer.')) - } - - expect(consoleOutput).toEqual([ - `Cursor error occurred during loadVerifiedDomainByKey: Error: Cursor error occurred.`, - ]) - }) - }) - }) - }) -}) diff --git a/api/src/verified-domains/loaders/__tests__/load-verified-domain-conn-by-org-id.test.js b/api/src/verified-domains/loaders/__tests__/load-verified-domain-conn-by-org-id.test.js deleted file mode 100644 index c956952d34..0000000000 --- a/api/src/verified-domains/loaders/__tests__/load-verified-domain-conn-by-org-id.test.js +++ /dev/null @@ -1,1623 +0,0 @@ -import { setupI18n } from '@lingui/core' -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { stringify } from 'jest-matcher-utils' -import { toGlobalId } from 'graphql-relay' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { cleanseInput } from '../../../validators' -import { loadVerifiedDomainConnectionsByOrgId, loadVerifiedDomainByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given the loadVerifiedDomainConnectionsByOrgId function', () => { - let query, drop, truncate, collections, user, org, domain, domainTwo, i18n - const consoleOutput = [] - const mockedError = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - beforeAll(() => { - console.error = mockedError - console.warn = mockedWarn - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given a successful load', () => { - beforeAll(async () => { - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - user = await collections.users.save({ - userName: 'test.account@istio.actually.exists', - displayName: 'Test Account', - tfaValidated: false, - emailValidated: false, - }) - org = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - await collections.affiliations.save({ - _from: org._id, - _to: user._id, - permission: 'user', - }) - domain = await collections.domains.save({ - domain: 'test.domain.gc.ca', - }) - await collections.claims.save({ - _from: org._id, - _to: domain._id, - }) - domainTwo = await collections.domains.save({ - domain: 'test.domain.canada.ca', - }) - await collections.claims.save({ - _from: org._id, - _to: domainTwo._id, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - describe('using after cursor', () => { - it('returns a domain', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomains = await domainLoader.loadMany([domain._key, domainTwo._key]) - - expectedDomains[0].id = expectedDomains[0]._key - expectedDomains[1].id = expectedDomains[1]._key - - const connectionArgs = { - first: 10, - after: toGlobalId('verifiedDomain', expectedDomains[0]._key), - } - const domains = await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', expectedDomains[1]._key), - node: { - ...expectedDomains[1], - }, - }, - ], - pageInfo: { - hasNextPage: false, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', expectedDomains[1]._key), - endCursor: toGlobalId('verifiedDomain', expectedDomains[1]._key), - }, - totalCount: 2, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('using before cursor', () => { - it('returns a domain', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomains = await domainLoader.loadMany([domain._key, domainTwo._key]) - - expectedDomains[0].id = expectedDomains[0]._key - expectedDomains[1].id = expectedDomains[1]._key - - const connectionArgs = { - first: 10, - before: toGlobalId('verifiedDomain', expectedDomains[1]._key), - } - const domains = await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', expectedDomains[0]._key), - node: { - ...expectedDomains[0], - }, - }, - ], - pageInfo: { - hasNextPage: true, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedDomain', expectedDomains[0]._key), - endCursor: toGlobalId('verifiedDomain', expectedDomains[0]._key), - }, - totalCount: 2, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('using first limit', () => { - it('returns a domain', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomains = await domainLoader.loadMany([domain._key, domainTwo._key]) - - expectedDomains[0].id = expectedDomains[0]._key - expectedDomains[1].id = expectedDomains[1]._key - - const connectionArgs = { - first: 1, - } - const domains = await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', expectedDomains[0]._key), - node: { - ...expectedDomains[0], - }, - }, - ], - pageInfo: { - hasNextPage: true, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedDomain', expectedDomains[0]._key), - endCursor: toGlobalId('verifiedDomain', expectedDomains[0]._key), - }, - totalCount: 2, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('using last limit', () => { - it('returns a domain', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomains = await domainLoader.loadMany([domain._key, domainTwo._key]) - - expectedDomains[0].id = expectedDomains[0]._key - expectedDomains[1].id = expectedDomains[1]._key - - const connectionArgs = { - last: 1, - } - const domains = await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', expectedDomains[1]._key), - node: { - ...expectedDomains[1], - }, - }, - ], - pageInfo: { - hasNextPage: false, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', expectedDomains[1]._key), - endCursor: toGlobalId('verifiedDomain', expectedDomains[1]._key), - }, - totalCount: 2, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('using the orderBy field', () => { - let domainOne, domainTwo, domainThree - beforeEach(async () => { - await truncate() - org = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - domainOne = await collections.domains.save({ - domain: 'test.domain.gc.a.ca', - status: { - dkim: 'fail', - dmarc: 'fail', - https: 'fail', - spf: 'fail', - ssl: 'fail', - }, - lastRan: '2021-01-01 12:12:12.000000', - }) - domainTwo = await collections.domains.save({ - domain: 'test.domain.gc.b.ca', - status: { - dkim: 'info', - dmarc: 'info', - https: 'info', - spf: 'info', - ssl: 'info', - }, - lastRan: '2021-01-02 12:12:12.000000', - }) - domainThree = await collections.domains.save({ - domain: 'test.domain.gc.c.ca', - status: { - dkim: 'pass', - dmarc: 'pass', - https: 'pass', - spf: 'pass', - ssl: 'pass', - }, - lastRan: '2021-01-03 12:12:12.000000', - }) - await collections.claims.save({ - _from: org._id, - _to: domainOne._id, - }) - await collections.claims.save({ - _from: org._id, - _to: domainTwo._id, - }) - await collections.claims.save({ - _from: org._id, - _to: domainThree._id, - }) - }) - describe('ordering on DOMAIN', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'domain', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'domain', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('ordering on LAST_RAN', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'last-ran', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'last-ran', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('ordering on DKIM_STATUS', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'dkim-status', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'dkim-status', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('ordering on DMARC_STATUS', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'dmarc-status', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'dmarc-status', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('ordering on HTTPS_STATUS', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'https-status', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'https-status', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('ordering on SPF_STATUS', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'spf-status', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'spf-status', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('ordering on SSL_STATUS', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'ssl-status', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - orgId: org._id, - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'ssl-status', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - }) - describe('no organizations are found', () => { - it('returns an empty structure', async () => { - await truncate() - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 10, - } - const domains = await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - - const expectedStructure = { - edges: [], - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - endCursor: '', - }, - totalCount: 0, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given an unsuccessful load', () => { - describe('limits are not set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = {} - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'You must provide a `first` or `last` value to properly paginate the `VerifiedDomain` connection.', - ), - ) - } - - expect(consoleOutput).toEqual([ - `User did not have either \`first\` or \`last\` arguments set for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - describe('both limits are set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 1, - last: 1, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Passing both `first` and `last` to paginate the `VerifiedDomain` connection is not supported.', - ), - ) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` and \`last\` arguments set for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - describe('limits are set below minimum', () => { - describe('first limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: -5, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('`first` on the `VerifiedDomain` connection cannot be less than zero.')) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` set below zero for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - describe('last limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: -5, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('`last` on the `VerifiedDomain` connection cannot be less than zero.')) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` set below zero for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - }) - describe('limits are set above maximum', () => { - describe('first limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 1000, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Requesting `1000` records on the `VerifiedDomain` connection exceeds the `first` limit of 100 records.', - ), - ) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` to 1000 for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - describe('last limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: 1000, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Requesting `1000` records on the `VerifiedDomain` connection exceeds the `last` limit of 100 records.', - ), - ) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` to 1000 for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - }) - describe('limits are not set to numbers', () => { - describe('first limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - it(`returns an error when first set to ${stringify(invalidInput)}`, async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: invalidInput, - } - - try { - await connectionLoader({ - domainId: domain._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error(`\`first\` must be of type \`number\` not \`${typeof invalidInput}\`.`)) - } - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` set as a ${typeof invalidInput} for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - }) - describe('last limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - it(`returns an error when last set to ${stringify(invalidInput)}`, async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: invalidInput, - } - - try { - await connectionLoader({ - domainId: domain._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error(`\`last\` must be of type \`number\` not \`${typeof invalidInput}\`.`)) - } - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` set as a ${typeof invalidInput} for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - }) - }) - }) - describe('given a database error', () => { - describe('when gathering domain keys that are claimed by orgs that the user has affiliations to', () => { - it('returns an error message', async () => { - const query = jest.fn().mockRejectedValue(new Error('Database Error Occurred.')) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('Unable to load verified domain(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Database error occurred while user was trying to gather domains in loadVerifiedDomainConnectionsByOrgId, error: Error: Database Error Occurred.`, - ]) - }) - }) - }) - describe('given a cursor error', () => { - describe('when gathering domain keys that are claimed by orgs that the user has affiliations to', () => { - it('returns an error message', async () => { - const cursor = { - next() { - throw new Error('Cursor error occurred.') - }, - } - const query = jest.fn().mockReturnValueOnce(cursor) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('Unable to load verified domain(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Cursor error occurred while user was trying to gather domains in loadVerifiedDomainConnectionsByOrgId, error: Error: Cursor error occurred.`, - ]) - }) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given an unsuccessful load', () => { - describe('limits are not set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = {} - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Vous devez fournir une valeur `first` ou `last` pour paginer correctement la connexion `VerifiedDomain`.', - ), - ) - } - - expect(consoleOutput).toEqual([ - `User did not have either \`first\` or \`last\` arguments set for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - describe('both limits are set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 1, - last: 1, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - "Passer à la fois `first` et `last` pour paginer la connexion `VerifiedDomain` n'est pas supporté.", - ), - ) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` and \`last\` arguments set for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - describe('limits are set below minimum', () => { - describe('first limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: -5, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('`first` sur la connexion `VerifiedDomain` ne peut être inférieur à zéro.')) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` set below zero for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - describe('last limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: -5, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('`last` sur la connexion `VerifiedDomain` ne peut être inférieur à zéro.')) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` set below zero for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - }) - describe('limits are set above maximum', () => { - describe('first limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 1000, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - "La demande d'enregistrements `1000` sur la connexion `VerifiedDomain` dépasse la limite `first` de 100 enregistrements.", - ), - ) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` to 1000 for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - describe('last limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: 1000, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - "La demande d'enregistrements `1000` sur la connexion `VerifiedDomain` dépasse la limite `last` de 100 enregistrements.", - ), - ) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` to 1000 for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - }) - describe('limits are not set to numbers', () => { - describe('first limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - it(`returns an error when first set to ${stringify(invalidInput)}`, async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: invalidInput, - } - - try { - await connectionLoader({ - domainId: domain._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error(`\`first\` doit être de type \`number\` et non \`${typeof invalidInput}\`.`), - ) - } - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` set as a ${typeof invalidInput} for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - }) - describe('last limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - it(`returns an error when last set to ${stringify(invalidInput)}`, async () => { - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: invalidInput, - } - - try { - await connectionLoader({ - domainId: domain._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error(`\`last\` doit être de type \`number\` et non \`${typeof invalidInput}\`.`), - ) - } - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` set as a ${typeof invalidInput} for: loadVerifiedDomainConnectionsByOrgId.`, - ]) - }) - }) - }) - }) - }) - describe('given a database error', () => { - describe('when gathering domain keys that are claimed by orgs that the user has affiliations to', () => { - it('returns an error message', async () => { - const query = jest.fn().mockRejectedValue(new Error('Database Error Occurred.')) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('Impossible de charger le(s) domaine(s) vérifié(s). Veuillez réessayer.')) - } - - expect(consoleOutput).toEqual([ - `Database error occurred while user was trying to gather domains in loadVerifiedDomainConnectionsByOrgId, error: Error: Database Error Occurred.`, - ]) - }) - }) - }) - describe('given a cursor error', () => { - describe('when gathering domain keys that are claimed by orgs that the user has affiliations to', () => { - it('returns an error message', async () => { - const cursor = { - next() { - throw new Error('Cursor error occurred.') - }, - } - const query = jest.fn().mockReturnValueOnce(cursor) - - const connectionLoader = loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('Impossible de charger le(s) domaine(s) vérifié(s). Veuillez réessayer.')) - } - - expect(consoleOutput).toEqual([ - `Cursor error occurred while user was trying to gather domains in loadVerifiedDomainConnectionsByOrgId, error: Error: Cursor error occurred.`, - ]) - }) - }) - }) - }) -}) diff --git a/api/src/verified-domains/loaders/__tests__/load-verified-domain-connections.test.js b/api/src/verified-domains/loaders/__tests__/load-verified-domain-connections.test.js deleted file mode 100644 index c5d31a5488..0000000000 --- a/api/src/verified-domains/loaders/__tests__/load-verified-domain-connections.test.js +++ /dev/null @@ -1,1585 +0,0 @@ -import { setupI18n } from '@lingui/core' -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { stringify } from 'jest-matcher-utils' -import { toGlobalId } from 'graphql-relay' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { cleanseInput } from '../../../validators' -import { loadVerifiedDomainConnections, loadVerifiedDomainByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given the load domain connection using org id function', () => { - let query, drop, truncate, collections, user, org, domain, domainTwo, i18n - const consoleOutput = [] - const mockedError = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - beforeAll(() => { - console.error = mockedError - console.warn = mockedWarn - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given a successful load', () => { - beforeAll(async () => { - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - user = await collections.users.save({ - userName: 'test.account@istio.actually.exists', - displayName: 'Test Account', - tfaValidated: false, - emailValidated: false, - }) - org = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - await collections.affiliations.save({ - _from: org._id, - _to: user._id, - permission: 'user', - }) - domain = await collections.domains.save({ - domain: 'test.domain.gc.ca', - }) - await collections.claims.save({ - _from: org._id, - _to: domain._id, - }) - domainTwo = await collections.domains.save({ - domain: 'test.domain.canada.ca', - }) - await collections.claims.save({ - _from: org._id, - _to: domainTwo._id, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - describe('using after cursor', () => { - it('returns a domain', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomains = await domainLoader.loadMany([domain._key, domainTwo._key]) - - expectedDomains[0].id = expectedDomains[0]._key - expectedDomains[1].id = expectedDomains[1]._key - - const connectionArgs = { - first: 10, - after: toGlobalId('verifiedDomain', expectedDomains[0]._key), - } - const domains = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', expectedDomains[1]._key), - node: { - ...expectedDomains[1], - }, - }, - ], - pageInfo: { - hasNextPage: false, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', expectedDomains[1]._key), - endCursor: toGlobalId('verifiedDomain', expectedDomains[1]._key), - }, - totalCount: 2, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('using before cursor', () => { - it('returns a domain', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomains = await domainLoader.loadMany([domain._key, domainTwo._key]) - - expectedDomains[0].id = expectedDomains[0]._key - expectedDomains[1].id = expectedDomains[1]._key - - const connectionArgs = { - first: 10, - before: toGlobalId('verifiedDomain', expectedDomains[1]._key), - } - const domains = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', expectedDomains[0]._key), - node: { - ...expectedDomains[0], - }, - }, - ], - pageInfo: { - hasNextPage: true, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedDomain', expectedDomains[0]._key), - endCursor: toGlobalId('verifiedDomain', expectedDomains[0]._key), - }, - totalCount: 2, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('using first limit', () => { - it('returns a domain', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomains = await domainLoader.loadMany([domain._key, domainTwo._key]) - - expectedDomains[0].id = expectedDomains[0]._key - expectedDomains[1].id = expectedDomains[1]._key - - const connectionArgs = { - first: 1, - } - const domains = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', expectedDomains[0]._key), - node: { - ...expectedDomains[0], - }, - }, - ], - pageInfo: { - hasNextPage: true, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedDomain', expectedDomains[0]._key), - endCursor: toGlobalId('verifiedDomain', expectedDomains[0]._key), - }, - totalCount: 2, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('using last limit', () => { - it('returns a domain', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomains = await domainLoader.loadMany([domain._key, domainTwo._key]) - - expectedDomains[0].id = expectedDomains[0]._key - expectedDomains[1].id = expectedDomains[1]._key - - const connectionArgs = { - last: 1, - } - const domains = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', expectedDomains[1]._key), - node: { - ...expectedDomains[1], - }, - }, - ], - pageInfo: { - hasNextPage: false, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', expectedDomains[1]._key), - endCursor: toGlobalId('verifiedDomain', expectedDomains[1]._key), - }, - totalCount: 2, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('using the orderBy field', () => { - let domainOne, domainTwo, domainThree - beforeEach(async () => { - await truncate() - org = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - domainOne = await collections.domains.save({ - domain: 'test.domain.gc.a.ca', - status: { - dkim: 'fail', - dmarc: 'fail', - https: 'fail', - spf: 'fail', - ssl: 'fail', - }, - lastRan: '2021-01-01 12:12:12.000000', - }) - domainTwo = await collections.domains.save({ - domain: 'test.domain.gc.b.ca', - status: { - dkim: 'info', - dmarc: 'info', - https: 'info', - spf: 'info', - ssl: 'info', - }, - lastRan: '2021-01-02 12:12:12.000000', - }) - domainThree = await collections.domains.save({ - domain: 'test.domain.gc.c.ca', - status: { - dkim: 'pass', - dmarc: 'pass', - https: 'pass', - spf: 'pass', - ssl: 'pass', - }, - lastRan: '2021-01-03 12:12:12.000000', - }) - await collections.claims.save({ - _from: org._id, - _to: domainOne._id, - }) - await collections.claims.save({ - _from: org._id, - _to: domainTwo._id, - }) - await collections.claims.save({ - _from: org._id, - _to: domainThree._id, - }) - }) - describe('ordering on DOMAIN', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'domain', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'domain', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('ordering on LAST_RAN', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'last-ran', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'last-ran', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('ordering on DKIM_STATUS', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'dkim-status', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'dkim-status', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('ordering on DMARC_STATUS', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'dmarc-status', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'dmarc-status', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('ordering on HTTPS_STATUS', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'https-status', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'https-status', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('ordering on SPF_STATUS', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'spf-status', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'spf-status', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('ordering on SSL_STATUS', () => { - describe('direction is ASC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainOne._key), - before: toGlobalId('verifiedDomain', domainThree._key), - orderBy: { - field: 'ssl-status', - direction: 'ASC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - describe('direction is DESC', () => { - it('returns domains in order', async () => { - const domainLoader = loadVerifiedDomainByKey({ query }) - const expectedDomain = await domainLoader.load(domainTwo._key) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedDomain', domainThree._key), - before: toGlobalId('verifiedDomain', domainOne._key), - orderBy: { - field: 'ssl-status', - direction: 'DESC', - }, - } - - const domains = await connectionLoader(connectionArgs) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domainTwo._key), - node: { - ...expectedDomain, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedDomain', domainTwo._key), - endCursor: toGlobalId('verifiedDomain', domainTwo._key), - }, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - }) - describe('no organizations are found', () => { - it('returns an empty structure', async () => { - await truncate() - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - }) - - const connectionArgs = { - first: 10, - } - const domains = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [], - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - endCursor: '', - }, - totalCount: 0, - } - - expect(domains).toEqual(expectedStructure) - }) - }) - }) - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given an unsuccessful load', () => { - describe('limits are not set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = {} - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'You must provide a `first` or `last` value to properly paginate the `VerifiedDomain` connection.', - ), - ) - } - - expect(consoleOutput).toEqual([ - `User did not have either \`first\` or \`last\` arguments set for: loadVerifiedDomainConnections.`, - ]) - }) - }) - describe('both limits are set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 1, - last: 1, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Passing both `first` and `last` to paginate the `VerifiedDomain` connection is not supported.', - ), - ) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` and \`last\` arguments set for: loadVerifiedDomainConnections.`, - ]) - }) - }) - describe('limits are set below minimum', () => { - describe('first limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: -5, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('`first` on the `VerifiedDomain` connection cannot be less than zero.')) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` set below zero for: loadVerifiedDomainConnections.`, - ]) - }) - }) - describe('last limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: -5, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('`last` on the `VerifiedDomain` connection cannot be less than zero.')) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` set below zero for: loadVerifiedDomainConnections.`, - ]) - }) - }) - }) - describe('limits are set above maximum', () => { - describe('first limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 1000, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Requesting `1000` records on the `VerifiedDomain` connection exceeds the `first` limit of 100 records.', - ), - ) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` to 1000 for: loadVerifiedDomainConnections.`, - ]) - }) - }) - describe('last limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: 1000, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Requesting `1000` records on the `VerifiedDomain` connection exceeds the `last` limit of 100 records.', - ), - ) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` to 1000 for: loadVerifiedDomainConnections.`, - ]) - }) - }) - }) - describe('limits are not set to numbers', () => { - describe('first limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - it(`returns an error when first set to ${stringify(invalidInput)}`, async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: invalidInput, - } - - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error(`\`first\` must be of type \`number\` not \`${typeof invalidInput}\`.`)) - } - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` set as a ${typeof invalidInput} for: loadVerifiedDomainConnections.`, - ]) - }) - }) - }) - describe('last limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - it(`returns an error when last set to ${stringify(invalidInput)}`, async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: invalidInput, - } - - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error(`\`last\` must be of type \`number\` not \`${typeof invalidInput}\`.`)) - } - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` set as a ${typeof invalidInput} for: loadVerifiedDomainConnections.`, - ]) - }) - }) - }) - }) - }) - describe('given a database error', () => { - describe('when gathering domain keys that are claimed by orgs that the user has affiliations to', () => { - it('returns an error message', async () => { - const query = jest.fn().mockRejectedValue(new Error('Database Error Occurred.')) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('Unable to load verified domain(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Database error occurred while user was trying to gather domains in loadVerifiedDomainConnections, error: Error: Database Error Occurred.`, - ]) - }) - }) - }) - describe('given a cursor error', () => { - describe('when gathering domain keys that are claimed by orgs that the user has affiliations to', () => { - it('returns an error message', async () => { - const cursor = { - next() { - throw new Error('Cursor error occurred.') - }, - } - const query = jest.fn().mockReturnValueOnce(cursor) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - } - try { - await connectionLoader({ - orgId: org._id, - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('Unable to load verified domain(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Cursor error occurred while user was trying to gather domains in loadVerifiedDomainConnections, error: Error: Cursor error occurred.`, - ]) - }) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given an unsuccessful load', () => { - describe('limits are not set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = {} - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Vous devez fournir une valeur `first` ou `last` pour paginer correctement la connexion `VerifiedDomain`.', - ), - ) - } - - expect(consoleOutput).toEqual([ - `User did not have either \`first\` or \`last\` arguments set for: loadVerifiedDomainConnections.`, - ]) - }) - }) - describe('both limits are set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 1, - last: 1, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - "Passer à la fois `first` et `last` pour paginer la connexion `VerifiedDomain` n'est pas supporté.", - ), - ) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` and \`last\` arguments set for: loadVerifiedDomainConnections.`, - ]) - }) - }) - describe('limits are set below minimum', () => { - describe('first limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: -5, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('`first` sur la connexion `VerifiedDomain` ne peut être inférieur à zéro.')) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` set below zero for: loadVerifiedDomainConnections.`, - ]) - }) - }) - describe('last limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: -5, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('`last` sur la connexion `VerifiedDomain` ne peut être inférieur à zéro.')) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` set below zero for: loadVerifiedDomainConnections.`, - ]) - }) - }) - }) - describe('limits are set above maximum', () => { - describe('first limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 1000, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - "La demande d'enregistrements `1000` sur la connexion `VerifiedDomain` dépasse la limite `first` de 100 enregistrements.", - ), - ) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` to 1000 for: loadVerifiedDomainConnections.`, - ]) - }) - }) - describe('last limit is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: 1000, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - "La demande d'enregistrements `1000` sur la connexion `VerifiedDomain` dépasse la limite `last` de 100 enregistrements.", - ), - ) - } - - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` to 1000 for: loadVerifiedDomainConnections.`, - ]) - }) - }) - }) - describe('limits are not set to numbers', () => { - describe('first limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - it(`returns an error when first set to ${stringify(invalidInput)}`, async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: invalidInput, - } - - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error(`\`first\` doit être de type \`number\` et non \`${typeof invalidInput}\`.`), - ) - } - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` set as a ${typeof invalidInput} for: loadVerifiedDomainConnections.`, - ]) - }) - }) - }) - describe('last limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - it(`returns an error when last set to ${stringify(invalidInput)}`, async () => { - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: invalidInput, - } - - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error(`\`last\` doit être de type \`number\` et non \`${typeof invalidInput}\`.`), - ) - } - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` set as a ${typeof invalidInput} for: loadVerifiedDomainConnections.`, - ]) - }) - }) - }) - }) - }) - describe('given a database error', () => { - describe('when gathering domain keys that are claimed by orgs that the user has affiliations to', () => { - it('returns an error message', async () => { - const query = jest.fn().mockRejectedValue(new Error('Database Error Occurred.')) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('Impossible de charger le(s) domaine(s) vérifié(s). Veuillez réessayer.')) - } - - expect(consoleOutput).toEqual([ - `Database error occurred while user was trying to gather domains in loadVerifiedDomainConnections, error: Error: Database Error Occurred.`, - ]) - }) - }) - }) - describe('given a cursor error', () => { - describe('when gathering domain keys that are claimed by orgs that the user has affiliations to', () => { - it('returns an error message', async () => { - const cursor = { - next() { - throw new Error('Cursor error occurred.') - }, - } - const query = jest.fn().mockReturnValueOnce(cursor) - - const connectionLoader = loadVerifiedDomainConnections({ - query, - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - } - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('Impossible de charger le(s) domaine(s) vérifié(s). Veuillez réessayer.')) - } - - expect(consoleOutput).toEqual([ - `Cursor error occurred while user was trying to gather domains in loadVerifiedDomainConnections, error: Error: Cursor error occurred.`, - ]) - }) - }) - }) - }) -}) diff --git a/api/src/verified-domains/loaders/index.js b/api/src/verified-domains/loaders/index.js deleted file mode 100644 index 9237da313c..0000000000 --- a/api/src/verified-domains/loaders/index.js +++ /dev/null @@ -1,4 +0,0 @@ -export * from './load-verified-domain-by-domain' -export * from './load-verified-domain-by-key' -export * from './load-verified-domain-connections' -export * from './load-verified-domain-connections-by-organization-id' diff --git a/api/src/verified-domains/loaders/load-verified-domain-by-domain.js b/api/src/verified-domains/loaders/load-verified-domain-by-domain.js deleted file mode 100644 index 6f0910e6f1..0000000000 --- a/api/src/verified-domains/loaders/load-verified-domain-by-domain.js +++ /dev/null @@ -1,42 +0,0 @@ -import DataLoader from 'dataloader' -import { t } from '@lingui/macro' - -export const loadVerifiedDomainsById = ({ query, i18n }) => - new DataLoader(async (domains) => { - let cursor - - try { - cursor = await query` - WITH claims, domains, organizations - FOR domain IN domains - FILTER domain.domain IN ${domains} - LET verifiedDomain = (LENGTH( - FOR v, e IN INBOUND domain._id claims FILTER v.verified == true RETURN v._key - ) > 0 ? true : false) - FILTER verifiedDomain == true - RETURN MERGE(domain, { id: domain._key, _type: "verifiedDomain" }) - ` - } catch (err) { - console.error( - `Database error occurred when running loadVerifiedDomainsById: ${err}`, - ) - throw new Error( - i18n._(t`Unable to load verified domain(s). Please try again.`), - ) - } - - const domainMap = {} - try { - await cursor.forEach((domain) => { - domainMap[domain.domain] = domain - }) - } catch (err) { - console.error( - `Cursor error occurred during loadVerifiedDomainsById: ${err}`, - ) - throw new Error( - i18n._(t`Unable to load verified domain(s). Please try again.`), - ) - } - return domains.map((domain) => domainMap[domain]) - }) diff --git a/api/src/verified-domains/loaders/load-verified-domain-by-key.js b/api/src/verified-domains/loaders/load-verified-domain-by-key.js deleted file mode 100644 index 3198be33b9..0000000000 --- a/api/src/verified-domains/loaders/load-verified-domain-by-key.js +++ /dev/null @@ -1,43 +0,0 @@ -import DataLoader from 'dataloader' -import { t } from '@lingui/macro' - -export const loadVerifiedDomainByKey = ({ query, i18n }) => - new DataLoader(async (keys) => { - let cursor - - try { - cursor = await query` - WITH claims, domains, organizations - FOR domain IN domains - FILTER domain._key IN ${keys} - LET verifiedDomain = (LENGTH( - FOR v, e IN INBOUND domain._id claims FILTER v.verified == true RETURN v._key - ) > 0 ? true : false) - FILTER verifiedDomain == true - RETURN MERGE(domain, { id: domain._key, _type: "verifiedDomain" }) - ` - } catch (err) { - console.error( - `Database error occurred when running loadVerifiedDomainByKey: ${err}`, - ) - throw new Error( - i18n._(t`Unable to load verified domain(s). Please try again.`), - ) - } - - const domainMap = {} - try { - await cursor.forEach(async (domain) => { - domainMap[domain._key] = domain - }) - } catch (err) { - console.error( - `Cursor error occurred during loadVerifiedDomainByKey: ${err}`, - ) - throw new Error( - i18n._(t`Unable to load verified domain(s). Please try again.`), - ) - } - - return keys.map((id) => domainMap[id]) - }) diff --git a/api/src/verified-domains/loaders/load-verified-domain-connections-by-organization-id.js b/api/src/verified-domains/loaders/load-verified-domain-connections-by-organization-id.js deleted file mode 100644 index 015f3deed4..0000000000 --- a/api/src/verified-domains/loaders/load-verified-domain-connections-by-organization-id.js +++ /dev/null @@ -1,352 +0,0 @@ -import { aql } from 'arangojs' -import { fromGlobalId, toGlobalId } from 'graphql-relay' -import { t } from '@lingui/macro' - -export const loadVerifiedDomainConnectionsByOrgId = - ({ query, cleanseInput, i18n }) => - async ({ orgId, after, before, first, last, orderBy }) => { - let afterTemplate = aql`` - let afterVar = aql`` - - if (typeof after !== 'undefined') { - const { id: afterId } = fromGlobalId(cleanseInput(after)) - if (typeof orderBy === 'undefined') { - afterTemplate = aql`FILTER TO_NUMBER(domain._key) > TO_NUMBER(${afterId})` - } else { - let afterTemplateDirection = aql`` - if (orderBy.direction === 'ASC') { - afterTemplateDirection = aql`>` - } else { - afterTemplateDirection = aql`<` - } - - afterVar = aql`LET afterVar = DOCUMENT(domains, ${afterId})` - - let documentField = aql`` - let domainField = aql`` - /* istanbul ignore else */ - if (orderBy.field === 'domain') { - documentField = aql`afterVar.domain` - domainField = aql`domain.domain` - } else if (orderBy.field === 'last-ran') { - documentField = aql`afterVar.lastRan` - domainField = aql`domain.lastRan` - } else if (orderBy.field === 'dkim-status') { - documentField = aql`afterVar.status.dkim` - domainField = aql`domain.status.dkim` - } else if (orderBy.field === 'dmarc-status') { - documentField = aql`afterVar.status.dmarc` - domainField = aql`domain.status.dmarc` - } else if (orderBy.field === 'https-status') { - documentField = aql`afterVar.status.https` - domainField = aql`domain.status.https` - } else if (orderBy.field === 'spf-status') { - documentField = aql`afterVar.status.spf` - domainField = aql`domain.status.spf` - } else if (orderBy.field === 'ssl-status') { - documentField = aql`afterVar.status.ssl` - domainField = aql`domain.status.ssl` - } - - afterTemplate = aql` - FILTER ${domainField} ${afterTemplateDirection} ${documentField} - OR (${domainField} == ${documentField} - AND TO_NUMBER(domain._key) > TO_NUMBER(${afterId})) - ` - } - } - - let beforeTemplate = aql`` - let beforeVar = aql`` - - if (typeof before !== 'undefined') { - const { id: beforeId } = fromGlobalId(cleanseInput(before)) - if (typeof orderBy === 'undefined') { - beforeTemplate = aql`FILTER TO_NUMBER(domain._key) < TO_NUMBER(${beforeId})` - } else { - let beforeTemplateDirection = aql`` - if (orderBy.direction === 'ASC') { - beforeTemplateDirection = aql`<` - } else { - beforeTemplateDirection = aql`>` - } - - beforeVar = aql`LET beforeVar = DOCUMENT(domains, ${beforeId})` - - let documentField = aql`` - let domainField = aql`` - /* istanbul ignore else */ - if (orderBy.field === 'domain') { - documentField = aql`beforeVar.domain` - domainField = aql`domain.domain` - } else if (orderBy.field === 'last-ran') { - documentField = aql`beforeVar.lastRan` - domainField = aql`domain.lastRan` - } else if (orderBy.field === 'dkim-status') { - documentField = aql`beforeVar.status.dkim` - domainField = aql`domain.status.dkim` - } else if (orderBy.field === 'dmarc-status') { - documentField = aql`beforeVar.status.dmarc` - domainField = aql`domain.status.dmarc` - } else if (orderBy.field === 'https-status') { - documentField = aql`beforeVar.status.https` - domainField = aql`domain.status.https` - } else if (orderBy.field === 'spf-status') { - documentField = aql`beforeVar.status.spf` - domainField = aql`domain.status.spf` - } else if (orderBy.field === 'ssl-status') { - documentField = aql`beforeVar.status.ssl` - domainField = aql`domain.status.ssl` - } - - beforeTemplate = aql` - FILTER ${domainField} ${beforeTemplateDirection} ${documentField} - OR (${domainField} == ${documentField} - AND TO_NUMBER(domain._key) < TO_NUMBER(${beforeId})) - ` - } - } - - let limitTemplate = aql`` - if (typeof first === 'undefined' && typeof last === 'undefined') { - console.warn( - `User did not have either \`first\` or \`last\` arguments set for: loadVerifiedDomainConnectionsByOrgId.`, - ) - throw new Error( - i18n._( - t`You must provide a \`first\` or \`last\` value to properly paginate the \`VerifiedDomain\` connection.`, - ), - ) - } else if (typeof first !== 'undefined' && typeof last !== 'undefined') { - console.warn( - `User attempted to have \`first\` and \`last\` arguments set for: loadVerifiedDomainConnectionsByOrgId.`, - ) - throw new Error( - i18n._( - t`Passing both \`first\` and \`last\` to paginate the \`VerifiedDomain\` connection is not supported.`, - ), - ) - } else if (typeof first === 'number' || typeof last === 'number') { - /* istanbul ignore else */ - if (first < 0 || last < 0) { - const argSet = typeof first !== 'undefined' ? 'first' : 'last' - console.warn( - `User attempted to have \`${argSet}\` set below zero for: loadVerifiedDomainConnectionsByOrgId.`, - ) - throw new Error( - i18n._( - t`\`${argSet}\` on the \`VerifiedDomain\` connection cannot be less than zero.`, - ), - ) - } else if (first > 100 || last > 100) { - const argSet = typeof first !== 'undefined' ? 'first' : 'last' - const amount = typeof first !== 'undefined' ? first : last - console.warn( - `User attempted to have \`${argSet}\` to ${amount} for: loadVerifiedDomainConnectionsByOrgId.`, - ) - throw new Error( - i18n._( - t`Requesting \`${amount}\` records on the \`VerifiedDomain\` connection exceeds the \`${argSet}\` limit of 100 records.`, - ), - ) - } else if (typeof first !== 'undefined' && typeof last === 'undefined') { - limitTemplate = aql`TO_NUMBER(domain._key) ASC LIMIT TO_NUMBER(${first})` - } else if (typeof first === 'undefined' && typeof last !== 'undefined') { - limitTemplate = aql`TO_NUMBER(domain._key) DESC LIMIT TO_NUMBER(${last})` - } - } else { - const argSet = typeof first !== 'undefined' ? 'first' : 'last' - const typeSet = typeof first !== 'undefined' ? typeof first : typeof last - console.warn( - `User attempted to have \`${argSet}\` set as a ${typeSet} for: loadVerifiedDomainConnectionsByOrgId.`, - ) - throw new Error( - i18n._(t`\`${argSet}\` must be of type \`number\` not \`${typeSet}\`.`), - ) - } - - let hasNextPageFilter = aql`FILTER TO_NUMBER(domain._key) > TO_NUMBER(LAST(retrievedDomains)._key)` - let hasPreviousPageFilter = aql`FILTER TO_NUMBER(domain._key) < TO_NUMBER(FIRST(retrievedDomains)._key)` - if (typeof orderBy !== 'undefined') { - let hasNextPageDirection = aql`` - let hasPreviousPageDirection = aql`` - if (orderBy.direction === 'ASC') { - hasNextPageDirection = aql`>` - hasPreviousPageDirection = aql`<` - } else { - hasNextPageDirection = aql`<` - hasPreviousPageDirection = aql`>` - } - - let domainField = aql`` - let hasNextPageDocumentField = aql`` - let hasPreviousPageDocumentField = aql`` - /* istanbul ignore else */ - if (orderBy.field === 'domain') { - domainField = aql`domain.domain` - hasNextPageDocumentField = aql`LAST(retrievedDomains).domain` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).domain` - } else if (orderBy.field === 'last-ran') { - domainField = aql`domain.lastRan` - hasNextPageDocumentField = aql`LAST(retrievedDomains).lastRan` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).lastRan` - } else if (orderBy.field === 'dkim-status') { - domainField = aql`domain.status.dkim` - hasNextPageDocumentField = aql`LAST(retrievedDomains).status.dkim` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).status.dkim` - } else if (orderBy.field === 'dmarc-status') { - domainField = aql`domain.status.dmarc` - hasNextPageDocumentField = aql`LAST(retrievedDomains).status.dmarc` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).status.dmarc` - } else if (orderBy.field === 'https-status') { - domainField = aql`domain.status.https` - hasNextPageDocumentField = aql`LAST(retrievedDomains).status.https` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).status.https` - } else if (orderBy.field === 'spf-status') { - domainField = aql`domain.status.spf` - hasNextPageDocumentField = aql`LAST(retrievedDomains).status.spf` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).status.spf` - } else if (orderBy.field === 'ssl-status') { - domainField = aql`domain.status.ssl` - hasNextPageDocumentField = aql`LAST(retrievedDomains).status.ssl` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).status.ssl` - } - - hasNextPageFilter = aql` - FILTER ${domainField} ${hasNextPageDirection} ${hasNextPageDocumentField} - OR (${domainField} == ${hasNextPageDocumentField} - AND TO_NUMBER(domain._key) > TO_NUMBER(LAST(retrievedDomains)._key)) - ` - hasPreviousPageFilter = aql` - FILTER ${domainField} ${hasPreviousPageDirection} ${hasPreviousPageDocumentField} - OR (${domainField} == ${hasPreviousPageDocumentField} - AND TO_NUMBER(domain._key) < TO_NUMBER(FIRST(retrievedDomains)._key)) - ` - } - - let sortByField = aql`` - if (typeof orderBy !== 'undefined') { - /* istanbul ignore else */ - if (orderBy.field === 'domain') { - sortByField = aql`domain.domain ${orderBy.direction},` - } else if (orderBy.field === 'last-ran') { - sortByField = aql`domain.lastRan ${orderBy.direction},` - } else if (orderBy.field === 'dkim-status') { - sortByField = aql`domain.status.dkim ${orderBy.direction},` - } else if (orderBy.field === 'dmarc-status') { - sortByField = aql`domain.status.dmarc ${orderBy.direction},` - } else if (orderBy.field === 'https-status') { - sortByField = aql`domain.status.https ${orderBy.direction},` - } else if (orderBy.field === 'spf-status') { - sortByField = aql`domain.status.spf ${orderBy.direction},` - } else if (orderBy.field === 'ssl-status') { - sortByField = aql`domain.status.ssl ${orderBy.direction},` - } - } - - let sortString = aql`` - if (typeof last !== 'undefined') { - sortString = aql`DESC` - } else { - sortString = aql`ASC` - } - - let requestedDomainInfo - try { - requestedDomainInfo = await query` - WITH claims, domains, organizations - LET domainIds = UNIQUE(FLATTEN( - FOR v, e IN 1..1 OUTBOUND ${orgId} claims RETURN v._key - )) - - ${afterVar} - ${beforeVar} - - LET retrievedDomains = ( - FOR domain IN domains - FILTER domain._key IN domainIds - ${afterTemplate} - ${beforeTemplate} - SORT - ${sortByField} - ${limitTemplate} - RETURN MERGE(domain, { id: domain._key, _type: "verifiedDomain" }) - ) - - LET hasNextPage = (LENGTH( - FOR domain IN domains - FILTER domain._key IN domainIds - ${hasNextPageFilter} - SORT ${sortByField} TO_NUMBER(domain._key) ${sortString} LIMIT 1 - RETURN domain - ) > 0 ? true : false) - - LET hasPreviousPage = (LENGTH( - FOR domain IN domains - FILTER domain._key IN domainIds - ${hasPreviousPageFilter} - SORT ${sortByField} TO_NUMBER(domain._key) ${sortString} LIMIT 1 - RETURN domain - ) > 0 ? true : false) - - RETURN { - "domains": retrievedDomains, - "totalCount": LENGTH(domainIds), - "hasNextPage": hasNextPage, - "hasPreviousPage": hasPreviousPage, - "startKey": FIRST(retrievedDomains)._key, - "endKey": LAST(retrievedDomains)._key - } - ` - } catch (err) { - console.error( - `Database error occurred while user was trying to gather domains in loadVerifiedDomainConnectionsByOrgId, error: ${err}`, - ) - throw new Error( - i18n._(t`Unable to load verified domain(s). Please try again.`), - ) - } - - let domainsInfo - try { - domainsInfo = await requestedDomainInfo.next() - } catch (err) { - console.error( - `Cursor error occurred while user was trying to gather domains in loadVerifiedDomainConnectionsByOrgId, error: ${err}`, - ) - throw new Error( - i18n._(t`Unable to load verified domain(s). Please try again.`), - ) - } - - if (domainsInfo.domains.length === 0) { - return { - edges: [], - totalCount: 0, - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - endCursor: '', - }, - } - } - - const edges = domainsInfo.domains.map((domain) => { - return { - cursor: toGlobalId('verifiedDomain', domain._key), - node: domain, - } - }) - - return { - edges, - totalCount: domainsInfo.totalCount, - pageInfo: { - hasNextPage: domainsInfo.hasNextPage, - hasPreviousPage: domainsInfo.hasPreviousPage, - startCursor: toGlobalId('verifiedDomain', domainsInfo.startKey), - endCursor: toGlobalId('verifiedDomain', domainsInfo.endKey), - }, - } - } diff --git a/api/src/verified-domains/loaders/load-verified-domain-connections.js b/api/src/verified-domains/loaders/load-verified-domain-connections.js deleted file mode 100644 index 25c31313ee..0000000000 --- a/api/src/verified-domains/loaders/load-verified-domain-connections.js +++ /dev/null @@ -1,358 +0,0 @@ -import { aql } from 'arangojs' -import { fromGlobalId, toGlobalId } from 'graphql-relay' -import { t } from '@lingui/macro' - -export const loadVerifiedDomainConnections = - ({ query, cleanseInput, i18n }) => - async ({ after, before, first, last, orderBy }) => { - let afterTemplate = aql`` - let afterVar = aql`` - - if (typeof after !== 'undefined') { - const { id: afterId } = fromGlobalId(cleanseInput(after)) - if (typeof orderBy === 'undefined') { - afterTemplate = aql`FILTER TO_NUMBER(domain._key) > TO_NUMBER(${afterId})` - } else { - let afterTemplateDirection = aql`` - if (orderBy.direction === 'ASC') { - afterTemplateDirection = aql`>` - } else { - afterTemplateDirection = aql`<` - } - - afterVar = aql`LET afterVar = DOCUMENT(domains, ${afterId})` - - let documentField = aql`` - let domainField = aql`` - /* istanbul ignore else */ - if (orderBy.field === 'domain') { - documentField = aql`afterVar.domain` - domainField = aql`domain.domain` - } else if (orderBy.field === 'last-ran') { - documentField = aql`afterVar.lastRan` - domainField = aql`domain.lastRan` - } else if (orderBy.field === 'dkim-status') { - documentField = aql`afterVar.status.dkim` - domainField = aql`domain.status.dkim` - } else if (orderBy.field === 'dmarc-status') { - documentField = aql`afterVar.status.dmarc` - domainField = aql`domain.status.dmarc` - } else if (orderBy.field === 'https-status') { - documentField = aql`afterVar.status.https` - domainField = aql`domain.status.https` - } else if (orderBy.field === 'spf-status') { - documentField = aql`afterVar.status.spf` - domainField = aql`domain.status.spf` - } else if (orderBy.field === 'ssl-status') { - documentField = aql`afterVar.status.ssl` - domainField = aql`domain.status.ssl` - } - - afterTemplate = aql` - FILTER ${domainField} ${afterTemplateDirection} ${documentField} - OR (${domainField} == ${documentField} - AND TO_NUMBER(domain._key) > TO_NUMBER(${afterId})) - ` - } - } - - let beforeTemplate = aql`` - let beforeVar = aql`` - - if (typeof before !== 'undefined') { - const { id: beforeId } = fromGlobalId(cleanseInput(before)) - if (typeof orderBy === 'undefined') { - beforeTemplate = aql`FILTER TO_NUMBER(domain._key) < TO_NUMBER(${beforeId})` - } else { - let beforeTemplateDirection = aql`` - if (orderBy.direction === 'ASC') { - beforeTemplateDirection = aql`<` - } else { - beforeTemplateDirection = aql`>` - } - - beforeVar = aql`LET beforeVar = DOCUMENT(domains, ${beforeId})` - - let documentField = aql`` - let domainField = aql`` - /* istanbul ignore else */ - if (orderBy.field === 'domain') { - documentField = aql`beforeVar.domain` - domainField = aql`domain.domain` - } else if (orderBy.field === 'last-ran') { - documentField = aql`beforeVar.lastRan` - domainField = aql`domain.lastRan` - } else if (orderBy.field === 'dkim-status') { - documentField = aql`beforeVar.status.dkim` - domainField = aql`domain.status.dkim` - } else if (orderBy.field === 'dmarc-status') { - documentField = aql`beforeVar.status.dmarc` - domainField = aql`domain.status.dmarc` - } else if (orderBy.field === 'https-status') { - documentField = aql`beforeVar.status.https` - domainField = aql`domain.status.https` - } else if (orderBy.field === 'spf-status') { - documentField = aql`beforeVar.status.spf` - domainField = aql`domain.status.spf` - } else if (orderBy.field === 'ssl-status') { - documentField = aql`beforeVar.status.ssl` - domainField = aql`domain.status.ssl` - } - - beforeTemplate = aql` - FILTER ${domainField} ${beforeTemplateDirection} ${documentField} - OR (${domainField} == ${documentField} - AND TO_NUMBER(domain._key) < TO_NUMBER(${beforeId})) - ` - } - } - - let limitTemplate = aql`` - if (typeof first === 'undefined' && typeof last === 'undefined') { - console.warn( - `User did not have either \`first\` or \`last\` arguments set for: loadVerifiedDomainConnections.`, - ) - throw new Error( - i18n._( - t`You must provide a \`first\` or \`last\` value to properly paginate the \`VerifiedDomain\` connection.`, - ), - ) - } else if (typeof first !== 'undefined' && typeof last !== 'undefined') { - console.warn( - `User attempted to have \`first\` and \`last\` arguments set for: loadVerifiedDomainConnections.`, - ) - throw new Error( - i18n._( - t`Passing both \`first\` and \`last\` to paginate the \`VerifiedDomain\` connection is not supported.`, - ), - ) - } else if (typeof first === 'number' || typeof last === 'number') { - /* istanbul ignore else */ - if (first < 0 || last < 0) { - const argSet = typeof first !== 'undefined' ? 'first' : 'last' - console.warn( - `User attempted to have \`${argSet}\` set below zero for: loadVerifiedDomainConnections.`, - ) - throw new Error( - i18n._( - t`\`${argSet}\` on the \`VerifiedDomain\` connection cannot be less than zero.`, - ), - ) - } else if (first > 100 || last > 100) { - const argSet = typeof first !== 'undefined' ? 'first' : 'last' - const amount = typeof first !== 'undefined' ? first : last - console.warn( - `User attempted to have \`${argSet}\` to ${amount} for: loadVerifiedDomainConnections.`, - ) - throw new Error( - i18n._( - t`Requesting \`${amount}\` records on the \`VerifiedDomain\` connection exceeds the \`${argSet}\` limit of 100 records.`, - ), - ) - } else if (typeof first !== 'undefined' && typeof last === 'undefined') { - limitTemplate = aql`TO_NUMBER(domain._key) ASC LIMIT TO_NUMBER(${first})` - } else if (typeof first === 'undefined' && typeof last !== 'undefined') { - limitTemplate = aql`TO_NUMBER(domain._key) DESC LIMIT TO_NUMBER(${last})` - } - } else { - const argSet = typeof first !== 'undefined' ? 'first' : 'last' - const typeSet = typeof first !== 'undefined' ? typeof first : typeof last - console.warn( - `User attempted to have \`${argSet}\` set as a ${typeSet} for: loadVerifiedDomainConnections.`, - ) - throw new Error( - i18n._(t`\`${argSet}\` must be of type \`number\` not \`${typeSet}\`.`), - ) - } - - let hasNextPageFilter = aql`FILTER TO_NUMBER(domain._key) > TO_NUMBER(LAST(retrievedDomains)._key)` - let hasPreviousPageFilter = aql`FILTER TO_NUMBER(domain._key) < TO_NUMBER(FIRST(retrievedDomains)._key)` - if (typeof orderBy !== 'undefined') { - let hasNextPageDirection = aql`` - let hasPreviousPageDirection = aql`` - if (orderBy.direction === 'ASC') { - hasNextPageDirection = aql`>` - hasPreviousPageDirection = aql`<` - } else { - hasNextPageDirection = aql`<` - hasPreviousPageDirection = aql`>` - } - - let domainField = aql`` - let hasNextPageDocumentField = aql`` - let hasPreviousPageDocumentField = aql`` - /* istanbul ignore else */ - if (orderBy.field === 'domain') { - domainField = aql`domain.domain` - hasNextPageDocumentField = aql`LAST(retrievedDomains).domain` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).domain` - } else if (orderBy.field === 'last-ran') { - domainField = aql`domain.lastRan` - hasNextPageDocumentField = aql`LAST(retrievedDomains).lastRan` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).lastRan` - } else if (orderBy.field === 'dkim-status') { - domainField = aql`domain.status.dkim` - hasNextPageDocumentField = aql`LAST(retrievedDomains).status.dkim` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).status.dkim` - } else if (orderBy.field === 'dmarc-status') { - domainField = aql`domain.status.dmarc` - hasNextPageDocumentField = aql`LAST(retrievedDomains).status.dmarc` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).status.dmarc` - } else if (orderBy.field === 'https-status') { - domainField = aql`domain.status.https` - hasNextPageDocumentField = aql`LAST(retrievedDomains).status.https` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).status.https` - } else if (orderBy.field === 'spf-status') { - domainField = aql`domain.status.spf` - hasNextPageDocumentField = aql`LAST(retrievedDomains).status.spf` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).status.spf` - } else if (orderBy.field === 'ssl-status') { - domainField = aql`domain.status.ssl` - hasNextPageDocumentField = aql`LAST(retrievedDomains).status.ssl` - hasPreviousPageDocumentField = aql`FIRST(retrievedDomains).status.ssl` - } - - hasNextPageFilter = aql` - FILTER ${domainField} ${hasNextPageDirection} ${hasNextPageDocumentField} - OR (${domainField} == ${hasNextPageDocumentField} - AND TO_NUMBER(domain._key) > TO_NUMBER(LAST(retrievedDomains)._key)) - ` - hasPreviousPageFilter = aql` - FILTER ${domainField} ${hasPreviousPageDirection} ${hasPreviousPageDocumentField} - OR (${domainField} == ${hasPreviousPageDocumentField} - AND TO_NUMBER(domain._key) < TO_NUMBER(FIRST(retrievedDomains)._key)) - ` - } - - let sortByField = aql`` - if (typeof orderBy !== 'undefined') { - /* istanbul ignore else */ - if (orderBy.field === 'domain') { - sortByField = aql`domain.domain ${orderBy.direction},` - } else if (orderBy.field === 'last-ran') { - sortByField = aql`domain.lastRan ${orderBy.direction},` - } else if (orderBy.field === 'dkim-status') { - sortByField = aql`domain.status.dkim ${orderBy.direction},` - } else if (orderBy.field === 'dmarc-status') { - sortByField = aql`domain.status.dmarc ${orderBy.direction},` - } else if (orderBy.field === 'https-status') { - sortByField = aql`domain.status.https ${orderBy.direction},` - } else if (orderBy.field === 'spf-status') { - sortByField = aql`domain.status.spf ${orderBy.direction},` - } else if (orderBy.field === 'ssl-status') { - sortByField = aql`domain.status.ssl ${orderBy.direction},` - } - } - - let sortString - if (typeof last !== 'undefined') { - sortString = aql`DESC` - } else { - sortString = aql`ASC` - } - - let requestedDomainInfo - try { - requestedDomainInfo = await query` - WITH claims, domains, organizations - LET verifiedOrgs = (FOR org IN organizations FILTER org.verified == true RETURN org._id) - - LET domainIds = UNIQUE(FLATTEN( - FOR orgId IN verifiedOrgs - LET tempDomainIds = UNIQUE(FLATTEN( - FOR v, e IN 1..1 OUTBOUND orgId claims RETURN v._key - )) - RETURN tempDomainIds - )) - - ${afterVar} - ${beforeVar} - - LET retrievedDomains = ( - FOR domain IN domains - FILTER domain._key IN domainIds - ${afterTemplate} - ${beforeTemplate} - SORT - ${sortByField} - ${limitTemplate} - RETURN MERGE(domain, { id: domain._key, _type: "verifiedDomain" }) - ) - - LET hasNextPage = (LENGTH( - FOR domain IN domains - FILTER domain._key IN domainIds - ${hasNextPageFilter} - SORT ${sortByField} TO_NUMBER(domain._key) ${sortString} LIMIT 1 - RETURN domain - ) > 0 ? true : false) - - LET hasPreviousPage = (LENGTH( - FOR domain IN domains - FILTER domain._key IN domainIds - ${hasPreviousPageFilter} - SORT ${sortByField} TO_NUMBER(domain._key) ${sortString} LIMIT 1 - RETURN domain - ) > 0 ? true : false) - - RETURN { - "domains": retrievedDomains, - "totalCount": LENGTH(domainIds), - "hasNextPage": hasNextPage, - "hasPreviousPage": hasPreviousPage, - "startKey": FIRST(retrievedDomains)._key, - "endKey": LAST(retrievedDomains)._key - } - ` - } catch (err) { - console.error( - `Database error occurred while user was trying to gather domains in loadVerifiedDomainConnections, error: ${err}`, - ) - throw new Error( - i18n._(t`Unable to load verified domain(s). Please try again.`), - ) - } - - let domainsInfo - try { - domainsInfo = await requestedDomainInfo.next() - } catch (err) { - console.error( - `Cursor error occurred while user was trying to gather domains in loadVerifiedDomainConnections, error: ${err}`, - ) - throw new Error( - i18n._(t`Unable to load verified domain(s). Please try again.`), - ) - } - - if (domainsInfo.domains.length === 0) { - return { - edges: [], - totalCount: 0, - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - endCursor: '', - }, - } - } - - const edges = domainsInfo.domains.map((domain) => { - return { - cursor: toGlobalId('verifiedDomain', domain._key), - node: domain, - } - }) - - return { - edges, - totalCount: domainsInfo.totalCount, - pageInfo: { - hasNextPage: domainsInfo.hasNextPage, - hasPreviousPage: domainsInfo.hasPreviousPage, - startCursor: toGlobalId('verifiedDomain', domainsInfo.startKey), - endCursor: toGlobalId('verifiedDomain', domainsInfo.endKey), - }, - } - } diff --git a/api/src/verified-domains/objects/__tests__/verified-domain-connection.test.js b/api/src/verified-domains/objects/__tests__/verified-domain-connection.test.js deleted file mode 100644 index 6ad87c9681..0000000000 --- a/api/src/verified-domains/objects/__tests__/verified-domain-connection.test.js +++ /dev/null @@ -1,22 +0,0 @@ -import { GraphQLInt } from 'graphql' -import { verifiedDomainConnection } from '../index' - -describe('given the verified domain connection object', () => { - describe('testing its field definitions', () => { - it('has a totalCount field', () => { - const demoType = verifiedDomainConnection.connectionType.getFields() - - expect(demoType).toHaveProperty('totalCount') - expect(demoType.totalCount.type).toMatchObject(GraphQLInt) - }) - }) - describe('testing its field resolvers', () => { - describe('testing the totalCount resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedDomainConnection.connectionType.getFields() - - expect(demoType.totalCount.resolve({ totalCount: 1 })).toEqual(1) - }) - }) - }) -}) diff --git a/api/src/verified-domains/objects/__tests__/verified-domain.test.js b/api/src/verified-domains/objects/__tests__/verified-domain.test.js deleted file mode 100644 index f001a14da0..0000000000 --- a/api/src/verified-domains/objects/__tests__/verified-domain.test.js +++ /dev/null @@ -1,149 +0,0 @@ -import { GraphQLNonNull, GraphQLID } from 'graphql' -import { toGlobalId } from 'graphql-relay' -import { GraphQLDateTime } from 'graphql-scalars' - -import { verifiedOrganizationConnection } from '../../../verified-organizations/objects' -import { verifiedDomainType } from '../index' -import { domainStatus } from '../../../domain/objects' -import { Domain } from '../../../scalars' - -describe('given the verified domains object', () => { - describe('testing the field definitions', () => { - it('has an id field', () => { - const demoType = verifiedDomainType.getFields() - - expect(demoType).toHaveProperty('id') - expect(demoType.id.type).toMatchObject(new GraphQLNonNull(GraphQLID)) - }) - it('has a domain field', () => { - const demoType = verifiedDomainType.getFields() - - expect(demoType).toHaveProperty('domain') - expect(demoType.domain.type).toMatchObject(Domain) - }) - it('has a lastRan field', () => { - const demoType = verifiedDomainType.getFields() - - expect(demoType).toHaveProperty('lastRan') - expect(demoType.lastRan.type).toMatchObject(GraphQLDateTime) - }) - it('has a status field', () => { - const demoType = verifiedDomainType.getFields() - - expect(demoType).toHaveProperty('status') - expect(demoType.status.type).toMatchObject(domainStatus) - }) - it('has a organizations field', () => { - const demoType = verifiedDomainType.getFields() - - expect(demoType).toHaveProperty('organizations') - expect(demoType.organizations.type).toMatchObject(verifiedOrganizationConnection.connectionType) - }) - }) - - describe('testing the field resolvers', () => { - describe('testing the id resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedDomainType.getFields() - - expect(demoType.id.resolve({ id: '1' })).toEqual(toGlobalId('verifiedDomain', 1)) - }) - }) - describe('testing the domain resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedDomainType.getFields() - - expect(demoType.domain.resolve({ domain: 'test.gc.ca' })).toEqual('test.gc.ca') - }) - }) - describe('testing the lastRan resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedDomainType.getFields() - - expect(demoType.lastRan.resolve({ lastRan: '2020-10-02T12:43:39Z' })).toEqual('2020-10-02T12:43:39Z') - }) - }) - describe('testing the status resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedDomainType.getFields() - - const status = { - dkim: 'pass', - dmarc: 'pass', - https: 'info', - spf: 'fail', - ssl: 'fail', - } - - expect(demoType.status.resolve({ status })).toEqual({ - dkim: 'pass', - dmarc: 'pass', - https: 'info', - spf: 'fail', - ssl: 'fail', - }) - }) - }) - describe('testing the organizations resolver', () => { - it('returns the resolved value', async () => { - const demoType = verifiedDomainType.getFields() - - const expectedResult = { - edges: [ - { - cursor: toGlobalId('verifiedOrganizations', '1'), - node: { - _id: 'organizations/1', - _key: '1', - _rev: 'rev', - _type: 'verifiedOrganization', - id: '1', - verified: true, - summaries: { - web: { - pass: 50, - fail: 1000, - total: 1050, - }, - mail: { - pass: 50, - fail: 1000, - total: 1050, - }, - }, - domainCount: 1, - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - ], - totalCount: 1, - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedOrganizations', '1'), - endCursor: toGlobalId('verifiedOrganizations', '1'), - }, - } - - expect( - demoType.organizations.resolve( - { _id: 'domains/1' }, - { first: 1 }, - { - loaders: { - loadVerifiedOrgConnectionsByDomainId: jest.fn().mockReturnValue(expectedResult), - }, - }, - ), - ).resolves.toEqual(expectedResult) - }) - }) - }) -}) diff --git a/api/src/verified-domains/objects/index.js b/api/src/verified-domains/objects/index.js deleted file mode 100644 index fbdf6b5d7e..0000000000 --- a/api/src/verified-domains/objects/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from './verified-domain' -export * from './verified-domain-connection' diff --git a/api/src/verified-domains/objects/verified-domain-connection.js b/api/src/verified-domains/objects/verified-domain-connection.js deleted file mode 100644 index f456ba3505..0000000000 --- a/api/src/verified-domains/objects/verified-domain-connection.js +++ /dev/null @@ -1,16 +0,0 @@ -import { GraphQLInt } from 'graphql' -import { connectionDefinitions } from 'graphql-relay' - -import { verifiedDomainType } from './verified-domain' - -export const verifiedDomainConnection = connectionDefinitions({ - name: 'VerifiedDomain', - nodeType: verifiedDomainType, - connectionFields: () => ({ - totalCount: { - type: GraphQLInt, - description: 'The total amount of verified domains.', - resolve: ({ totalCount }) => totalCount, - }, - }), -}) diff --git a/api/src/verified-domains/objects/verified-domain.js b/api/src/verified-domains/objects/verified-domain.js deleted file mode 100644 index 281eba3768..0000000000 --- a/api/src/verified-domains/objects/verified-domain.js +++ /dev/null @@ -1,51 +0,0 @@ -import { GraphQLObjectType } from 'graphql' -import { connectionArgs, globalIdField } from 'graphql-relay' -import { GraphQLDateTime } from 'graphql-scalars' - -import { domainStatus } from '../../domain/objects' -import { Domain } from '../../scalars' -import { verifiedOrganizationOrder } from '../../verified-organizations/inputs' -import { verifiedOrganizationConnection } from '../../verified-organizations/objects' -import { nodeInterface } from '../../node' - -export const verifiedDomainType = new GraphQLObjectType({ - name: 'VerifiedDomain', - fields: () => ({ - id: globalIdField('verifiedDomain'), - domain: { - type: Domain, - description: 'Domain that scans will be ran on.', - resolve: ({ domain }) => domain, - }, - lastRan: { - type: GraphQLDateTime, - description: 'The last time that a scan was ran on this domain.', - resolve: ({ lastRan }) => lastRan, - }, - status: { - type: domainStatus, - description: 'The domains scan status, based on the latest scan data.', - resolve: ({ status }) => status, - }, - organizations: { - type: verifiedOrganizationConnection.connectionType, - args: { - orderBy: { - type: verifiedOrganizationOrder, - description: 'Ordering options for verified organization connections.', - }, - ...connectionArgs, - }, - description: 'The organization that this domain belongs to.', - resolve: async ({ _id }, args, { loaders: { loadVerifiedOrgConnectionsByDomainId } }) => { - const orgs = await loadVerifiedOrgConnectionsByDomainId({ - domainId: _id, - ...args, - }) - return orgs - }, - }, - }), - interfaces: [nodeInterface], - description: 'Domain object containing information for a given domain.', -}) diff --git a/api/src/verified-domains/queries/__tests__/find-verified-domain-by-domain.test.js b/api/src/verified-domains/queries/__tests__/find-verified-domain-by-domain.test.js deleted file mode 100644 index c9a4463a0a..0000000000 --- a/api/src/verified-domains/queries/__tests__/find-verified-domain-by-domain.test.js +++ /dev/null @@ -1,249 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema, GraphQLError } from 'graphql' -import { toGlobalId } from 'graphql-relay' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { cleanseInput } from '../../../validators' -import { loadVerifiedOrgConnectionsByDomainId } from '../../../verified-organizations/loaders' -import { loadVerifiedDomainsById } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given findVerifiedDomainByDomain query', () => { - let query, drop, truncate, schema, collections, domain, org, i18n - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - - beforeAll(async () => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given successful query', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - org = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - domain = await collections.domains.save({ - domain: 'test.gc.ca', - lastRan: null, - selectors: ['selector1', 'selector2'], - status: { - dkim: 'pass', - dmarc: 'pass', - https: 'info', - spf: 'fail', - ssl: 'fail', - }, - }) - await collections.claims.save({ - _to: domain._id, - _from: org._id, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - it('returns domain', async () => { - const response = await graphql({ - schema, - source: ` - query { - findVerifiedDomainByDomain(domain: "test.gc.ca") { - id - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: query, - validators: { - cleanseInput, - }, - loaders: { - loadVerifiedDomainsById: loadVerifiedDomainsById({ query }), - loadVerifiedOrgConnectionsByDomainId: loadVerifiedOrgConnectionsByDomainId(query, 'en', cleanseInput), - }, - }, - }) - - const expectedResponse = { - data: { - findVerifiedDomainByDomain: { - id: toGlobalId('verifiedDomain', domain._key), - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - describe('given an unsuccessful query', () => { - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful domain retrieval', () => { - describe('domain cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - findVerifiedDomainByDomain(domain: "not-test.gc.ca") { - id - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: query, - validators: { - cleanseInput, - }, - loaders: { - loadVerifiedDomainsById: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`No verified domain with the provided domain could be found.`)] - - expect(response.errors).toEqual(error) - }) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful domain retrieval', () => { - describe('domain cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - findVerifiedDomainByDomain(domain: "not-test.gc.ca") { - id - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: query, - validators: { - cleanseInput, - }, - loaders: { - loadVerifiedDomainsById: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`Aucun domaine vérifié avec le domaine fourni n'a pu être trouvé.`)] - - expect(response.errors).toEqual(error) - }) - }) - }) - }) - }) -}) diff --git a/api/src/verified-domains/queries/__tests__/find-verified-domains.test.js b/api/src/verified-domains/queries/__tests__/find-verified-domains.test.js deleted file mode 100644 index 6857181e3b..0000000000 --- a/api/src/verified-domains/queries/__tests__/find-verified-domains.test.js +++ /dev/null @@ -1,244 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema } from 'graphql' -import { toGlobalId } from 'graphql-relay' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { cleanseInput } from '../../../validators' -import { loadVerifiedOrgConnectionsByDomainId } from '../../../verified-organizations' -import { loadVerifiedDomainConnections } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given findVerifiedDomains query', () => { - let query, drop, truncate, schema, collections, domain, org, i18n - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - - beforeAll(async () => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - afterEach(async () => { - consoleOutput.length = 0 - }) - - describe('given successful query', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - org = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - domain = await collections.domains.save({ - domain: 'test.gc.ca', - lastRan: null, - selectors: ['selector1', 'selector2'], - status: { - dkim: 'pass', - dmarc: 'pass', - https: 'info', - spf: 'fail', - ssl: 'fail', - }, - }) - await collections.claims.save({ - _to: domain._id, - _from: org._id, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - it('returns domain', async () => { - const response = await graphql({ - schema, - source: ` - query { - findVerifiedDomains(first: 5) { - edges { - cursor - node { - id - } - } - totalCount - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: query, - validators: { - cleanseInput, - }, - loaders: { - loadVerifiedDomainConnections: loadVerifiedDomainConnections({ - query, - cleanseInput, - }), - loadVerifiedOrgConnectionsByDomainId: loadVerifiedOrgConnectionsByDomainId(query, 'en', cleanseInput), - }, - }, - }) - - const expectedResponse = { - data: { - findVerifiedDomains: { - edges: [ - { - cursor: toGlobalId('verifiedDomain', domain._key), - node: { - id: toGlobalId('verifiedDomain', domain._key), - }, - }, - ], - totalCount: 1, - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedDomain', domain._key), - endCursor: toGlobalId('verifiedDomain', domain._key), - }, - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - describe('given an unsuccessful query', () => { - describe('given unsuccessful domain retrieval', () => { - describe('domain cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - findVerifiedDomains(first: 5) { - edges { - cursor - node { - id - } - } - totalCount - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: query, - validators: { - cleanseInput, - }, - loaders: { - loadVerifiedDomainConnections: jest.fn().mockReturnValue({ - edges: [], - totalCount: 0, - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - endCursor: '', - }, - }), - }, - }, - }) - - const expectedResponse = { - data: { - findVerifiedDomains: { - edges: [], - totalCount: 0, - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - endCursor: '', - }, - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - }) - }) -}) diff --git a/api/src/verified-domains/queries/find-verified-domain-by-domain.js b/api/src/verified-domains/queries/find-verified-domain-by-domain.js deleted file mode 100644 index 0100b1d4a0..0000000000 --- a/api/src/verified-domains/queries/find-verified-domain-by-domain.js +++ /dev/null @@ -1,30 +0,0 @@ -import { GraphQLNonNull } from 'graphql' -import { t } from '@lingui/macro' -import { Domain } from '../../scalars' -import { verifiedDomainType } from '../objects' - -export const findVerifiedDomainByDomain = { - type: verifiedDomainType, - description: 'Retrieve a specific verified domain by providing a domain.', - args: { - domain: { - type: new GraphQLNonNull(Domain), - description: 'The domain you wish to retrieve information for.', - }, - }, - resolve: async (_, args, { i18n, loaders: { loadVerifiedDomainsById }, validators: { cleanseInput } }) => { - // Cleanse input - const domainInput = cleanseInput(args.domain) - - // Retrieve domain by domain - const domain = await loadVerifiedDomainsById.load(domainInput) - - if (typeof domain === 'undefined') { - console.warn(`User could not retrieve verified domain.`) - throw new Error(i18n._(t`No verified domain with the provided domain could be found.`)) - } - - domain.id = domain._key - return domain - }, -} diff --git a/api/src/verified-domains/queries/find-verified-domains.js b/api/src/verified-domains/queries/find-verified-domains.js deleted file mode 100644 index 04a31a1a68..0000000000 --- a/api/src/verified-domains/queries/find-verified-domains.js +++ /dev/null @@ -1,24 +0,0 @@ -import { connectionArgs } from 'graphql-relay' - -import { verifiedDomainOrder } from '../inputs' -import { verifiedDomainConnection } from '../objects' - -export const findVerifiedDomains = { - type: verifiedDomainConnection.connectionType, - description: 'Select verified check domains', - args: { - orderBy: { - type: verifiedDomainOrder, - description: 'Ordering options for verified domain connections.', - }, - ...connectionArgs, - }, - resolve: async (_, args, { loaders: { loadVerifiedDomainConnections } }) => { - const domainConnections = await loadVerifiedDomainConnections(args) - return domainConnections - }, -} - -module.exports = { - findVerifiedDomains, -} diff --git a/api/src/verified-domains/queries/index.js b/api/src/verified-domains/queries/index.js deleted file mode 100644 index 8e92f5a1a1..0000000000 --- a/api/src/verified-domains/queries/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from './find-verified-domain-by-domain' -export * from './find-verified-domains' diff --git a/api/src/verified-organizations/index.js b/api/src/verified-organizations/index.js deleted file mode 100644 index 7dab4e57a0..0000000000 --- a/api/src/verified-organizations/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './loaders' -export * from './objects' -export * from './queries' diff --git a/api/src/verified-organizations/inputs/__tests__/verified-organization-order.test.js b/api/src/verified-organizations/inputs/__tests__/verified-organization-order.test.js deleted file mode 100644 index b0123540a1..0000000000 --- a/api/src/verified-organizations/inputs/__tests__/verified-organization-order.test.js +++ /dev/null @@ -1,21 +0,0 @@ -import { GraphQLNonNull } from 'graphql' - -import { verifiedOrganizationOrder } from '../verified-organization-order' -import { OrderDirection, VerifiedOrganizationOrderField } from '../../../enums' - -describe('given the verifiedOrganizationOrder input object', () => { - describe('testing fields', () => { - it('has a direction field', () => { - const demoType = verifiedOrganizationOrder.getFields() - - expect(demoType).toHaveProperty('direction') - expect(demoType.direction.type).toMatchObject(new GraphQLNonNull(OrderDirection)) - }) - it('has a field field', () => { - const demoType = verifiedOrganizationOrder.getFields() - - expect(demoType).toHaveProperty('field') - expect(demoType.field.type).toMatchObject(new GraphQLNonNull(VerifiedOrganizationOrderField)) - }) - }) -}) diff --git a/api/src/verified-organizations/inputs/index.js b/api/src/verified-organizations/inputs/index.js deleted file mode 100644 index c08d5c39c5..0000000000 --- a/api/src/verified-organizations/inputs/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './verified-organization-order' diff --git a/api/src/verified-organizations/inputs/verified-organization-order.js b/api/src/verified-organizations/inputs/verified-organization-order.js deleted file mode 100644 index dff98ecd79..0000000000 --- a/api/src/verified-organizations/inputs/verified-organization-order.js +++ /dev/null @@ -1,18 +0,0 @@ -import { GraphQLInputObjectType, GraphQLNonNull } from 'graphql' - -import { OrderDirection, VerifiedOrganizationOrderField } from '../../enums' - -export const verifiedOrganizationOrder = new GraphQLInputObjectType({ - name: 'VerifiedOrganizationOrder', - description: 'Ordering options for verified organization connections.', - fields: () => ({ - field: { - type: new GraphQLNonNull(VerifiedOrganizationOrderField), - description: 'The field to order verified organizations by.', - }, - direction: { - type: new GraphQLNonNull(OrderDirection), - description: 'The ordering direction.', - }, - }), -}) diff --git a/api/src/verified-organizations/loaders/__tests__/load-verified-org-conn-by-domain-id.test.js b/api/src/verified-organizations/loaders/__tests__/load-verified-org-conn-by-domain-id.test.js deleted file mode 100644 index 2419fbb120..0000000000 --- a/api/src/verified-organizations/loaders/__tests__/load-verified-org-conn-by-domain-id.test.js +++ /dev/null @@ -1,2731 +0,0 @@ -import { stringify } from 'jest-matcher-utils' -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { toGlobalId } from 'graphql-relay' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { cleanseInput } from '../../../validators' -import { loadVerifiedOrgConnectionsByDomainId, loadVerifiedOrgByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -const i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, -}) - -const orgOneSummaryData = { - web: { - pass: 50, - fail: 1000, - total: 1050, - }, - mail: { - pass: 50, - fail: 1000, - total: 1050, - }, -} - -const orgOneData = { - verified: true, - orgDetails: { - en: { - slug: 'slug-org-one', - acronym: 'ONE', - name: 'org One', - zone: 'zone one', - sector: 'sector one', - country: 'country one', - province: 'province one', - city: 'city one', - }, - fr: { - slug: 'slug-org-one', - acronym: 'ONE', - name: 'org One', - zone: 'zone one', - sector: 'sector one', - country: 'country one', - province: 'province one', - city: 'city one', - }, - }, -} - -const orgTwoSummaryData = { - web: { - pass: 52, - fail: 1002, - total: 1054, - }, - mail: { - pass: 52, - fail: 1002, - total: 1054, - }, -} - -const orgTwoData = { - verified: true, - orgDetails: { - en: { - slug: 'slug-org-two', - acronym: 'TWO', - name: 'org two', - zone: 'zone two', - sector: 'sector two', - country: 'country two', - province: 'province two', - city: 'city two', - }, - fr: { - slug: 'slug-org-two', - acronym: 'TWO', - name: 'org two', - zone: 'zone two', - sector: 'sector two', - country: 'country two', - province: 'province two', - city: 'city two', - }, - }, -} - -const orgThreeSummaryData = { - web: { - pass: 51, - fail: 1001, - total: 1052, - }, - mail: { - pass: 51, - fail: 1001, - total: 1052, - }, -} - -const orgThreeData = { - verified: true, - orgDetails: { - en: { - slug: 'slug-org-three', - acronym: 'THREE', - name: 'org three', - zone: 'zone three', - sector: 'sector three', - country: 'country three', - province: 'province three', - city: 'city three', - }, - fr: { - slug: 'slug-org-three', - acronym: 'THREE', - name: 'org three', - zone: 'zone three', - sector: 'sector three', - country: 'country three', - province: 'province three', - city: 'city three', - }, - }, -} - -const domainOneData = { - domain: 'test.domain.gc.ca', -} - -const domainTwoData = { - domain: 'test.domain.canada.ca', -} - -const domainThreeData = { - domain: 'test.domain.canada.gc.ca', -} - -describe('given the load organizations connection function', () => { - describe('given a successful load', () => { - describe('users language is english', () => { - describe('using after cursor', () => { - let consoleOutput = [] - const mockedError = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - console.error = mockedError - console.warn = mockedWarn - - let query, drop, truncate, collections, db, org, orgTwo, domain, domainTwo, domainThree - - beforeAll(async () => { - ;({ query, drop, truncate, collections, db } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - org = await collections.organizations.save(orgOneData) - const orgSummary = await collections.organizationSummaries.save({ - organization: org._id, - ...orgOneSummaryData, - }) - await db.collection("organizations").update(org._key, { latestSummaryId: orgSummary._id }) - orgTwo = await collections.organizations.save(orgTwoData) - const orgTwoSummary = await collections.organizationSummaries.save({ - organization: orgTwo._id, - ...orgTwoSummaryData, - }) - await db.collection("organizations").update(orgTwo._key, { latestSummaryId: orgTwoSummary._id }) - - domain = await collections.domains.save(domainOneData) - domainTwo = await collections.domains.save(domainTwoData) - domainThree = await collections.domains.save(domainThreeData) - - await collections.claims.import([ - { - _from: org._id, - _to: domain._id, - }, - { - _from: orgTwo._id, - _to: domain._id, - }, - { - _from: orgTwo._id, - _to: domainTwo._id, - }, - { - _from: orgTwo._id, - _to: domainThree._id, - }, - ]) - }) - - afterEach(async () => { - consoleOutput = [] - await truncate() - }) - - afterAll(async () => { - await drop() - }) - - it('returns an organization', async () => { - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const orgLoader = loadVerifiedOrgByKey({ query, language: 'en' }) - const expectedOrgs = await orgLoader.loadMany([org._key, orgTwo._key]) - - expectedOrgs[0].id = expectedOrgs[0]._key - expectedOrgs[1].id = expectedOrgs[1]._key - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', expectedOrgs[0].id), - } - const orgs = await connectionLoader({ - domainId: domain._id, - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - node: { - ...expectedOrgs[1], - }, - }, - ], - totalCount: 2, - pageInfo: { - hasNextPage: false, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('using before cursor', () => { - let consoleOutput = [] - const mockedError = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - console.error = mockedError - console.warn = mockedWarn - - let query, drop, truncate, collections, db, org, orgTwo, domain, domainTwo, domainThree - - beforeEach(async () => { - ;({ query, drop, truncate, collections, db } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - org = await collections.organizations.save(orgOneData) - const orgSummary = await collections.organizationSummaries.save({ - organization: org._id, - ...orgOneSummaryData, - }) - await db.collection("organizations").update(org._key, { latestSummaryId: orgSummary._id }) - orgTwo = await collections.organizations.save(orgTwoData) - const orgTwoSummary = await collections.organizationSummaries.save({ - organization: orgTwo._id, - ...orgTwoSummaryData, - }) - await db.collection("organizations").update(orgTwo._key, { latestSummaryId: orgTwoSummary._id }) - - domain = await collections.domains.save(domainOneData) - domainTwo = await collections.domains.save(domainTwoData) - domainThree = await collections.domains.save(domainThreeData) - - await collections.claims.import([ - { - _from: org._id, - _to: domain._id, - }, - { - _from: orgTwo._id, - _to: domain._id, - }, - { - _from: orgTwo._id, - _to: domainTwo._id, - }, - { - _from: orgTwo._id, - _to: domainThree._id, - }, - ]) - }) - - afterEach(async () => { - consoleOutput = [] - await truncate() - }) - - afterAll(async () => { - await drop() - }) - - it('returns an organization', async () => { - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const orgLoader = loadVerifiedOrgByKey({ query, language: 'en' }) - const expectedOrgs = await orgLoader.loadMany([org._key, orgTwo._key]) - - expectedOrgs[0].id = expectedOrgs[0]._key - expectedOrgs[1].id = expectedOrgs[1]._key - - const connectionArgs = { - first: 5, - before: toGlobalId('verifiedOrganization', expectedOrgs[1].id), - } - const orgs = await connectionLoader({ - domainId: domain._id, - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - node: { - ...expectedOrgs[0], - }, - }, - ], - totalCount: 2, - pageInfo: { - hasNextPage: true, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('using first limit', () => { - let consoleOutput = [] - const mockedError = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - console.error = mockedError - console.warn = mockedWarn - - let query, drop, truncate, collections, db, org, orgTwo, domain, domainTwo, domainThree - - beforeEach(async () => { - ;({ query, drop, truncate, collections, db } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - org = await collections.organizations.save(orgOneData) - const orgSummary = await collections.organizationSummaries.save({ - organization: org._id, - ...orgOneSummaryData, - }) - await db.collection("organizations").update(org._key, { latestSummaryId: orgSummary._id }) - orgTwo = await collections.organizations.save(orgTwoData) - const orgTwoSummary = await collections.organizationSummaries.save({ - organization: orgTwo._id, - ...orgTwoSummaryData, - }) - await db.collection("organizations").update(orgTwo._key, { latestSummaryId: orgTwoSummary._id }) - - domain = await collections.domains.save(domainOneData) - domainTwo = await collections.domains.save(domainTwoData) - domainThree = await collections.domains.save(domainThreeData) - - await collections.claims.import([ - { - _from: org._id, - _to: domain._id, - }, - { - _from: orgTwo._id, - _to: domain._id, - }, - { - _from: orgTwo._id, - _to: domainTwo._id, - }, - { - _from: orgTwo._id, - _to: domainThree._id, - }, - ]) - }) - - afterEach(async () => { - consoleOutput = [] - await truncate() - }) - - afterAll(async () => { - await drop() - }) - - it('returns an organization', async () => { - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const orgLoader = loadVerifiedOrgByKey({ query, language: 'en' }) - const expectedOrgs = await orgLoader.loadMany([org._key, orgTwo._key]) - - expectedOrgs[0].id = expectedOrgs[0]._key - expectedOrgs[1].id = expectedOrgs[1]._key - - const connectionArgs = { - first: 1, - } - const orgs = await connectionLoader({ - domainId: domain._id, - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - node: { - ...expectedOrgs[0], - }, - }, - ], - totalCount: 2, - pageInfo: { - hasNextPage: true, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('using last limit', () => { - let consoleOutput = [] - const mockedError = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - console.error = mockedError - console.warn = mockedWarn - - let query, drop, truncate, collections, db, org, orgTwo, domain, domainTwo, domainThree - - beforeEach(async () => { - ;({ query, drop, truncate, collections, db } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - org = await collections.organizations.save(orgOneData) - const orgSummary = await collections.organizationSummaries.save({ - organization: org._id, - ...orgOneSummaryData, - }) - await db.collection("organizations").update(org._key, { latestSummaryId: orgSummary._id }) - orgTwo = await collections.organizations.save(orgTwoData) - const orgTwoSummary = await collections.organizationSummaries.save({ - organization: orgTwo._id, - ...orgTwoSummaryData, - }) - await db.collection("organizations").update(orgTwo._key, { latestSummaryId: orgTwoSummary._id }) - - domain = await collections.domains.save(domainOneData) - domainTwo = await collections.domains.save(domainTwoData) - domainThree = await collections.domains.save(domainThreeData) - - await collections.claims.import([ - { - _from: org._id, - _to: domain._id, - }, - { - _from: orgTwo._id, - _to: domain._id, - }, - { - _from: orgTwo._id, - _to: domainTwo._id, - }, - { - _from: orgTwo._id, - _to: domainThree._id, - }, - ]) - }) - - afterEach(async () => { - consoleOutput = [] - await truncate() - }) - - afterAll(async () => { - await drop() - }) - - it('returns an organization', async () => { - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const orgLoader = loadVerifiedOrgByKey({ query, language: 'en' }) - const expectedOrgs = await orgLoader.loadMany([org._key, orgTwo._key]) - - expectedOrgs[0].id = expectedOrgs[0]._key - expectedOrgs[1].id = expectedOrgs[1]._key - - const connectionArgs = { - last: 1, - } - const orgs = await connectionLoader({ - domainId: domain._id, - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - node: { - ...expectedOrgs[1], - }, - }, - ], - totalCount: 2, - pageInfo: { - hasNextPage: false, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('using the orderBy field', () => { - let consoleOutput = [] - const mockedError = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - console.error = mockedError - console.warn = mockedWarn - - let query, drop, truncate, collections, db, org, orgTwo, domain, domainTwo, domainThree, orgThree - - beforeEach(async () => { - ;({ query, drop, truncate, collections, db } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - - org = await collections.organizations.save(orgOneData) - const orgSummary = await collections.organizationSummaries.save({ - organization: org._id, - ...orgOneSummaryData, - }) - await db.collection("organizations").update(org._key, { latestSummaryId: orgSummary._id }) - orgTwo = await collections.organizations.save(orgTwoData) - const orgTwoSummary = await collections.organizationSummaries.save({ - organization: orgTwo._id, - ...orgTwoSummaryData, - }) - await db.collection("organizations").update(orgTwo._key, { latestSummaryId: orgTwoSummary._id }) - orgThree = await collections.organizations.save(orgThreeData) - const orgThreeSummary = await collections.organizationSummaries.save({ - organization: orgThree._id, - ...orgThreeSummaryData, - }) - await db.collection("organizations").update(orgThree._key, { latestSummaryId: orgThreeSummary._id }) - - domain = await collections.domains.save(domainOneData) - domainTwo = await collections.domains.save(domainTwoData) - domainThree = await collections.domains.save(domainThreeData) - - await collections.claims.import([ - { - _from: org._id, - _to: domain._id, - }, - { - _from: orgTwo._id, - _to: domain._id, - }, - { - _from: orgTwo._id, - _to: domainTwo._id, - }, - { - _from: orgTwo._id, - _to: domainThree._id, - }, - { - _from: orgThree._id, - _to: domain._id, - }, - { - _from: orgThree._id, - _to: domainTwo._id, - }, - ]) - }) - - afterEach(async () => { - consoleOutput = [] - await truncate() - }) - - afterAll(async () => { - await drop() - }) - - describe('ordering by ACRONYM', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'acronym', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'acronym', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by NAME', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'name', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'name', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by ZONE', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'zone', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'zone', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SECTOR', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'sector', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'sector', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by COUNTRY', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'country', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'country', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_MAIL_PASS', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-mail-pass', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-mail-pass', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_MAIL_FAIL', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-mail-fail', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-mail-fail', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_MAIL_TOTAL', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-mail-total', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-mail-total', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_WEB_PASS', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-web-pass', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-web-pass', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_WEB_FAIL', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-web-fail', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-web-fail', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - - describe('ordering by SUMMARY_WEB_TOTAL', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-web-total', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-web-total', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by DOMAIN_COUNT', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'domain-count', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - domainId: domain._id, - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'domain-count', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - }) - describe('no organizations are found', () => { - let query, drop - - beforeEach(async () => { - ;({ query, drop } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - - afterAll(async () => { - await drop() - }) - - it('returns empty structure', async () => { - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const orgs = await connectionLoader({ - domainId: 'domains/1', - last: 1, - }) - - const expectedStructure = { - edges: [], - totalCount: 0, - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - endCursor: '', - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - }) - describe('given an unsuccessful load', () => { - let i18n - describe('users language is english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('limits are not set', () => { - let warn, connectionLoader - - beforeAll(() => { - warn = console.warn - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - afterAll(() => { - console.warn = warn - }) - it('returns an error message', async () => { - console.warn = jest.fn() - - try { - await connectionLoader({ - domainId: '1234', - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'You must provide a `first` or `last` value to properly paginate the `VerifiedOrganization` connection.', - ), - ) - } - - expect(console.warn.mock.calls).toEqual([ - ['User did not have either `first` or `last` arguments set for: loadVerifiedOrgConnectionsByDomainId.'], - ]) - }) - }) - describe('user has first and last arguments set at the same time', () => { - let warn, connectionLoader - - beforeEach(() => { - warn = console.warn - - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - afterAll(() => { - console.warn = warn - }) - - it('returns an error message', async () => { - console.warn = jest.fn() - try { - await connectionLoader({ - domainId: '1234', - first: 1, - last: 1, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Passing both `first` and `last` to paginate the `VerifiedOrganization` connection is not supported.', - ), - ) - } - - expect(console.warn.mock.calls).toEqual([ - ['User attempted to have `first` and `last` arguments set for: loadVerifiedOrgConnectionsByDomainId.'], - ]) - }) - }) - describe('limits are set below minimum', () => { - let warn, connectionLoader - - beforeEach(() => { - warn = console.warn - - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - afterAll(() => { - console.warn = warn - }) - it('rejects values for first below zero', async () => { - console.warn = jest.fn() - - try { - await connectionLoader({ - domainId: '1234', - first: -1, - }) - } catch (err) { - expect(err).toEqual(new Error('`first` on the `VerifiedOrganization` connection cannot be less than zero.')) - } - - expect(console.warn.mock.calls).toEqual([ - ['User attempted to have `first` set below zero for: loadVerifiedOrgConnectionsByDomainId.'], - ]) - }) - }) - describe('limits are set below minimum', () => { - let warn, connectionLoader - - beforeEach(() => { - warn = console.warn - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - afterAll(() => { - console.warn = warn - }) - - it('rejects values for last below zero', async () => { - console.warn = jest.fn() - try { - await connectionLoader({ - domainId: '1234', - last: -1, - }) - } catch (err) { - expect(err).toEqual(new Error('`last` on the `VerifiedOrganization` connection cannot be less than zero.')) - } - - expect(console.warn.mock.calls).toEqual([ - ['User attempted to have `last` set below zero for: loadVerifiedOrgConnectionsByDomainId.'], - ]) - }) - }) - describe('limits are set above maximum', () => { - let warn, connectionLoader - - beforeEach(async () => { - warn = console.warn - - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - afterAll(() => { - console.warn = warn - }) - it('returns an error message', async () => { - console.warn = jest.fn() - - try { - await connectionLoader({ - domainId: '1234', - first: 101, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Requesting `101` records on the `VerifiedOrganization` connection exceeds the `first` limit of 100 records.', - ), - ) - } - - expect(console.warn.mock.calls).toEqual([ - ['User attempted to have `first` to 101 for: loadVerifiedOrgConnectionsByDomainId.'], - ]) - }) - }) - describe('last is set', () => { - let warn, connectionLoader - - beforeEach(() => { - warn = console.warn - - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - afterAll(() => { - console.warn = warn - }) - it('returns an error message', async () => { - console.warn = jest.fn() - - try { - await connectionLoader({ - domainId: '1234', - last: 101, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Requesting `101` records on the `VerifiedOrganization` connection exceeds the `last` limit of 100 records.', - ), - ) - } - - expect(console.warn.mock.calls).toEqual([ - ['User attempted to have `last` to 101 for: loadVerifiedOrgConnectionsByDomainId.'], - ]) - }) - }) - describe('limits are not set to numbers', () => { - describe('first limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - let warn, connectionLoader - - beforeAll(async () => { - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - beforeEach(() => { - console.warn = jest.fn() - }) - afterEach(() => { - console.warn = warn - }) - afterAll(() => { - console.warn = warn - }) - it(`returns an error when first set is to ${stringify(invalidInput)}`, async () => { - try { - await connectionLoader({ - first: invalidInput, - }) - } catch (err) { - expect(err).toEqual(new Error(`\`first\` must be of type \`number\` not \`${typeof invalidInput}\`.`)) - } - expect(console.warn.mock.calls).toEqual([ - [ - `User attempted to have \`first\` set as a ${typeof invalidInput} for: loadVerifiedOrgConnectionsByDomainId.`, - ], - ]) - }) - }) - }) - describe('last limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - let warn, connectionLoader - - beforeAll(() => { - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - beforeEach(() => { - console.warn = jest.fn() - }) - afterEach(() => { - console.warn = warn - }) - afterAll(() => { - console.warn = warn - }) - it(`returns an error when last is set to ${stringify(invalidInput)}`, async () => { - try { - await connectionLoader({ - last: invalidInput, - }) - } catch (err) { - expect(err).toEqual(new Error(`\`last\` must be of type \`number\` not \`${typeof invalidInput}\`.`)) - } - expect(console.warn.mock.calls).toEqual([ - [ - `User attempted to have \`last\` set as a ${typeof invalidInput} for: loadVerifiedOrgConnectionsByDomainId.`, - ], - ]) - }) - }) - }) - }) - describe('given a database error', () => { - describe('when gathering organizations', () => { - it('returns an error message', async () => { - const error = console.error - console.error = jest.fn() - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), - language: 'en', - cleanseInput, - i18n, - }) - - await expect(() => - connectionLoader({ - domainId: '1234', - first: 5, - }), - ).rejects.toThrow('Unable to load verified organization(s). Please try again.') - - expect(console.error.mock.calls).toEqual([ - [ - `Database error occurred while user was trying to gather orgs in loadVerifiedOrgConnectionsByDomainId, error: Error: Database error occurred.`, - ], - ]) - console.error = error - }) - }) - }) - describe('given a cursor error', () => { - describe('when gathering organizations', () => { - it('returns an error message', async () => { - const error = console.error - console.error = jest.fn() - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn().mockReturnValueOnce({ - next() { - throw new Error('Cursor error occurred.') - }, - }), - language: 'en', - cleanseInput, - i18n, - }) - - await expect(() => - connectionLoader({ - domainId: '1234', - first: 5, - }), - ).rejects.toThrow('Unable to load verified organization(s). Please try again.') - - expect(console.error.mock.calls).toEqual([ - [ - `Cursor error occurred while user was trying to gather orgs in loadVerifiedOrgConnectionsByDomainId, error: Error: Cursor error occurred.`, - ], - ]) - console.error = error - }) - }) - }) - }) - describe('users language is french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('limits are not set', () => { - let warn, connectionLoader - - beforeAll(() => { - warn = console.warn - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - afterAll(() => { - console.warn = warn - }) - it('returns an error message', async () => { - console.warn = jest.fn() - - try { - await connectionLoader({ - domainId: '1234', - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Vous devez fournir une valeur `first` ou `last` pour paginer correctement la connexion `VerifiedOrganization`.', - ), - ) - } - - expect(console.warn.mock.calls).toEqual([ - ['User did not have either `first` or `last` arguments set for: loadVerifiedOrgConnectionsByDomainId.'], - ]) - }) - }) - describe('user has first and last arguments set at the same time', () => { - let warn, connectionLoader - - beforeEach(() => { - warn = console.warn - - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - afterAll(() => { - console.warn = warn - }) - - it('returns an error message', async () => { - console.warn = jest.fn() - try { - await connectionLoader({ - domainId: '1234', - first: 1, - last: 1, - }) - } catch (err) { - expect(err).toEqual( - new Error( - "Passer à la fois `first` et `last` pour paginer la connexion `VerifiedOrganization` n'est pas supporté.", - ), - ) - } - - expect(console.warn.mock.calls).toEqual([ - ['User attempted to have `first` and `last` arguments set for: loadVerifiedOrgConnectionsByDomainId.'], - ]) - }) - }) - describe('limits are set below minimum', () => { - let warn, connectionLoader - - beforeEach(() => { - warn = console.warn - - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - afterAll(() => { - console.warn = warn - }) - it('rejects values for first below zero', async () => { - console.warn = jest.fn() - - try { - await connectionLoader({ - domainId: '1234', - first: -1, - }) - } catch (err) { - expect(err).toEqual( - new Error('`first` sur la connexion `VerifiedOrganization` ne peut être inférieur à zéro.'), - ) - } - - expect(console.warn.mock.calls).toEqual([ - ['User attempted to have `first` set below zero for: loadVerifiedOrgConnectionsByDomainId.'], - ]) - }) - }) - describe('limits are set below minimum', () => { - let warn, connectionLoader - - beforeEach(() => { - warn = console.warn - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - afterAll(() => { - console.warn = warn - }) - - it('rejects values for last below zero', async () => { - console.warn = jest.fn() - try { - await connectionLoader({ - domainId: '1234', - last: -1, - }) - } catch (err) { - expect(err).toEqual( - new Error('`last` sur la connexion `VerifiedOrganization` ne peut être inférieur à zéro.'), - ) - } - - expect(console.warn.mock.calls).toEqual([ - ['User attempted to have `last` set below zero for: loadVerifiedOrgConnectionsByDomainId.'], - ]) - }) - }) - describe('limits are set above maximum', () => { - let warn, connectionLoader - - beforeEach(async () => { - warn = console.warn - - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - afterAll(() => { - console.warn = warn - }) - it('returns an error message', async () => { - console.warn = jest.fn() - - try { - await connectionLoader({ - domainId: '1234', - first: 101, - }) - } catch (err) { - expect(err).toEqual( - new Error( - "La demande d'enregistrements `101` sur la connexion `VerifiedOrganization` dépasse la limite `first` de 100 enregistrements.", - ), - ) - } - - expect(console.warn.mock.calls).toEqual([ - ['User attempted to have `first` to 101 for: loadVerifiedOrgConnectionsByDomainId.'], - ]) - }) - }) - describe('last is set', () => { - let warn, connectionLoader - - beforeEach(() => { - warn = console.warn - - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - afterAll(() => { - console.warn = warn - }) - it('returns an error message', async () => { - console.warn = jest.fn() - - try { - await connectionLoader({ - domainId: '1234', - last: 101, - }) - } catch (err) { - expect(err).toEqual( - new Error( - "La demande d'enregistrements `101` sur la connexion `VerifiedOrganization` dépasse la limite `last` de 100 enregistrements.", - ), - ) - } - - expect(console.warn.mock.calls).toEqual([ - ['User attempted to have `last` to 101 for: loadVerifiedOrgConnectionsByDomainId.'], - ]) - }) - }) - describe('limits are not set to numbers', () => { - describe('first limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - let warn, connectionLoader - - beforeAll(async () => { - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - beforeEach(() => { - console.warn = jest.fn() - }) - afterEach(() => { - console.warn = warn - }) - afterAll(() => { - console.warn = warn - }) - it(`returns an error when first set is to ${stringify(invalidInput)}`, async () => { - try { - await connectionLoader({ - first: invalidInput, - }) - } catch (err) { - expect(err).toEqual( - new Error(`\`first\` doit être de type \`number\` et non \`${typeof invalidInput}\`.`), - ) - } - expect(console.warn.mock.calls).toEqual([ - [ - `User attempted to have \`first\` set as a ${typeof invalidInput} for: loadVerifiedOrgConnectionsByDomainId.`, - ], - ]) - }) - }) - }) - describe('last limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - let warn, connectionLoader - - beforeAll(() => { - connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn(), - language: 'en', - cleanseInput, - i18n, - }) - }) - beforeEach(() => { - console.warn = jest.fn() - }) - afterEach(() => { - console.warn = warn - }) - afterAll(() => { - console.warn = warn - }) - it(`returns an error when last is set to ${stringify(invalidInput)}`, async () => { - try { - await connectionLoader({ - last: invalidInput, - }) - } catch (err) { - expect(err).toEqual( - new Error(`\`last\` doit être de type \`number\` et non \`${typeof invalidInput}\`.`), - ) - } - expect(console.warn.mock.calls).toEqual([ - [ - `User attempted to have \`last\` set as a ${typeof invalidInput} for: loadVerifiedOrgConnectionsByDomainId.`, - ], - ]) - }) - }) - }) - }) - describe('given a database error', () => { - describe('when gathering organizations', () => { - it('returns an error message', async () => { - const error = console.error - console.error = jest.fn() - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), - language: 'en', - cleanseInput, - i18n, - }) - - await expect(() => - connectionLoader({ - domainId: '1234', - first: 5, - }), - ).rejects.toThrow('Impossible de charger le(s) organisme(s) vérifié(s). Veuillez réessayer.') - - expect(console.error.mock.calls).toEqual([ - [ - `Database error occurred while user was trying to gather orgs in loadVerifiedOrgConnectionsByDomainId, error: Error: Database error occurred.`, - ], - ]) - console.error = error - }) - }) - }) - describe('given a cursor error', () => { - describe('when gathering organizations', () => { - it('returns an error message', async () => { - const error = console.error - console.error = jest.fn() - - const connectionLoader = loadVerifiedOrgConnectionsByDomainId({ - query: jest.fn().mockReturnValueOnce({ - next() { - throw new Error('Cursor error occurred.') - }, - }), - language: 'en', - cleanseInput, - i18n, - }) - - await expect(() => - connectionLoader({ - domainId: '1234', - first: 5, - }), - ).rejects.toThrow('Impossible de charger le(s) organisme(s) vérifié(s). Veuillez réessayer.') - - expect(console.error.mock.calls).toEqual([ - [ - `Cursor error occurred while user was trying to gather orgs in loadVerifiedOrgConnectionsByDomainId, error: Error: Cursor error occurred.`, - ], - ]) - console.error = error - }) - }) - }) - }) - }) -}) diff --git a/api/src/verified-organizations/loaders/__tests__/load-verified-org-conn.test.js b/api/src/verified-organizations/loaders/__tests__/load-verified-org-conn.test.js deleted file mode 100644 index 67ebce6778..0000000000 --- a/api/src/verified-organizations/loaders/__tests__/load-verified-org-conn.test.js +++ /dev/null @@ -1,3727 +0,0 @@ -import { stringify } from 'jest-matcher-utils' -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { toGlobalId } from 'graphql-relay' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { cleanseInput } from '../../../validators' -import { loadVerifiedOrgConnections, loadVerifiedOrgByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given the load organizations connection function', () => { - let query, drop, truncate, collections, db, org, orgTwo, i18n, domain, domainTwo, domainThree - - const consoleOutput = [] - const mockedError = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - beforeAll(() => { - console.error = mockedError - console.warn = mockedWarn - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given a successful load', () => { - beforeAll(async () => { - ;({ query, drop, truncate, collections, db } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - org = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'slug-org-one', - acronym: 'ONE', - name: 'org One', - zone: 'zone one', - sector: 'sector one', - country: 'country one', - province: 'province one', - city: 'city one', - }, - fr: { - slug: 'slug-org-one', - acronym: 'ONE', - name: 'org One', - zone: 'zone one', - sector: 'sector one', - country: 'country one', - province: 'province one', - city: 'city one', - }, - }, - }) - const orgSummary = await collections.organizationSummaries.save({ - organization: org._id, - web: { pass: 50, fail: 1000, total: 1050 }, - mail: { pass: 50, fail: 1000, total: 1050 }, - }) - await db.collection('organizations').update(org._key, { latestSummaryId: orgSummary._id }) - - orgTwo = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'slug-org-two', - acronym: 'TWO', - name: 'org two', - zone: 'zone two', - sector: 'sector two', - country: 'country two', - province: 'province two', - city: 'city two', - }, - fr: { - slug: 'slug-org-two', - acronym: 'TWO', - name: 'org two', - zone: 'zone two', - sector: 'sector two', - country: 'country two', - province: 'province two', - city: 'city two', - }, - }, - }) - const orgTwoSummary = await collections.organizationSummaries.save({ - organization: orgTwo._id, - web: { pass: 52, fail: 1002, total: 1054 }, - mail: { pass: 52, fail: 1002, total: 1054 }, - }) - await db.collection('organizations').update(orgTwo._key, { latestSummaryId: orgTwoSummary._id }) - domain = await collections.domains.save({ - domain: 'test.domain.gc.ca', - }) - domainThree = await collections.domains.save({ - domain: 'test.domain.canada.gc.ca', - }) - domainTwo = await collections.domains.save({ - domain: 'test.domain.canada.ca', - }) - await collections.claims.save({ - _from: org._id, - _to: domain._id, - }) - await collections.claims.save({ - _from: orgTwo._id, - _to: domain._id, - }) - await collections.claims.save({ - _from: orgTwo._id, - _to: domainTwo._id, - }) - await collections.claims.save({ - _from: orgTwo._id, - _to: domainThree._id, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - describe('users language is english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('using after cursor', () => { - it('returns an organization', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const orgLoader = loadVerifiedOrgByKey({ query, language: 'en' }) - const expectedOrgs = await orgLoader.loadMany([org._key, orgTwo._key]) - - expectedOrgs[0].id = expectedOrgs[0]._key - expectedOrgs[1].id = expectedOrgs[1]._key - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', expectedOrgs[0].id), - } - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - node: { - ...expectedOrgs[1], - }, - }, - ], - totalCount: 2, - pageInfo: { - hasNextPage: false, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('using before cursor', () => { - it('returns an organization', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const orgLoader = loadVerifiedOrgByKey({ query, language: 'en' }) - const expectedOrgs = await orgLoader.loadMany([org._key, orgTwo._key]) - - expectedOrgs[0].id = expectedOrgs[0]._key - expectedOrgs[1].id = expectedOrgs[1]._key - - const connectionArgs = { - first: 5, - before: toGlobalId('verifiedOrganization', expectedOrgs[1].id), - } - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - node: { - ...expectedOrgs[0], - }, - }, - ], - totalCount: 2, - pageInfo: { - hasNextPage: true, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('using first limit', () => { - it('returns an organization', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const orgLoader = loadVerifiedOrgByKey({ query, language: 'en' }) - const expectedOrgs = await orgLoader.loadMany([org._key, orgTwo._key]) - - expectedOrgs[0].id = expectedOrgs[0]._key - expectedOrgs[1].id = expectedOrgs[1]._key - - const connectionArgs = { - first: 1, - } - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - node: { - ...expectedOrgs[0], - }, - }, - ], - totalCount: 2, - pageInfo: { - hasNextPage: true, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('using last limit', () => { - it('returns an organization', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const orgLoader = loadVerifiedOrgByKey({ query, language: 'en' }) - const expectedOrgs = await orgLoader.loadMany([org._key, orgTwo._key]) - - expectedOrgs[0].id = expectedOrgs[0]._key - expectedOrgs[1].id = expectedOrgs[1]._key - - const connectionArgs = { - last: 1, - } - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - node: { - ...expectedOrgs[1], - }, - }, - ], - totalCount: 2, - pageInfo: { - hasNextPage: false, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('using the orderBy field', () => { - let orgThree - beforeEach(async () => { - orgThree = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'slug-org-three', - acronym: 'THREE', - name: 'org three', - zone: 'zone three', - sector: 'sector three', - country: 'country three', - province: 'province three', - city: 'city three', - }, - fr: { - slug: 'slug-org-three', - acronym: 'THREE', - name: 'org three', - zone: 'zone three', - sector: 'sector three', - country: 'country three', - province: 'province three', - city: 'city three', - }, - }, - }) - const orgThreeSummary = await collections.organizationSummaries.save({ - organization: orgThree._id, - web: { pass: 51, fail: 1001, total: 1052 }, - mail: { pass: 51, fail: 1001, total: 1052 }, - }) - await db.collection('organizations').update(orgThree._key, { latestSummaryId: orgThreeSummary._id }) - await collections.claims.save({ - _from: orgThree._id, - _to: domain._id, - }) - await collections.claims.save({ - _from: orgThree._id, - _to: domainTwo._id, - }) - }) - describe('ordering by ACRONYM', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'acronym', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'acronym', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by NAME', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'name', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'name', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by ZONE', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'zone', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'zone', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SECTOR', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'sector', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'sector', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by COUNTRY', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'country', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'country', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_MAIL_PASS', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-mail-pass', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-mail-pass', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_MAIL_FAIL', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-mail-fail', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-mail-fail', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_MAIL_TOTAL', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-mail-total', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-mail-total', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_WEB_PASS', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-web-pass', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-web-pass', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_WEB_FAIL', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-web-fail', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-web-fail', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_WEB_TOTAL', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-web-total', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-web-total', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by DOMAIN_COUNT', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'domain-count', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'en', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'domain-count', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - }) - describe('no organizations are found', () => { - it('returns empty structure', async () => { - await truncate() - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: 1, - } - const orgs = await connectionLoader({ - domainId: 'domains/1', - ...connectionArgs, - }) - - const expectedStructure = { - edges: [], - totalCount: 0, - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - endCursor: '', - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('users language is french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('using after cursor', () => { - it('returns an organization', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const orgLoader = loadVerifiedOrgByKey({ query, language: 'fr' }) - const expectedOrgs = await orgLoader.loadMany([org._key, orgTwo._key]) - - expectedOrgs[0].id = expectedOrgs[0]._key - expectedOrgs[1].id = expectedOrgs[1]._key - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', expectedOrgs[0].id), - } - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - node: { - ...expectedOrgs[1], - }, - }, - ], - totalCount: 2, - pageInfo: { - hasNextPage: false, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('using before cursor', () => { - it('returns an organization', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const orgLoader = loadVerifiedOrgByKey({ query, language: 'fr' }) - const expectedOrgs = await orgLoader.loadMany([org._key, orgTwo._key]) - - expectedOrgs[0].id = expectedOrgs[0]._key - expectedOrgs[1].id = expectedOrgs[1]._key - - const connectionArgs = { - first: 5, - before: toGlobalId('verifiedOrganization', expectedOrgs[1].id), - } - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - node: { - ...expectedOrgs[0], - }, - }, - ], - totalCount: 2, - pageInfo: { - hasNextPage: true, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('using first limit', () => { - it('returns an organization', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const orgLoader = loadVerifiedOrgByKey({ query, language: 'fr' }) - const expectedOrgs = await orgLoader.loadMany([org._key, orgTwo._key]) - - expectedOrgs[0].id = expectedOrgs[0]._key - expectedOrgs[1].id = expectedOrgs[1]._key - - const connectionArgs = { - first: 1, - } - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - node: { - ...expectedOrgs[0], - }, - }, - ], - totalCount: 2, - pageInfo: { - hasNextPage: true, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrgs[0]._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('using last limit', () => { - it('returns an organization', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const orgLoader = loadVerifiedOrgByKey({ query, language: 'fr' }) - const expectedOrgs = await orgLoader.loadMany([org._key, orgTwo._key]) - - expectedOrgs[0].id = expectedOrgs[0]._key - expectedOrgs[1].id = expectedOrgs[1]._key - - const connectionArgs = { - last: 1, - } - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - node: { - ...expectedOrgs[1], - }, - }, - ], - totalCount: 2, - pageInfo: { - hasNextPage: false, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrgs[1]._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('using the orderBy field', () => { - let orgThree - beforeEach(async () => { - orgThree = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'slug-org-three', - acronym: 'THREE', - name: 'org three', - zone: 'zone three', - sector: 'sector three', - country: 'country three', - province: 'province three', - city: 'city three', - }, - fr: { - slug: 'slug-org-three', - acronym: 'THREE', - name: 'org three', - zone: 'zone three', - sector: 'sector three', - country: 'country three', - province: 'province three', - city: 'city three', - }, - }, - }) - const orgThreeSummary = await collections.organizationSummaries.save({ - organization: orgThree._id, - web: { pass: 51, fail: 1001, total: 1052 }, - mail: { pass: 51, fail: 1001, total: 1052 }, - }) - await db.collection('organizations').update(orgThree._key, { latestSummaryId: orgThreeSummary._id }) - await collections.claims.save({ - _from: orgThree._id, - _to: domain._id, - }) - await collections.claims.save({ - _from: orgThree._id, - _to: domainTwo._id, - }) - }) - describe('ordering by ACRONYM', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'acronym', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'acronym', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by NAME', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'name', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'name', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by ZONE', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'zone', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'zone', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SECTOR', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'sector', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'sector', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by COUNTRY', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'country', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'country', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_MAIL_PASS', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-mail-pass', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-mail-pass', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_MAIL_FAIL', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-mail-fail', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-mail-fail', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_MAIL_TOTAL', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-mail-total', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-mail-total', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_WEB_PASS', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-web-pass', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-web-pass', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_WEB_FAIL', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-web-fail', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-web-fail', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by SUMMARY_WEB_TOTAL', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'summary-web-total', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'summary-web-total', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - describe('ordering by DOMAIN_COUNT', () => { - describe('direction is set to ASC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', org._key), - before: toGlobalId('verifiedOrganization', orgTwo._key), - orderBy: { - field: 'domain-count', - direction: 'ASC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - describe('direction is set to DESC', () => { - it('returns organizations', async () => { - const orgLoader = loadVerifiedOrgByKey({ - query, - language: 'fr', - }) - const expectedOrg = await orgLoader.load(orgThree._key) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: 5, - after: toGlobalId('verifiedOrganization', orgTwo._key), - before: toGlobalId('verifiedOrganization', org._key), - orderBy: { - field: 'domain-count', - direction: 'DESC', - }, - } - - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', expectedOrg._key), - node: { - ...expectedOrg, - }, - }, - ], - totalCount: 3, - pageInfo: { - hasNextPage: true, - hasPreviousPage: true, - startCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - endCursor: toGlobalId('verifiedOrganization', expectedOrg._key), - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - }) - describe('no organizations are found', () => { - it('returns empty structure', async () => { - await truncate() - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: 1, - } - const orgs = await connectionLoader({ - ...connectionArgs, - }) - - const expectedStructure = { - edges: [], - totalCount: 0, - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - endCursor: '', - }, - } - - expect(orgs).toEqual(expectedStructure) - }) - }) - }) - }) - describe('given an unsuccessful load', () => { - describe('users language is english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given an unsuccessful load', () => { - describe('limits are not set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = {} - await connectionLoader({ ...connectionArgs }) - } catch (err) { - expect(err).toEqual( - new Error( - 'You must provide a `first` or `last` value to properly paginate the `VerifiedOrganization` connection.', - ), - ) - } - - expect(consoleOutput).toEqual([ - 'User did not have either `first` or `last` arguments set for: loadVerifiedOrgConnections.', - ]) - }) - }) - describe('user has first and last arguments set at the same time', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - first: 1, - last: 1, - } - await connectionLoader({ ...connectionArgs }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Passing both `first` and `last` to paginate the `VerifiedOrganization` connection is not supported.', - ), - ) - } - - expect(consoleOutput).toEqual([ - 'User attempted to have `first` and `last` arguments set for: loadVerifiedOrgConnections.', - ]) - }) - }) - describe('limits are set below minimum', () => { - describe('first is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - first: -1, - } - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error('`first` on the `VerifiedOrganization` connection cannot be less than zero.'), - ) - } - - expect(consoleOutput).toEqual([ - 'User attempted to have `first` set below zero for: loadVerifiedOrgConnections.', - ]) - }) - }) - describe('last is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - last: -1, - } - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error('`last` on the `VerifiedOrganization` connection cannot be less than zero.'), - ) - } - - expect(consoleOutput).toEqual([ - 'User attempted to have `last` set below zero for: loadVerifiedOrgConnections.', - ]) - }) - }) - }) - describe('limits are set above maximum', () => { - describe('first is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - first: 101, - } - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Requesting `101` records on the `VerifiedOrganization` connection exceeds the `first` limit of 100 records.', - ), - ) - } - - expect(consoleOutput).toEqual(['User attempted to have `first` to 101 for: loadVerifiedOrgConnections.']) - }) - }) - describe('last is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - last: 101, - } - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Requesting `101` records on the `VerifiedOrganization` connection exceeds the `last` limit of 100 records.', - ), - ) - } - - expect(consoleOutput).toEqual(['User attempted to have `last` to 101 for: loadVerifiedOrgConnections.']) - }) - }) - }) - describe('limits are not set to numbers', () => { - describe('first limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - it(`returns an error when first set to ${stringify(invalidInput)}`, async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: invalidInput, - } - - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error(`\`first\` must be of type \`number\` not \`${typeof invalidInput}\`.`)) - } - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` set as a ${typeof invalidInput} for: loadVerifiedOrgConnections.`, - ]) - }) - }) - }) - describe('last limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - it(`returns an error when last set to ${stringify(invalidInput)}`, async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: invalidInput, - } - - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error(`\`last\` must be of type \`number\` not \`${typeof invalidInput}\`.`)) - } - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` set as a ${typeof invalidInput} for: loadVerifiedOrgConnections.`, - ]) - }) - }) - }) - }) - }) - describe('given a database error', () => { - describe('when gathering organizations', () => { - it('returns an error message', async () => { - const query = jest.fn().mockRejectedValue(new Error('Database error occurred.')) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - first: 5, - } - await connectionLoader({ ...connectionArgs }) - } catch (err) { - expect(err).toEqual(new Error('Unable to load verified organization(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Database error occurred while user was trying to gather orgs in loadVerifiedOrgConnections, error: Error: Database error occurred.`, - ]) - }) - }) - describe('given a cursor error', () => { - describe('when gathering organizations', () => { - it('returns an error message', async () => { - const cursor = { - next() { - throw new Error('Cursor error occurred.') - }, - } - const query = jest.fn().mockReturnValueOnce(cursor) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - first: 5, - } - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual(new Error('Unable to load verified organization(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Cursor error occurred while user was trying to gather orgs in loadVerifiedOrgConnections, error: Error: Cursor error occurred.`, - ]) - }) - }) - }) - }) - }) - describe('users language is french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given an unsuccessful load', () => { - describe('limits are not set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = {} - await connectionLoader({ ...connectionArgs }) - } catch (err) { - expect(err).toEqual( - new Error( - 'Vous devez fournir une valeur `first` ou `last` pour paginer correctement la connexion `VerifiedOrganization`.', - ), - ) - } - - expect(consoleOutput).toEqual([ - 'User did not have either `first` or `last` arguments set for: loadVerifiedOrgConnections.', - ]) - }) - }) - describe('user has first and last arguments set at the same time', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - first: 1, - last: 1, - } - await connectionLoader({ ...connectionArgs }) - } catch (err) { - expect(err).toEqual( - new Error( - "Passer à la fois `first` et `last` pour paginer la connexion `VerifiedOrganization` n'est pas supporté.", - ), - ) - } - - expect(consoleOutput).toEqual([ - 'User attempted to have `first` and `last` arguments set for: loadVerifiedOrgConnections.', - ]) - }) - }) - describe('limits are set below minimum', () => { - describe('first is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - first: -1, - } - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error('`first` sur la connexion `VerifiedOrganization` ne peut être inférieur à zéro.'), - ) - } - - expect(consoleOutput).toEqual([ - 'User attempted to have `first` set below zero for: loadVerifiedOrgConnections.', - ]) - }) - }) - describe('last is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - last: -1, - } - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error('`last` sur la connexion `VerifiedOrganization` ne peut être inférieur à zéro.'), - ) - } - - expect(consoleOutput).toEqual([ - 'User attempted to have `last` set below zero for: loadVerifiedOrgConnections.', - ]) - }) - }) - }) - describe('limits are set above maximum', () => { - describe('first is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - first: 101, - } - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - "La demande d'enregistrements `101` sur la connexion `VerifiedOrganization` dépasse la limite `first` de 100 enregistrements.", - ), - ) - } - - expect(consoleOutput).toEqual(['User attempted to have `first` to 101 for: loadVerifiedOrgConnections.']) - }) - }) - describe('last is set', () => { - it('returns an error message', async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - last: 101, - } - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error( - "La demande d'enregistrements `101` sur la connexion `VerifiedOrganization` dépasse la limite `last` de 100 enregistrements.", - ), - ) - } - - expect(consoleOutput).toEqual(['User attempted to have `last` to 101 for: loadVerifiedOrgConnections.']) - }) - }) - }) - describe('limits are not set to numbers', () => { - describe('first limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - it(`returns an error when first set to ${stringify(invalidInput)}`, async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - first: invalidInput, - } - - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error(`\`first\` doit être de type \`number\` et non \`${typeof invalidInput}\`.`), - ) - } - expect(consoleOutput).toEqual([ - `User attempted to have \`first\` set as a ${typeof invalidInput} for: loadVerifiedOrgConnections.`, - ]) - }) - }) - }) - describe('last limit is set', () => { - ;['123', {}, [], null, true].forEach((invalidInput) => { - it(`returns an error when last set to ${stringify(invalidInput)}`, async () => { - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - const connectionArgs = { - last: invalidInput, - } - - try { - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error(`\`last\` doit être de type \`number\` et non \`${typeof invalidInput}\`.`), - ) - } - expect(consoleOutput).toEqual([ - `User attempted to have \`last\` set as a ${typeof invalidInput} for: loadVerifiedOrgConnections.`, - ]) - }) - }) - }) - }) - }) - describe('given a database error', () => { - describe('when gathering organizations', () => { - it('returns an error message', async () => { - const query = jest.fn().mockRejectedValue(new Error('Database error occurred.')) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - first: 5, - } - await connectionLoader({ ...connectionArgs }) - } catch (err) { - expect(err).toEqual(new Error('Impossible de charger le(s) organisme(s) vérifié(s). Veuillez réessayer.')) - } - - expect(consoleOutput).toEqual([ - `Database error occurred while user was trying to gather orgs in loadVerifiedOrgConnections, error: Error: Database error occurred.`, - ]) - }) - }) - describe('given a cursor error', () => { - describe('when gathering organizations', () => { - it('returns an error message', async () => { - const cursor = { - next() { - throw new Error('Cursor error occurred.') - }, - } - const query = jest.fn().mockReturnValueOnce(cursor) - - const connectionLoader = loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }) - - try { - const connectionArgs = { - first: 5, - } - await connectionLoader({ - ...connectionArgs, - }) - } catch (err) { - expect(err).toEqual( - new Error('Impossible de charger le(s) organisme(s) vérifié(s). Veuillez réessayer.'), - ) - } - - expect(consoleOutput).toEqual([ - `Cursor error occurred while user was trying to gather orgs in loadVerifiedOrgConnections, error: Error: Cursor error occurred.`, - ]) - }) - }) - }) - }) - }) - }) -}) diff --git a/api/src/verified-organizations/loaders/__tests__/load-verified-organization-by-key.test.js b/api/src/verified-organizations/loaders/__tests__/load-verified-organization-by-key.test.js deleted file mode 100644 index eb2a3dd12d..0000000000 --- a/api/src/verified-organizations/loaders/__tests__/load-verified-organization-by-key.test.js +++ /dev/null @@ -1,369 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { loadVerifiedOrgByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given a loadVerifiedOrgByKey dataloader', () => { - let query, drop, truncate, collections, db, i18n - - const consoleOutput = [] - const mockedError = (output) => consoleOutput.push(output) - beforeAll(() => { - console.error = mockedError - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given a successful load', () => { - beforeAll(async () => { - ;({ query, drop, truncate, collections, db } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - const org1 = await collections.organizations.save({ - verified: true, - policies: { - psd: false, - pgs: false, - }, - orgDetails: { - en: { - slug: 'communications-security-establishment', - acronym: 'CSE', - name: 'Communications Security Establishment', - zone: 'FED', - sector: 'DND', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'centre-de-la-securite-des-telecommunications', - acronym: 'CST', - name: 'Centre de la Securite des Telecommunications', - zone: 'FED', - sector: 'DND', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - const summary1 = await collections.organizationSummaries.save({ - organization: org1._id, - web: { - pass: 50, - fail: 1000, - total: 1050, - }, - mail: { - pass: 50, - fail: 1000, - total: 1050, - }, - }) - await db.collection('organizations').update(org1._key, { latestSummaryId: summary1._id }) - const org2 = await collections.organizations.save({ - verified: true, - policies: { - psd: false, - pgs: false, - }, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - const summary2 = await collections.organizationSummaries.save({ - organization: org2._id, - web: { - pass: 50, - fail: 1000, - total: 1050, - }, - mail: { - pass: 50, - fail: 1000, - total: 1050, - }, - }) - await db.collection('organizations').update(org2._key, { latestSummaryId: summary2._id }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - describe('language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('provided a single id', () => { - it('returns a single org', async () => { - // Get User From db - const expectedCursor = await query` - FOR org IN organizations - FILTER org.orgDetails.en.slug == "communications-security-establishment" - LET domains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - RETURN MERGE({ _id: org._id, _key: org._key, id: org._key, _rev: org._rev, _type: "verifiedOrganization", verified: org.verified, policies: { psd: false, pgs: false }, domainCount: COUNT(domains), summaries: org.latestSummaryId ? DOCUMENT(org.latestSummaryId) : null }, TRANSLATE("en", org.orgDetails)) - ` - const expectedOrg = await expectedCursor.next() - - const loader = loadVerifiedOrgByKey({ query, language: 'en', i18n }) - const org = await loader.load(expectedOrg._key) - - expect(org).toEqual(expectedOrg) - }) - }) - describe('given a list of ids', () => { - it('returns a list of orgs', async () => { - const orgIds = [] - const expectedOrgs = [] - const expectedCursor = await query` - FOR org IN organizations - LET domains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - RETURN MERGE({ _id: org._id, _key: org._key, id: org._key, _rev: org._rev, _type: "verifiedOrganization", verified: org.verified, policies: org.policies, domainCount: COUNT(domains), summaries: org.latestSummaryId ? DOCUMENT(org.latestSummaryId) : null }, TRANSLATE("en", org.orgDetails)) - ` - - while (expectedCursor.hasMore) { - const tempOrg = await expectedCursor.next() - orgIds.push(tempOrg._key) - expectedOrgs.push(tempOrg) - } - - const loader = loadVerifiedOrgByKey({ query, language: 'en', i18n }) - const orgs = await loader.loadMany(orgIds) - expect(orgs).toEqual(expectedOrgs) - }) - }) - }) - describe('language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('provided a single id', () => { - it('returns a single org', async () => { - // Get User From db - const expectedCursor = await query` - FOR org IN organizations - FILTER org.orgDetails.fr.slug == "centre-de-la-securite-des-telecommunications" - LET domains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - RETURN MERGE({ _id: org._id, _key: org._key, id: org._key, _rev: org._rev, _type: "verifiedOrganization", verified: org.verified, policies: org.policies, domainCount: COUNT(domains), summaries: org.latestSummaryId ? DOCUMENT(org.latestSummaryId) : null }, TRANSLATE("fr", org.orgDetails)) - ` - const expectedOrg = await expectedCursor.next() - - const loader = loadVerifiedOrgByKey({ query, language: 'fr', i18n }) - const org = await loader.load(expectedOrg._key) - - expect(org).toEqual(expectedOrg) - }) - }) - describe('provided a list of ids', () => { - it('returns a list of orgs', async () => { - const orgIds = [] - const expectedOrgs = [] - const expectedCursor = await query` - FOR org IN organizations - LET domains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - RETURN MERGE({ _id: org._id, _key: org._key, id: org._key, _rev: org._rev, _type: "verifiedOrganization", verified: org.verified, policies: org.policies, domainCount: COUNT(domains), summaries: org.latestSummaryId ? DOCUMENT(org.latestSummaryId) : null }, TRANSLATE("fr", org.orgDetails)) - ` - - while (expectedCursor.hasMore) { - const tempOrg = await expectedCursor.next() - orgIds.push(tempOrg._key) - expectedOrgs.push(tempOrg) - } - - const loader = loadVerifiedOrgByKey({ query, language: 'fr', i18n }) - const orgs = await loader.loadMany(orgIds) - expect(orgs).toEqual(expectedOrgs) - }) - }) - }) - }) - describe('given an unsuccessful load', () => { - describe('language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('database error is raised', () => { - it('returns an error', async () => { - const mockedQuery = jest.fn().mockRejectedValue(new Error('Database error occurred.')) - const loader = loadVerifiedOrgByKey({ - query: mockedQuery, - language: 'en', - i18n, - }) - - try { - await loader.load('1') - } catch (err) { - expect(err).toEqual(new Error('Unable to find verified organization(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Database error when running loadVerifiedOrgByKey: Error: Database error occurred.`, - ]) - }) - }) - describe('cursor error is raised', () => { - it('returns an error', async () => { - const cursor = { - forEach() { - throw new Error('Cursor error occurred.') - }, - } - const mockedQuery = jest.fn().mockReturnValue(cursor) - const loader = loadVerifiedOrgByKey({ - query: mockedQuery, - language: 'en', - i18n, - }) - - try { - await loader.load('1') - } catch (err) { - expect(err).toEqual(new Error('Unable to find verified organization(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Cursor error occurred during loadVerifiedOrgByKey: Error: Cursor error occurred.`, - ]) - }) - }) - }) - describe('language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('database error is raised', () => { - it('returns an error', async () => { - const mockedQuery = jest.fn().mockRejectedValue(new Error('Database error occurred.')) - const loader = loadVerifiedOrgByKey({ - query: mockedQuery, - language: 'fr', - i18n, - }) - - try { - await loader.load('1') - } catch (err) { - expect(err).toEqual( - new Error('Impossible de trouver une ou plusieurs organisations vérifiées. Veuillez réessayer.'), - ) - } - - expect(consoleOutput).toEqual([ - `Database error when running loadVerifiedOrgByKey: Error: Database error occurred.`, - ]) - }) - }) - describe('cursor error is raised', () => { - it('returns an error', async () => { - const cursor = { - forEach() { - throw new Error('Cursor error occurred.') - }, - } - const mockedQuery = jest.fn().mockReturnValue(cursor) - const loader = loadVerifiedOrgByKey({ - query: mockedQuery, - language: 'fr', - i18n, - }) - - try { - await loader.load('1') - } catch (err) { - expect(err).toEqual( - new Error('Impossible de trouver une ou plusieurs organisations vérifiées. Veuillez réessayer.'), - ) - } - - expect(consoleOutput).toEqual([ - `Cursor error occurred during loadVerifiedOrgByKey: Error: Cursor error occurred.`, - ]) - }) - }) - }) - }) -}) diff --git a/api/src/verified-organizations/loaders/__tests__/load-verified-organization-by-slug.test.js b/api/src/verified-organizations/loaders/__tests__/load-verified-organization-by-slug.test.js deleted file mode 100644 index 025ca3b7af..0000000000 --- a/api/src/verified-organizations/loaders/__tests__/load-verified-organization-by-slug.test.js +++ /dev/null @@ -1,365 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { loadVerifiedOrgBySlug } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given a loadVerifiedOrgBySlug dataloader', () => { - let query, drop, truncate, collections, db, i18n - - const consoleOutput = [] - const mockedError = (output) => consoleOutput.push(output) - beforeAll(() => { - console.error = mockedError - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given a successful load', () => { - beforeAll(async () => { - ;({ query, drop, truncate, collections, db } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - const org1 = await collections.organizations.save({ - verified: true, - policies: { - psd: false, - pgs: false, - }, - orgDetails: { - en: { - slug: 'communications-security-establishment', - acronym: 'CSE', - name: 'Communications Security Establishment', - zone: 'FED', - sector: 'DND', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'centre-de-la-securite-des-telecommunications', - acronym: 'CST', - name: 'Centre de la Securite des Telecommunications', - zone: 'FED', - sector: 'DND', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - const summary1 = await collections.organizationSummaries.save({ - organization: org1._id, - web: { - pass: 50, - fail: 1000, - total: 1050, - }, - mail: { - pass: 50, - fail: 1000, - total: 1050, - }, - }) - await db.collection('organizations').update(org1._key, { latestSummaryId: summary1._id }) - const org2 = await collections.organizations.save({ - verified: true, - policies: { - psd: false, - pgs: false, - }, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - const summary2 = await collections.organizationSummaries.save({ - organization: org2._id, - web: { - pass: 50, - fail: 1000, - total: 1050, - }, - mail: { - pass: 50, - fail: 1000, - total: 1050, - }, - }) - await db.collection('organizations').update(org2._key, { latestSummaryId: summary2._id }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - describe('language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('provided a single slug', () => { - it('returns a single org', async () => { - // Get Org From db - const expectedCursor = await query` - FOR org IN organizations - FILTER org.orgDetails.en.slug == "communications-security-establishment" - LET domains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - RETURN MERGE({ _id: org._id, _key: org._key, id: org._key, _rev: org._rev, _type: "verifiedOrganization", verified: org.verified, policies: org.policies, domainCount: COUNT(domains), summaries: org.latestSummaryId ? DOCUMENT(org.latestSummaryId) : null }, TRANSLATE("en", org.orgDetails)) - ` - const expectedOrg = await expectedCursor.next() - - const loader = loadVerifiedOrgBySlug({ query, language: 'en', i18n }) - const org = await loader.load(expectedOrg.slug) - - expect(org).toEqual(expectedOrg) - }) - }) - describe('provided a list of slugs', () => { - it('returns a list of orgs', async () => { - const orgSlugs = [] - const expectedOrgs = [] - const expectedCursor = await query` - FOR org IN organizations - LET domains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - RETURN MERGE({ _id: org._id, _key: org._key, id: org._key, _rev: org._rev, _type: "verifiedOrganization", verified: org.verified, policies: org.policies, domainCount: COUNT(domains), summaries: org.latestSummaryId ? DOCUMENT(org.latestSummaryId) : null }, TRANSLATE("en", org.orgDetails)) - ` - - while (expectedCursor.hasMore) { - const tempOrg = await expectedCursor.next() - orgSlugs.push(tempOrg.slug) - expectedOrgs.push(tempOrg) - } - - const loader = loadVerifiedOrgBySlug({ query, language: 'en', i18n }) - const orgs = await loader.loadMany(orgSlugs) - expect(orgs).toEqual(expectedOrgs) - }) - }) - }) - describe('language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('provided a single slug', () => { - it('returns a single org', async () => { - // Get Org From db - const expectedCursor = await query` - FOR org IN organizations - FILTER org.orgDetails.fr.slug == "centre-de-la-securite-des-telecommunications" - LET domains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - RETURN MERGE({ _id: org._id, _key: org._key, id: org._key, _rev: org._rev, _type: "verifiedOrganization", verified: org.verified, policies: org.policies, domainCount: COUNT(domains), summaries: org.latestSummaryId ? DOCUMENT(org.latestSummaryId) : null }, TRANSLATE("fr", org.orgDetails)) - ` - const expectedOrg = await expectedCursor.next() - - const loader = loadVerifiedOrgBySlug({ query, language: 'fr', i18n }) - const org = await loader.load(expectedOrg.slug) - - expect(org).toEqual(expectedOrg) - }) - }) - describe('provided a list of slugs', () => { - it('returns a list of orgs', async () => { - const orgSlugs = [] - const expectedOrgs = [] - const expectedCursor = await query` - FOR org IN organizations - LET domains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - RETURN MERGE({ _id: org._id, _key: org._key, id: org._key, _rev: org._rev, _type: "verifiedOrganization", verified: org.verified, policies: org.policies, domainCount: COUNT(domains), summaries: org.latestSummaryId ? DOCUMENT(org.latestSummaryId) : null }, TRANSLATE("fr", org.orgDetails)) - ` - - while (expectedCursor.hasMore) { - const tempOrg = await expectedCursor.next() - orgSlugs.push(tempOrg.slug) - expectedOrgs.push(tempOrg) - } - - const loader = loadVerifiedOrgBySlug({ query, language: 'fr', i18n }) - const orgs = await loader.loadMany(orgSlugs) - expect(orgs).toEqual(expectedOrgs) - }) - }) - }) - }) - describe('given an unsuccessful load', () => { - describe('language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('database error is raised', () => { - it('returns an error', async () => { - const mockedQuery = jest.fn().mockRejectedValue(new Error('Database error occurred.')) - const loader = loadVerifiedOrgBySlug({ - query: mockedQuery, - language: 'en', - i18n, - }) - - try { - await loader.load('slug') - } catch (err) { - expect(err).toEqual(new Error('Unable to find verified organization(s). Please try again.')) - } - - expect(consoleOutput).toEqual([ - `Database error when running loadVerifiedOrgBySlug: Error: Database error occurred.`, - ]) - }) - }) - describe('cursor error is raised', () => { - it('returns an error', async () => { - const cursor = { - forEach() { - throw new Error('Cursor error occurred.') - }, - } - const mockedQuery = jest.fn().mockReturnValue(cursor) - const loader = loadVerifiedOrgBySlug({ - query: mockedQuery, - language: 'en', - i18n, - }) - - try { - await loader.load('slug') - } catch (err) { - expect(err).toEqual(new Error('Unable to find verified organization(s). Please try again.')) - } - - expect(consoleOutput).toEqual([`Cursor error during loadVerifiedOrgBySlug: Error: Cursor error occurred.`]) - }) - }) - }) - describe('language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('database error is raised', () => { - it('returns an error', async () => { - const mockedQuery = jest.fn().mockRejectedValue(new Error('Database error occurred.')) - const loader = loadVerifiedOrgBySlug({ - query: mockedQuery, - language: 'fr', - i18n, - }) - - try { - await loader.load('slug') - } catch (err) { - expect(err).toEqual( - new Error('Impossible de trouver une ou plusieurs organisations vérifiées. Veuillez réessayer.'), - ) - } - - expect(consoleOutput).toEqual([ - `Database error when running loadVerifiedOrgBySlug: Error: Database error occurred.`, - ]) - }) - }) - describe('cursor error is raised', () => { - it('returns an error', async () => { - const cursor = { - forEach() { - throw new Error('Cursor error occurred.') - }, - } - const mockedQuery = jest.fn().mockReturnValue(cursor) - const loader = loadVerifiedOrgBySlug({ - query: mockedQuery, - language: 'fr', - i18n, - }) - - try { - await loader.load('slug') - } catch (err) { - expect(err).toEqual( - new Error('Impossible de trouver une ou plusieurs organisations vérifiées. Veuillez réessayer.'), - ) - } - - expect(consoleOutput).toEqual([`Cursor error during loadVerifiedOrgBySlug: Error: Cursor error occurred.`]) - }) - }) - }) - }) -}) diff --git a/api/src/verified-organizations/loaders/index.js b/api/src/verified-organizations/loaders/index.js deleted file mode 100644 index ce09e3dcc2..0000000000 --- a/api/src/verified-organizations/loaders/index.js +++ /dev/null @@ -1,4 +0,0 @@ -export * from './load-verified-organization-by-key' -export * from './load-verified-organization-by-slug' -export * from './load-verified-organization-connections-by-domain-id' -export * from './load-verified-organizations-connections' diff --git a/api/src/verified-organizations/loaders/load-verified-organization-by-key.js b/api/src/verified-organizations/loaders/load-verified-organization-by-key.js deleted file mode 100644 index 161ef72d55..0000000000 --- a/api/src/verified-organizations/loaders/load-verified-organization-by-key.js +++ /dev/null @@ -1,50 +0,0 @@ -import DataLoader from 'dataloader' -import { t } from '@lingui/macro' - -export const loadVerifiedOrgByKey = ({ query, language, i18n }) => - new DataLoader(async (keys) => { - let cursor - - try { - cursor = await query` - WITH claims, domains, organizations - FOR org IN organizations - FILTER org._key IN ${keys} - FILTER org.verified == true - LET orgDomains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - RETURN MERGE( - { - _id: org._id, - _key: org._key, - id: org._key, - _rev: org._rev, - _type: "verifiedOrganization", - verified: org.verified, - domainCount: COUNT(orgDomains), - policies: org.policies, - summaries: org.latestSummaryId ? DOCUMENT(org.latestSummaryId) : null - }, - TRANSLATE(${language}, org.orgDetails) - ) - ` - } catch (err) { - console.error(`Database error when running loadVerifiedOrgByKey: ${err}`) - throw new Error( - i18n._(t`Unable to find verified organization(s). Please try again.`), - ) - } - - const orgMap = {} - try { - await cursor.forEach((org) => { - orgMap[org._key] = org - }) - } catch (err) { - console.error(`Cursor error occurred during loadVerifiedOrgByKey: ${err}`) - throw new Error( - i18n._(t`Unable to find verified organization(s). Please try again.`), - ) - } - - return keys.map((id) => orgMap[id]) - }) diff --git a/api/src/verified-organizations/loaders/load-verified-organization-by-slug.js b/api/src/verified-organizations/loaders/load-verified-organization-by-slug.js deleted file mode 100644 index da45a45f0c..0000000000 --- a/api/src/verified-organizations/loaders/load-verified-organization-by-slug.js +++ /dev/null @@ -1,50 +0,0 @@ -import DataLoader from 'dataloader' -import { t } from '@lingui/macro' - -export const loadVerifiedOrgBySlug = ({ query, language, i18n }) => - new DataLoader(async (slugs) => { - let cursor - - try { - cursor = await query` - WITH claims, domains, organizations - FOR org IN organizations - FILTER TRANSLATE(${language}, org.orgDetails).slug IN ${slugs} - FILTER org.verified == true - LET orgDomains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - RETURN MERGE( - { - _id: org._id, - _key: org._key, - id: org._key, - _rev: org._rev, - _type: "verifiedOrganization", - verified: org.verified, - domainCount: COUNT(orgDomains), - policies: org.policies, - summaries: org.latestSummaryId ? DOCUMENT(org.latestSummaryId) : null - }, - TRANSLATE(${language}, org.orgDetails) - ) - ` - } catch (err) { - console.error(`Database error when running loadVerifiedOrgBySlug: ${err}`) - throw new Error( - i18n._(t`Unable to find verified organization(s). Please try again.`), - ) - } - - const orgMap = {} - try { - await cursor.forEach((org) => { - orgMap[org.slug] = org - }) - } catch (err) { - console.error(`Cursor error during loadVerifiedOrgBySlug: ${err}`) - throw new Error( - i18n._(t`Unable to find verified organization(s). Please try again.`), - ) - } - - return slugs.map((slug) => orgMap[slug]) - }) diff --git a/api/src/verified-organizations/loaders/load-verified-organization-connections-by-domain-id.js b/api/src/verified-organizations/loaders/load-verified-organization-connections-by-domain-id.js deleted file mode 100644 index 8f9f394152..0000000000 --- a/api/src/verified-organizations/loaders/load-verified-organization-connections-by-domain-id.js +++ /dev/null @@ -1,473 +0,0 @@ -import { aql } from 'arangojs' -import { fromGlobalId, toGlobalId } from 'graphql-relay' -import { t } from '@lingui/macro' - -export const loadVerifiedOrgConnectionsByDomainId = - ({ query, language, cleanseInput, i18n }) => - async ({ domainId, after, before, first, last, orderBy }) => { - let afterTemplate = aql`` - let afterVar = aql`` - if (typeof after !== 'undefined') { - const { id: afterId } = fromGlobalId(cleanseInput(after)) - if (typeof orderBy === 'undefined') { - afterTemplate = aql`FILTER TO_NUMBER(org._key) > TO_NUMBER(${afterId})` - } else { - let afterTemplateDirection = aql`<` - if (orderBy.direction === 'ASC') { - afterTemplateDirection = aql`>` - } - - afterVar = aql`LET afterVar = DOCUMENT(organizations, ${afterId})` - - let documentField = aql`` - let orgField = aql`` - /* istanbul ignore else */ - if (orderBy.field === 'acronym') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).acronym` - orgField = aql`TRANSLATE(${language}, org.orgDetails).acronym` - } else if (orderBy.field === 'name') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).name` - orgField = aql`TRANSLATE(${language}, org.orgDetails).name` - } else if (orderBy.field === 'slug') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).slug` - orgField = aql`TRANSLATE(${language}, org.orgDetails).slug` - } else if (orderBy.field === 'zone') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).zone` - orgField = aql`TRANSLATE(${language}, org.orgDetails).zone` - } else if (orderBy.field === 'sector') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).sector` - orgField = aql`TRANSLATE(${language}, org.orgDetails).sector` - } else if (orderBy.field === 'country') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).country` - orgField = aql`TRANSLATE(${language}, org.orgDetails).country` - } else if (orderBy.field === 'province') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).province` - orgField = aql`TRANSLATE(${language}, org.orgDetails).province` - } else if (orderBy.field === 'city') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).city` - orgField = aql`TRANSLATE(${language}, org.orgDetails).city` - } else if (orderBy.field === 'verified') { - documentField = aql`afterVar.verified` - orgField = aql`org.verified` - } else if (orderBy.field === 'summary-mail-pass') { - documentField = aql`DOCUMENT(afterVar.latestSummaryId).mail.pass` - orgField = aql`DOCUMENT(org.latestSummaryId).mail.pass` - } else if (orderBy.field === 'summary-mail-fail') { - documentField = aql`DOCUMENT(afterVar.latestSummaryId).mail.fail` - orgField = aql`DOCUMENT(org.latestSummaryId).mail.fail` - } else if (orderBy.field === 'summary-mail-total') { - documentField = aql`DOCUMENT(afterVar.latestSummaryId).mail.total` - orgField = aql`DOCUMENT(org.latestSummaryId).mail.total` - } else if (orderBy.field === 'summary-web-pass') { - documentField = aql`DOCUMENT(afterVar.latestSummaryId).web.pass` - orgField = aql`DOCUMENT(org.latestSummaryId).web.pass` - } else if (orderBy.field === 'summary-web-fail') { - documentField = aql`DOCUMENT(afterVar.latestSummaryId).web.fail` - orgField = aql`DOCUMENT(org.latestSummaryId).web.fail` - } else if (orderBy.field === 'summary-web-total') { - documentField = aql`DOCUMENT(afterVar.latestSummaryId).web.total` - orgField = aql`DOCUMENT(org.latestSummaryId).web.total` - } else if (orderBy.field === 'domain-count') { - documentField = aql`COUNT(FOR v, e IN 1..1 OUTBOUND afterVar._id claims RETURN e._to)` - orgField = aql`COUNT(orgDomains)` - } - - afterTemplate = aql` - FILTER ${orgField} ${afterTemplateDirection} ${documentField} - OR (${orgField} == ${documentField} - AND TO_NUMBER(org._key) > TO_NUMBER(${afterId})) - ` - } - } - - let beforeTemplate = aql`` - let beforeVar = aql`` - if (typeof before !== 'undefined') { - const { id: beforeId } = fromGlobalId(cleanseInput(before)) - if (typeof orderBy === 'undefined') { - beforeTemplate = aql`FILTER TO_NUMBER(org._key) < TO_NUMBER(${beforeId})` - } else { - let beforeTemplateDirection = aql`` - if (orderBy.direction === 'ASC') { - beforeTemplateDirection = aql`<` - } else { - beforeTemplateDirection = aql`>` - } - - beforeVar = aql`LET beforeVar = DOCUMENT(organizations, ${beforeId})` - - let documentField = aql`` - let orgField = aql`` - /* istanbul ignore else */ - if (orderBy.field === 'acronym') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).acronym` - orgField = aql`TRANSLATE(${language}, org.orgDetails).acronym` - } else if (orderBy.field === 'name') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).name` - orgField = aql`TRANSLATE(${language}, org.orgDetails).name` - } else if (orderBy.field === 'slug') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).slug` - orgField = aql`TRANSLATE(${language}, org.orgDetails).slug` - } else if (orderBy.field === 'zone') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).zone` - orgField = aql`TRANSLATE(${language}, org.orgDetails).zone` - } else if (orderBy.field === 'sector') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).sector` - orgField = aql`TRANSLATE(${language}, org.orgDetails).sector` - } else if (orderBy.field === 'country') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).country` - orgField = aql`TRANSLATE(${language}, org.orgDetails).country` - } else if (orderBy.field === 'province') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).province` - orgField = aql`TRANSLATE(${language}, org.orgDetails).province` - } else if (orderBy.field === 'city') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).city` - orgField = aql`TRANSLATE(${language}, org.orgDetails).city` - } else if (orderBy.field === 'verified') { - documentField = aql`beforeVar.verified` - orgField = aql`org.verified` - } else if (orderBy.field === 'summary-mail-pass') { - documentField = aql`DOCUMENT(beforeVar.latestSummaryId).mail.pass` - orgField = aql`DOCUMENT(org.latestSummaryId).mail.pass` - } else if (orderBy.field === 'summary-mail-fail') { - documentField = aql`DOCUMENT(beforeVar.latestSummaryId).mail.fail` - orgField = aql`DOCUMENT(org.latestSummaryId).mail.fail` - } else if (orderBy.field === 'summary-mail-total') { - documentField = aql`DOCUMENT(beforeVar.latestSummaryId).mail.total` - orgField = aql`DOCUMENT(org.latestSummaryId).mail.total` - } else if (orderBy.field === 'summary-web-pass') { - documentField = aql`DOCUMENT(beforeVar.latestSummaryId).web.pass` - orgField = aql`DOCUMENT(org.latestSummaryId).web.pass` - } else if (orderBy.field === 'summary-web-fail') { - documentField = aql`DOCUMENT(beforeVar.latestSummaryId).web.fail` - orgField = aql`DOCUMENT(org.latestSummaryId).web.fail` - } else if (orderBy.field === 'summary-web-total') { - documentField = aql`DOCUMENT(beforeVar.latestSummaryId).web.total` - orgField = aql`DOCUMENT(org.latestSummaryId).web.total` - } else if (orderBy.field === 'domain-count') { - documentField = aql`COUNT(FOR v, e IN 1..1 OUTBOUND beforeVar._id claims RETURN e._to)` - orgField = aql`COUNT(orgDomains)` - } - - beforeTemplate = aql` - FILTER ${orgField} ${beforeTemplateDirection} ${documentField} - OR (${orgField} == ${documentField} - AND TO_NUMBER(org._key) < TO_NUMBER(${beforeId})) - ` - } - } - - let limitTemplate = aql`` - if (typeof first === 'undefined' && typeof last === 'undefined') { - console.warn( - `User did not have either \`first\` or \`last\` arguments set for: loadVerifiedOrgConnectionsByDomainId.`, - ) - throw new Error( - i18n._( - t`You must provide a \`first\` or \`last\` value to properly paginate the \`VerifiedOrganization\` connection.`, - ), - ) - } else if (typeof first !== 'undefined' && typeof last !== 'undefined') { - console.warn( - `User attempted to have \`first\` and \`last\` arguments set for: loadVerifiedOrgConnectionsByDomainId.`, - ) - throw new Error( - i18n._( - t`Passing both \`first\` and \`last\` to paginate the \`VerifiedOrganization\` connection is not supported.`, - ), - ) - } else if (typeof first === 'number' || typeof last === 'number') { - /* istanbul ignore else */ - if (first < 0 || last < 0) { - const argSet = typeof first !== 'undefined' ? 'first' : 'last' - console.warn( - `User attempted to have \`${argSet}\` set below zero for: loadVerifiedOrgConnectionsByDomainId.`, - ) - throw new Error( - i18n._( - t`\`${argSet}\` on the \`VerifiedOrganization\` connection cannot be less than zero.`, - ), - ) - } else if (first > 100 || last > 100) { - const argSet = typeof first !== 'undefined' ? 'first' : 'last' - const amount = typeof first !== 'undefined' ? first : last - console.warn( - `User attempted to have \`${argSet}\` to ${amount} for: loadVerifiedOrgConnectionsByDomainId.`, - ) - throw new Error( - i18n._( - t`Requesting \`${amount}\` records on the \`VerifiedOrganization\` connection exceeds the \`${argSet}\` limit of 100 records.`, - ), - ) - } else if (typeof first !== 'undefined' && typeof last === 'undefined') { - limitTemplate = aql`TO_NUMBER(org._key) ASC LIMIT TO_NUMBER(${first})` - } else if (typeof first === 'undefined' && typeof last !== 'undefined') { - limitTemplate = aql`TO_NUMBER(org._key) DESC LIMIT TO_NUMBER(${last})` - } - } else { - const argSet = typeof first !== 'undefined' ? 'first' : 'last' - const typeSet = typeof first !== 'undefined' ? typeof first : typeof last - console.warn( - `User attempted to have \`${argSet}\` set as a ${typeSet} for: loadVerifiedOrgConnectionsByDomainId.`, - ) - throw new Error( - i18n._(t`\`${argSet}\` must be of type \`number\` not \`${typeSet}\`.`), - ) - } - - let hasNextPageFilter = aql`FILTER TO_NUMBER(org._key) > TO_NUMBER(LAST(retrievedOrgs)._key)` - let hasPreviousPageFilter = aql`FILTER TO_NUMBER(org._key) < TO_NUMBER(FIRST(retrievedOrgs)._key)` - if (typeof orderBy !== 'undefined') { - let hasNextPageDirection = aql`<` - let hasPreviousPageDirection = aql`>` - if (orderBy.direction === 'ASC') { - hasNextPageDirection = aql`>` - hasPreviousPageDirection = aql`<` - } - - let orgField = aql`` - let hasNextPageDocumentField = aql`` - let hasPreviousPageDocumentField = aql`` - /* istanbul ignore else */ - if (orderBy.field === 'acronym') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).acronym` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).acronym` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).acronym` - } else if (orderBy.field === 'name') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).name` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).name` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).name` - } else if (orderBy.field === 'slug') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).slug` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).slug` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).slug` - } else if (orderBy.field === 'zone') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).zone` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).zone` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).zone` - } else if (orderBy.field === 'sector') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).sector` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).sector` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).sector` - } else if (orderBy.field === 'country') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).country` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).country` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).country` - } else if (orderBy.field === 'province') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).province` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).province` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).province` - } else if (orderBy.field === 'city') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).city` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).city` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).city` - } else if (orderBy.field === 'verified') { - orgField = aql`org.verified` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).verified` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).verified` - } else if (orderBy.field === 'summary-mail-pass') { - orgField = aql`DOCUMENT(org.latestSummaryId).mail.pass` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).summaries.mail.pass` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).summaries.mail.pass` - } else if (orderBy.field === 'summary-mail-fail') { - orgField = aql`DOCUMENT(org.latestSummaryId).mail.fail` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).summaries.mail.fail` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).summaries.mail.fail` - } else if (orderBy.field === 'summary-mail-total') { - orgField = aql`DOCUMENT(org.latestSummaryId).mail.total` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).summaries.mail.total` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).summaries.mail.total` - } else if (orderBy.field === 'summary-web-pass') { - orgField = aql`DOCUMENT(org.latestSummaryId).web.pass` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).summaries.web.pass` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).summaries.web.pass` - } else if (orderBy.field === 'summary-web-fail') { - orgField = aql`DOCUMENT(org.latestSummaryId).web.fail` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).summaries.web.fail` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).summaries.web.fail` - } else if (orderBy.field === 'summary-web-total') { - orgField = aql`DOCUMENT(org.latestSummaryId).web.total` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).summaries.web.total` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).summaries.web.total` - } else if (orderBy.field === 'domain-count') { - orgField = aql`COUNT(domains)` - hasNextPageDocumentField = aql`COUNT(FOR v, e IN 1..1 OUTBOUND LAST(retrievedOrgs)._id claims RETURN e._to)` - hasPreviousPageDocumentField = aql`COUNT(FOR v, e IN 1..1 OUTBOUND FIRST(retrievedOrgs)._id claims RETURN e._to)` - } - - hasNextPageFilter = aql` - FILTER ${orgField} ${hasNextPageDirection} ${hasNextPageDocumentField} - OR (${orgField} == ${hasNextPageDocumentField} - AND TO_NUMBER(org._key) > TO_NUMBER(FIRST(retrievedOrgs)._key)) - ` - hasPreviousPageFilter = aql` - FILTER ${orgField} ${hasPreviousPageDirection} ${hasPreviousPageDocumentField} - OR (${orgField} == ${hasPreviousPageDocumentField} - AND TO_NUMBER(org._key) < TO_NUMBER(FIRST(retrievedOrgs)._key)) - ` - } - - let sortByField = aql`` - if (typeof orderBy !== 'undefined') { - /* istanbul ignore else */ - if (orderBy.field === 'acronym') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).acronym ${orderBy.direction},` - } else if (orderBy.field === 'name') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).name ${orderBy.direction},` - } else if (orderBy.field === 'slug') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).slug ${orderBy.direction},` - } else if (orderBy.field === 'zone') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).zone ${orderBy.direction},` - } else if (orderBy.field === 'sector') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).sector ${orderBy.direction},` - } else if (orderBy.field === 'country') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).country ${orderBy.direction},` - } else if (orderBy.field === 'province') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).province ${orderBy.direction},` - } else if (orderBy.field === 'city') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).city ${orderBy.direction},` - } else if (orderBy.field === 'verified') { - sortByField = aql`org.verified ${orderBy.direction},` - } else if (orderBy.field === 'summary-mail-pass') { - sortByField = aql`DOCUMENT(org.latestSummaryId).mail.pass ${orderBy.direction},` - } else if (orderBy.field === 'summary-mail-fail') { - sortByField = aql`DOCUMENT(org.latestSummaryId).mail.fail ${orderBy.direction},` - } else if (orderBy.field === 'summary-mail-total') { - sortByField = aql`DOCUMENT(org.latestSummaryId).mail.total ${orderBy.direction},` - } else if (orderBy.field === 'summary-web-pass') { - sortByField = aql`DOCUMENT(org.latestSummaryId).web.pass ${orderBy.direction},` - } else if (orderBy.field === 'summary-web-fail') { - sortByField = aql`DOCUMENT(org.latestSummaryId).web.fail ${orderBy.direction},` - } else if (orderBy.field === 'summary-web-total') { - sortByField = aql`DOCUMENT(org.latestSummaryId).web.total ${orderBy.direction},` - } else if (orderBy.field === 'domain-count') { - sortByField = aql`COUNT(domains) ${orderBy.direction},` - } - } - - let sortString = aql`` - if (typeof last !== 'undefined') { - sortString = aql`DESC` - } else { - sortString = aql`ASC` - } - - let organizationInfoCursor - try { - organizationInfoCursor = await query` - WITH claims, domains, organizations - LET verifiedOrgs = FLATTEN( - FOR v, e IN INBOUND ${domainId} claims FILTER v.verified == true RETURN v._key - ) - - ${afterVar} - ${beforeVar} - - LET retrievedOrgs = ( - FOR org IN organizations - FILTER org._key IN verifiedOrgs - LET orgDomains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - ${afterTemplate} - ${beforeTemplate} - SORT - ${sortByField} - ${limitTemplate} - RETURN MERGE( - { - _id: org._id, - _key: org._key, - id: org._key, - _rev: org._rev, - _type: "verifiedOrganization", - verified: org.verified, - domainCount: COUNT(orgDomains), - policies: org.policies, - summaries: org.latestSummaryId ? DOCUMENT(org.latestSummaryId) : null - }, - TRANSLATE(${language}, org.orgDetails) - ) - ) - - LET hasNextPage = (LENGTH( - FOR org IN organizations - FILTER org._key IN verifiedOrgs - LET domains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - ${hasNextPageFilter} - SORT ${sortByField} TO_NUMBER(org._key) ${sortString} LIMIT 1 - RETURN org - ) > 0 ? true : false) - - LET hasPreviousPage = (LENGTH( - FOR org IN organizations - FILTER org._key IN verifiedOrgs - LET domains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - ${hasPreviousPageFilter} - SORT ${sortByField} TO_NUMBER(org._key) ${sortString} LIMIT 1 - RETURN org - ) > 0 ? true : false) - - RETURN { - "verifiedOrgs": verifiedOrgs, - "organizations": retrievedOrgs, - "totalCount": LENGTH(verifiedOrgs), - "hasNextPage": hasNextPage, - "hasPreviousPage": hasPreviousPage, - "startKey": FIRST(retrievedOrgs)._key, - "endKey": LAST(retrievedOrgs)._key - } - ` - } catch (err) { - console.error( - `Database error occurred while user was trying to gather orgs in loadVerifiedOrgConnectionsByDomainId, error: ${err}`, - ) - throw new Error( - i18n._(t`Unable to load verified organization(s). Please try again.`), - ) - } - - let organizationInfo - try { - organizationInfo = await organizationInfoCursor.next() - } catch (err) { - console.error( - `Cursor error occurred while user was trying to gather orgs in loadVerifiedOrgConnectionsByDomainId, error: ${err}`, - ) - throw new Error( - i18n._(t`Unable to load verified organization(s). Please try again.`), - ) - } - - if (organizationInfo.organizations.length === 0) { - return { - edges: [], - totalCount: 0, - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - endCursor: '', - }, - } - } - - const edges = organizationInfo.organizations.map((organization) => { - return { - cursor: toGlobalId('verifiedOrganization', organization._key), - node: organization, - } - }) - - return { - edges, - totalCount: organizationInfo.totalCount, - pageInfo: { - hasNextPage: organizationInfo.hasNextPage, - hasPreviousPage: organizationInfo.hasPreviousPage, - startCursor: toGlobalId( - 'verifiedOrganization', - organizationInfo.startKey, - ), - endCursor: toGlobalId('verifiedOrganization', organizationInfo.endKey), - }, - } - } diff --git a/api/src/verified-organizations/loaders/load-verified-organizations-connections.js b/api/src/verified-organizations/loaders/load-verified-organizations-connections.js deleted file mode 100644 index 5891d0f52b..0000000000 --- a/api/src/verified-organizations/loaders/load-verified-organizations-connections.js +++ /dev/null @@ -1,472 +0,0 @@ -import { aql } from 'arangojs' -import { fromGlobalId, toGlobalId } from 'graphql-relay' -import { t } from '@lingui/macro' - -export const loadVerifiedOrgConnections = - ({ query, language, cleanseInput, i18n }) => - async ({ after, before, first, last, orderBy }) => { - let afterTemplate = aql`` - let afterVar = aql`` - if (typeof after !== 'undefined') { - const { id: afterId } = fromGlobalId(cleanseInput(after)) - if (typeof orderBy === 'undefined') { - afterTemplate = aql`FILTER TO_NUMBER(org._key) > TO_NUMBER(${afterId})` - } else { - let afterTemplateDirection = aql`<` - if (orderBy.direction === 'ASC') { - afterTemplateDirection = aql`>` - } - - afterVar = aql`LET afterVar = DOCUMENT(organizations, ${afterId})` - - let documentField = aql`` - let orgField = aql`` - /* istanbul ignore else */ - if (orderBy.field === 'acronym') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).acronym` - orgField = aql`TRANSLATE(${language}, org.orgDetails).acronym` - } else if (orderBy.field === 'name') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).name` - orgField = aql`TRANSLATE(${language}, org.orgDetails).name` - } else if (orderBy.field === 'slug') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).slug` - orgField = aql`TRANSLATE(${language}, org.orgDetails).slug` - } else if (orderBy.field === 'zone') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).zone` - orgField = aql`TRANSLATE(${language}, org.orgDetails).zone` - } else if (orderBy.field === 'sector') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).sector` - orgField = aql`TRANSLATE(${language}, org.orgDetails).sector` - } else if (orderBy.field === 'country') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).country` - orgField = aql`TRANSLATE(${language}, org.orgDetails).country` - } else if (orderBy.field === 'province') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).province` - orgField = aql`TRANSLATE(${language}, org.orgDetails).province` - } else if (orderBy.field === 'city') { - documentField = aql`TRANSLATE(${language}, afterVar.orgDetails).city` - orgField = aql`TRANSLATE(${language}, org.orgDetails).city` - } else if (orderBy.field === 'verified') { - documentField = aql`afterVar.verified` - orgField = aql`org.verified` - } else if (orderBy.field === 'summary-mail-pass') { - documentField = aql`DOCUMENT(afterVar.latestSummaryId).mail.pass` - orgField = aql`DOCUMENT(org.latestSummaryId).mail.pass` - } else if (orderBy.field === 'summary-mail-fail') { - documentField = aql`DOCUMENT(afterVar.latestSummaryId).mail.fail` - orgField = aql`DOCUMENT(org.latestSummaryId).mail.fail` - } else if (orderBy.field === 'summary-mail-total') { - documentField = aql`DOCUMENT(afterVar.latestSummaryId).mail.total` - orgField = aql`DOCUMENT(org.latestSummaryId).mail.total` - } else if (orderBy.field === 'summary-web-pass') { - documentField = aql`DOCUMENT(afterVar.latestSummaryId).web.pass` - orgField = aql`DOCUMENT(org.latestSummaryId).web.pass` - } else if (orderBy.field === 'summary-web-fail') { - documentField = aql`DOCUMENT(afterVar.latestSummaryId).web.fail` - orgField = aql`DOCUMENT(org.latestSummaryId).web.fail` - } else if (orderBy.field === 'summary-web-total') { - documentField = aql`DOCUMENT(afterVar.latestSummaryId).web.total` - orgField = aql`DOCUMENT(org.latestSummaryId).web.total` - } else if (orderBy.field === 'domain-count') { - documentField = aql`COUNT(FOR v, e IN 1..1 OUTBOUND afterVar._id claims RETURN e._to)` - orgField = aql`COUNT(orgDomains)` - } - - afterTemplate = aql` - FILTER ${orgField} ${afterTemplateDirection} ${documentField} - OR (${orgField} == ${documentField} - AND TO_NUMBER(org._key) > TO_NUMBER(${afterId})) - ` - } - } - - let beforeTemplate = aql`` - let beforeVar = aql`` - if (typeof before !== 'undefined') { - const { id: beforeId } = fromGlobalId(cleanseInput(before)) - if (typeof orderBy === 'undefined') { - beforeTemplate = aql`FILTER TO_NUMBER(org._key) < TO_NUMBER(${beforeId})` - } else { - let beforeTemplateDirection = aql`>` - if (orderBy.direction === 'ASC') { - beforeTemplateDirection = aql`<` - } - - beforeVar = aql`LET beforeVar = DOCUMENT(organizations, ${beforeId})` - - let documentField = aql`` - let orgField = aql`` - /* istanbul ignore else */ - if (orderBy.field === 'acronym') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).acronym` - orgField = aql`TRANSLATE(${language}, org.orgDetails).acronym` - } else if (orderBy.field === 'name') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).name` - orgField = aql`TRANSLATE(${language}, org.orgDetails).name` - } else if (orderBy.field === 'slug') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).slug` - orgField = aql`TRANSLATE(${language}, org.orgDetails).slug` - } else if (orderBy.field === 'zone') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).zone` - orgField = aql`TRANSLATE(${language}, org.orgDetails).zone` - } else if (orderBy.field === 'sector') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).sector` - orgField = aql`TRANSLATE(${language}, org.orgDetails).sector` - } else if (orderBy.field === 'country') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).country` - orgField = aql`TRANSLATE(${language}, org.orgDetails).country` - } else if (orderBy.field === 'province') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).province` - orgField = aql`TRANSLATE(${language}, org.orgDetails).province` - } else if (orderBy.field === 'city') { - documentField = aql`TRANSLATE(${language}, beforeVar.orgDetails).city` - orgField = aql`TRANSLATE(${language}, org.orgDetails).city` - } else if (orderBy.field === 'verified') { - documentField = aql`beforeVar.verified` - orgField = aql`org.verified` - } else if (orderBy.field === 'summary-mail-pass') { - documentField = aql`DOCUMENT(beforeVar.latestSummaryId).mail.pass` - orgField = aql`DOCUMENT(org.latestSummaryId).mail.pass` - } else if (orderBy.field === 'summary-mail-fail') { - documentField = aql`DOCUMENT(beforeVar.latestSummaryId).mail.fail` - orgField = aql`DOCUMENT(org.latestSummaryId).mail.fail` - } else if (orderBy.field === 'summary-mail-total') { - documentField = aql`DOCUMENT(beforeVar.latestSummaryId).mail.total` - orgField = aql`DOCUMENT(org.latestSummaryId).mail.total` - } else if (orderBy.field === 'summary-web-pass') { - documentField = aql`DOCUMENT(beforeVar.latestSummaryId).web.pass` - orgField = aql`DOCUMENT(org.latestSummaryId).web.pass` - } else if (orderBy.field === 'summary-web-fail') { - documentField = aql`DOCUMENT(beforeVar.latestSummaryId).web.fail` - orgField = aql`DOCUMENT(org.latestSummaryId).web.fail` - } else if (orderBy.field === 'summary-web-total') { - documentField = aql`DOCUMENT(beforeVar.latestSummaryId).web.total` - orgField = aql`DOCUMENT(org.latestSummaryId).web.total` - } else if (orderBy.field === 'domain-count') { - documentField = aql`COUNT(FOR v, e IN 1..1 OUTBOUND beforeVar._id claims RETURN e._to)` - orgField = aql`COUNT(orgDomains)` - } - - beforeTemplate = aql` - FILTER ${orgField} ${beforeTemplateDirection} ${documentField} - OR (${orgField} == ${documentField} - AND TO_NUMBER(org._key) < TO_NUMBER(${beforeId})) - ` - } - } - - let limitTemplate = aql`` - if (typeof first === 'undefined' && typeof last === 'undefined') { - console.warn( - `User did not have either \`first\` or \`last\` arguments set for: loadVerifiedOrgConnections.`, - ) - throw new Error( - i18n._( - t`You must provide a \`first\` or \`last\` value to properly paginate the \`VerifiedOrganization\` connection.`, - ), - ) - } else if (typeof first !== 'undefined' && typeof last !== 'undefined') { - console.warn( - `User attempted to have \`first\` and \`last\` arguments set for: loadVerifiedOrgConnections.`, - ) - throw new Error( - i18n._( - t`Passing both \`first\` and \`last\` to paginate the \`VerifiedOrganization\` connection is not supported.`, - ), - ) - } else if (typeof first === 'number' || typeof last === 'number') { - /* istanbul ignore else */ - if (first < 0 || last < 0) { - const argSet = typeof first !== 'undefined' ? 'first' : 'last' - console.warn( - `User attempted to have \`${argSet}\` set below zero for: loadVerifiedOrgConnections.`, - ) - throw new Error( - i18n._( - t`\`${argSet}\` on the \`VerifiedOrganization\` connection cannot be less than zero.`, - ), - ) - } else if (first > 100 || last > 100) { - const argSet = typeof first !== 'undefined' ? 'first' : 'last' - const amount = typeof first !== 'undefined' ? first : last - console.warn( - `User attempted to have \`${argSet}\` to ${amount} for: loadVerifiedOrgConnections.`, - ) - throw new Error( - i18n._( - t`Requesting \`${amount}\` records on the \`VerifiedOrganization\` connection exceeds the \`${argSet}\` limit of 100 records.`, - ), - ) - } else if (typeof first !== 'undefined' && typeof last === 'undefined') { - limitTemplate = aql`TO_NUMBER(org._key) ASC LIMIT TO_NUMBER(${first})` - } else if (typeof first === 'undefined' && typeof last !== 'undefined') { - limitTemplate = aql`TO_NUMBER(org._key) DESC LIMIT TO_NUMBER(${last})` - } - } else { - const argSet = typeof first !== 'undefined' ? 'first' : 'last' - const typeSet = typeof first !== 'undefined' ? typeof first : typeof last - console.warn( - `User attempted to have \`${argSet}\` set as a ${typeSet} for: loadVerifiedOrgConnections.`, - ) - throw new Error( - i18n._(t`\`${argSet}\` must be of type \`number\` not \`${typeSet}\`.`), - ) - } - - let hasNextPageFilter = aql`FILTER TO_NUMBER(org._key) > TO_NUMBER(LAST(retrievedOrgs)._key)` - let hasPreviousPageFilter = aql`FILTER TO_NUMBER(org._key) < TO_NUMBER(FIRST(retrievedOrgs)._key)` - if (typeof orderBy !== 'undefined') { - let hasNextPageDirection = aql`<` - let hasPreviousPageDirection = aql`>` - if (orderBy.direction === 'ASC') { - hasNextPageDirection = aql`>` - hasPreviousPageDirection = aql`<` - } - - let orgField = aql`` - let hasNextPageDocumentField = aql`` - let hasPreviousPageDocumentField = aql`` - /* istanbul ignore else */ - if (orderBy.field === 'acronym') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).acronym` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).acronym` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).acronym` - } else if (orderBy.field === 'name') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).name` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).name` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).name` - } else if (orderBy.field === 'slug') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).slug` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).slug` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).slug` - } else if (orderBy.field === 'zone') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).zone` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).zone` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).zone` - } else if (orderBy.field === 'sector') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).sector` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).sector` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).sector` - } else if (orderBy.field === 'country') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).country` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).country` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).country` - } else if (orderBy.field === 'province') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).province` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).province` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).province` - } else if (orderBy.field === 'city') { - orgField = aql`TRANSLATE(${language}, org.orgDetails).city` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).city` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).city` - } else if (orderBy.field === 'verified') { - orgField = aql`org.verified` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).verified` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).verified` - } else if (orderBy.field === 'summary-mail-pass') { - orgField = aql`DOCUMENT(org.latestSummaryId).mail.pass` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).summaries.mail.pass` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).summaries.mail.pass` - } else if (orderBy.field === 'summary-mail-fail') { - orgField = aql`DOCUMENT(org.latestSummaryId).mail.fail` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).summaries.mail.fail` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).summaries.mail.fail` - } else if (orderBy.field === 'summary-mail-total') { - orgField = aql`DOCUMENT(org.latestSummaryId).mail.total` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).summaries.mail.total` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).summaries.mail.total` - } else if (orderBy.field === 'summary-web-pass') { - orgField = aql`DOCUMENT(org.latestSummaryId).web.pass` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).summaries.web.pass` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).summaries.web.pass` - } else if (orderBy.field === 'summary-web-fail') { - orgField = aql`DOCUMENT(org.latestSummaryId).web.fail` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).summaries.web.fail` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).summaries.web.fail` - } else if (orderBy.field === 'summary-web-total') { - orgField = aql`DOCUMENT(org.latestSummaryId).web.total` - hasNextPageDocumentField = aql`LAST(retrievedOrgs).summaries.web.total` - hasPreviousPageDocumentField = aql`FIRST(retrievedOrgs).summaries.web.total` - } else if (orderBy.field === 'domain-count') { - orgField = aql`COUNT(domains)` - hasNextPageDocumentField = aql`COUNT(FOR v, e IN 1..1 OUTBOUND LAST(retrievedOrgs)._id claims RETURN e._to)` - hasPreviousPageDocumentField = aql`COUNT(FOR v, e IN 1..1 OUTBOUND FIRST(retrievedOrgs)._id claims RETURN e._to)` - } - - hasNextPageFilter = aql` - FILTER ${orgField} ${hasNextPageDirection} ${hasNextPageDocumentField} - OR (${orgField} == ${hasNextPageDocumentField} - AND TO_NUMBER(org._key) > TO_NUMBER(LAST(retrievedOrgs)._key)) - ` - hasPreviousPageFilter = aql` - FILTER ${orgField} ${hasPreviousPageDirection} ${hasPreviousPageDocumentField} - OR (${orgField} == ${hasPreviousPageDocumentField} - AND TO_NUMBER(org._key) < TO_NUMBER(FIRST(retrievedOrgs)._key)) - ` - } - - let sortByField = aql`` - if (typeof orderBy !== 'undefined') { - /* istanbul ignore else */ - if (orderBy.field === 'acronym') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).acronym ${orderBy.direction},` - } else if (orderBy.field === 'name') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).name ${orderBy.direction},` - } else if (orderBy.field === 'slug') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).slug ${orderBy.direction},` - } else if (orderBy.field === 'zone') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).zone ${orderBy.direction},` - } else if (orderBy.field === 'sector') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).sector ${orderBy.direction},` - } else if (orderBy.field === 'country') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).country ${orderBy.direction},` - } else if (orderBy.field === 'province') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).province ${orderBy.direction},` - } else if (orderBy.field === 'city') { - sortByField = aql`TRANSLATE(${language}, org.orgDetails).city ${orderBy.direction},` - } else if (orderBy.field === 'verified') { - sortByField = aql`org.verified ${orderBy.direction},` - } else if (orderBy.field === 'summary-mail-pass') { - sortByField = aql`DOCUMENT(org.latestSummaryId).mail.pass ${orderBy.direction},` - } else if (orderBy.field === 'summary-mail-fail') { - sortByField = aql`DOCUMENT(org.latestSummaryId).mail.fail ${orderBy.direction},` - } else if (orderBy.field === 'summary-mail-total') { - sortByField = aql`DOCUMENT(org.latestSummaryId).mail.total ${orderBy.direction},` - } else if (orderBy.field === 'summary-web-pass') { - sortByField = aql`DOCUMENT(org.latestSummaryId).web.pass ${orderBy.direction},` - } else if (orderBy.field === 'summary-web-fail') { - sortByField = aql`DOCUMENT(org.latestSummaryId).web.fail ${orderBy.direction},` - } else if (orderBy.field === 'summary-web-total') { - sortByField = aql`DOCUMENT(org.latestSummaryId).web.total ${orderBy.direction},` - } else if (orderBy.field === 'domain-count') { - sortByField = aql`COUNT(domains) ${orderBy.direction},` - } - } - - let sortString - if (typeof last !== 'undefined') { - sortString = aql`DESC` - } else { - sortString = aql`ASC` - } - - let organizationInfoCursor - try { - organizationInfoCursor = await query` - WITH claims, domains, organizations - LET verifiedOrgs = FLATTEN( - FOR org IN organizations - FILTER org.verified == true - RETURN org._key - ) - - ${afterVar} - ${beforeVar} - - LET retrievedOrgs = ( - FOR org IN organizations - FILTER org._key IN verifiedOrgs - LET orgDomains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - ${afterTemplate} - ${beforeTemplate} - SORT - ${sortByField} - ${limitTemplate} - RETURN MERGE( - { - _id: org._id, - _key: org._key, - id: org._key, - _rev: org._rev, - _type: "verifiedOrganization", - verified: org.verified, - domainCount: COUNT(orgDomains), - policies: org.policies, - summaries: org.latestSummaryId ? DOCUMENT(org.latestSummaryId) : null - }, - TRANSLATE(${language}, org.orgDetails) - ) - ) - - LET hasNextPage = (LENGTH( - FOR org IN organizations - FILTER org._key IN verifiedOrgs - LET domains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - ${hasNextPageFilter} - SORT ${sortByField} TO_NUMBER(org._key) ${sortString} LIMIT 1 - RETURN org - ) > 0 ? true : false) - - LET hasPreviousPage = (LENGTH( - FOR org IN organizations - FILTER org._key IN verifiedOrgs - LET domains = (FOR v, e IN 1..1 OUTBOUND org._id claims RETURN e._to) - ${hasPreviousPageFilter} - SORT ${sortByField} TO_NUMBER(org._key) ${sortString} LIMIT 1 - RETURN org - ) > 0 ? true : false) - - RETURN { - "organizations": retrievedOrgs, - "totalCount": LENGTH(verifiedOrgs), - "hasNextPage": hasNextPage, - "hasPreviousPage": hasPreviousPage, - "startKey": FIRST(retrievedOrgs)._key, - "endKey": LAST(retrievedOrgs)._key - } - ` - } catch (err) { - console.error( - `Database error occurred while user was trying to gather orgs in loadVerifiedOrgConnections, error: ${err}`, - ) - throw new Error( - i18n._(t`Unable to load verified organization(s). Please try again.`), - ) - } - - let organizationInfo - try { - organizationInfo = await organizationInfoCursor.next() - } catch (err) { - console.error( - `Cursor error occurred while user was trying to gather orgs in loadVerifiedOrgConnections, error: ${err}`, - ) - throw new Error( - i18n._(t`Unable to load verified organization(s). Please try again.`), - ) - } - - if (organizationInfo.organizations.length === 0) { - return { - edges: [], - totalCount: 0, - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - endCursor: '', - }, - } - } - - const edges = organizationInfo.organizations.map((organization) => { - return { - cursor: toGlobalId('verifiedOrganization', organization._key), - node: organization, - } - }) - - return { - edges, - totalCount: organizationInfo.totalCount, - pageInfo: { - hasNextPage: organizationInfo.hasNextPage, - hasPreviousPage: organizationInfo.hasPreviousPage, - startCursor: toGlobalId( - 'verifiedOrganization', - organizationInfo.startKey, - ), - endCursor: toGlobalId('verifiedOrganization', organizationInfo.endKey), - }, - } - } diff --git a/api/src/verified-organizations/objects/__tests__/verified-organization-connection.test.js b/api/src/verified-organizations/objects/__tests__/verified-organization-connection.test.js deleted file mode 100644 index 265f06ac79..0000000000 --- a/api/src/verified-organizations/objects/__tests__/verified-organization-connection.test.js +++ /dev/null @@ -1,23 +0,0 @@ -import { GraphQLInt } from 'graphql' -import { verifiedOrganizationConnection } from '../index' - -describe('given the verified organization connection object', () => { - describe('testing its field definitions', () => { - it('has a totalCount field', () => { - const demoType = verifiedOrganizationConnection.connectionType.getFields() - - expect(demoType).toHaveProperty('totalCount') - expect(demoType.totalCount.type).toMatchObject(GraphQLInt) - }) - }) - describe('testing its field resolvers', () => { - describe('testing the totalCount resolver', () => { - it('returns the resolved value', () => { - const demoType = - verifiedOrganizationConnection.connectionType.getFields() - - expect(demoType.totalCount.resolve({ totalCount: 1 })).toEqual(1) - }) - }) - }) -}) diff --git a/api/src/verified-organizations/objects/__tests__/verified-organization.test.js b/api/src/verified-organizations/objects/__tests__/verified-organization.test.js deleted file mode 100644 index a626f92b39..0000000000 --- a/api/src/verified-organizations/objects/__tests__/verified-organization.test.js +++ /dev/null @@ -1,245 +0,0 @@ -import { GraphQLInt, GraphQLBoolean, GraphQLString, GraphQLNonNull, GraphQLID } from 'graphql' -import { toGlobalId } from 'graphql-relay' - -import { verifiedDomainConnection } from '../../../verified-domains/objects' -import { verifiedOrganizationType } from '../index' -import { organizationSummaryType } from '../../../organization/objects' -import { Acronym, Slug } from '../../../scalars' - -describe('given the verified organization object', () => { - describe('testing the field definitions', () => { - it('has an id field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('id') - expect(demoType.id.type).toMatchObject(new GraphQLNonNull(GraphQLID)) - }) - it('has an acronym field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('acronym') - expect(demoType.acronym.type).toMatchObject(Acronym) - }) - it('has a name field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('name') - expect(demoType.name.type).toMatchObject(GraphQLString) - }) - it('has a slug field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('slug') - expect(demoType.slug.type).toMatchObject(Slug) - }) - it('has a zone field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('zone') - expect(demoType.zone.type).toMatchObject(GraphQLString) - }) - it('has a sector field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('sector') - expect(demoType.sector.type).toMatchObject(GraphQLString) - }) - it('has a country field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('country') - expect(demoType.country.type).toMatchObject(GraphQLString) - }) - it('has a province field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('province') - expect(demoType.province.type).toMatchObject(GraphQLString) - }) - it('has a city field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('city') - expect(demoType.city.type).toEqual(GraphQLString) - }) - it('has a verified field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('verified') - expect(demoType.verified.type).toMatchObject(GraphQLBoolean) - }) - it('has a summaries field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('summaries') - expect(demoType.summaries.type).toMatchObject(organizationSummaryType) - }) - it('has a domainCount field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('domainCount') - expect(demoType.domainCount.type).toMatchObject(GraphQLInt) - }) - it('has a domains field', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType).toHaveProperty('domains') - expect(demoType.domains.type).toMatchObject(verifiedDomainConnection.connectionType) - }) - }) - - describe('testing the field resolvers', () => { - describe('testing the id resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType.id.resolve({ id: '1' })).toEqual(toGlobalId('verifiedOrganization', 1)) - }) - }) - describe('testing the acronym resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType.acronym.resolve({ acronym: 'GOC' })).toEqual('GOC') - }) - }) - describe('testing the name resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType.name.resolve({ name: 'Name' })).toEqual('Name') - }) - }) - describe('testing the slug resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType.slug.resolve({ slug: 'organization-name' })).toEqual('organization-name') - }) - }) - describe('testing the zone resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType.zone.resolve({ zone: 'zone' })).toEqual('zone') - }) - }) - describe('testing the sector resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType.sector.resolve({ sector: 'sector' })).toEqual('sector') - }) - }) - describe('testing the country resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType.country.resolve({ country: 'Canada' })).toEqual('Canada') - }) - }) - describe('testing the province resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType.province.resolve({ province: 'province' })).toEqual('province') - }) - }) - describe('testing the city resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType.city.resolve({ city: 'city' })).toEqual('city') - }) - }) - describe('testing the verified resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType.verified.resolve({ verified: true })).toEqual(true) - }) - }) - describe('testing the summaries resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedOrganizationType.getFields() - - const org = { - summaries: { - web: { - pass: 50, - fail: 1000, - total: 1050, - }, - mail: { - pass: 50, - fail: 1000, - total: 1050, - }, - }, - } - - const expectedResult = { - web: { - pass: 50, - fail: 1000, - total: 1050, - }, - mail: { - pass: 50, - fail: 1000, - total: 1050, - }, - } - - expect(demoType.summaries.resolve(org)).toEqual(expectedResult) - }) - }) - describe('testing the domainCount resolver', () => { - it('returns the resolved value', () => { - const demoType = verifiedOrganizationType.getFields() - - expect(demoType.domainCount.resolve({ domainCount: 5 })).toEqual(5) - }) - }) - describe('testing the domains resolver', () => { - it('returns the resolved value', async () => { - const demoType = verifiedOrganizationType.getFields() - - const expectedResult = { - edges: [ - { - cursor: toGlobalId('verifiedDomains', '1'), - node: { - _id: 'domains/1', - _key: '1', - _rev: 'rev', - _type: 'verifiedDomain', - id: '1', - domain: 'test.gc.ca', - }, - }, - ], - totalCount: 1, - pageInfo: { - hasNextPage: false, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedDomains', '1'), - endCursor: toGlobalId('verifiedDomains', '1'), - }, - } - - await expect( - demoType.domains.resolve( - { _id: 'organizations/1' }, - { first: 1 }, - { - loaders: { - loadVerifiedDomainConnectionsByOrgId: jest.fn().mockReturnValue(expectedResult), - }, - }, - ), - ).resolves.toEqual(expectedResult) - }) - }) - }) -}) diff --git a/api/src/verified-organizations/objects/index.js b/api/src/verified-organizations/objects/index.js deleted file mode 100644 index 93ec6305e8..0000000000 --- a/api/src/verified-organizations/objects/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from './verified-organization' -export * from './verified-organization-connection' diff --git a/api/src/verified-organizations/objects/verified-organization-connection.js b/api/src/verified-organizations/objects/verified-organization-connection.js deleted file mode 100644 index c434cb0261..0000000000 --- a/api/src/verified-organizations/objects/verified-organization-connection.js +++ /dev/null @@ -1,16 +0,0 @@ -import { GraphQLInt } from 'graphql' -import { connectionDefinitions } from 'graphql-relay' - -import { verifiedOrganizationType } from './verified-organization' - -export const verifiedOrganizationConnection = connectionDefinitions({ - name: 'VerifiedOrganization', - nodeType: verifiedOrganizationType, - connectionFields: () => ({ - totalCount: { - type: GraphQLInt, - description: 'The total amount of verified organizations.', - resolve: ({ totalCount }) => totalCount, - }, - }), -}) diff --git a/api/src/verified-organizations/objects/verified-organization.js b/api/src/verified-organizations/objects/verified-organization.js deleted file mode 100644 index 9d01497fde..0000000000 --- a/api/src/verified-organizations/objects/verified-organization.js +++ /dev/null @@ -1,101 +0,0 @@ -import { - GraphQLBoolean, - GraphQLInt, - GraphQLObjectType, - GraphQLString, -} from 'graphql' -import { connectionArgs, globalIdField } from 'graphql-relay' - -import { verifiedDomainOrder } from '../../verified-domains/inputs' -import { verifiedDomainConnection } from '../../verified-domains/objects' -import { organizationSummaryType } from '../../organization/objects' -import { Acronym, Slug } from '../../scalars' -import { nodeInterface } from '../../node' - -export const verifiedOrganizationType = new GraphQLObjectType({ - name: 'VerifiedOrganization', - fields: () => ({ - id: globalIdField('verifiedOrganization'), - acronym: { - type: Acronym, - description: 'The organizations acronym.', - resolve: ({ acronym }) => acronym, - }, - name: { - type: GraphQLString, - description: 'The full name of the organization.', - resolve: ({ name }) => name, - }, - slug: { - type: Slug, - description: 'Slugified name of the organization.', - resolve: ({ slug }) => slug, - }, - zone: { - type: GraphQLString, - description: 'The zone which the organization belongs to.', - resolve: ({ zone }) => zone, - }, - sector: { - type: GraphQLString, - description: 'The sector which the organization belongs to.', - resolve: ({ sector }) => sector, - }, - country: { - type: GraphQLString, - description: 'The country in which the organization resides.', - resolve: ({ country }) => country, - }, - province: { - type: GraphQLString, - description: 'The province in which the organization resides.', - resolve: ({ province }) => province, - }, - city: { - type: GraphQLString, - description: 'The city in which the organization resides.', - resolve: ({ city }) => city, - }, - verified: { - type: GraphQLBoolean, - description: 'Whether the organization is a verified organization.', - resolve: ({ verified }) => verified, - }, - summaries: { - type: organizationSummaryType, - description: - 'Summaries based on scan types that are preformed on the given organizations domains.', - resolve: ({ summaries }) => summaries, - }, - domainCount: { - type: GraphQLInt, - description: 'The number of domains associated with this organization.', - resolve: ({ domainCount }) => domainCount, - }, - domains: { - type: verifiedDomainConnection.connectionType, - description: 'The domains which are associated with this organization.', - args: { - orderBy: { - type: verifiedDomainOrder, - description: 'Ordering options for verified domain connections.', - }, - ...connectionArgs, - }, - resolve: async ( - { _id }, - args, - { loaders: { loadVerifiedDomainConnectionsByOrgId } }, - ) => { - const domains = await loadVerifiedDomainConnectionsByOrgId({ - orgId: _id, - ...args, - }) - return domains - }, - }, - }), - interfaces: [nodeInterface], - description: - 'Verified Organization object containing information for a given Organization.', -}) diff --git a/api/src/verified-organizations/queries/__tests__/find-verified-organization-by-slug.test.js b/api/src/verified-organizations/queries/__tests__/find-verified-organization-by-slug.test.js deleted file mode 100644 index c994d08ea4..0000000000 --- a/api/src/verified-organizations/queries/__tests__/find-verified-organization-by-slug.test.js +++ /dev/null @@ -1,316 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema, GraphQLError } from 'graphql' -import { toGlobalId } from 'graphql-relay' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { cleanseInput } from '../../../validators' -import { loadVerifiedDomainConnectionsByOrgId } from '../../../verified-domains/loaders' -import { loadVerifiedOrgBySlug } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given findOrganizationBySlugQuery', () => { - let query, drop, truncate, schema, collections, org, domain, i18n - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - - beforeAll(() => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given a successful query', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - org = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - domain = await collections.domains.save({}) - await collections.claims.save({ - _from: org._id, - _to: domain._id, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('authorized user queries organization by slug', () => { - it('returns organization', async () => { - const response = await graphql({ - schema, - source: ` - query { - findVerifiedOrganizationBySlug( - orgSlug: "treasury-board-secretariat" - ) { - id - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: query, - validators: { - cleanseInput, - }, - loaders: { - loadVerifiedOrgBySlug: loadVerifiedOrgBySlug({ - query, - language: 'en', - i18n, - }), - loadVerifiedDomainConnectionsByOrgId: loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }), - }, - }, - }) - - const expectedResponse = { - data: { - findVerifiedOrganizationBySlug: { - id: toGlobalId('verifiedOrganization', org._key), - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('authorized user queries organization by slug', () => { - it('returns organization', async () => { - const response = await graphql({ - schema, - source: ` - query { - findVerifiedOrganizationBySlug( - orgSlug: "secretariat-conseil-tresor" - ) { - id - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: query, - validators: { - cleanseInput, - }, - loaders: { - loadVerifiedOrgBySlug: loadVerifiedOrgBySlug({ - query, - language: 'fr', - i18n, - }), - loadVerifiedDomainConnectionsByOrgId: loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }), - }, - }, - }) - - const expectedResponse = { - data: { - findVerifiedOrganizationBySlug: { - id: toGlobalId('verifiedOrganization', org._key), - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - }) - }) - - describe('given unsuccessful organization retrieval', () => { - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('organization can not be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - findVerifiedOrganizationBySlug( - orgSlug: "not-treasury-board-secretariat" - ) { - id - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn(), - validators: { - cleanseInput, - }, - loaders: { - loadVerifiedOrgBySlug: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`No verified organization with the provided slug could be found.`)] - - expect(response.errors).toEqual(error) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('organization can not be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - findVerifiedOrganizationBySlug( - orgSlug: "ne-pas-secretariat-conseil-tresor" - ) { - id - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn(), - validators: { - cleanseInput, - }, - loaders: { - loadVerifiedOrgBySlug: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`Aucune organisation vérifiée avec le slug fourni n'a pu être trouvée.`)] - - expect(response.errors).toEqual(error) - }) - }) - }) - }) -}) diff --git a/api/src/verified-organizations/queries/__tests__/find-verified-organizations.test.js b/api/src/verified-organizations/queries/__tests__/find-verified-organizations.test.js deleted file mode 100644 index 2b212ac3d8..0000000000 --- a/api/src/verified-organizations/queries/__tests__/find-verified-organizations.test.js +++ /dev/null @@ -1,409 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema } from 'graphql' -import { toGlobalId } from 'graphql-relay' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { cleanseInput } from '../../../validators' -import { loadVerifiedDomainConnectionsByOrgId } from '../../../verified-domains/loaders' -import { loadVerifiedOrgConnections } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given findVerifiedOrganizations', () => { - let query, drop, truncate, schema, collections, orgOne, orgTwo, i18n - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - - beforeAll(() => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given a successful query', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - orgOne = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - orgTwo = await collections.organizations.save({ - verified: true, - orgDetails: { - en: { - slug: 'not-treasury-board-secretariat', - acronym: 'NTBS', - name: 'Not Treasury Board of Canada Secretariat', - zone: 'NFED', - sector: 'NTBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'ne-pas-secretariat-conseil-tresor', - acronym: 'NPSCT', - name: 'Ne Pas Secrétariat du Conseil Trésor du Canada', - zone: 'NPFED', - sector: 'NPTBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('user queries for verified organizations', () => { - it('returns organizations', async () => { - const response = await graphql({ - schema, - source: ` - query { - findVerifiedOrganizations(first: 5) { - edges { - cursor - node { - id - } - } - totalCount - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadVerifiedOrgConnections: loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }), - loadVerifiedDomainConnectionsByOrgId: loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }), - }, - }, - }) - - const expectedResponse = { - data: { - findVerifiedOrganizations: { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', orgOne._key), - node: { - id: toGlobalId('verifiedOrganization', orgOne._key), - }, - }, - { - cursor: toGlobalId('verifiedOrganization', orgTwo._key), - node: { - id: toGlobalId('verifiedOrganization', orgTwo._key), - }, - }, - ], - totalCount: 2, - pageInfo: { - endCursor: toGlobalId('verifiedOrganization', orgTwo._key), - hasNextPage: false, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedOrganization', orgOne._key), - }, - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - describe('no organizations are found', () => { - it('returns empty connection fields', async () => { - await truncate() - const response = await graphql({ - schema, - source: ` - query { - findVerifiedOrganizations(first: 5) { - edges { - cursor - node { - id - } - } - totalCount - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadVerifiedOrgConnections: loadVerifiedOrgConnections({ - query, - language: 'en', - cleanseInput, - i18n, - }), - loadVerifiedDomainConnectionsByOrgId: loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }), - }, - }, - }) - - const expectedResponse = { - data: { - findVerifiedOrganizations: { - edges: [], - totalCount: 0, - pageInfo: { - endCursor: '', - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - }, - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('user queries for verified organizations', () => { - it('returns organizations', async () => { - const response = await graphql({ - schema, - source: ` - query { - findVerifiedOrganizations(first: 5) { - edges { - cursor - node { - id - } - } - totalCount - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadVerifiedOrgConnections: loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }), - loadVerifiedDomainConnectionsByOrgId: loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }), - }, - }, - }) - - const expectedResponse = { - data: { - findVerifiedOrganizations: { - edges: [ - { - cursor: toGlobalId('verifiedOrganization', orgOne._key), - node: { - id: toGlobalId('verifiedOrganization', orgOne._key), - }, - }, - { - cursor: toGlobalId('verifiedOrganization', orgTwo._key), - node: { - id: toGlobalId('verifiedOrganization', orgTwo._key), - }, - }, - ], - totalCount: 2, - pageInfo: { - endCursor: toGlobalId('verifiedOrganization', orgTwo._key), - hasNextPage: false, - hasPreviousPage: false, - startCursor: toGlobalId('verifiedOrganization', orgOne._key), - }, - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - describe('no organizations are found', () => { - it('returns empty connection fields', async () => { - await truncate() - const response = await graphql({ - schema, - source: ` - query { - findVerifiedOrganizations(first: 5) { - edges { - cursor - node { - id - } - } - totalCount - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadVerifiedOrgConnections: loadVerifiedOrgConnections({ - query, - language: 'fr', - cleanseInput, - i18n, - }), - loadVerifiedDomainConnectionsByOrgId: loadVerifiedDomainConnectionsByOrgId({ - query, - cleanseInput, - i18n, - }), - }, - }, - }) - - const expectedResponse = { - data: { - findVerifiedOrganizations: { - edges: [], - totalCount: 0, - pageInfo: { - endCursor: '', - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - }, - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - }) - }) -}) diff --git a/api/src/verified-organizations/queries/find-verified-organization-by-slug.js b/api/src/verified-organizations/queries/find-verified-organization-by-slug.js deleted file mode 100644 index e45d1ab8a9..0000000000 --- a/api/src/verified-organizations/queries/find-verified-organization-by-slug.js +++ /dev/null @@ -1,29 +0,0 @@ -import { GraphQLNonNull } from 'graphql' -import { t } from '@lingui/macro' -import { Slug } from '../../scalars' -import { verifiedOrganizationType } from '../objects' - -export const findVerifiedOrganizationBySlug = { - type: verifiedOrganizationType, - description: 'Select all information on a selected verified organization.', - args: { - orgSlug: { - type: new GraphQLNonNull(Slug), - description: 'The slugified organization name you want to retrieve data for.', - }, - }, - resolve: async (_, args, { i18n, loaders: { loadVerifiedOrgBySlug }, validators: { cleanseInput } }) => { - // Cleanse input - const orgSlug = cleanseInput(args.orgSlug) - - // Retrieve organization by slug - const org = await loadVerifiedOrgBySlug.load(orgSlug) - - if (typeof org === 'undefined') { - console.warn(`User could not retrieve verified organization.`) - throw new Error(i18n._(t`No verified organization with the provided slug could be found.`)) - } - - return org - }, -} diff --git a/api/src/verified-organizations/queries/find-verified-organizations.js b/api/src/verified-organizations/queries/find-verified-organizations.js deleted file mode 100644 index 2137520ed8..0000000000 --- a/api/src/verified-organizations/queries/find-verified-organizations.js +++ /dev/null @@ -1,20 +0,0 @@ -import { connectionArgs } from 'graphql-relay' - -import { verifiedOrganizationOrder } from '../inputs' -import { verifiedOrganizationConnection } from '../objects' - -export const findVerifiedOrganizations = { - type: verifiedOrganizationConnection.connectionType, - description: 'Select organizations a user has access to.', - args: { - orderBy: { - type: verifiedOrganizationOrder, - description: 'Ordering options for verified organization connections.', - }, - ...connectionArgs, - }, - resolve: async (_, args, { loaders: { loadVerifiedOrgConnections } }) => { - const orgConnections = await loadVerifiedOrgConnections(args) - return orgConnections - }, -} diff --git a/api/src/verified-organizations/queries/index.js b/api/src/verified-organizations/queries/index.js deleted file mode 100644 index f995936874..0000000000 --- a/api/src/verified-organizations/queries/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from './find-verified-organization-by-slug' -export * from './find-verified-organizations'