diff --git a/src/controllers/organization.controller.js b/src/controllers/organization.controller.js index f5197e25..3c354067 100644 --- a/src/controllers/organization.controller.js +++ b/src/controllers/organization.controller.js @@ -8,6 +8,7 @@ import { assertIfReadOnlyMode, assertCanDeleteOrg, assertNoPendingCommits, + assertOrgDoesNotExist, } from '../utils/data-assertions'; import { getDataModelVersion } from '../utils/helpers'; @@ -181,12 +182,13 @@ export const resetHomeOrg = async (req, res) => { ]); res.json({ - message: 'Your home organization was reset, please create a new one.', + message: + 'Your home organization was deleted from this instance. (note that it still exists in datalayer)', success: true, }); } catch (error) { res.status(400).json({ - message: 'Error resetting your organization', + message: 'Error deleting your organization', error: error.message, success: false, }); @@ -199,14 +201,15 @@ export const importOrg = async (req, res) => { await assertWalletIsSynced(); const { orgUid } = req.body; + await assertOrgDoesNotExist(orgUid); - res.json({ + await Organization.importOrganization(orgUid); + + res.status(200).json({ message: - 'Importing and subscribing organization this can take a few mins.', + 'Successfully imported organization. CADT will begin syncing data from datalayer shortly', success: true, }); - - return Organization.importOrganization(orgUid); } catch (error) { console.trace(error); res.status(400).json({ @@ -223,17 +226,19 @@ export const importHomeOrg = async (req, res) => { await assertWalletIsSynced(); const { orgUid } = req.body; + await assertOrgDoesNotExist(orgUid); - await Organization.importHomeOrg(orgUid); + // asserts home org stores are owned + await Organization.importOrganization(orgUid, true); - res.json({ - message: 'Importing home organization.', + res.status(200).json({ + message: + 'Successfully imported home organization. CADT will begin syncing data from datalayer shortly', success: true, }); } catch (error) { - console.trace(error); res.status(400).json({ - message: 'Error importing organization', + message: 'Error importing home organization', error: error.message, success: false, }); @@ -244,7 +249,6 @@ export const subscribeToOrganization = async (req, res) => { try { await assertIfReadOnlyMode(); await assertWalletIsSynced(); - await assertHomeOrgExists(); await Organization.subscribeToOrganization(req.body.orgUid); @@ -284,12 +288,12 @@ export const deleteImportedOrg = async (req, res) => { return res.json({ message: - 'UnSubscribed to organization, you will no longer receive updates.', + 'Removed all organization records. cadt will not sync the organizations data from datalayer', success: true, }); } catch (error) { res.status(400).json({ - message: 'Error unsubscribing to organization', + message: 'Error deleting organization', error: error.message, success: false, }); diff --git a/src/datalayer/persistance.js b/src/datalayer/persistance.js index 0a803058..e0b8f1b1 100644 --- a/src/datalayer/persistance.js +++ b/src/datalayer/persistance.js @@ -357,22 +357,21 @@ const getStoreData = async (storeId, rootHash) => { const data = response.body; if (data.success) { - if (!_.isEmpty(data.keys_values)) { - logger.info(`Downloaded Data, root hash: ${rootHash || 'latest'}`); + if (_.isEmpty(data.keys_values)) { + logger.warn( + `datalayer get_keys_values returned no data for store ${storeId} at root hash: ${rootHash || 'latest'}`, + ); } return data; + } else { + throw new Error(JSON.stringify(data)); } - - logger.error( - `FAILED GETTING STORE DATA FOR ${storeId}: ${JSON.stringify(data)}`, - ); } catch (error) { - logger.info( - `Unable to find store data for ${storeId} at root ${ + logger.error( + `failed to get keys and values from datalayer for store ${storeId} at root ${ rootHash || 'latest' - }`, + }. Error: ${error.message}`, ); - logger.error(error.message); return false; } } @@ -396,14 +395,19 @@ const getRoot = async (storeId, ignoreEmptyStore = false) => { .send({ id: storeId }); const { confirmed, hash } = response.body; + logger.debug( + `the current root data for store ${storeId} is ${JSON.stringify(response.body)}`, + ); - if (confirmed && (!ignoreEmptyStore || !hash.includes('0x00000000000'))) { + if (confirmed && (ignoreEmptyStore || !hash.includes('0x00000000000'))) { return response.body; } return false; } catch (error) { - logger.error(error.message); + logger.error( + `failed to get root for store ${storeId}. error: ${error.message}`, + ); return false; } }; @@ -522,26 +526,12 @@ const createDataLayerStore = async () => { } }; -const subscribeToStoreOnDataLayer = async ( - storeId, - restoreHomeOrgOverride = false, -) => { +const subscribeToStoreOnDataLayer = async (storeId) => { if (!storeId) { logger.info(`No storeId found to subscribe to: ${storeId}`); return false; } - const homeOrg = await Organization.getHomeOrg(); - - if ( - !restoreHomeOrgOverride && - homeOrg && - [(homeOrg.orgUid, homeOrg.registryId)].includes(storeId) - ) { - logger.info(`Cant subscribe to self: ${storeId}`); - return { success: true }; - } - const { storeIds: subscriptions, success } = await getSubscriptions(); if (!success) { return false; @@ -549,7 +539,7 @@ const subscribeToStoreOnDataLayer = async ( if (subscriptions.includes(storeId)) { logger.info(`Already subscribed to: ${storeId}`); - return { success: true }; + return true; } const url = `${CONFIG.DATALAYER_URL}/subscribe`; @@ -577,7 +567,7 @@ const subscribeToStoreOnDataLayer = async ( await addMirror(storeId, mirrorUrl, true); - return data; + return true; } return false; diff --git a/src/datalayer/syncService.js b/src/datalayer/syncService.js index 9488e897..ad4ac016 100644 --- a/src/datalayer/syncService.js +++ b/src/datalayer/syncService.js @@ -26,6 +26,12 @@ const subscribeToStoreOnDataLayer = async (storeId) => { } }; +/** + * gets and decodes data from a subscribed store. + * will subscribe to any store id for which there is no subscription. + * @param storeId to retrieve data from + * @returns {Promise} + */ const getSubscribedStoreData = async (storeId) => { const { storeIds: subscriptions, success } = await dataLayer.getSubscriptions(); @@ -36,23 +42,26 @@ const getSubscribedStoreData = async (storeId) => { if (!alreadySubscribed) { logger.info(`No Subscription Found for ${storeId}, Subscribing...`); - const response = await subscribeToStoreOnDataLayer(storeId); + const response = await dataLayer.subscribeToStoreOnDataLayer(storeId); - if (!response || !response.success) { + if (!response) { throw new Error(`Failed to subscribe to ${storeId}`); } } - logger.info(`Subscription Found for ${storeId}.`); + logger.debug(`Subscription Found for ${storeId}.`); if (!USE_SIMULATOR) { - logger.info(`Getting confirmation for ${storeId}.`); + logger.debug( + `syncService getSubscribedData() checking that data is available for ${storeId}.`, + ); const storeExistAndIsConfirmed = await dataLayer.getRoot(storeId, true); - logger.info(`Store found in DataLayer: ${storeId}.`); if (!storeExistAndIsConfirmed) { throw new Error(`Store not found in DataLayer: ${storeId}.`); } else { - logger.debug(`Store is confirmed, proceeding to get data ${storeId}`); + logger.debug( + `store data is confirmed available, proceeding to get data ${storeId}`, + ); } } @@ -64,7 +73,9 @@ const getSubscribedStoreData = async (storeId) => { } if (_.isEmpty(encodedData?.keys_values)) { - throw new Error(`No data found for store ${storeId}`); + throw new Error( + `getSubscribedStoreData() found no data for store ${storeId}`, + ); } const decodedData = decodeDataLayerResponse(encodedData); @@ -147,9 +158,13 @@ const getCurrentStoreData = async (storeId) => { const encodedData = await dataLayer.getStoreData(storeId); if (encodedData) { - return decodeDataLayerResponse(encodedData); + const decodedData = decodeDataLayerResponse(encodedData); + return decodedData.reduce((obj, current) => { + obj[current.key] = current.value; + return obj; + }, {}); } else { - return []; + return undefined; } }; diff --git a/src/models/file-store/file-store.model.js b/src/models/file-store/file-store.model.js index 1207e8eb..123b7acf 100644 --- a/src/models/file-store/file-store.model.js +++ b/src/models/file-store/file-store.model.js @@ -29,7 +29,20 @@ class FileStore extends Model { } await datalayer.subscribeToStoreOnDataLayer(organization.fileStoreId); - Organization.update({ fileStoreSubscribed: true }); + + /* todo: this is code is now valid but it wasnt previously resulting in the records not updating and the filestore always + being marked as not subscribed. at the moment, not sure what the impact of marking them as subscribed would + be so leaving this commented out to revisit at a later date (today is 12/9/24) + await Organization.update( + { fileStoreSubscribed: true }, + { + where: { + orgUid, + }, + }, + ); + + */ } static async unsubscribeFromFileStore(orgUid) { diff --git a/src/models/organizations/organizations.model.js b/src/models/organizations/organizations.model.js index 87b30419..bcb57ecb 100644 --- a/src/models/organizations/organizations.model.js +++ b/src/models/organizations/organizations.model.js @@ -19,6 +19,7 @@ import { getConfig } from '../../utils/config-loader'; const { USE_SIMULATOR, AUTO_SUBSCRIBE_FILESTORE } = getConfig().APP; import ModelTypes from './organizations.modeltypes.cjs'; +import { assertStoreIsOwned } from '../../utils/data-assertions.js'; class Organization extends Model { static async getHomeOrg(includeAddress = true) { @@ -205,7 +206,6 @@ class Organization extends Model { return newOrganizationId; } catch (error) { - console.trace(error); logger.error(error.message); logger.info('Reverting Failed Organization'); await Organization.destroy({ where: { isHome: true } }); @@ -225,113 +225,225 @@ class Organization extends Model { await datalayer.addMirror(storeId, url, force); } - static async importHomeOrg(orgUid) { - const orgData = await datalayer.getLocalStoreData(orgUid); + /** + * subscribes to and imports an organization. + * + * if importing as home, asserts all stores related to organization are owned. + * + * NOTE: assertions should be used at the controller level, but given that the data model version store id + * and registry store id need to be derived as part of this process, this function asserts their ownership status + * @param orgUid the orgUid of the organization to import + * @param isHome import the org as a home org + * @returns {Promise} + */ + static async importOrganization(orgUid, isHome = false) { + if (isHome) { + try { + await assertStoreIsOwned(orgUid); + } catch { + throw new Error( + `orgUid store ${orgUid} is not owned by this chia wallet. cannot import organization ${orgUid} as home`, + ); + } + } - if (!orgData) { - throw new Error('Your node does not have write access to this orgUid'); + logger.info(`importing unowned (not home) organization ${orgUid}`); + logger.debug( + `running the organization model subscription process on ${orgUid}`, + ); + + let storeIds = null; + try { + storeIds = await Organization.subscribeToOrganization(orgUid); + } catch (error) { + logger.error( + `failure validating or adding subscriptions for org import. cannot import. Error: ${error.message}`, + ); + throw new Error( + `failed to subscribe to, or validate subscribed store data for, organization ${orgUid}`, + ); } - const orgDataObj = orgData.reduce((obj, curr) => { - obj[curr.key] = curr.value; - return obj; - }, {}); + if (isHome) { + try { + await assertStoreIsOwned(storeIds.dataModelVersionStoreId); + } catch { + throw new Error( + `datamodel version store ${storeIds.dataModelVersionStoreId} is not owned by this chia wallet. cannot import organization ${orgUid} as home`, + ); + } - const registryData = await datalayer.getLocalStoreData( - orgDataObj.registryId, - ); + try { + await assertStoreIsOwned(storeIds.registryStoreId); + } catch { + throw new Error( + `registry store ${storeIds.registryStoreId} is not owned by this chia wallet. cannot import organization ${orgUid} as home`, + ); + } + } - const registryDataObj = registryData.reduce((obj, curr) => { - obj[curr.key] = curr.value; - return obj; - }, {}); + const orgData = await datalayer.getCurrentStoreData(storeIds.orgUid); + if (!orgData) { + throw new Error(`failed to get organization data for ${orgUid}`); + } - const dataModelVersion = getDataModelVersion(); + const dataModelInfo = await datalayer.getCurrentStoreData( + storeIds.dataModelVersionStoreId, + ); + if (!dataModelInfo) { + throw new Error( + `failed to determine datamodel version for organization ${orgUid}`, + ); + } - if (!registryDataObj[dataModelVersion]) { - registryDataObj[dataModelVersion] = await Organization.appendNewRegistry( - orgDataObj.registryId, - dataModelVersion, + const instanceDataModelVersion = getDataModelVersion(); + if (!dataModelInfo[instanceDataModelVersion]) { + throw new Error( + `this cadt instance is using datamodel version ${instanceDataModelVersion}. organization ${orgUid} does not have data for this datamodel. cannot import`, ); } - await Organization.upsert({ + const organizationData = { orgUid, - name: orgDataObj.name, - icon: orgDataObj.icon, - registryId: registryDataObj[dataModelVersion], + name: orgData.name, + icon: orgData.icon, + registryId: storeIds.registryStoreId, + fileStoreId: orgData?.fileStoreId, subscribed: true, - isHome: true, - }); + isHome: false, + }; + + logger.info( + `adding and organization with the following info ${organizationData}`, + ); + + await Organization.create(organizationData); } - static async importOrganization(orgUid) { - try { - logger.info('Importing organization ' + orgUid); - const orgData = await datalayer.getSubscribedStoreData(orgUid); + /** + * Subscribes to all 3 required stores for a CADT organization. + * + * CADT organization stores: + * + * + * @param {string} orgUid - The unique identifier of the organization to subscribe to. + * @returns {Promise<{orgUid: string, dataModelVersionStoreId: string, registryStoreId: string}>} + * Resolves to an object containing: + * - `orgUid`: The unique identifier of the organization. + * - `dataModelVersionStoreId`: The identifier of the data model version store. + * - `registryStoreId`: The identifier of the registry store. + */ - if (!orgData.registryId) { - logger.error( - 'Corrupted organization, no registryId on the datalayer, can not import', + static async subscribeToOrganization(orgUid) { + // we'll give datalayer 10 minutes to get data where it needs to be and complete this process + const timeout = Date.now() + 600000; + const reachedTimeout = () => { + return Date.now() > timeout; + }; + const onTimeout = (error) => { + const message = `reached timeout before subscribing to all required stores. Failure at time out: ${error.message}`; + logger.error(message); + throw new Error(message); + }; + + logger.debug( + `determining datamodel version singleton id for org ${orgUid}`, + ); + let dataModelVersionStoreId = null; + while (!dataModelVersionStoreId) { + try { + const orgStoreData = await datalayer.getSubscribedStoreData(orgUid); + // here registryId is actually the data model version store that points to the registry store + dataModelVersionStoreId = orgStoreData?.registryId; + if (!dataModelVersionStoreId) { + throw new Error( + `failed to get registry datamodel version singleton id from orgUid store ${orgUid}. rpc function returned: ${orgStoreData}`, + ); + } + logger.debug( + `the registry datamodel version pointer singleton id for organization ${orgUid} is ${dataModelVersionStoreId}`, ); - return; + } catch (error) { + if (reachedTimeout()) { + onTimeout(error); + } + logger.debug(`${error.message}. RETRYING`); + } finally { + await new Promise((resolve) => setTimeout(resolve, 300)); } + } - logger.info(`IMPORTING REGISTRY: ${orgData.registryId}`); - - const registryData = await datalayer.getSubscribedStoreData( - orgData.registryId, - ); - - const dataModelVersion = getDataModelVersion(); - - if (!registryData[dataModelVersion]) { - throw new Error( - `Organization has no registry for the ${dataModelVersion} datamodel, can not import`, + logger.debug(`determining registry store singleton id for org ${orgUid}`); + let registryStoreId = null; + while (!registryStoreId) { + try { + const dataModelVersionStoreData = + await datalayer.getSubscribedStoreData(dataModelVersionStoreId); + // here v1 is actually the registry store id + registryStoreId = dataModelVersionStoreData?.v1; + if (!registryStoreId) { + throw new Error( + `failed to get registry singleton id from datamodel version singleton store ${dataModelVersionStoreId}. rpc function returned: ${dataModelVersionStoreData}`, + ); + } + logger.debug( + `the registry singleton id for organization ${orgUid} is ${dataModelVersionStoreId}`, ); + } catch (error) { + if (reachedTimeout()) { + onTimeout(error); + } + logger.debug(`${error.message}. RETRYING`); + } finally { + await new Promise((resolve) => setTimeout(resolve, 300)); } + } - logger.info(`IMPORTING REGISTRY ${dataModelVersion}: `, registryData.v1); - - await datalayer.subscribeToStoreOnDataLayer(registryData.v1); - - logger.info( - `setting the following organization information: ${{ - orgUid, - name: orgData.name, - icon: orgData.icon, - registryId: registryData[dataModelVersion], - subscribed: true, - isHome: false, - }}`, + logger.debug(`checking registry store singleton for org ${orgUid}`); + const subscribedToRegistryStore = + await datalayer.subscribeToStoreOnDataLayer(registryStoreId); + if (!subscribedToRegistryStore) { + throw new Error( + `failed to subscribe to or validate subscription for registry store ${registryStoreId}`, ); + } - await Organization.upsert({ - orgUid, - name: orgData.name, - icon: orgData.icon, - registryId: registryData[dataModelVersion], - subscribed: true, - isHome: false, - }); - - if (AUTO_SUBSCRIBE_FILESTORE) { + if (AUTO_SUBSCRIBE_FILESTORE) { + logger.info(`subscribing to file store for organization ${orgUid}`); + try { await FileStore.subscribeToFileStore(orgUid); + } catch (error) { + logger.warn( + `failed to subscribe to file store. Error: ${error.message}`, + ); } - } catch (error) { - logger.info(error.message); } - } - static async subscribeToOrganization(orgUid) { - const exists = await Organization.findOne({ where: { orgUid } }); - if (exists) { - await Organization.update({ subscribed: true }, { where: { orgUid } }); - } else { - throw new Error( - 'Can not subscribe, please import this organization first', - ); - } + return { + orgUid, + dataModelVersionStoreId, + registryStoreId, + }; } static async unsubscribeToOrganization(orgUid) { @@ -422,8 +534,14 @@ class Organization extends Model { const exists = await Organization.findOne({ where: { orgUid: org.orgUid }, }); + logger.debug( + `sync dafault orgs task checking default org ${org.orgUid}`, + ); if (!exists) { + logger.debug( + `default organization ${org.orgUid} was not found in the organizations table. running the import process to correct`, + ); await Organization.importOrganization(org.orgUid); } } diff --git a/src/tasks/check-organization-subscriptions.js b/src/tasks/check-organization-subscriptions.js index eb0d5017..865543d5 100644 --- a/src/tasks/check-organization-subscriptions.js +++ b/src/tasks/check-organization-subscriptions.js @@ -1,16 +1,12 @@ import { SimpleIntervalJob, Task } from 'toad-scheduler'; import { getConfig } from '../utils/config-loader.js'; import { Meta, Organization } from '../models/index.js'; -import { - getOwnedStores, - getSubscriptions, - subscribeToStoreOnDataLayer, -} from '../datalayer/persistance.js'; +import { getOwnedStores } from '../datalayer/persistance.js'; import { logger } from '../config/logger.js'; const CONFIG = getConfig(); -const task = new Task('check-oranization-subscriptions', async () => { +const task = new Task('check-organization-subscriptions', async () => { const hasMigratedToNewSyncMethod = await Meta.findOne({ where: { metaKey: 'migratedToNewSync' }, }); @@ -30,76 +26,54 @@ const task = new Task('check-oranization-subscriptions', async () => { try { const organizations = await Organization.findAll(); - const subscribedStores = await getSubscriptions(); const ownedStores = await getOwnedStores(); - if (!subscribedStores?.success) { - throw new Error('failed to get subscriptions from datalayer'); - } - for (const organization of organizations) { - const { orgUid, registryId, isHome, name } = organization; - logger.debug( - `validating that datalayer is subscribed org store ${orgUid} and registry store ${registryId} belonging to ${name}`, - ); + try { + const { orgUid, registryId, isHome, name } = organization; - if (isHome) { - const homeOrgStoreOwned = ownedStores.storeIds.includes(orgUid); - const homeRegistryStoreOwned = - ownedStores.storeIds.includes(registryId); + logger.debug( + `running the organization subscription process on organization ${name} (orgUid ${orgUid})`, + ); - if (!homeOrgStoreOwned) { - throw new Error( - `your wallet does not own your home organization store ${orgUid}. this is serious issue that CADT cannot resolve`, - ); - } + const datalayerOrganizationStoreIds = + await Organization.subscribeToOrganization(orgUid); - if (!homeRegistryStoreOwned) { - throw new Error( - `your wallet does not own your home registry store ${registryId}. this is serious issue that CADT cannot resolve`, + if (isHome) { + const homeOrgStoreOwned = ownedStores.storeIds.includes(orgUid); + const dataModelVersionStoreOwned = ownedStores.storeIds.includes( + datalayerOrganizationStoreIds.dataModelVersionStoreId, ); + const homeRegistryStoreOwned = + ownedStores.storeIds.includes(registryId); + + if (!homeOrgStoreOwned) { + throw new Error( + `your wallet does not own your home organization store ${orgUid}. this is a serious issue that CADT cannot resolve`, + ); + } + + if (!dataModelVersionStoreOwned) { + throw new Error( + `your wallet does not own your home datamodel version store ${datalayerOrganizationStoreIds.dataModelVersionStoreId}. this is a serious issue that CADT cannot resolve`, + ); + } + + if (!homeRegistryStoreOwned) { + throw new Error( + `your wallet does not own your home registry store ${registryId}. this is a serious issue that CADT cannot resolve`, + ); + } } - } - - const subscribedToOrgStore = subscribedStores.storeIds.includes(orgUid); - const subscribedToRegistryStore = - subscribedStores.storeIds.includes(registryId); - - if (!subscribedToOrgStore) { - logger.info( - `datalayer is not subscribed to orgUid store ${orgUid}, subscribing ...`, + } catch (error) { + logger.error( + `check-organization-subscriptions task error while processing org ${organization?.orgUid}. Error: ${error.message}`, ); - - const result = await subscribeToStoreOnDataLayer(orgUid, true); - if (result) { - logger.info(`subscribed to store ${orgUid}`); - } else { - logger.error(`failed to subscribe to store ${orgUid}`); - } - - // wait 5 secs to give RPC a break - await new Promise((resolve) => setTimeout(resolve, 5000)); - } - - if (!subscribedToRegistryStore) { - logger.info( - `datalayer is not subscribed to registryId store ${registryId}, subscribing ...`, - ); - - const result = await subscribeToStoreOnDataLayer(registryId, true); - if (result) { - logger.info(`subscribed to store ${registryId}`); - } else { - logger.error(`failed to subscribe to store ${registryId}`); - } - - // wait 5 secs to give RPC a break - await new Promise((resolve) => setTimeout(resolve, 5000)); } } } catch (error) { logger.error( - `check-organization-subscriptions task encountered an error: ${error.message}`, + `check-organization-subscriptions task encountered an error and could not complete: ${error.message}`, ); } }); diff --git a/src/tasks/sync-registries.js b/src/tasks/sync-registries.js index 5e85c053..9c9e0664 100644 --- a/src/tasks/sync-registries.js +++ b/src/tasks/sync-registries.js @@ -249,8 +249,16 @@ const syncOrganizationAudit = async (organization) => { process.env.NODE_ENV !== 'test' && rootHistory.length - 1 !== sync_status?.generation ) { - logger.warn( - `the root history length does not match the number of synced generations for ${organization.name} (registry store Id ${organization.registryId}). something is wrong and the sync for this organization will be paused until this is resolved. `, + logger.debug( + `the root history length does not match the number of synced generations for ${organization.name} (registry store Id ${organization.registryId}). pausing the sync for this organization until the root history length and number of synced generations match`, + ); + return; + } else if ( + process.env.NODE_ENV !== 'test' && + rootHistory.length - 1 !== sync_status?.target_generation + ) { + logger.debug( + `the root history length does not match the target generation number for ${organization.name} (registry store Id ${organization.registryId}). something is wrong and the sync for this organization will be paused until this is resolved. `, ); return; } diff --git a/src/utils/data-assertions.js b/src/utils/data-assertions.js index e0591ba7..823013f8 100644 --- a/src/utils/data-assertions.js +++ b/src/utils/data-assertions.js @@ -5,7 +5,8 @@ import _ from 'lodash'; import { Organization, Unit, Project, Staging, Meta } from '../models'; import datalayer from '../datalayer'; import { formatModelAssociationName } from './model-utils.js'; -import { getConfig } from '../utils/config-loader'; +import { getConfig } from './config-loader'; +import { getOwnedStores } from '../datalayer/persistance.js'; const { IS_GOVERNANCE_BODY, READ_ONLY, USE_SIMULATOR, CHIA_NETWORK } = getConfig().APP; @@ -256,3 +257,23 @@ export const assertNoActiveOfferFile = async () => { throw new Error(`There is an active offer pending`); } }; + +export const assertStoreIsOwned = async (storeId) => { + const { storeIds, success } = await getOwnedStores(); + if (!success) { + throw new Error('failed to get owned stores list from datalayer'); + } + + if (!storeIds.includes(storeId)) { + throw new Error(`store id ${storeId} is not owned by this chia wallet`); + } +}; + +export const assertOrgDoesNotExist = async (orgUid) => { + const result = await Organization.findOne({ where: { orgUid }, raw: true }); + if (result) { + throw new Error( + `organization ${orgUid} already exists in the CADT database`, + ); + } +}; diff --git a/tests/resources/organization.spec.js b/tests/resources/organization.spec.js index 308f4a52..b3be94a1 100644 --- a/tests/resources/organization.spec.js +++ b/tests/resources/organization.spec.js @@ -26,7 +26,7 @@ describe('Orgainzation Resource CRUD', function () { const response = await supertest(app).delete(`/v1/organizations`).send(); expect(response.body.message).to.equal( - 'Your home organization was reset, please create a new one.', + 'Your home organization was deleted from this instance. (note that it still exists in datalayer)', ); const stagingData = await testFixtures.getLastCreatedStagingRecord();