Skip to content

Commit

Permalink
feat: load user data in classroom
Browse files Browse the repository at this point in the history
  • Loading branch information
pyphilia committed May 28, 2020
1 parent 9d5cc83 commit 30bfa7d
Show file tree
Hide file tree
Showing 35 changed files with 1,192 additions and 303 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
"react-redux-toastr": "7.6.4",
"react-router": "5.1.2",
"react-router-dom": "5.1.2",
"react-select": "3.1.0",
"react-split-pane": "0.1.89",
"recharts": "1.8.5",
"redux": "4.0.5",
Expand Down
2 changes: 2 additions & 0 deletions public/app/config/channels.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,6 @@ module.exports = {
'prompt:classroom:user:delete:respond',
EDIT_USER_IN_CLASSROOM_CHANNEL: 'classroom:user:edit',
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',
};
2 changes: 2 additions & 0 deletions public/app/config/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const ERROR_ACCESS_DENIED_CLASSROOM = 'ERROR_ACCESS_DENIED_CLASSROOM';
const ERROR_DUPLICATE_USERNAME_IN_CLASSROOM =
'ERROR_DUPLICATE_USERNAME_IN_CLASSROOM';
const ERROR_NO_USER_TO_DELETE = 'ERROR_NO_USER_TO_DELETE';
const ERROR_INVALID_USERNAME = 'ERROR_INVALID_USERNAME';

