Skip to content

Commit

Permalink
feat: save file locally when receiving postFile message
Browse files Browse the repository at this point in the history
  • Loading branch information
pyphilia committed Aug 31, 2020
1 parent ba4627a commit d308f36
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 1 deletion.
1 change: 1 addition & 0 deletions public/app/config/channels.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,5 @@ module.exports = {
GET_SPACE_IN_CLASSROOM_CHANNEL: 'classroom:space:get',
LOAD_SPACE_IN_CLASSROOM_CHANNEL: 'classroom:space:load',
GET_SPACE_TO_LOAD_IN_CLASSROOM_CHANNEL: 'classroom:space:load:get-space',
POST_FILE_CHANNEL: 'file:post',
};
8 changes: 8 additions & 0 deletions public/app/config/config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// eslint-disable-next-line import/no-extraneous-dependencies
const { app } = require('electron');
const ObjectId = require('bson-objectid');
const isWindows = require('../utils/isWindows');

// types that we support downloading
Expand Down Expand Up @@ -84,6 +85,12 @@ const ACTIONS_VERBS = {
LOGOUT: 'logout',
};

const buildFilesPath = ({ userId, spaceId, name }) => {
// add generated id to handle duplicate files
const generatedId = ObjectId().str;
return `${VAR_FOLDER}/${spaceId}/files/${userId}/${generatedId}_${name}`;
};

