From 1d39da85ea9ddb598c278c455c86f64ef72df036 Mon Sep 17 00:00:00 2001 From: pyphilia Date: Thu, 12 Mar 2020 14:27:40 +0100 Subject: [PATCH] feat: factor out appInstanceResources adapt clearUserInput --- public/app/db.js | 3 ++ public/app/listeners/clearUserInput.js | 52 +++++-------------- public/app/listeners/getAppInstance.js | 42 +++++++++++++++ .../app/listeners/getAppInstanceResources.js | 38 +++----------- public/app/listeners/index.js | 2 + .../app/listeners/patchAppInstanceResource.js | 46 +++------------- .../app/listeners/postAppInstanceResource.js | 38 +++----------- public/electron.js | 40 +------------- src/actions/space.js | 8 ++- src/components/space/ClearButton.js | 13 +++-- src/components/space/SpaceHeader.js | 2 +- src/data/sample.json | 44 +++++++--------- 12 files changed, 117 insertions(+), 211 deletions(-) create mode 100644 public/app/listeners/getAppInstance.js diff --git a/public/app/db.js b/public/app/db.js index 0df99706..b8ba720c 100644 --- a/public/app/db.js +++ b/public/app/db.js @@ -11,6 +11,7 @@ const fsPromises = fs.promises; const SPACES_COLLECTION = 'spaces'; const ACTIONS_COLLECTION = 'actions'; const USERS_COLLECTION = 'users'; +const APP_INSTANCE_RESOURCES_COLLECTION = 'resources'; // bootstrap database const ensureDatabaseExists = async (dbPath = DATABASE_PATH) => { @@ -37,6 +38,7 @@ const bootstrapDatabase = (dbPath = DATABASE_PATH) => { [USERS_COLLECTION]: [], user: { lang: DEFAULT_LANG }, [ACTIONS_COLLECTION]: [], + [APP_INSTANCE_RESOURCES_COLLECTION]: [], }).write(); return db; }; @@ -44,6 +46,7 @@ const bootstrapDatabase = (dbPath = DATABASE_PATH) => { module.exports = { SPACES_COLLECTION, USERS_COLLECTION, + APP_INSTANCE_RESOURCES_COLLECTION, ensureDatabaseExists, bootstrapDatabase, }; diff --git a/public/app/listeners/clearUserInput.js b/public/app/listeners/clearUserInput.js index 48f7930d..83d6a5fd 100644 --- a/public/app/listeners/clearUserInput.js +++ b/public/app/listeners/clearUserInput.js @@ -1,50 +1,26 @@ -const _ = require('lodash'); const { CLEARED_USER_INPUT_CHANNEL } = require('../config/channels'); const { ERROR_GENERAL } = require('../config/errors'); -const { SPACES_COLLECTION } = require('../db'); +const { + SPACES_COLLECTION, + APP_INSTANCE_RESOURCES_COLLECTION, +} = require('../db'); const logger = require('../logger'); -const clearUserInput = (mainWindow, db) => async (event, { id }) => { +const clearUserInput = (mainWindow, db) => async ( + event, + { spaceId, userId } +) => { try { - logger.debug(`clearing user input for space ${id}`); + logger.debug(`clearing user input for space ${spaceId} of user ${userId}`); - // get handle to the space - const spaceHandle = db.get(SPACES_COLLECTION).find({ id }); - - // get handle to regular items - const regularItems = spaceHandle - .get('phases') - // we only care about phases with items - .filter(phase => phase.items) - // ensure all items are in the same level of the array - .flatMap(phase => phase.items); - - // get handle to tools - const tools = spaceHandle.get('items'); - - // remove user input in items within phases then - // remove user input in tools - [regularItems, tools].forEach(handle => { - // we only care about items with app instances - handle - .filter(item => item.appInstance) - // ensure all app instances are in the same level - .flatMap(item => item.appInstance) - // user input is saved inside resources - .filter(appInstance => appInstance.resources) - // iterate through app instances to be able to delete - // reference to the original resource array and thus - // mutate the db object - .forEach(appInstance => { - const resources = _.get(appInstance, 'resources'); - // we should not remove resources marked as public - _.remove(resources, resource => resource.visibility !== 'public'); - }) - .write(); - }); + db.get(APP_INSTANCE_RESOURCES_COLLECTION) + .remove({ visibility: 'private', spaceId, user: userId }) + .write(); // we need to return the value of the mutated // space object to the frontend + // get handle to the space + const spaceHandle = db.get(SPACES_COLLECTION).find({ id: spaceId }); const space = spaceHandle.value(); mainWindow.webContents.send(CLEARED_USER_INPUT_CHANNEL, space); diff --git a/public/app/listeners/getAppInstance.js b/public/app/listeners/getAppInstance.js new file mode 100644 index 00000000..1f4a7907 --- /dev/null +++ b/public/app/listeners/getAppInstance.js @@ -0,0 +1,42 @@ +const { GET_APP_INSTANCE_CHANNEL } = require('../config/channels'); + +const getAppInstance = (mainWindow, db) => (event, payload = {}) => { + try { + const { spaceId, subSpaceId, id } = payload; + + let appInstance; + + // tools live on the parent + const tool = spaceId === subSpaceId; + + // if not a tool, we need to go one step further into the phase + if (!tool) { + appInstance = db + .get('spaces') + .find({ id: spaceId }) + .get('phases') + .find({ id: subSpaceId }) + .get('items') + .filter(item => item.appInstance) + .map(item => item.appInstance) + .find({ id }) + .value(); + } else { + appInstance = db + .get('spaces') + .find({ id: spaceId }) + .get('items') + .filter(item => item.appInstance) + .map(item => item.appInstance) + .find({ id }) + .value(); + } + + mainWindow.webContents.send(GET_APP_INSTANCE_CHANNEL, appInstance); + } catch (e) { + console.error(e); + mainWindow.webContents.send(GET_APP_INSTANCE_CHANNEL, null); + } +}; + +module.exports = getAppInstance; diff --git a/public/app/listeners/getAppInstanceResources.js b/public/app/listeners/getAppInstanceResources.js index 6dc638bd..bd7988ba 100644 --- a/public/app/listeners/getAppInstanceResources.js +++ b/public/app/listeners/getAppInstanceResources.js @@ -1,39 +1,13 @@ const { GET_APP_INSTANCE_RESOURCES_CHANNEL } = require('../config/channels'); +const { APP_INSTANCE_RESOURCES_COLLECTION } = require('../db'); -const getAppInstanceResources = (mainWindow, db) => async ( - event, - data = {} -) => { +const getAppInstanceResources = (mainWindow, db) => (event, data = {}) => { const defaultResponse = []; - const { userId, appInstanceId, spaceId, subSpaceId, type } = data; + const { userId, appInstanceId, type } = data; try { - // tools live on the parent - const tool = spaceId === subSpaceId; - - let appInstanceResourcesHandle; - - // if not a tool, we need to go one step further into the phase - if (!tool) { - appInstanceResourcesHandle = db - .get('spaces') - .find({ id: spaceId }) - .get('phases') - .find({ id: subSpaceId }) - .get('items') - .filter(item => item.appInstance) - .map(item => item.appInstance) - .find({ id: appInstanceId }) - .get('resources'); - } else { - appInstanceResourcesHandle = db - .get('spaces') - .find({ id: spaceId }) - .get('items') - .filter(item => item.appInstance) - .map(item => item.appInstance) - .find({ id: appInstanceId }) - .get('resources'); - } + const appInstanceResourcesHandle = db + .get(APP_INSTANCE_RESOURCES_COLLECTION) + .filter({ appInstance: appInstanceId }); // only filter by type if provided if (type) { diff --git a/public/app/listeners/index.js b/public/app/listeners/index.js index fa372159..cd6d8799 100644 --- a/public/app/listeners/index.js +++ b/public/app/listeners/index.js @@ -25,6 +25,7 @@ const isAuthenticated = require('./isAuthenticated'); const getAppInstanceResources = require('./getAppInstanceResources'); const postAppInstanceResource = require('./postAppInstanceResource'); const patchAppInstanceResource = require('./patchAppInstanceResource'); +const getAppInstance = require('./getAppInstance'); module.exports = { loadSpace, @@ -54,4 +55,5 @@ module.exports = { getAppInstanceResources, postAppInstanceResource, patchAppInstanceResource, + getAppInstance, }; diff --git a/public/app/listeners/patchAppInstanceResource.js b/public/app/listeners/patchAppInstanceResource.js index 1e48034f..b0253cb0 100644 --- a/public/app/listeners/patchAppInstanceResource.js +++ b/public/app/listeners/patchAppInstanceResource.js @@ -1,50 +1,20 @@ const { PATCH_APP_INSTANCE_RESOURCE_CHANNEL } = require('../config/channels'); +const { APP_INSTANCE_RESOURCES_COLLECTION } = require('../db'); -const patchAppInstanceResource = (mainWindow, db) => async ( - event, - payload = {} -) => { +const patchAppInstanceResource = (mainWindow, db) => (event, payload = {}) => { try { - const { appInstanceId, spaceId, subSpaceId, data, id } = payload; + const { appInstanceId: appInstance, data, id } = payload; const now = new Date(); const fieldsToUpdate = { updatedAt: now, data, }; - let resource; - - // tools live on the parent - const tool = spaceId === subSpaceId; - - // if not a tool, we need to go one step further into the phase - if (!tool) { - resource = db - .get('spaces') - .find({ id: spaceId }) - .get('phases') - .find({ id: subSpaceId }) - .get('items') - .filter(item => item.appInstance) - .map(item => item.appInstance) - .find({ id: appInstanceId }) - .get('resources') - .find({ id }) - .assign(fieldsToUpdate) - .value(); - } else { - resource = db - .get('spaces') - .find({ id: spaceId }) - .get('items') - .filter(item => item.appInstance) - .map(item => item.appInstance) - .find({ id: appInstanceId }) - .get('resources') - .find({ id }) - .assign(fieldsToUpdate) - .value(); - } + const resource = db + .get(APP_INSTANCE_RESOURCES_COLLECTION) + .find({ appInstance, id }) + .assign(fieldsToUpdate) + .value(); db.write(); mainWindow.webContents.send(PATCH_APP_INSTANCE_RESOURCE_CHANNEL, resource); diff --git a/public/app/listeners/postAppInstanceResource.js b/public/app/listeners/postAppInstanceResource.js index a948bd41..4b498daf 100644 --- a/public/app/listeners/postAppInstanceResource.js +++ b/public/app/listeners/postAppInstanceResource.js @@ -1,16 +1,13 @@ const ObjectId = require('bson-objectid'); const { POST_APP_INSTANCE_RESOURCE_CHANNEL } = require('../config/channels'); +const { APP_INSTANCE_RESOURCES_COLLECTION } = require('../db'); -const postAppInstanceResource = (mainWindow, db) => async ( - event, - payload = {} -) => { +const postAppInstanceResource = (mainWindow, db) => (event, payload = {}) => { try { const { userId, appInstanceId, spaceId, - subSpaceId, format, type, data, @@ -23,6 +20,7 @@ const postAppInstanceResource = (mainWindow, db) => async ( // prepare the resource that we will create const resourceToWrite = { appInstance: appInstanceId, + spaceId, createdAt: now, updatedAt: now, data, @@ -33,34 +31,10 @@ const postAppInstanceResource = (mainWindow, db) => async ( id: ObjectId().str, }; - // tools live on the parent - const tool = spaceId === subSpaceId; - // write the resource to the database - // if not a tool, we need to go one step further into the phase - if (!tool) { - db.get('spaces') - .find({ id: spaceId }) - .get('phases') - .find({ id: subSpaceId }) - .get('items') - .filter(item => item.appInstance) - .map(item => item.appInstance) - .find({ id: appInstanceId }) - .get('resources') - .push(resourceToWrite) - .write(); - } else { - db.get('spaces') - .find({ id: spaceId }) - .get('items') - .filter(item => item.appInstance) - .map(item => item.appInstance) - .find({ id: appInstanceId }) - .get('resources') - .push(resourceToWrite) - .write(); - } + db.get(APP_INSTANCE_RESOURCES_COLLECTION) + .push(resourceToWrite) + .write(); // send back the resource mainWindow.webContents.send( diff --git a/public/electron.js b/public/electron.js index ae829a88..d0c1722c 100644 --- a/public/electron.js +++ b/public/electron.js @@ -83,6 +83,7 @@ const { getAppInstanceResources, postAppInstanceResource, patchAppInstanceResource, + getAppInstance, } = require('./app/listeners'); const isMac = require('./app/utils/isMac'); @@ -433,44 +434,7 @@ app.on('ready', async () => { ); // called when getting an AppInstance - ipcMain.on(GET_APP_INSTANCE_CHANNEL, (event, payload = {}) => { - try { - const { spaceId, subSpaceId, id } = payload; - - let appInstance; - - // tools live on the parent - const tool = spaceId === subSpaceId; - - // if not a tool, we need to go one step further into the phase - if (!tool) { - appInstance = db - .get('spaces') - .find({ id: spaceId }) - .get('phases') - .find({ id: subSpaceId }) - .get('items') - .filter(item => item.appInstance) - .map(item => item.appInstance) - .find({ id }) - .value(); - } else { - appInstance = db - .get('spaces') - .find({ id: spaceId }) - .get('items') - .filter(item => item.appInstance) - .map(item => item.appInstance) - .find({ id }) - .value(); - } - - mainWindow.webContents.send(GET_APP_INSTANCE_CHANNEL, appInstance); - } catch (e) { - console.error(e); - mainWindow.webContents.send(GET_APP_INSTANCE_CHANNEL, null); - } - }); + ipcMain.on(GET_APP_INSTANCE_CHANNEL, getAppInstance(mainWindow, db)); // called when getting the database ipcMain.on(GET_DATABASE_CHANNEL, async () => { diff --git a/src/actions/space.js b/src/actions/space.js index 059f1b92..b2ba805d 100644 --- a/src/actions/space.js +++ b/src/actions/space.js @@ -293,7 +293,7 @@ const deleteSpace = ({ id }) => dispatch => { }); }; -const clearUserInput = async ({ id }) => async dispatch => { +const clearUserInput = async ({ spaceId, userId }) => async dispatch => { try { // show confirmation prompt window.ipcRenderer.send(SHOW_CLEAR_USER_INPUT_PROMPT_CHANNEL); @@ -304,13 +304,17 @@ const clearUserInput = async ({ id }) => async dispatch => { (event, response) => { if (response === 1) { dispatch(flagClearingUserInput(true)); - window.ipcRenderer.send(CLEAR_USER_INPUT_CHANNEL, { id }); + window.ipcRenderer.send(CLEAR_USER_INPUT_CHANNEL, { + spaceId, + userId, + }); } } ); // listen for response from backend window.ipcRenderer.once(CLEARED_USER_INPUT_CHANNEL, (event, response) => { + console.log('response', response); if (response === ERROR_GENERAL) { toastr.error(ERROR_MESSAGE_HEADER, ERROR_CLEARING_USER_INPUT_MESSAGE); } else { diff --git a/src/components/space/ClearButton.js b/src/components/space/ClearButton.js index 89d6c4e1..f1e04077 100644 --- a/src/components/space/ClearButton.js +++ b/src/components/space/ClearButton.js @@ -17,13 +17,14 @@ class ClearButton extends Component { button: PropTypes.string, }).isRequired, t: PropTypes.func.isRequired, - id: PropTypes.string.isRequired, + spaceId: PropTypes.string.isRequired, + userId: PropTypes.string.isRequired, dispatchClearUserInput: PropTypes.func.isRequired, }; handleClearUserInput = () => { - const { id, dispatchClearUserInput } = this.props; - dispatchClearUserInput({ id }); + const { spaceId, userId, dispatchClearUserInput } = this.props; + dispatchClearUserInput({ spaceId, userId }); }; render() { @@ -42,6 +43,10 @@ class ClearButton extends Component { } } +const mapStateToProps = ({ authentication }) => ({ + userId: authentication.getIn(['user', 'userId']), +}); + const mapDispatchToProps = { dispatchClearUserInput: clearUserInput, }; @@ -51,7 +56,7 @@ const StyledComponent = withStyles(Styles)(ClearButton); const TranslatedComponent = withTranslation()(StyledComponent); const ConnectedComponent = connect( - null, + mapStateToProps, mapDispatchToProps )(TranslatedComponent); diff --git a/src/components/space/SpaceHeader.js b/src/components/space/SpaceHeader.js index 5661284d..134aeb3b 100644 --- a/src/components/space/SpaceHeader.js +++ b/src/components/space/SpaceHeader.js @@ -132,7 +132,7 @@ class SpaceHeader extends Component { const { space } = this.props; const { saved, id } = space; if (saved) { - return ; + return ; } return null; } diff --git a/src/data/sample.json b/src/data/sample.json index 1cc7aeb2..1615c587 100644 --- a/src/data/sample.json +++ b/src/data/sample.json @@ -62,19 +62,7 @@ "settings": { "headerVisible": false }, - "resources": [ - { - "appInstance": "5ce2c2e23a209c1877b3dc80", - "createdAt": "2019-05-21T17:06:29.683Z", - "updatedAt": "2019-05-24T13:24:05.073Z", - "data": "Sample text.", - "format": "v1", - "type": "input", - "visibility": "private", - "user": "5ce422795fe28eeca1001e0a", - "id": "5ce430152f6f6672b16fca57" - } - ], + "resources": [], "createdAt": "2019-05-21T17:06:29.683Z", "updatedAt": "2019-05-24T13:24:05.073Z" } @@ -180,18 +168,21 @@ "geolocationEnabled": false } }, - "actions": [ { - "appInstance": "5ce2c2323a209c1877b3dc80", - "createdAt": "2019-05-21T17:06:29.683Z", - "updatedAt": "2019-05-24T13:24:05.073Z", - "data": "Sample text.", - "format": "v1", - "type": "input", - "visibility": "private", - "user": "5ce422795fe28eeca1001e0a", - "id": "5ce430152f6f6672b16fca57", - "verb": "saved", - "spaceId": "6ccb068bbb18b80359966631"}], + "actions": [ + { + "appInstance": "5ce2c2323a209c1877b3dc80", + "createdAt": "2019-05-21T17:06:29.683Z", + "updatedAt": "2019-05-24T13:24:05.073Z", + "data": "Sample text.", + "format": "v1", + "type": "input", + "visibility": "private", + "user": "5ce422795fe28eeca1001e0a", + "id": "5ce430152f6f6672b16fca57", + "verb": "saved", + "spaceId": "6ccb068bbb18b80359966631" + } + ], "users": [ { "userId": 1, @@ -202,5 +193,6 @@ "geolocationEnabled": false } } - ] + ], + "resources": [] }