Skip to content

Commit 74b0855

Browse files
authored
Merge pull request #3 from oslabs-beta/staging-faast
Added backend express server, login functions, basic routing
2 parents dd24825 + 6b1388a commit 74b0855

26 files changed

+937
-30
lines changed

.babelrc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
}
88
],
99
"react",
10-
"stage-0",
10+
"stage-0"
1111
],
1212
"plugins": ["transform-es2015-modules-commonjs"],
1313
"env": {
1414
"test": {
1515
"plugins": ["transform-es2015-modules-commonjs"]
1616
}
17-
}
17+
}
1818
}

main.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@ const { initSplashScreen, OfficeTemplate } = require('electron-splashscreen');
44
//path resolver dependency for splash screen
55
const { resolve } = require('app-root-path');
66

7-
87
const {
98
app,
109
BrowserWindow,
1110
Menu,
1211
shell,
1312
dialog,
1413
ipcMain,
15-
globalShortcut
14+
globalShortcut,
15+
session
1616
} = require('electron');
1717

1818
// Uncomment below for hot reloading during development
19-
// require('electron-reload')(__dirname);
19+
require('electron-reload')(__dirname);
2020

2121
// const isDev = true;
2222
const isDev =
@@ -119,7 +119,8 @@ const createWindow = () => {
119119
});
120120