module.exports = {
DEFAULT_LOGGING_LEVEL,
DEFAULT_PROTOCOL,
Expand All @@ -110,4 +117,5 @@ module.exports = {
VISIBILITIES,
DEFAULT_FORMAT,
ACTIONS_VERBS,
buildFilesPath,
};
2 changes: 2 additions & 0 deletions public/app/config/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ const ERROR_GETTING_SPACE_IN_CLASSROOM_MESSAGE =
const ERROR_SETTING_ACTION_ACCESSIBILITY =
'There was an error setting the action accessibility';
const ERROR_SETTING_ACTIONS_AS_ENABLED = 'There was an error enabling actions';
const ERROR_POSTING_FILE_MESSAGE = 'There was an error uploading the file';

module.exports = {
ERROR_GETTING_DEVELOPER_MODE,
Expand Down Expand Up @@ -172,4 +173,5 @@ module.exports = {
ERROR_INVALID_USERNAME_MESSAGE,
ERROR_SETTING_ACTION_ACCESSIBILITY,
ERROR_SETTING_ACTIONS_AS_ENABLED,
ERROR_POSTING_FILE_MESSAGE,
};
2 changes: 2 additions & 0 deletions public/app/listeners/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const loadSpaceInClassroom = require('./loadSpaceInClassroom');
const setActionAccessibility = require('./setActionAccessibility');
const setActionsAsEnabled = require('./setActionsAsEnabled');
const windowAllClosed = require('./windowAllClosed');
const postFile = require('./postFile');

module.exports = {
loadSpace,
Expand Down Expand Up @@ -103,4 +104,5 @@ module.exports = {
setActionAccessibility,
setActionsAsEnabled,
windowAllClosed,
postFile,
};
36 changes: 36 additions & 0 deletions public/app/listeners/postFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const fs = require('fs');
const { POST_FILE_CHANNEL } = require('../config/channels');
const { buildFilesPath } = require('../config/config');
const { ensureDirectoryExistence } = require('../utilities');
const logger = require('../logger');
const { ERROR_GENERAL } = require('../config/errors');

const postFile = mainWindow => (event, payload = {}) => {
try {
const { userId, spaceId, data } = payload;

// download file given path
const { path, name } = data;

const savePath = buildFilesPath({ userId, spaceId, name });
ensureDirectoryExistence(savePath);
fs.copyFile(path, savePath, err => {
if (err) {
throw err;
}
logger.debug(`the file ${name} was uploaded`);
});

// update data
const newData = { name, uri: `file://${savePath}` };
const newPayload = { ...payload, data: newData };

// send back the resource
mainWindow.webContents.send(POST_FILE_CHANNEL, newPayload);
} catch (e) {
console.error(e);
mainWindow.webContents.send(POST_FILE_CHANNEL, ERROR_GENERAL);
}
};

module.exports = postFile;
14 changes: 14 additions & 0 deletions public/app/utilities.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const mkdirp = require('mkdirp');
const rimraf = require('rimraf');
const path = require('path');
const { promisify } = require('util');
const mime = require('mime-types');
const md5 = require('md5');
Expand Down Expand Up @@ -135,8 +136,21 @@ const clean = async dir => {
return promisify(rimraf)(dir);
};

/**
* Ensure directories for given filepath exist
*/
function ensureDirectoryExistence(filePath) {
const dirname = path.dirname(filePath);
if (fs.existsSync(dirname)) {
return true;
}
ensureDirectoryExistence(dirname);
return fs.mkdirSync(dirname);
}

module.exports = {
clean,
ensureDirectoryExistence,
performFileSystemOperation,
getExtension,
isDownloadable,
Expand Down
6 changes: 6 additions & 0 deletions public/electron.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ const {
LOAD_SPACE_IN_CLASSROOM_CHANNEL,
SET_ACTION_ACCESSIBILITY_CHANNEL,
SET_ACTIONS_AS_ENABLED_CHANNEL,
POST_FILE_CHANNEL,
} = require('./app/config/channels');
const env = require('./env.json');
const {
Expand Down Expand Up @@ -127,6 +128,7 @@ const {
setActionAccessibility,
setActionsAsEnabled,
windowAllClosed,
postFile,
} = require('./app/listeners');
const isMac = require('./app/utils/isMac');

Expand Down Expand Up @@ -488,6 +490,10 @@ app.on('ready', async () => {

// called when creating an action
ipcMain.on(POST_ACTION_CHANNEL, postAction(mainWindow, db));

// called when creating a file
ipcMain.on(POST_FILE_CHANNEL, postFile(mainWindow, db));

// called when logging in a user
ipcMain.on(SIGN_IN_CHANNEL, signIn(mainWindow, db));

Expand Down
41 changes: 41 additions & 0 deletions src/actions/file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { POST_FILE_CHANNEL } from '../config/channels';
import { POST_FILE_SUCCEEDED, POST_FILE_FAILED } from '../types';
import { ERROR_GENERAL } from '../config/errors';
import { ERROR_POSTING_FILE_MESSAGE } from '../config/messages';

// eslint-disable-next-line import/prefer-default-export
export const postFile = async (
{ userId, appInstanceId, spaceId, subSpaceId, format, data, type } = {},
callback
) => () => {
try {
window.ipcRenderer.send(POST_FILE_CHANNEL, {
userId,
appInstanceId,
spaceId,
subSpaceId,
format,
type,
data,
});

window.ipcRenderer.once(POST_FILE_CHANNEL, async (event, response) => {
if (response === ERROR_GENERAL) {
callback({
appInstanceId,
type: POST_FILE_FAILED,
payload: ERROR_POSTING_FILE_MESSAGE,
});
} else {
callback({
// have to include the appInstanceId to avoid broadcasting
appInstanceId,
type: POST_FILE_SUCCEEDED,
payload: response,
});
}
});
} catch (err) {
console.error(err);
}
};
1 change: 1 addition & 0 deletions src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export * from './syncSpace';
export * from './loadSpace';
export * from './exportSpace';
export * from './classroom';
export * from './file';
20 changes: 19 additions & 1 deletion src/components/phase/PhaseApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ import {
APP_INSTANCE_RESOURCE_TYPES,
POST_ACTION,
ACTION_TYPES,
POST_FILE,
FILE_TYPES,
} from '../../types';
import {
getAppInstanceResources,
patchAppInstanceResource,
postAppInstanceResource,
getAppInstance,
postAction,
postFile,
} from '../../actions';
import {
DEFAULT_LANGUAGE,
Expand Down Expand Up @@ -51,6 +54,7 @@ class PhaseApp extends Component {
folder: PropTypes.string.isRequired,
dispatchGetAppInstance: PropTypes.func.isRequired,
dispatchPostAction: PropTypes.func.isRequired,
dispatchPostFile: PropTypes.func.isRequired,
id: PropTypes.string.isRequired,
phaseId: PropTypes.string.isRequired,
spaceId: PropTypes.string.isRequired,
Expand Down Expand Up @@ -115,6 +119,7 @@ class PhaseApp extends Component {
try {
const {
dispatchGetAppInstance,
dispatchPostFile,
appInstance,
dispatchPostAction,
user,
Expand All @@ -125,7 +130,13 @@ class PhaseApp extends Component {
const { id: componentAppInstanceId } = appInstance || {};
const { type, payload } = JSON.parse(event.data);
let { id: messageAppInstanceId } = payload;
if ([...APP_INSTANCE_RESOURCE_TYPES, ...ACTION_TYPES].includes(type)) {
if (
[
...APP_INSTANCE_RESOURCE_TYPES,
...ACTION_TYPES,
...FILE_TYPES,
].includes(type)
) {
({ appInstanceId: messageAppInstanceId } = payload);
}

Expand Down Expand Up @@ -153,6 +164,12 @@ class PhaseApp extends Component {
}
break;
}
case POST_FILE: {
if (isSpaceSaved) {
return dispatchPostFile(payload, this.postMessage);
}
break;
}
default:
return false;
}
Expand Down Expand Up @@ -324,6 +341,7 @@ const mapStateToProps = ({ authentication, Space }) => ({
const mapDispatchToProps = {
dispatchGetAppInstance: getAppInstance,
dispatchPostAction: postAction,
dispatchPostFile: postFile,
};

const ConnectedComponent = connect(
Expand Down
1 change: 1 addition & 0 deletions src/config/channels.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,5 @@ module.exports = {
GET_SPACE_IN_CLASSROOM_CHANNEL: 'classroom:space:get',
LOAD_SPACE_IN_CLASSROOM_CHANNEL: 'classroom:space:load',
GET_SPACE_TO_LOAD_IN_CLASSROOM_CHANNEL: 'classroom:space:load:get-space',
POST_FILE_CHANNEL: 'file:post',
};
2 changes: 2 additions & 0 deletions src/config/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ const ERROR_INVALID_USERNAME_MESSAGE = 'This username is invalid';
const ERROR_SETTING_ACTION_ACCESSIBILITY =
'There was an error setting the action accessibility';
const ERROR_SETTING_ACTIONS_AS_ENABLED = 'There was an error enabling actions';
const ERROR_POSTING_FILE_MESSAGE = 'There was an error uploading the file';

module.exports = {
ERROR_GETTING_DEVELOPER_MODE,
Expand Down Expand Up @@ -172,4 +173,5 @@ module.exports = {
ERROR_INVALID_USERNAME_MESSAGE,
ERROR_SETTING_ACTION_ACCESSIBILITY,
ERROR_SETTING_ACTIONS_AS_ENABLED,
ERROR_POSTING_FILE_MESSAGE,
};
5 changes: 5 additions & 0 deletions src/types/file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const POST_FILE = 'POST_FILE';
export const POST_FILE_SUCCEEDED = 'POST_FILE_SUCCEEDED';
export const POST_FILE_FAILED = 'POST_FILE_FAILED';

export const FILE_TYPES = [POST_FILE, POST_FILE_SUCCEEDED, POST_FILE_FAILED];
1 change: 1 addition & 0 deletions src/types/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export * from './syncSpace';
export * from './loadSpace';
export * from './exportSpace';
export * from './classroom';
export * from './file';

0 comments on commit d308f36

Please sign in to comment.