Skip to content

Commit 442092b

Browse files
committed
feat: add signin and signout actions, refactor dashboard
1 parent 040ac55 commit 442092b

File tree

12 files changed

+219
-117
lines changed

12 files changed

+219
-117
lines changed

public/app/config/config.js

+7
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ const VISIBILITIES = {
7979
PRIVATE: 'private',
8080
};
8181

82+
const DEFAULT_FORMAT = 'v1';
83+
const ACTIONS_VERBS = {
84+
SIGNOUT: 'signout',
85+
};
86+
8287
module.exports = {
8388
DEFAULT_LOGGING_LEVEL,
8489
DEFAULT_PROTOCOL,
@@ -103,4 +108,6 @@ module.exports = {
103108
DEFAULT_USER_MODE,
104109
MAX_RECENT_SPACES,
105110
VISIBILITIES,
111+
DEFAULT_FORMAT,
112+
ACTIONS_VERBS,
106113
};

public/app/db.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const fsPromises = fs.promises;
1010

1111
const SPACES_COLLECTION = 'spaces';
1212
const ACTIONS_COLLECTION = 'actions';
13+
const USER_COLLECTION = 'user';
1314
const USERS_COLLECTION = 'users';
1415
const APP_INSTANCE_RESOURCES_COLLECTION = 'appInstanceResources';
1516
const CLASSROOMS_COLLECTION = 'classrooms';
@@ -37,7 +38,7 @@ const bootstrapDatabase = (dbPath = DATABASE_PATH) => {
3738
db.defaults({
3839
[SPACES_COLLECTION]: [],
3940
[USERS_COLLECTION]: [],
40-
user: { lang: DEFAULT_LANG },
41+
[USER_COLLECTION]: { lang: DEFAULT_LANG },
4142
[ACTIONS_COLLECTION]: [],
4243
[APP_INSTANCE_RESOURCES_COLLECTION]: [],
4344
[CLASSROOMS_COLLECTION]: [],
@@ -47,6 +48,7 @@ const bootstrapDatabase = (dbPath = DATABASE_PATH) => {
4748

4849
module.exports = {
4950
SPACES_COLLECTION,
51+
USER_COLLECTION,
5052
USERS_COLLECTION,
5153
APP_INSTANCE_RESOURCES_COLLECTION,
5254
ACTIONS_COLLECTION,

public/app/listeners/postAction.js

+12-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const ObjectId = require('bson-objectid');
22
const { POST_ACTION_CHANNEL } = require('../config/channels');
33
const logger = require('../logger');
4+
const { DEFAULT_FORMAT } = require('../config/config');
45

56
const postAction = (mainWindow, db) => (event, payload = {}) => {
67
try {
@@ -9,7 +10,7 @@ const postAction = (mainWindow, db) => (event, payload = {}) => {
910
appInstanceId,
1011
spaceId,
1112
subSpaceId,
12-
format,
13+
format = DEFAULT_FORMAT,
1314
verb,
1415
data,
1516
geolocation,
@@ -21,9 +22,9 @@ const postAction = (mainWindow, db) => (event, payload = {}) => {
2122

2223
// prepare the action that we will create
2324
const actionToWrite = {
24-
spaceId,
25-
subSpaceId,
26-
appInstanceId,
25+
...(spaceId ? { spaceId } : {}),
26+
...(subSpaceId ? { subSpaceId } : {}),
27+
...(appInstanceId ? { appInstanceId } : {}),
2728
createdAt: now,
2829
updatedAt: now,
2930
data,
@@ -40,11 +41,13 @@ const postAction = (mainWindow, db) => (event, payload = {}) => {
4041
.push(actionToWrite)
4142
.write();
4243

43-
// send back the resource
44-
mainWindow.webContents.send(
45-
`${POST_ACTION_CHANNEL}_${appInstanceId}`,
46-
actionToWrite
47-
);
44+
// send back the action to the app
45+
if (appInstanceId) {
46+
mainWindow.webContents.send(
47+
`${POST_ACTION_CHANNEL}_${appInstanceId}`,
48+
actionToWrite
49+
);
50+
}
4851
} catch (e) {
4952
logger.error(e);
5053
mainWindow.webContents.send(POST_ACTION_CHANNEL, null);

public/electron.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,17 @@ const ua = require('universal-analytics');
1515
const { machineIdSync } = require('node-machine-id');
1616
const openAboutWindow = require('about-window').default;
1717
const logger = require('./app/logger');
18-
const { ensureDatabaseExists, bootstrapDatabase } = require('./app/db');
18+
const {
19+
ensureDatabaseExists,
20+
bootstrapDatabase,
21+
USER_COLLECTION,
22+
} = require('./app/db');
1923
const {
2024
DATABASE_PATH,
2125
ICON_PATH,
2226
PRODUCT_NAME,
2327
escapeEscapeCharacter,
28+
ACTIONS_VERBS,
2429
} = require('./app/config/config');
2530
const {
2631
LOAD_SPACE_CHANNEL,
@@ -602,6 +607,18 @@ app.on('ready', async () => {
602607
});
603608

604609
app.on('window-all-closed', () => {
610+
// post sign out action
611+
const db = bootstrapDatabase(DATABASE_PATH);
612+
const { id: userId, username, anonymous, geolocation } = db
613+
.get(USER_COLLECTION)
614+
.value();
615+
postAction(mainWindow, db)(null, {
616+
userId,
617+
verb: ACTIONS_VERBS.SIGNOUT,
618+
data: { id: userId, username, anonymous },
619+
geolocation,
620+
});
621+
605622
app.quit();
606623
});
607624

src/actions/action.js

+54-22
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,76 @@
11
import { POST_ACTION_SUCCEEDED } from '../types';
22
import { POST_ACTION_CHANNEL } from '../config/channels';
3+
import {
4+
DEFAULT_ACTIONS_AS_ENABLED,
5+
DEFAULT_GEOLOCATION_ENABLED,
6+
} from '../config/constants';
37

48
const postAction = async (
59
{
6-
userId,
10+
userId: actionUserId,
711
appInstanceId,
812
spaceId,
913
subSpaceId,
1014
format,
1115
data,
1216
verb,
13-
geolocation,
1417
visibility,
1518
} = {},
19+
user,
1620
callback
1721
) => () => {
1822
try {
19-
window.ipcRenderer.send(POST_ACTION_CHANNEL, {
20-
userId,
21-
appInstanceId,
22-
spaceId,
23-
subSpaceId,
24-
format,
25-
data,
26-
verb,
23+
const mutableUser = user.toJS();
24+
const {
25+
id,
26+
settings: {
27+
actionsEnabled = DEFAULT_ACTIONS_AS_ENABLED,
28+
geolocationEnabled = DEFAULT_GEOLOCATION_ENABLED,
29+
},
2730
geolocation,
28-
visibility,
29-
});
31+
} = mutableUser;
3032

31-
window.ipcRenderer.once(
32-
`${POST_ACTION_CHANNEL}_${appInstanceId}`,
33-
async (event, response) => {
34-
callback({
35-
// have to include the appInstanceId to avoid broadcasting
36-
appInstanceId,
37-
type: POST_ACTION_SUCCEEDED,
38-
payload: response,
39-
});
33+
if (actionsEnabled) {
34+
// get user id
35+
let userId = actionUserId;
36+
if (!actionUserId) {
37+
userId = id;
4038
}
41-
);
39+
40+
// add geolocation to action if enabled
41+
let geolocationLatLong = null;
42+
if (geolocationEnabled) {
43+
const { latitude, longitude } = geolocation;
44+
geolocationLatLong = { ll: [latitude, longitude] };
45+
}
46+
47+
window.ipcRenderer.send(POST_ACTION_CHANNEL, {
48+
userId,
49+
appInstanceId,
50+
spaceId,
51+
subSpaceId,
52+
format,
53+
data,
54+
verb,
55+
geolocation: geolocationLatLong,
56+
visibility,
57+
});
58+
59+
// if action from app, wait in app channel
60+
if (appInstanceId) {
61+
window.ipcRenderer.once(
62+
`${POST_ACTION_CHANNEL}_${appInstanceId}`,
63+
async (event, response) => {
64+
callback({
65+
// have to include the appInstanceId to avoid broadcasting
66+
appInstanceId,
67+
type: POST_ACTION_SUCCEEDED,
68+
payload: response,
69+
});
70+
}
71+
);
72+
}
73+
}
4274
} catch (err) {
4375
// do nothing
4476
}

src/actions/authentication.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import {
2020
} from '../config/channels';
2121
import { createFlag } from './common';
2222
import { ERROR_GENERAL } from '../config/errors';
23+
import { postAction } from './action';
24+
import { ACTION_VERBS } from '../config/constants';
2325

2426
const flagSigningIn = createFlag(FLAG_SIGNING_IN);
2527
const flagSigningOut = createFlag(FLAG_SIGNING_OUT);
@@ -37,6 +39,7 @@ const signIn = async ({ username, anonymous }) => async dispatch => {
3739
type: SIGN_IN_SUCCEEDED,
3840
payload: user,
3941
});
42+
// action is sent in sign in redirection
4043
}
4144
dispatch(flagSigningIn(false));
4245
});
@@ -46,7 +49,7 @@ const signIn = async ({ username, anonymous }) => async dispatch => {
4649
}
4750
};
4851

49-
const signOut = () => dispatch => {
52+
const signOut = user => dispatch => {
5053
try {
5154
dispatch(flagSigningOut(true));
5255
window.ipcRenderer.send(SIGN_OUT_CHANNEL);
@@ -58,6 +61,18 @@ const signOut = () => dispatch => {
5861
type: SIGN_OUT_SUCCEEDED,
5962
payload: response,
6063
});
64+
const username = user.get('username');
65+
const id = user.get('id');
66+
const anonymous = user.get('anonymous');
67+
dispatch(
68+
postAction(
69+
{
70+
verb: ACTION_VERBS.SIGNOUT,
71+
data: { username, id, anonymous },
72+
},
73+
user
74+
)
75+
);
6176
}
6277
dispatch(flagSigningOut(false));
6378
});

src/components/common/MainMenu.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { Component } from 'react';
2+
import { Map } from 'immutable';
23
import PropTypes from 'prop-types';
34
import { withRouter } from 'react-router';
45
import { connect } from 'react-redux';
@@ -58,6 +59,11 @@ export class MainMenu extends Component {
5859
location: PropTypes.shape({ pathname: PropTypes.string.isRequired })
5960
.isRequired,
6061
userMode: PropTypes.oneOf(Object.values(USER_MODES)).isRequired,
62+
user: PropTypes.instanceOf(Map),
63+
};
64+
65+
static defaultProps = {
66+
user: Map(),
6167
};
6268

6369
handleClick = path => {
@@ -74,12 +80,12 @@ export class MainMenu extends Component {
7480

7581
handleSignOut() {
7682
// pathname inside location matches the path in url
77-
const { location: { pathname } = {}, dispatchSignOut } = this.props;
83+
const { location: { pathname } = {}, dispatchSignOut, user } = this.props;
7884
if (pathname) {
7985
sessionStorage.setItem('redirect', pathname);
8086
}
8187

82-
dispatchSignOut();
88+
dispatchSignOut(user);
8389
}
8490

8591
renderSignOut() {
@@ -342,6 +348,7 @@ const mapStateToProps = ({ authentication }) => ({
342348
developerMode: authentication.getIn(['user', 'settings', 'developerMode']),
343349
userMode: authentication.getIn(['user', 'settings', 'userMode']),
344350
activity: Boolean(authentication.getIn(['current', 'activity']).size),
351+
user: authentication.get('user'),
345352
});
346353
const mapDispatchToProps = {
347354
dispatchSignOut: signOut,

0 commit comments

Comments
 (0)