Skip to content

Commit dbd32bd

Browse files
committed
Merge branch 'addServer' of https://github.com/andrewjcho84/ReacType into storage
2 parents c696aca + e10439d commit dbd32bd

File tree

15 files changed

+354
-18
lines changed

15 files changed

+354
-18
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: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ 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,
@@ -16,7 +15,7 @@ const {
1615
} = require('electron');
1716

1817
// Uncomment below for hot reloading during development
19-
// require('electron-reload')(__dirname);
18+
require('electron-reload')(__dirname);
2019

2120
// const isDev = true;
2221
const isDev =

package.json

Lines changed: 10 additions & 1 deletion
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"
@@ -121,10 +122,13 @@
121122
"app-root-path": "^3.0.0",
122123
"autoprefixer": "^9.0.1",
123124
"babel-polyfill": "^6.26.0",
125+
"bcryptjs": "^2.4.3",
126+
"body-parser": "^1.19.0",
124127
"classnames": "^2.2.6",
125128
"cli-spinner": "^0.2.8",
126129
"commander": "^2.17.1",
127130
"concurrently": "^5.1.0",
131+
"cookie-parser": "^1.4.5",
128132
"core-js": "^3.6.4",
129133
"csstype": "^2.6.9",
130134
"d3": "^5.9.2",
@@ -173,6 +177,7 @@
173177
"copy-webpack-plugin": "^4.5.2",
174178
"cross-env": "^5.2.1",
175179
"css-loader": "^2.1.1",
180+
"dotenv": "^8.2.0",
176181
"electron": "^2.0.7",
177182
"electron-builder": "^20.44.4",
178183
"electron-devtools-installer": "^2.2.4",
@@ -184,11 +189,15 @@
184189
"eslint-plugin-jest": "^21.21.0",
185190
"eslint-plugin-jsx-a11y": "^6.1.1",
186191
"eslint-plugin-react": "^7.10.0",
192+
"express": "^4.17.1",
187193
"extract-text-webpack-plugin": "^4.0.0-beta.0",
188194
"html-webpack-plugin": "^3.1.0",
189195
"identity-obj-proxy": "^3.0.0",
190196
"jest": "^25.2.6",
197+
"mongodb": "^3.5.9",
198+
"mongoose": "^5.9.20",
191199
"node-sass": "^4.13.1",
200+
"nodemon": "^2.0.4",
192201
"postcss-loader": "^2.1.6",
193202
"redux-mock-store": "^1.5.4",
194203
"sass-loader": "^7.0.3",
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const cookieController = {};
2+
3+
// setCookie = set a cookie with a random number
4+
5+
cookieController.setCookie = (req, res, next) => {
6+
// set cookie with key of 'secret' and value of a random number between 0 and 1000
7+
res.cookie('secret', Math.floor(Math.random() * 1000));
8+
console.log('Successful setCookie');
9+
return next();
10+
};
11+
12+
// setSSIDCookie - store the user id from database in cookie
13+
cookieController.setSSIDCookie = (req, res, next) => {
14+
// set cookie with key 'ssid' and value to user's id, also set http only
15+
res.cookie('ssid', res.locals.id, { httpOnly: true });
16+
console.log('Successful setSSIDCookie');
17+
return next();
18+
};
19+
20+
module.exports = cookieController;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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 cookie with current user's ssid value
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+
// if valid user logged in/signed up, res.locals.id should be user's id generated from mongodb
28+
console.log('Inside startSession');
29+
Session.create({ cookieId: res.locals.id }, err => {
30+
if (err) {
31+
return next({
32+
log: `Error in sessionController.startSession: ${err}`,
33+
message: {
34+
err: `Error in sessionController.startSession, check server logs for details`
35+
}
36+
});
37+
}
38+
console.log('Successful startSession');
39+
return next();
40+
});
41+
};
42+
43+
module.exports = sessionController;