121121
// and load the index.html of the app.
122-
mainWindow.loadURL(`file://${__dirname}/build/index.html`);
122+
// now loading what the server serves, this url will need to change when/if we decide to put reactype on the web
123+
mainWindow.loadURL(`http://localhost:8080`);
123124
// load page once window is loaded
124125
mainWindow.once('ready-to-show', () => {
125126
mainWindow.show();
@@ -265,9 +266,9 @@ const createWindow = () => {
265266

266267
// UNCOMMENT THIS DURING DEVELOPMENT TO ENABLE CONSOLE TO OPEN UPON LAUNCH
267268
// dev tools opened on every browser creation
268-
// mainWindow.webContents.once('dom-ready', () => {
269-
// mainWindow.webContents.openDevTools();
270-
// });
269+
mainWindow.webContents.once('dom-ready', () => {
270+
mainWindow.webContents.openDevTools();
271+
});
271272
};
272273

273274
// This method will be called when Electron has finished

package.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@
7575
"test:update-snap": "cross-env NODE_ENV=test jest --updateSnapshot",
7676
"test:clear": "cross-env NODE_ENV=test jest --clearCache",
7777
"linter": "eslint src",
78-
"develop": "concurrently \"npm run dev\" \"npm run electron\""
78+
"develop": "concurrently \"npm run dev\" \"npm run electron\"",
79+
"server": "cross-env NODE_ENV=development nodemon server/server.js"
7980
},
8081
"bin": {
8182
"reactype": "./index.js"
@@ -116,15 +117,19 @@
116117
"@types/react": "^16.8.14",
117118
"@types/react-dom": "^16.8.4",
118119
"@types/react-redux": "^7.0.8",
120+
"@types/react-router-dom": "^5.1.5",
119121
"@types/react-syntax-highlighter": "^11.0.4",
120122
"ace-builds": "^1.4.8",
121123
"app-root-path": "^3.0.0",
122124
"autoprefixer": "^9.0.1",
123125
"babel-polyfill": "^6.26.0",
126+
"bcryptjs": "^2.4.3",
127+
"body-parser": "^1.19.0",
124128
"classnames": "^2.2.6",
125129
"cli-spinner": "^0.2.8",
126130
"commander": "^2.17.1",
127131
"concurrently": "^5.1.0",
132+
"cookie-parser": "^1.4.5",
128133
"core-js": "^3.6.4",
129134
"csstype": "^2.6.9",
130135
"d3": "^5.9.2",
@@ -145,7 +150,8 @@
145150
"react-dom": "^16.4.1",
146151
"react-draggable": "^3.0.5",
147152
"react-konva": "^16.12.0-0",
148-
"react-redux": "^5.0.7",
153+
"react-redux": "^7.2.0",
154+
"react-router-dom": "^5.2.0",
149155
"react-simple-code-editor": "^0.11.0",
150156
"react-sortable-tree": "^2.2.0",
151157
"react-syntax-highlighter": "^10.2.1",
@@ -173,6 +179,7 @@
173179
"copy-webpack-plugin": "^4.5.2",
174180
"cross-env": "^5.2.1",
175181
"css-loader": "^2.1.1",
182+
"dotenv": "^8.2.0",
176183
"electron": "^2.0.7",
177184
"electron-builder": "^20.44.4",
178185
"electron-devtools-installer": "^2.2.4",
@@ -184,11 +191,15 @@
184191
"eslint-plugin-jest": "^21.21.0",
185192
"eslint-plugin-jsx-a11y": "^6.1.1",
186193
"eslint-plugin-react": "^7.10.0",
194+
"express": "^4.17.1",
187195
"extract-text-webpack-plugin": "^4.0.0-beta.0",
188196
"html-webpack-plugin": "^3.1.0",
189197
"identity-obj-proxy": "^3.0.0",
190198
"jest": "^25.2.6",
199+
"mongodb": "^3.5.9",
200+
"mongoose": "^5.9.20",
191201
"node-sass": "^4.13.1",
202+
"nodemon": "^2.0.4",
192203
"postcss-loader": "^2.1.6",
193204
"redux-mock-store": "^1.5.4",
194205
"sass-loader": "^7.0.3",
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const cookieController = {};
2+
3+
// setSSIDCookie - store the user id from database in cookie
4+
cookieController.setSSIDCookie = (req, res, next) => {
5+
// set cookie with key 'ssid' and value to user's id, also set http only
6+
res.cookie('ssid', res.locals.id, { maxAge: 3600000 });
7+
console.log('Successful setSSIDCookie');
8+
return next();
9+
};
10+
11+
module.exports = cookieController;
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
const Session = require('../models/sessionModel');
2+
const sessionController = {};
3+
4+
// isLoggedIn finds appropriate session for this request in database, then verifies whether or not the session is still valid
5+
sessionController.isLoggedIn = (req, res, next) => {
6+
// find session from request session ID in mongodb
7+
Session.findOne({ cookieId: req.cookies.ssid }, (err, session) => {
8+
if (err) {
9+
return next({
10+
log: `Error in sessionController.isLoggedIn: ${err}`,
11+
message: {
12+
err: `Error in sessionController.isLoggedIn, check server logs for details`
13+
}
14+
});
15+
// no session found, redirect to signup page
16+
} else if (!session) {
17+
return res.redirect('/signup');
18+
} else {
19+
// session found, move onto next middleware
20+
return next();
21+
}
22+
});
23+
};
24+
25+
// startSession - create and save a new session into the database
26+
sessionController.startSession = (req, res, next) => {
27+
console.log('Inside startSession');
28+
// first check if user is logged in already
29+
Session.findOne({ cookieId: res.locals.id }, (err, session) => {
30+
if (err) {
31+
return next({
32+
log: `Error in sessionController.startSession find session: ${err}`,
33+
message: {
34+
err: `Error in sessionController.startSession find session, check server logs for details`
35+
}
36+
});
37+
// if session doesn't exist, create a session
38+
// if valid user logged in/signed up, res.locals.id should be user's id generated from mongodb, which we will set as this session's cookieId
39+
} else if (!session) {
40+
Session.create({ cookieId: res.locals.id }, (err, session) => {
41+
if (err) {
42+
return next({
43+
log: `Error in sessionController.startSession create session: ${err}`,
44+
message: {
45+
err: `Error in sessionController.startSession create session, check server logs for details`
46+
}
47+
});
48+
} else {
49+
console.log('Successful startSession');
50+
res.locals.ssid = session.id;
51+
return next();
52+
}
53+
});
54+
// if session exists, move onto next middleware
55+
} else {
56+
console.log('Session exists, moving on');
57+
res.locals.ssid = session.id;
58+
return next();
59+
}
60+
});
61+
};
62+
module.exports = sessionController;

server/controllers/userController.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// middleware functions create a new user and verify users
2+
3+
const Users = require('../models/userModel');
4+
5+
const userController = {};
6+
const bcrypt = require('bcryptjs');
7+
8+
userController.createUser = (req, res, next) => {
9+
console.log('Creating user...');
10+
const { username, password } = req.body;
11+
// error handling if username or password is missing
12+
if (!username) {
13+
return res.status(400).json('No username input');
14+
}
15+
if (!password) {
16+
return res.status(400).json('No password input');
17+
}
18+
const projects = [];
19+
// create user using username and password
20+
Users.create({ username, password, projects }, (err, newUser) => {
21+
if (err) {
22+
return next({
23+
log: `Error in userController.createUser: ${err}`,
24+
message: {
25+
err: `Error in userController.createUser. Check server logs for details`
26+
}
27+
});
28+
} else {
29+
// this id property will be used in other middleware for cookie
30+
console.log('Successful createUser');
31+
res.locals.id = newUser.id;
32+
return next();
33+
}
34+
});
35+
};
36+
37+
// verifyUser - Obtain username and password from the request body, locate
38+
// the appropriate user in the database, and then authenticate the submitted password against the password stored in the database.
39+
40+
userController.verifyUser = (req, res, next) => {
41+
console.log('Verifying user...');
42+
const { username, password } = req.body;
43+
if (!username) {
44+
return res.status(400).json('No username input');
45+
}
46+
if (!password) {
47+
return res.status(400).json('No password input');
48+
}
49+
Users.findOne({ username }, (err, user) => {
50+
if (err) {
51+
return next({
52+
log: `Error in userController.verifyUser: ${err}`,
53+
message: {
54+
err: `Error in userController.verifyUser, check server logs for details`
55+
}
56+
});
57+
} else if (user) {
58+
// bcrypt compare function checks input password against hashed password
59+
bcrypt.compare(password, user.password).then(isMatch => {
60+
if (isMatch) {
61+
// if password matches, save user id for following middleware
62+
console.log('Successful verifyUser');
63+
res.locals.id = user.id;
64+
return next();
65+
} else {
66+
// if password does not match, redirect to ?
67+
return res.status(400).json('Incorrect password');
68+
}
69+
});
70+
} else {
71+
return res.status(400).json('No such user found');
72+
}
73+
});
74+
};
75+
76+
module.exports = userController;

server/models/sessionModel.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const mongoose = require('mongoose');
2+
const Schema = mongoose.Schema;
3+
4+
// Mongo has an automatic document expiration service that we can use via the 'expires' property in the schema. This sets it so each session can only last an hour
5+
const sessionSchema = new Schema({
6+
cookieId: { type: String, required: true, unique: true },
7+
createdAt: { type: Date, expires: 3600, default: Date.now }
8+
});
9+
10+
module.exports = mongoose.model('Sessions', sessionSchema);

server/models/userModel.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const mongoose = require('mongoose');
2+
require('dotenv').config();
3+
4+
const Schema = mongoose.Schema;
5+
6+
const userSchema = new Schema({
7+
username: { type: String, required: true, unique: true },
8+
password: { type: String, required: true },
9+
projects: Array
10+
});
11+
12+
// salt will go through 10 rounds of hashing
13+
const SALT_WORK_FACTOR = 10;
14+
const bcrypt = require('bcryptjs');
15+
const { session } = require('electron');
16+
17+
// mongoose middleware that will run before the save to collection happens (user gets put into database)
18+
// cannot use arrow function here as context of 'this' is important
19+
userSchema.pre('save', function(next) {
20+
// within this context, 'this' refers to the document (new user) about to be saved, in our case, it should have properties username, password, and projects array
21+
bcrypt.hash(this.password, SALT_WORK_FACTOR, (err, hash) => {
22+
if (err) {
23+
return next({
24+
log: `bcrypt password hashing error: ${err}`,
25+
message: {
26+
err: `bcrypt hash error: check server logs for details`
27+
}
28+
});
29+
}
30+
this.password = hash;
31+
return next();
32+
});
33+
});
34+
35+
module.exports = mongoose.model('Users', userSchema);

0 commit comments

Comments
 (0)