module.exports = {
ERROR_ZIP_CORRUPTED,
Expand All @@ -22,4 +23,5 @@ module.exports = {
ERROR_ACCESS_DENIED_CLASSROOM,
ERROR_DUPLICATE_USERNAME_IN_CLASSROOM,
ERROR_NO_USER_TO_DELETE,
ERROR_INVALID_USERNAME,
};
2 changes: 1 addition & 1 deletion public/app/config/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ module.exports = {
ERROR_EDITING_USER_IN_CLASSROOM_MESSAGE,
SUCCESS_DELETING_USERS_IN_CLASSROOM_MESSAGE,
SUCCESS_EDITING_USER_IN_CLASSROOM_MESSAGE,
ERROR_INVALID_USERNAME_MESSAGE,
ERROR_NO_USER_TO_DELETE_MESSAGE,
ERROR_GETTING_SPACE_IN_CLASSROOM_MESSAGE,
ERROR_INVALID_USERNAME_MESSAGE,
};
5 changes: 5 additions & 0 deletions public/app/listeners/addClassroom.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const {
USERS_COLLECTION,
} = require('../db');
const logger = require('../logger');
const { createClassroomDirectory } = require('../utilities');

const DEFAULT_CLASSROOM = {
[SPACES_COLLECTION]: [],
Expand All @@ -39,6 +40,10 @@ const addClassroom = (mainWindow, db) => async (event, { name, userId }) => {

// create new classroom
const id = ObjectId().str;

// create directory where resources will be stored
createClassroomDirectory({ id });

const now = new Date();
const newClassroom = {
..._.cloneDeep(DEFAULT_CLASSROOM),
Expand Down
71 changes: 46 additions & 25 deletions public/app/listeners/addUserInClassroom.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,67 @@ const { ADD_USER_IN_CLASSROOM_CHANNEL } = require('../config/channels');
const { createNewUser } = require('./signIn');
const {
ERROR_DUPLICATE_USERNAME_IN_CLASSROOM,
ERROR_INVALID_USERNAME,
ERROR_GENERAL,
} = require('../config/errors');

const logger = require('../logger');

const addUserInClassroomDatabase = (db, { username, id }) => {
// check username validity
if (!username || !username.length) {
throw new Error(ERROR_INVALID_USERNAME);
}

const users = db
.get(CLASSROOMS_COLLECTION)
.find({ id })
.get(USERS_COLLECTION);

const now = new Date();

// check in db if username exists
const found = users.find({ username }).value();

if (found) {
throw new Error(ERROR_DUPLICATE_USERNAME_IN_CLASSROOM);
}

const user = createNewUser(username, now);
users.push(user).write();
return user;
};

const addUserInClassroom = (mainWindow, db) => async (
event,
{ username, classroomId: id }
) => {
logger.debug('adding a user in a classroom');

try {
const users = db
.get(CLASSROOMS_COLLECTION)
.find({ id })
.get(USERS_COLLECTION);

const now = new Date();

// check in db if username exists
const found = users.find({ username }).value();

if (found) {
return mainWindow.webContents.send(
ADD_USER_IN_CLASSROOM_CHANNEL,
ERROR_DUPLICATE_USERNAME_IN_CLASSROOM
);
}

const user = createNewUser(username, now);
users.push(user).write();
const user = addUserInClassroomDatabase(db, { username, id });

return mainWindow.webContents.send(ADD_USER_IN_CLASSROOM_CHANNEL, user);
} catch (err) {
logger.error(err);
return mainWindow.webContents.send(
ADD_USER_IN_CLASSROOM_CHANNEL,
ERROR_GENERAL
);
switch (err) {
case ERROR_DUPLICATE_USERNAME_IN_CLASSROOM:
return mainWindow.webContents.send(
ADD_USER_IN_CLASSROOM_CHANNEL,
ERROR_DUPLICATE_USERNAME_IN_CLASSROOM
);
case ERROR_INVALID_USERNAME:
return mainWindow.webContents.send(
ADD_USER_IN_CLASSROOM_CHANNEL,
ERROR_INVALID_USERNAME
);
default:
logger.error(err);
return mainWindow.webContents.send(
ADD_USER_IN_CLASSROOM_CHANNEL,
ERROR_GENERAL
);
}
}
};

module.exports = addUserInClassroom;
module.exports = { addUserInClassroom, addUserInClassroomDatabase };
2 changes: 2 additions & 0 deletions public/app/listeners/deleteClassroom.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const deleteClassroomAndResources = (db, id) => {
.write();

// todo: remove containing spaces

// todo: remove folder
};

const deleteClassroom = (mainWindow, db) => async (event, { id }) => {
Expand Down
4 changes: 3 additions & 1 deletion public/app/listeners/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ const editClassroom = require('./editClassroom');
const showDeleteClassroomPrompt = require('./showDeleteClassroomPrompt');
const showDeleteUsersInClassroomPrompt = require('./showDeleteUsersInClassroomPrompt');
const getClassroom = require('./getClassroom');
const addUserInClassroom = require('./addUserInClassroom');
const { addUserInClassroom } = require('./addUserInClassroom');
const deleteUsersInClassroom = require('./deleteUsersInClassroom');
const editUserInClassroom = require('./editUserInClassroom');
const getSpaceInClassroom = require('./getSpaceInClassroom');
const loadSpaceInClassroom = require('./loadSpaceInClassroom');

module.exports = {
loadSpace,
Expand Down Expand Up @@ -95,4 +96,5 @@ module.exports = {
showDeleteUsersInClassroomPrompt,
editUserInClassroom,
getSpaceInClassroom,
loadSpaceInClassroom,
};
10 changes: 9 additions & 1 deletion public/app/listeners/loadSpace.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ const loadSpace = (mainWindow, db) => async (
db.get(SPACES_COLLECTION)
.push(space)
.write();
} else {
// clean temp space folder
clean(extractPath);
}

const userId = db.get('user.id').value();
Expand Down Expand Up @@ -214,4 +217,9 @@ const loadSpace = (mainWindow, db) => async (
}
};

module.exports = { clearLoadSpace, extractFileToLoadSpace, loadSpace };
module.exports = {
clearLoadSpace,
extractFileToLoadSpace,
loadSpace,
renameSpaceFolder,
};
177 changes: 177 additions & 0 deletions public/app/listeners/loadSpaceInClassroom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
const _ = require('lodash');
const { VAR_FOLDER } = require('../config/config');
const { LOAD_SPACE_IN_CLASSROOM_CHANNEL } = require('../config/channels');
const {
ERROR_GENERAL,
ERROR_DUPLICATE_USERNAME_IN_CLASSROOM,
ERROR_INVALID_USERNAME,
} = require('../config/errors');
const logger = require('../logger');
const { isFileAvailable, clean } = require('../utilities');
const {
SPACES_COLLECTION,
APP_INSTANCE_RESOURCES_COLLECTION,
ACTIONS_COLLECTION,
CLASSROOMS_COLLECTION,
USERS_COLLECTION,
} = require('../db');
const { renameSpaceFolder } = require('./loadSpace');
const { deleteSpaceAndResources } = require('./deleteSpace');
const { addUserInClassroomDatabase } = require('./addUserInClassroom');

const loadSpaceInClassroom = (mainWindow, db) => async (
event,
{
extractPath,
classroomId,
username,
elements: { space, actions, appInstanceResources },
selection: {
space: isSpaceSelected,
appInstanceResources: isResourcesSelected,
actions: isActionsSelected,
},
}
) => {
logger.debug('loading a space in a classroom');

try {
const classroom = db.get(CLASSROOMS_COLLECTION).find({ id: classroomId });

// add user if doesn't exist
let user = classroom
.get(USERS_COLLECTION)
.find({ username })
.value();
if (!user) {
user = addUserInClassroomDatabase(db, { username, id: classroomId });
}

// todo: check teacher can write in classroom

// space should always be defined
if (_.isEmpty(space)) {
logger.debug('try to load undefined space');
return mainWindow.webContents.send(
LOAD_SPACE_IN_CLASSROOM_CHANNEL,
ERROR_GENERAL
);
}

// write space to database if selected
if (isSpaceSelected) {
const { id } = space;
const finalPath = `${VAR_FOLDER}/${classroomId}/${id}`;
const tmpPath = `${VAR_FOLDER}/${classroomId}/.previousSpace-${id}`;

// temporary rename previous space if exists
if (await isFileAvailable(finalPath)) {
const wasRenamed = await renameSpaceFolder(finalPath, tmpPath);
if (!wasRenamed) {
logger.error('unable to rename previous space folder');
clean(extractPath);
return mainWindow.webContents.send(
LOAD_SPACE_IN_CLASSROOM_CHANNEL,
ERROR_GENERAL
);
}
}

// we need to wrap this operation to avoid errors in windows
const wasRenamed = await renameSpaceFolder(extractPath, finalPath);
if (!wasRenamed) {
logger.error('unable to rename previous temporary new space folder');
clean(extractPath);
return mainWindow.webContents.send(
LOAD_SPACE_IN_CLASSROOM_CHANNEL,
ERROR_GENERAL
);
}

// remove previous space
deleteSpaceAndResources(db, id, tmpPath);

// add new space in database
classroom
.get(SPACES_COLLECTION)
.push(space)
.write();
} else {
// clean temp space folder
clean(extractPath);
}

const { id: userId } = user;

// write resources to database if selected
if (isResourcesSelected) {
if (_.isEmpty(appInstanceResources)) {
logger.debug('try to load empty resources');
return mainWindow.webContents.send(
LOAD_SPACE_IN_CLASSROOM_CHANNEL,
ERROR_GENERAL
);
}

const savedResources = classroom.get(APP_INSTANCE_RESOURCES_COLLECTION);

// todo: replace resources

const newResources = appInstanceResources
// keep only non-duplicate resources
.filter(({ id }) => !savedResources.find({ id }).value())
// change user id with given user
.map(action => ({ ...action, user: userId }));

savedResources.push(...newResources).write();
}

// write actions to database if selected
if (isActionsSelected) {
if (_.isEmpty(actions)) {
logger.debug('try to load empty actions');
return mainWindow.webContents.send(
LOAD_SPACE_IN_CLASSROOM_CHANNEL,
ERROR_GENERAL
);
}

const savedActions = classroom.get(ACTIONS_COLLECTION);

// todo: replace actions

const newActions = actions
// keep only non-duplicate actions
.filter(({ id }) => !savedActions.find({ id }).value())
// change user id with given user
.map(action => ({ ...action, user: userId }));

savedActions.push(...newActions).write();
}

return mainWindow.webContents.send(LOAD_SPACE_IN_CLASSROOM_CHANNEL, {
spaceId: space.id,
});
} catch (err) {
switch (err) {
case ERROR_DUPLICATE_USERNAME_IN_CLASSROOM:
return mainWindow.webContents.send(
LOAD_SPACE_IN_CLASSROOM_CHANNEL,
ERROR_DUPLICATE_USERNAME_IN_CLASSROOM
);
case ERROR_INVALID_USERNAME:
return mainWindow.webContents.send(
LOAD_SPACE_IN_CLASSROOM_CHANNEL,
ERROR_INVALID_USERNAME
);
default:
logger.error(err);
return mainWindow.webContents.send(
LOAD_SPACE_IN_CLASSROOM_CHANNEL,
ERROR_GENERAL
);
}
}
};

module.exports = loadSpaceInClassroom;
Loading

0 comments on commit 30bfa7d

Please sign in to comment.