server/controllers/userController.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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('Inside createUser');
10+
const { username, password } = req.body;
11+
// error handling if username or password is missing
12+
if (!username || !password) {
13+
return next('Missing username or password in userController.createUser');
14+
}
15+
const projects = [];
16+
// create user using username and password
17+
Users.create({ username, password, projects }, (err, newUser) => {
18+
if (err) {
19+
return next({
20+
log: `Error in userController.createUser: ${err}`,
21+
message: {
22+
err: `Error in userController.createUser. Check server logs for details`
23+
}
24+
});
25+
} else {
26+
// this id property will be used in other middleware for cookie
27+
console.log('Successfule createUser');
28+
res.locals.id = newUser.id;
29+
return next();
30+
}
31+
});
32+
};
33+
34+
// verifyUser - Obtain username and password from the request body, locate
35+
// the appropriate user in the database, and then authenticate the submitted password against the password stored in the database.
36+
37+
userController.verifyUser = (req, res, next) => {
38+
console.log('Inside verifyUser');
39+
const { username, password } = req.body;
40+
Users.findOne({ username }, (err, user) => {
41+
if (err) {
42+
return next({
43+
log: `Error in userController.verifyUser: ${err}`,
44+
message: {
45+
err: `Error in userController.verifyUser, check server logs for details`
46+
}
47+
});
48+
} else {
49+
// bcrypt compare function checks input password against hashed password
50+
bcrypt.compare(password, user.password).then(isMatch => {
51+
if (isMatch) {
52+
// if password matches, save user id for following middleware
53+
console.log('Successful verifyUser');
54+
res.locals.id = user.id;
55+
return next();
56+
} else {
57+
// if password does not match, redirect to ?
58+
return res.status(400).send('Incorrect password');
59+
}
60+
});
61+
}
62+
});
63+
};
64+
65+
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);

server/server.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
const express = require('express');
2+
const mongoose = require('mongoose');
3+
const path = require('path');
4+
const cookieParser = require('cookie-parser');
5+
const userController = require('./controllers/userController');
6+
const cookieController = require('./controllers/cookieController');
7+
const sessionController = require('./controllers/sessionController');
8+
const app = express();
9+
const PORT = 8080;
10+
11+
// connect to mongo db
12+
mongoose
13+
.connect(process.env.MONGO_URI, {
14+
// options for the connect method to parse the URI
15+
useNewUrlParser: true,
16+
useUnifiedTopology: true,
17+
useCreateIndex: true,
18+
// sets the name of the DB that our collections are part of
19+
dbName: 'ReacType'
20+
})
21+
.then(() => console.log('Connected to Mongo DB.'))
22+
.catch(err => console.log(err));
23+
24+
// handle parsing request body
25+
app.use(express.json());
26+
// cookie parser
27+
app.use(cookieParser());
28+
29+
// statically serve everything in build folder
30+
app.use('/build', express.static(path.resolve(__dirname, '../build')));
31+
32+
app.get('/', cookieController.setCookie, (req, res) => {
33+
res.status(200).sendFile(path.resolve(__dirname, '../src/public/index.html'));
34+
});
35+
36+
app.post(
37+
'/signup',
38+
userController.createUser,
39+
cookieController.setSSIDCookie,
40+
sessionController.startSession,
41+
(req, res) => {
42+
return res.status(200).json(res.locals.id);
43+
}
44+
);
45+
46+
app.post(
47+
'/login',
48+
userController.verifyUser,
49+
cookieController.setSSIDCookie,
50+
sessionController.startSession,
51+
(req, res) => {
52+
return res.status(200).json(res.locals.id);
53+
}
54+
);
55+
56+
// catch-all route handler
57+
app.use('*', (req, res) => {
58+
return res.status(404).send('Page not found');
59+
});
60+
61+
// Global error handler
62+
app.use((err, req, res, next) => {
63+
console.log('invoking global error handler');
64+
const defaultErr = {
65+
log: 'Express error handler caught unknown middleware',
66+
status: 500,
67+
message: { err: 'An error occurred' }
68+
};
69+
70+
const errorObj = Object.assign({}, defaultErr, err);
71+
console.log(errorObj.log);
72+
return res.status(errorObj.status).json(errorObj.message);
73+
});
74+
75+
// starts server on PORT
76+
app.listen(PORT, () => {
77+
console.log(`Server listening on port: ${PORT}`);
78+
});

src/actions/actionCreators.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export const addComponent = ({ title }: { title: string }): Action => ({
6161
type: ADD_COMPONENT,
6262
payload: { title }
6363
});
64+
6465
export const addProp = ({
6566
key,
6667
type

src/components/bottom/HtmlAttr.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ class HtmlAttr extends Component<HTMLAttrPropsInt, StateInt> {
170170
<p style={{ color: 'black' }}>
171171
{focusChild.HTMLInfo[attr]
172172
? focusChild.HTMLInfo[attr]
173-
: ' no attribute assigned'}
173+
: 'no attribute assigned'}
174174
</p>
175175
</Paper>
176176
</Grid>

0 commit comments

Comments
 (0)