From f5ac1f7c43aedbcbd533af32fd195ea88a98c352 Mon Sep 17 00:00:00 2001 From: pdelancy Date: Thu, 9 Nov 2017 10:54:30 -0800 Subject: [PATCH 01/28] header --- backend/routes.js | 1 + env.sh | 2 ++ frontend/components/Header.js | 44 +++++++++++++++++++++++++++++ frontend/containers/AppContainer.js | 4 +++ frontend/containers/Root.dev.js | 8 ++++-- models.js | 39 +++++++++++++++++++++++++ package.json | 10 +++++++ server.js | 39 ++++++++++++++++++++++++- sync.js | 13 +++++++++ 9 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 env.sh create mode 100644 frontend/components/Header.js create mode 100644 models.js create mode 100644 sync.js diff --git a/backend/routes.js b/backend/routes.js index 9dd2215..7a63945 100644 --- a/backend/routes.js +++ b/backend/routes.js @@ -3,6 +3,7 @@ const router = express.Router(); // YOUR API ROUTES HERE + // SAMPLE ROUTE router.use('/users', (req, res) => { res.json({ success: true }); diff --git a/env.sh b/env.sh new file mode 100644 index 0000000..01b2493 --- /dev/null +++ b/env.sh @@ -0,0 +1,2 @@ +export DATABASE_URL="postgresql://postgres@localhost/reddit"; +export DATABASE_NAME="reddit"; diff --git a/frontend/components/Header.js b/frontend/components/Header.js new file mode 100644 index 0000000..11e4f24 --- /dev/null +++ b/frontend/components/Header.js @@ -0,0 +1,44 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Navbar } from 'react-bootstrap'; + + +const Header = ( { name } ) => { + return ( + + {/* + */} +
+
+
+ +
+
+
+ REDDIT +
+
+ + {/*
+
*/} + {/* */} +
+ ); +}; + +Header.propTypes = { + // name: PropTypes.string, +}; + + +export default Header; diff --git a/frontend/containers/AppContainer.js b/frontend/containers/AppContainer.js index 7c29205..0a3ae02 100644 --- a/frontend/containers/AppContainer.js +++ b/frontend/containers/AppContainer.js @@ -2,11 +2,15 @@ import PropTypes from 'prop-types'; import React from 'react'; import { connect } from 'react-redux'; import Title from '../components/Title'; +import DevTools from './DevTools'; +import Header from '../components/Header'; const AppContainer = ({ name }) => { return (
+
+ <DevTools/> </div> ); }; diff --git a/frontend/containers/Root.dev.js b/frontend/containers/Root.dev.js index c0f8d69..031836e 100644 --- a/frontend/containers/Root.dev.js +++ b/frontend/containers/Root.dev.js @@ -3,13 +3,17 @@ import React from 'react'; import {Provider} from 'react-redux'; import AppContainer from './AppContainer.js'; import DevTools from './DevTools'; +import { HashRouter, Route, Switch } from 'react-router-dom'; export default function Root({ store }) { return ( <Provider store={store}> <div> - <AppContainer /> - <DevTools /> + <HashRouter> + <Switch> + <Route exact path="/" component={AppContainer}/> + </Switch> + </HashRouter> </div> </Provider> ); diff --git a/models.js b/models.js new file mode 100644 index 0000000..97d8732 --- /dev/null +++ b/models.js @@ -0,0 +1,39 @@ +"use strict"; + +var Sequelize = require('sequelize'); +var sequelize = new Sequelize(process.env.DATABASE_NAME, 'postgres', process.env.DATABASE_PASSWORD, { + dialect: 'postgres' +}); + +sequelize +.authenticate() +.then(() => { + console.log('Connection has been established successfully.'); +}) +.catch(err => { + console.error('Unable to connect to the database:', err); +}); + +// MODELS GO HERE +var User = sequelize.define('user', { + id: { + type: Sequelize.INTEGER, + primaryKey: true, + autoIncrement: true + }, + username: { + type: Sequelize.STRING, + allowNull: false, + unique: true + }, + password: { + type: Sequelize.STRING, + allowNull: false + }, + // ADD MORE ATTRIBUTES HERE +}); + +module.exports = { + sequelize, + User, +}; diff --git a/package.json b/package.json index 54019e8..7803287 100644 --- a/package.json +++ b/package.json @@ -18,21 +18,31 @@ "babel-loader": "^6.4.1", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", + "bcrypt": "^1.0.3", + "body-parser": "^1.18.2", "css-loader": "^0.28.0", "enzyme": "^2.8.1", "expect": "^1.20.2", "express": "^4.15.2", "mocha": "^3.2.0", "node-sass": "^4.5.2", + "passport": "^0.4.0", + "passport-local": "^1.0.0", + "pg": "^7.4.0", + "pg-hstore": "^2.3.2", "prop-types": "^15.5.8", "react": "^15.5.4", + "react-bootstrap": "^0.31.5", "react-dom": "^15.5.4", "react-redux": "^5.0.5", + "react-router": "^4.2.0", + "react-router-dom": "^4.2.2", "redux": "^3.7.2", "redux-devtools": "^3.4.0", "redux-devtools-dock-monitor": "^1.1.2", "redux-devtools-log-monitor": "^1.3.0", "sass-loader": "^6.0.3", + "sequelize": "^4.22.5", "style-loader": "^0.16.1", "webpack": "^2.3.3" }, diff --git a/server.js b/server.js index ac6e4f3..53b62ea 100644 --- a/server.js +++ b/server.js @@ -1,15 +1,52 @@ const path = require('path'); const express = require('express'); const app = express(); +const bodyParser = require('body-parser'); const PORT = process.env.PORT || 3000; const api = require('./backend/routes'); +const passport = require('passport'); +const LocalStrategy = require('passport-local'); +const bcrypt = require('bcrypt'); +const sequelize = require('./models'); app.use(express.static(path.join(__dirname, 'public'))); - +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: false })); app.get('/', (request, response) => { response.sendFile(__dirname + '/public/index.html'); // For React/Redux }); +// Passport +passport.serializeUser((user, done) => { + done(null, user.id); +}); + +passport.deserializeUser((id, done) => { + sequelize.query(`SELECT * FROM users WHERE id = $1`, [id]) + .then(user => done(null, user.rows[0])) + .catch((err) => {throw new Error(err);}); +}); + +passport.use(new LocalStrategy((username, password, done) => { + sequelize.query(`SELECT * FROM users WHERE username = $1`, [username]) + .then(user => { + if(user.rows.length === 0) { + return done(null, false); + } + bcrypt.compare(password, user.rows[0].password, (err, res) => { + if(res) { + return done(null, user.rows[0]); + } + return null; + }); + return null; + }) + .catch((err) => {return done(err);}); +})); + +app.use(passport.initialize()); +app.use(passport.session()); + app.use('/api', api); app.listen(PORT, error => { diff --git a/sync.js b/sync.js new file mode 100644 index 0000000..4f753aa --- /dev/null +++ b/sync.js @@ -0,0 +1,13 @@ +"use strict"; + +var models = require('./models'); + +models.sequelize.sync({ force: true }) + .then(function() { + console.log('Successfully updated database tables!'); + process.exit(0); + }) + .catch(function(error) { + console.log('Error updating database tables', error); + process.exit(1); + }); From dd2bbeaf0d1ccc2e5ee0bbcee144d2740592db92 Mon Sep 17 00:00:00 2001 From: pdelancy <pdelancy94@gmail.com> Date: Thu, 9 Nov 2017 11:42:58 -0800 Subject: [PATCH 02/28] stuff --- frontend/components/Header.js | 38 +++++++++++++++-------------- frontend/components/Title.js | 5 +++- frontend/containers/AppContainer.js | 2 +- public/index.html | 4 ++- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/frontend/components/Header.js b/frontend/components/Header.js index 11e4f24..bf16a55 100644 --- a/frontend/components/Header.js +++ b/frontend/components/Header.js @@ -1,43 +1,45 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Navbar } from 'react-bootstrap'; - +import { Navbar, Nav, NavDropdown, MenuItem } from 'react-bootstrap'; const Header = ( { name } ) => { return ( - <Navbar fixedTop={true}> + <Navbar fixedTop={true} fluid={true} style={{padding: '0px', margin: '0px'}}> {/* <Navbar.Header> <Navbar.Brand> */} <div style={{width: '100%', backgroundColor: 'lightBlue', padding:'0px', display: 'flex', height: '100px', alignItems: 'center'}}> <div style={{flex: 1, height:'100%', display: 'flex', alignItems: 'center', paddingLeft: '20px'}}> <div> - <img src="https://www.acquia.com/sites/default/files/reddit_logo.png" style={{height: '80', }}/> + <img src="https://www.acquia.com/sites/default/files/reddit_logo.png" style={{height: '80px', }}/> </div> </div> - <div style={{flex: 6, fontSize: '50', color: 'white', textShadow: '2px 2px orange', fontFamily:"Arial, Sans-serif" }}> - REDDIT + <div style={{flex: 3, fontSize: '50px', color: 'white', textShadow: '2px 2px orange', fontFamily:"Arial, Sans-serif" }}> + R/ {name} + </div> + <div style={{flex: 4}}> + <Nav> + {/* <NavItem eventKey={1} href="#">Link</NavItem> + <NavItem eventKey={2} href="#">Link</NavItem> */} + <NavDropdown eventKey={3} title="Dropdown" id="basic-nav-dropdown"> + <MenuItem eventKey={3.1}>Action</MenuItem> + <MenuItem eventKey={3.2}>Another action</MenuItem> + <MenuItem eventKey={3.3}>Something else here</MenuItem> + <MenuItem divider /> + <MenuItem eventKey={3.4}>Separated link</MenuItem> + </NavDropdown> + </Nav> </div> </div> {/* </Navbar.Brand> </Navbar.Header> */} - {/* <Nav> - <NavItem eventKey={1} href="#">Link</NavItem> - <NavItem eventKey={2} href="#">Link</NavItem> - <NavDropdown eventKey={3} title="Dropdown" id="basic-nav-dropdown"> - <MenuItem eventKey={3.1}>Action</MenuItem> - <MenuItem eventKey={3.2}>Another action</MenuItem> - <MenuItem eventKey={3.3}>Something else here</MenuItem> - <MenuItem divider /> - <MenuItem eventKey={3.4}>Separated link</MenuItem> - </NavDropdown> - </Nav> */} + </Navbar> ); }; Header.propTypes = { - // name: PropTypes.string, + name: PropTypes.string, }; diff --git a/frontend/components/Title.js b/frontend/components/Title.js index e20bf57..8a30889 100644 --- a/frontend/components/Title.js +++ b/frontend/components/Title.js @@ -3,7 +3,10 @@ import PropTypes from 'prop-types'; const Title = ( { name } ) => { return ( - <h1>{name}</h1> + <div style={{height: '2000px'}}> + <h1>{name}</h1> + </div> + ); }; diff --git a/frontend/containers/AppContainer.js b/frontend/containers/AppContainer.js index 0a3ae02..62ff122 100644 --- a/frontend/containers/AppContainer.js +++ b/frontend/containers/AppContainer.js @@ -8,7 +8,7 @@ import Header from '../components/Header'; const AppContainer = ({ name }) => { return ( <div> - <Header /> + <Header name={name}/> <Title name={name} /> <DevTools/> </div> diff --git a/public/index.html b/public/index.html index 9604aed..a4ff9be 100644 --- a/public/index.html +++ b/public/index.html @@ -1,6 +1,8 @@ <!DOCTYPE html> <html> <head> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css"> + <meta charset="utf-8"> <title>Node + React Starter @@ -8,4 +10,4 @@
- \ No newline at end of file + From 18a2362bbf3b1439babab6310f8b4f68f2c2d5cd Mon Sep 17 00:00:00 2001 From: pdelancy Date: Thu, 9 Nov 2017 14:30:44 -0800 Subject: [PATCH 03/28] user backend --- backend/routes.js | 69 ++++++++++++++++++++++++++++++++++++++++++++--- server.js | 2 +- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/backend/routes.js b/backend/routes.js index 7a63945..08ddfb2 100644 --- a/backend/routes.js +++ b/backend/routes.js @@ -1,12 +1,73 @@ const express = require('express'); const router = express.Router(); +const { User } = require('../models'); +const bcrypt = require('bcrypt'); +let hashedPassword; +module.exports = (passport) => { // YOUR API ROUTES HERE + router.post('/register', (req, res) => { + User.findAll({where: {username: req.body.username}}) + .then(users => { + if(req.body.password === req.body.repeatPassword && !users[0]) { + bcrypt.hash(req.body.password, 10, (err, hash) => { + hashedPassword = hash; + User.create({ + username: req.body.username, + password: hashedPassword + }) + .then(() => { + res.json({success: true}); + }); + }); + } else { + res.json({success: false}); + } + }) + .catch((err)=>console.log(err)); + }); + router.post('/login', passport.authenticate('local', { + successRedirect: '/dashboard', + failureRedirect: '/login' + })); + + // router.use((req, res, next) => { + // if (! req.user) { + // res.redirect('/login'); + // } else { + // next(); + // } + // }); + + router.get('/logout', (req, res) => { + req.logout(); + res.redirect('/'); + }); + + router.get('/:username', (req, res) => { + User.findOne({where: {username: req.params.username}}) + .then((user) => { + if(user) { + console.log(user.dataValues); + res.json({success: true, user: Object.assign({}, user.dataValues, {password: null})}); + } else { + res.json({success: false, user: null}); + } + }); + }); + + router.get('/user', (req, res) => { + User.findOne({where: {username: req.user.username}}) + .then((user) => { + res.json({success: true, user: user.dataValues}); + }); + }); // SAMPLE ROUTE -router.use('/users', (req, res) => { - res.json({ success: true }); -}); + router.use('/users', (req, res) => { + res.json({ success: true }); + }); -module.exports = router; + return router; +}; diff --git a/server.js b/server.js index 53b62ea..3183d9f 100644 --- a/server.js +++ b/server.js @@ -47,7 +47,7 @@ passport.use(new LocalStrategy((username, password, done) => { app.use(passport.initialize()); app.use(passport.session()); -app.use('/api', api); +app.use('/api', api(passport)); app.listen(PORT, error => { error From 06e8d1647e96fd3c945d87dcd24f78e132ae372d Mon Sep 17 00:00:00 2001 From: Samuel Lefcourt Date: Thu, 9 Nov 2017 14:46:39 -0800 Subject: [PATCH 04/28] created feed.js and updated models.js and created NewPost component --- env.sh | 2 + frontend/components/Feed.js | 43 +++++++++++++++++++ frontend/components/Header.js | 0 frontend/components/NewPost.js | 63 +++++++++++++++++++++++++++ frontend/components/Sidebar.js | 0 frontend/containers/AppContainer.js | 6 +++ frontend/containers/Root.dev.js | 25 +++++++---- models.js | 66 +++++++++++++++++++++++++++++ package.json | 9 ++++ public/index.html | 3 +- server.js | 37 +++++++++++++++- sync.js | 13 ++++++ 12 files changed, 256 insertions(+), 11 deletions(-) create mode 100644 env.sh create mode 100644 frontend/components/Feed.js create mode 100644 frontend/components/Header.js create mode 100644 frontend/components/NewPost.js create mode 100644 frontend/components/Sidebar.js create mode 100644 models.js create mode 100644 sync.js diff --git a/env.sh b/env.sh new file mode 100644 index 0000000..b916cb7 --- /dev/null +++ b/env.sh @@ -0,0 +1,2 @@ +export DATABASE_URL='postgresql://postgres@localhost/reddit' +export DATABASE_NAME='reddit' diff --git a/frontend/components/Feed.js b/frontend/components/Feed.js new file mode 100644 index 0000000..89a8274 --- /dev/null +++ b/frontend/components/Feed.js @@ -0,0 +1,43 @@ +var React = require('react'); +var PropTypes = require('prop-types'); + +// This assumes we are passing in posts +// Each post has: img (string url) and description + +//posts +const Feed = ( { } ) => { + console.log('in feed..'); + let posts = [{img: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Moose_superior.jpg/1200px-Moose_superior.jpg', + description: "This is what humans call a 'moose' "}, + {img: 'http://i.telegraph.co.uk/multimedia/archive/02622/geese_2622145b.jpg', + description: "This is what humans call 'geese'. The singular term is 'goose'. They are notorious for pooping in groups over the skies."}] + return ( +
+ { + posts.map((post) => { + return (
+ + + + + + + {post.description} +
); + }) + } +
+ + ); +}; + +// Feed.propTypes = { +// posts: PropTypes.array, +// }; + + +export default Feed; diff --git a/frontend/components/Header.js b/frontend/components/Header.js new file mode 100644 index 0000000..e69de29 diff --git a/frontend/components/NewPost.js b/frontend/components/NewPost.js new file mode 100644 index 0000000..4256ffb --- /dev/null +++ b/frontend/components/NewPost.js @@ -0,0 +1,63 @@ +var React = require('react'); +var {Navbar, FormGroup, FormControl, Button, Checkbox, Col, Form, ControlLabel, HelpBlock} = require('react-bootstrap'); + +class NewPost extends React.Component { + constructor(props) { + super(props); + } + render() { + function FieldGroup({ id, type, label, help }) { + return ( + + {label} + + {help && {help}} + + ); + } + + return ( +
+
+ + + Title + + + + + + + + + Description + + + + + + + + Select image + + + + + + + + + +
+ ); + } +} + +export default NewPost; diff --git a/frontend/components/Sidebar.js b/frontend/components/Sidebar.js new file mode 100644 index 0000000..e69de29 diff --git a/frontend/containers/AppContainer.js b/frontend/containers/AppContainer.js index 7c29205..9286b6f 100644 --- a/frontend/containers/AppContainer.js +++ b/frontend/containers/AppContainer.js @@ -2,11 +2,17 @@ import PropTypes from 'prop-types'; import React from 'react'; import { connect } from 'react-redux'; import Title from '../components/Title'; +import DevTools from './DevTools'; +import Feed from '../components/Feed'; +import NewPost from '../components/NewPost'; const AppContainer = ({ name }) => { return (
+ {/* <Feed /> */} + <NewPost /> + <DevTools /> </div> ); }; diff --git a/frontend/containers/Root.dev.js b/frontend/containers/Root.dev.js index c0f8d69..8fc404b 100644 --- a/frontend/containers/Root.dev.js +++ b/frontend/containers/Root.dev.js @@ -2,19 +2,26 @@ import PropTypes from 'prop-types'; import React from 'react'; import {Provider} from 'react-redux'; import AppContainer from './AppContainer.js'; +import Feed from '../components/Feed.js'; +import NewPost from '../components/NewPost.js'; import DevTools from './DevTools'; +import { HashRouter, Route, Switch } from 'react-router-dom'; export default function Root({ store }) { - return ( - <Provider store={store}> - <div> - <AppContainer /> - <DevTools /> - </div> - </Provider> - ); + return ( + <Provider store={store}> + <HashRouter> + <Switch> + <Route exact path='/' component={AppContainer}/> + <Route exact path='/feed' component={AppContainer}/> + <Route exact path='/post/new' component={NewPost}/> + + </Switch> + </HashRouter> + </Provider> + ); } Root.propTypes = { - store: PropTypes.object.isRequired + store: PropTypes.object.isRequired }; diff --git a/models.js b/models.js new file mode 100644 index 0000000..e15defa --- /dev/null +++ b/models.js @@ -0,0 +1,66 @@ +"use strict"; + +var Sequelize = require('sequelize'); +var sequelize = new Sequelize(process.env.DATABASE_NAME, 'postgres', process.env.DATABASE_PASSWORD, { + dialect: 'postgres' +}); + +sequelize +.authenticate() +.then(() => { + console.log('Connection has been established successfully.'); +}) +.catch(err => { + console.error('Unable to connect to the database:', err); +}); + +// MODELS GO HERE +var User = sequelize.define('user', { + id: { + type: Sequelize.INTEGER, + primaryKey: true, + autoIncrement: true + }, + username: { + type: Sequelize.STRING, + allowNull: false, + unique: true + }, + password: { + type: Sequelize.STRING, + allowNull: false + }, + // ADD MORE ATTRIBUTES HERE +}); + +var Posts = sequelize.define('posts', { + id: { + type: Sequelize.INTEGER, + primaryKey: true, + autoIncrement: true + }, + + fk_post_id: { + type: Sequelize.INTEGER, + allowNull: true + }, + img: { + type: Sequelize.STRING, + allowNull: true + }, + description: { + type: Sequelize.STRING, + allowNull: true + }, + fk_user_id: { + type: Sequelize.INTEGER, + sllowNull: false + } +}) + +module.exports = { + sequelize, + User, + Posts, + // EXPORT models HERE +}; diff --git a/package.json b/package.json index 54019e8..e88c76c 100644 --- a/package.json +++ b/package.json @@ -18,21 +18,30 @@ "babel-loader": "^6.4.1", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", + "bcrypt": "^1.0.3", + "body-parser": "^1.18.2", "css-loader": "^0.28.0", "enzyme": "^2.8.1", "expect": "^1.20.2", "express": "^4.15.2", "mocha": "^3.2.0", "node-sass": "^4.5.2", + "passport": "^0.4.0", + "passport-local": "^1.0.0", + "pg": "^7.4.0", + "pg-hstore": "^2.3.2", "prop-types": "^15.5.8", "react": "^15.5.4", + "react-bootstrap": "^0.31.5", "react-dom": "^15.5.4", "react-redux": "^5.0.5", + "react-router-dom": "^4.2.2", "redux": "^3.7.2", "redux-devtools": "^3.4.0", "redux-devtools-dock-monitor": "^1.1.2", "redux-devtools-log-monitor": "^1.3.0", "sass-loader": "^6.0.3", + "sequelize": "^4.22.5", "style-loader": "^0.16.1", "webpack": "^2.3.3" }, diff --git a/public/index.html b/public/index.html index 9604aed..96dfa03 100644 --- a/public/index.html +++ b/public/index.html @@ -1,6 +1,7 @@ <!DOCTYPE html> <html> <head> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css"> <meta charset="utf-8"> <title>Node + React Starter @@ -8,4 +9,4 @@
- \ No newline at end of file + diff --git a/server.js b/server.js index ac6e4f3..7f3f0e0 100644 --- a/server.js +++ b/server.js @@ -1,15 +1,50 @@ const path = require('path'); const express = require('express'); const app = express(); +const bodyParser = require('body-parser'); +const passport = require('passport'); +const LocalStrategy = require('passport-local'); +const bcrypt = require('bcrypt'); +const sequelize = require('./models'); const PORT = process.env.PORT || 3000; const api = require('./backend/routes'); app.use(express.static(path.join(__dirname, 'public'))); - +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: false })); app.get('/', (request, response) => { response.sendFile(__dirname + '/public/index.html'); // For React/Redux }); +passport.serializeUser(function(user, done) { + done(null, user.id); +}); + +passport.deserializeUser(function(id, done) { + sequelize.query(`SELECT * FROM users WHERE id = $1`,[id]) + .then(user => done(null, user.rows[0])) + .catch((err) => {throw new Error(err);}); +}); + +passport.use(new LocalStrategy(function(username, password, done) { + sequelize.query(`SELECT * FROM users WHERE username = $1`, [username]) + .then(user => { + if(user.rows.length === 0){ + return done(null, false); + } else { + bcrypt.compare(password, user.rows[0].password, function(err, res) { + if(res){ + return done(null, user.rows[0]); + } + }); + } + }) + .catch((err) => {return done(err);}); +})); + +app.use(passport.initialize()); +app.use(passport.session()); + app.use('/api', api); app.listen(PORT, error => { diff --git a/sync.js b/sync.js new file mode 100644 index 0000000..ecfbfc9 --- /dev/null +++ b/sync.js @@ -0,0 +1,13 @@ +"use strict"; + +var models = require('./models'); + +models.sequelize.sync({ force: true }) +.then(function() { + console.log('Successfully updated database tables!'); + process.exit(0); +}) +.catch(function(error) { + console.log('Error updating database tables', error); + process.exit(1); +}); From a206c59802cf32077cb544a85b46e75aa20875a4 Mon Sep 17 00:00:00 2001 From: borajimin Date: Thu, 9 Nov 2017 14:56:37 -0800 Subject: [PATCH 05/28] first commit --- .gitignore | 1 + frontend/actions/index.js | 28 ++++++++++++ frontend/components/Description.js | 17 ++++++++ frontend/components/Login.js | 68 +++++++++++++++++++++++++++++ frontend/components/SideBar.js | 35 +++++++++++++++ frontend/components/SubmitPost.js | 16 +++++++ frontend/containers/AppContainer.js | 26 +++++++++-- frontend/containers/Root.dev.js | 15 ++++--- frontend/reducers/index.js | 23 +++++++++- models.js | 39 +++++++++++++++++ package.json | 10 +++++ public/index.html | 3 +- server.js | 37 +++++++++++++++- sync.js | 13 ++++++ 14 files changed, 317 insertions(+), 14 deletions(-) create mode 100644 frontend/components/Description.js create mode 100644 frontend/components/Login.js create mode 100644 frontend/components/SideBar.js create mode 100644 frontend/components/SubmitPost.js create mode 100644 models.js create mode 100644 sync.js diff --git a/.gitignore b/.gitignore index 028e2a6..9c301b7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ public/bundle.js package-lock.json *hot-update.js *hot-update.json +env.sh diff --git a/frontend/actions/index.js b/frontend/actions/index.js index 2bba168..ae1160f 100644 --- a/frontend/actions/index.js +++ b/frontend/actions/index.js @@ -1,3 +1,31 @@ // Action Creators // import * as types from './types'; +export function toggleLoginModal() { + return { + type: 'TOGGLE_LOGIN_MODAL' + }; +} + +export function loginUserClick(username, password) { + return { + type: 'LOGIN', + username: username, + password: password + } +}; + +export function registerUserClick(username, password, rpw) { + return { + type: 'REGISTER', + username: username, + password: password, + rpw: rpw + } +}; + +export function toggleSignUpClick(){ + return { + type: 'SIGN_UP' + } +}; diff --git a/frontend/components/Description.js b/frontend/components/Description.js new file mode 100644 index 0000000..06db410 --- /dev/null +++ b/frontend/components/Description.js @@ -0,0 +1,17 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const Description = ( { description } ) => { + return ( +
+

{description}

+
+ ); +}; + +Description.propTypes = { + description: PropTypes.string, +}; + + +export default Description; diff --git a/frontend/components/Login.js b/frontend/components/Login.js new file mode 100644 index 0000000..64517b1 --- /dev/null +++ b/frontend/components/Login.js @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Button, Modal, Glyphicon } from 'react-bootstrap'; + +let username = ''; +let password = ''; +let rPassword = ''; + +function onUsernameChange(e) { + username = e.target.value; +} +function onPasswordChange(e) { + password = e.target.value; +} +function onRPasswordChange(e) { + rPassword = e.targat.value; +} + +const Login = ({ modalOpen, state, login, register, onSignUp }) => { + return ( +
+ + modalOpen()}> + + Hey Fam! + + + + {(state.signUp) ? ( + onRPasswordChange(e)} placeholder="repeat password" name="rPassword"/> + ) : ( +
+ onUsernameChange(e)} placeholder="username" name="username"/> + onPasswordChange(e)} placeholder="password" name="password"/> +
+ )} + +
+ + + {(state.signUp) ? ( + + ) : ( +
+ + + +
+ )} + + +
+ +
+
+ ); +}; + +Login.propTypes = { + state: PropTypes.object, + modalOpen: PropTypes.func, + login: PropTypes.func, + register: PropTypes.func, + onSignUp: PropTypes.func +}; + + +export default Login; diff --git a/frontend/components/SideBar.js b/frontend/components/SideBar.js new file mode 100644 index 0000000..a21b5b6 --- /dev/null +++ b/frontend/components/SideBar.js @@ -0,0 +1,35 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import { ButtonGroup, ButtonToolbar, Panel} from 'react-bootstrap'; +import SubmitPost from './SubmitPost'; +import Login from './Login'; +import Description from './Description'; + +const SideBar = ({ state, toggleLogin, loginUser, registerUser, toggleSignUp }) => { + return ( +
+ + + + + + + + + + + +
+ ); +}; + +SideBar.propTypes = { + state: PropTypes.object, + toggleLogin: PropTypes.func, + loginUser: PropTypes.func, + registerUser: PropTypes.func, + toggleSignUp: PropTypes.func + +}; + +export default SideBar; diff --git a/frontend/components/SubmitPost.js b/frontend/components/SubmitPost.js new file mode 100644 index 0000000..5994d3a --- /dev/null +++ b/frontend/components/SubmitPost.js @@ -0,0 +1,16 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Button } from 'react-bootstrap'; + +const SubmitPost = ({ }) => { + return ( + + ); +}; + +SubmitPost.propTypes = { + modalOpen: PropTypes.func +}; + + +export default SubmitPost; diff --git a/frontend/containers/AppContainer.js b/frontend/containers/AppContainer.js index 7c29205..f6709fa 100644 --- a/frontend/containers/AppContainer.js +++ b/frontend/containers/AppContainer.js @@ -2,27 +2,45 @@ import PropTypes from 'prop-types'; import React from 'react'; import { connect } from 'react-redux'; import Title from '../components/Title'; +import DevTools from './DevTools'; +import SideBar from '../components/SideBar'; -const AppContainer = ({ name }) => { +import { toggleLoginModal, loginUserClick, registerUserClick, toggleSignUpClick } from '../actions/index'; + +const AppContainer = ({ state, toggleLogin, loginUser, registerUser, toggleSignUp }) => { return (
+ <SideBar toggleLogin={toggleLogin} + loginUser={loginUser} + registerUser={registerUser} + toggleSignUp={toggleSignUp} + state={state}/> + <DevTools /> </div> ); }; AppContainer.propTypes = { - name: PropTypes.string, + state: PropTypes.object, + toggleLogin: PropTypes.func, + loginUser: PropTypes.func, + registerUser: PropTypes.func, + toggleSignUp: PropTypes.func }; const mapStateToProps = (state) => { return { - name: state.name + state: state }; }; -const mapDispatchToProps = (/* dispatch */) => { +const mapDispatchToProps = (dispatch) => { return { + toggleLogin: () => {dispatch(toggleLoginModal());}, + loginUser: (u, p) => {dispatch(loginUserClick(u, p));}, + registerUser: (u, p) => {dispatch(registerUserClick(u, p));}, + toggleSignUp: () => {dispatch(toggleSignUpClick())} }; }; diff --git a/frontend/containers/Root.dev.js b/frontend/containers/Root.dev.js index c0f8d69..aba74ac 100644 --- a/frontend/containers/Root.dev.js +++ b/frontend/containers/Root.dev.js @@ -1,17 +1,18 @@ import PropTypes from 'prop-types'; import React from 'react'; import {Provider} from 'react-redux'; +import { HashRouter, Route, Switch } from 'react-router-dom'; import AppContainer from './AppContainer.js'; -import DevTools from './DevTools'; export default function Root({ store }) { return ( - <Provider store={store}> - <div> - <AppContainer /> - <DevTools /> - </div> - </Provider> + <Provider store={store}> + <HashRouter> + <Switch> + <Route exact path="/" component={AppContainer}/> + </Switch> + </HashRouter> + </Provider> ); } diff --git a/frontend/reducers/index.js b/frontend/reducers/index.js index 4d415fd..34f7f74 100644 --- a/frontend/reducers/index.js +++ b/frontend/reducers/index.js @@ -1,5 +1,26 @@ -function rootReducer(state = {name: 'Horizons'}, action) { +const axios = require('axios'); + +function rootReducer(state = {name: 'Horizons', +isModalOpen: false, +description: "something", loggedIn: '', signUp: false}, action) { switch (action.type) { + case "TOGGLE_LOGIN_MODAL": + return Object.assign({}, state, {isModalOpen: !state.isModalOpen}); + case "LOGIN": + axios.post('http://localhost:3000/api/login', { + username: action.username, + password: action.password + }) + return state; + case "Register": + axios.post('http://localhost:3000/api/register',{ + username: action.username, + password: action.password, + repeatedPassword: action.rpw + }) + return state; + case "SIGN_UP": + return Object.assign({}, state, {signUp: !state.signUp}); default: return state; } diff --git a/models.js b/models.js new file mode 100644 index 0000000..5bbe0f5 --- /dev/null +++ b/models.js @@ -0,0 +1,39 @@ +"use strict"; + +var Sequelize = require('sequelize'); +var sequelize = new Sequelize(process.env.DATABASE_NAME, 'postgres', process.env.DATABASE_PASSWORD, { + dialect: 'postgres' +}); + +sequelize +.authenticate() +.then(() => { + console.log('Connection has been established successfully.'); +}) +.catch(err => { + console.error('Unable to connect to the database:', err); +}); + +var User = sequelize.define('user', { + id: { + type: Sequelize.INTEGER, + primaryKey: true, + autoIncrement: true + }, + username: { + type: Sequelize.STRING, + allowNull: false, + unique: true + }, + password: { + type: Sequelize.STRING, + allowNull: false + }, + // ADD MORE ATTRIBUTES HERE +}); + +module.exports = { + sequelize, + User + // EXPORT models HERE +}; diff --git a/package.json b/package.json index 54019e8..75489b0 100644 --- a/package.json +++ b/package.json @@ -14,25 +14,35 @@ "author": "", "license": "ISC", "dependencies": { + "axios": "^0.17.0", "babel-core": "^6.24.1", "babel-loader": "^6.4.1", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", + "bcrypt": "^1.0.3", + "body-parser": "^1.18.2", "css-loader": "^0.28.0", "enzyme": "^2.8.1", "expect": "^1.20.2", "express": "^4.15.2", "mocha": "^3.2.0", "node-sass": "^4.5.2", + "passport": "^0.4.0", + "passport-local": "^1.0.0", + "pg": "^7.4.0", + "pg-hstore": "^2.3.2", "prop-types": "^15.5.8", "react": "^15.5.4", + "react-bootstrap": "^0.31.5", "react-dom": "^15.5.4", "react-redux": "^5.0.5", + "react-router-dom": "^4.2.2", "redux": "^3.7.2", "redux-devtools": "^3.4.0", "redux-devtools-dock-monitor": "^1.1.2", "redux-devtools-log-monitor": "^1.3.0", "sass-loader": "^6.0.3", + "sequelize": "^4.22.5", "style-loader": "^0.16.1", "webpack": "^2.3.3" }, diff --git a/public/index.html b/public/index.html index 9604aed..a56a6f3 100644 --- a/public/index.html +++ b/public/index.html @@ -3,9 +3,10 @@ <head> <meta charset="utf-8"> <title>Node + React Starter +
- \ No newline at end of file + diff --git a/server.js b/server.js index ac6e4f3..199bfdb 100644 --- a/server.js +++ b/server.js @@ -1,15 +1,50 @@ const path = require('path'); const express = require('express'); const app = express(); +const bodyParser = require('body-parser'); +const passport = require('passport'); +const LocalStrategy = require('passport-local'); +const bcrypt = require('bcrypt'); +const sequelize = require('./models'); const PORT = process.env.PORT || 3000; const api = require('./backend/routes'); app.use(express.static(path.join(__dirname, 'public'))); - +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: false })); app.get('/', (request, response) => { response.sendFile(__dirname + '/public/index.html'); // For React/Redux }); +passport.serializeUser(function(user, done) { + done(null, user.id); +}); + +passport.deserializeUser(function(id, done) { + sequelize.query(`SELECT * FROM users WHERE id = $1`, [id]) + .then(user => done(null, user.rows[0])) + .catch((err) => {throw new Error(err);}); +}); + +passport.use(new LocalStrategy(function(username, password, done) { + sequelize.query(`SELECT * FROM users WHERE username = $1`, [username]) + .then(user => { + if(user.rows.length === 0){ + return done(null, false); + } else { + bcrypt.compare(password, user.rows[0].password, function(err, res) { + if(res) { + return done(null, user.rows[0]); + } + }); + } + }) + .catch((err) => {return done(err);}); +})); + +app.use(passport.initialize()); +app.use(passport.session()); + app.use('/api', api); app.listen(PORT, error => { diff --git a/sync.js b/sync.js new file mode 100644 index 0000000..d894fc9 --- /dev/null +++ b/sync.js @@ -0,0 +1,13 @@ +"use strict"; + +var models = require('./models'); + +models.sequelize.sync({ force: true }) + .then(function() { + console.log('Successfully updated database tables!'); + process.exit(0); + }) + .catch(function(error) { + console.log('Error updating database tables', error); + process.exit(1); + }); From 05572e3de2831ed3a1409ef91ecad29a8469d865 Mon Sep 17 00:00:00 2001 From: pdelancy Date: Thu, 9 Nov 2017 14:57:34 -0800 Subject: [PATCH 06/28] Revert "Pdelancy" --- backend/routes.js | 70 ++--------------------------- env.sh | 2 - frontend/components/Header.js | 46 ------------------- frontend/components/Title.js | 5 +-- frontend/containers/AppContainer.js | 4 -- frontend/containers/Root.dev.js | 8 +--- models.js | 39 ---------------- package.json | 10 ----- public/index.html | 4 +- server.js | 41 +---------------- sync.js | 13 ------ 11 files changed, 10 insertions(+), 232 deletions(-) delete mode 100644 env.sh delete mode 100644 frontend/components/Header.js delete mode 100644 models.js delete mode 100644 sync.js diff --git a/backend/routes.js b/backend/routes.js index 08ddfb2..9dd2215 100644 --- a/backend/routes.js +++ b/backend/routes.js @@ -1,73 +1,11 @@ const express = require('express'); const router = express.Router(); -const { User } = require('../models'); -const bcrypt = require('bcrypt'); -let hashedPassword; -module.exports = (passport) => { // YOUR API ROUTES HERE - router.post('/register', (req, res) => { - User.findAll({where: {username: req.body.username}}) - .then(users => { - if(req.body.password === req.body.repeatPassword && !users[0]) { - bcrypt.hash(req.body.password, 10, (err, hash) => { - hashedPassword = hash; - User.create({ - username: req.body.username, - password: hashedPassword - }) - .then(() => { - res.json({success: true}); - }); - }); - } else { - res.json({success: false}); - } - }) - .catch((err)=>console.log(err)); - }); - - router.post('/login', passport.authenticate('local', { - successRedirect: '/dashboard', - failureRedirect: '/login' - })); - - // router.use((req, res, next) => { - // if (! req.user) { - // res.redirect('/login'); - // } else { - // next(); - // } - // }); - - router.get('/logout', (req, res) => { - req.logout(); - res.redirect('/'); - }); - - router.get('/:username', (req, res) => { - User.findOne({where: {username: req.params.username}}) - .then((user) => { - if(user) { - console.log(user.dataValues); - res.json({success: true, user: Object.assign({}, user.dataValues, {password: null})}); - } else { - res.json({success: false, user: null}); - } - }); - }); - - router.get('/user', (req, res) => { - User.findOne({where: {username: req.user.username}}) - .then((user) => { - res.json({success: true, user: user.dataValues}); - }); - }); // SAMPLE ROUTE - router.use('/users', (req, res) => { - res.json({ success: true }); - }); +router.use('/users', (req, res) => { + res.json({ success: true }); +}); - return router; -}; +module.exports = router; diff --git a/env.sh b/env.sh deleted file mode 100644 index 01b2493..0000000 --- a/env.sh +++ /dev/null @@ -1,2 +0,0 @@ -export DATABASE_URL="postgresql://postgres@localhost/reddit"; -export DATABASE_NAME="reddit"; diff --git a/frontend/components/Header.js b/frontend/components/Header.js deleted file mode 100644 index bf16a55..0000000 --- a/frontend/components/Header.js +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Navbar, Nav, NavDropdown, MenuItem } from 'react-bootstrap'; - -const Header = ( { name } ) => { - return ( - - {/* - */} -
-
-
- -
-
-
- R/ {name} -
-
- -
-
- - {/*
-
*/} - -
- ); -}; - -Header.propTypes = { - name: PropTypes.string, -}; - - -export default Header; diff --git a/frontend/components/Title.js b/frontend/components/Title.js index 8a30889..e20bf57 100644 --- a/frontend/components/Title.js +++ b/frontend/components/Title.js @@ -3,10 +3,7 @@ import PropTypes from 'prop-types'; const Title = ( { name } ) => { return ( -
-

{name}

-
- +

{name}

); }; diff --git a/frontend/containers/AppContainer.js b/frontend/containers/AppContainer.js index 62ff122..7c29205 100644 --- a/frontend/containers/AppContainer.js +++ b/frontend/containers/AppContainer.js @@ -2,15 +2,11 @@ import PropTypes from 'prop-types'; import React from 'react'; import { connect } from 'react-redux'; import Title from '../components/Title'; -import DevTools from './DevTools'; -import Header from '../components/Header'; const AppContainer = ({ name }) => { return (
-
- <DevTools/> </div> ); }; diff --git a/frontend/containers/Root.dev.js b/frontend/containers/Root.dev.js index 031836e..c0f8d69 100644 --- a/frontend/containers/Root.dev.js +++ b/frontend/containers/Root.dev.js @@ -3,17 +3,13 @@ import React from 'react'; import {Provider} from 'react-redux'; import AppContainer from './AppContainer.js'; import DevTools from './DevTools'; -import { HashRouter, Route, Switch } from 'react-router-dom'; export default function Root({ store }) { return ( <Provider store={store}> <div> - <HashRouter> - <Switch> - <Route exact path="/" component={AppContainer}/> - </Switch> - </HashRouter> + <AppContainer /> + <DevTools /> </div> </Provider> ); diff --git a/models.js b/models.js deleted file mode 100644 index 97d8732..0000000 --- a/models.js +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; - -var Sequelize = require('sequelize'); -var sequelize = new Sequelize(process.env.DATABASE_NAME, 'postgres', process.env.DATABASE_PASSWORD, { - dialect: 'postgres' -}); - -sequelize -.authenticate() -.then(() => { - console.log('Connection has been established successfully.'); -}) -.catch(err => { - console.error('Unable to connect to the database:', err); -}); - -// MODELS GO HERE -var User = sequelize.define('user', { - id: { - type: Sequelize.INTEGER, - primaryKey: true, - autoIncrement: true - }, - username: { - type: Sequelize.STRING, - allowNull: false, - unique: true - }, - password: { - type: Sequelize.STRING, - allowNull: false - }, - // ADD MORE ATTRIBUTES HERE -}); - -module.exports = { - sequelize, - User, -}; diff --git a/package.json b/package.json index 7803287..54019e8 100644 --- a/package.json +++ b/package.json @@ -18,31 +18,21 @@ "babel-loader": "^6.4.1", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", - "bcrypt": "^1.0.3", - "body-parser": "^1.18.2", "css-loader": "^0.28.0", "enzyme": "^2.8.1", "expect": "^1.20.2", "express": "^4.15.2", "mocha": "^3.2.0", "node-sass": "^4.5.2", - "passport": "^0.4.0", - "passport-local": "^1.0.0", - "pg": "^7.4.0", - "pg-hstore": "^2.3.2", "prop-types": "^15.5.8", "react": "^15.5.4", - "react-bootstrap": "^0.31.5", "react-dom": "^15.5.4", "react-redux": "^5.0.5", - "react-router": "^4.2.0", - "react-router-dom": "^4.2.2", "redux": "^3.7.2", "redux-devtools": "^3.4.0", "redux-devtools-dock-monitor": "^1.1.2", "redux-devtools-log-monitor": "^1.3.0", "sass-loader": "^6.0.3", - "sequelize": "^4.22.5", "style-loader": "^0.16.1", "webpack": "^2.3.3" }, diff --git a/public/index.html b/public/index.html index a4ff9be..9604aed 100644 --- a/public/index.html +++ b/public/index.html @@ -1,8 +1,6 @@ <!DOCTYPE html> <html> <head> - <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css"> - <meta charset="utf-8"> <title>Node + React Starter @@ -10,4 +8,4 @@
- + \ No newline at end of file diff --git a/server.js b/server.js index 3183d9f..ac6e4f3 100644 --- a/server.js +++ b/server.js @@ -1,53 +1,16 @@ const path = require('path'); const express = require('express'); const app = express(); -const bodyParser = require('body-parser'); const PORT = process.env.PORT || 3000; const api = require('./backend/routes'); -const passport = require('passport'); -const LocalStrategy = require('passport-local'); -const bcrypt = require('bcrypt'); -const sequelize = require('./models'); app.use(express.static(path.join(__dirname, 'public'))); -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: false })); + app.get('/', (request, response) => { response.sendFile(__dirname + '/public/index.html'); // For React/Redux }); -// Passport -passport.serializeUser((user, done) => { - done(null, user.id); -}); - -passport.deserializeUser((id, done) => { - sequelize.query(`SELECT * FROM users WHERE id = $1`, [id]) - .then(user => done(null, user.rows[0])) - .catch((err) => {throw new Error(err);}); -}); - -passport.use(new LocalStrategy((username, password, done) => { - sequelize.query(`SELECT * FROM users WHERE username = $1`, [username]) - .then(user => { - if(user.rows.length === 0) { - return done(null, false); - } - bcrypt.compare(password, user.rows[0].password, (err, res) => { - if(res) { - return done(null, user.rows[0]); - } - return null; - }); - return null; - }) - .catch((err) => {return done(err);}); -})); - -app.use(passport.initialize()); -app.use(passport.session()); - -app.use('/api', api(passport)); +app.use('/api', api); app.listen(PORT, error => { error diff --git a/sync.js b/sync.js deleted file mode 100644 index 4f753aa..0000000 --- a/sync.js +++ /dev/null @@ -1,13 +0,0 @@ -"use strict"; - -var models = require('./models'); - -models.sequelize.sync({ force: true }) - .then(function() { - console.log('Successfully updated database tables!'); - process.exit(0); - }) - .catch(function(error) { - console.log('Error updating database tables', error); - process.exit(1); - }); From ddf31a45196ebc69043e8c78f3b0051c17a6ecbf Mon Sep 17 00:00:00 2001 From: borajimin Date: Thu, 9 Nov 2017 15:16:10 -0800 Subject: [PATCH 07/28] Changes in style --- frontend/components/SideBar.js | 26 +++++++++++++++----------- frontend/reducers/index.js | 2 +- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/frontend/components/SideBar.js b/frontend/components/SideBar.js index a21b5b6..cd16ed7 100644 --- a/frontend/components/SideBar.js +++ b/frontend/components/SideBar.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { ButtonGroup, ButtonToolbar, Panel} from 'react-bootstrap'; +import { ButtonGroup, ButtonToolbar, Panel, Grid, Row, Col} from 'react-bootstrap'; import SubmitPost from './SubmitPost'; import Login from './Login'; import Description from './Description'; @@ -8,17 +8,21 @@ import Description from './Description'; const SideBar = ({ state, toggleLogin, loginUser, registerUser, toggleSignUp }) => { return (
- - - - - - - - + + + + + + + + + + - - + + + +
); }; diff --git a/frontend/reducers/index.js b/frontend/reducers/index.js index 34f7f74..92fe5f5 100644 --- a/frontend/reducers/index.js +++ b/frontend/reducers/index.js @@ -13,7 +13,7 @@ description: "something", loggedIn: '', signUp: false}, action) { }) return state; case "Register": - axios.post('http://localhost:3000/api/register',{ + axios.post('http://localhost:3000/api/register', { username: action.username, password: action.password, repeatedPassword: action.rpw From ed84b4a3e74a138fa987d039fff1a0d083ea574b Mon Sep 17 00:00:00 2001 From: borajimin Date: Thu, 9 Nov 2017 15:30:25 -0800 Subject: [PATCH 08/28] Sam's env.sh --- env.sh | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 env.sh diff --git a/env.sh b/env.sh deleted file mode 100644 index b916cb7..0000000 --- a/env.sh +++ /dev/null @@ -1,2 +0,0 @@ -export DATABASE_URL='postgresql://postgres@localhost/reddit' -export DATABASE_NAME='reddit' From 767d5b2f7424d93676dd14d669793a6e71e152d4 Mon Sep 17 00:00:00 2001 From: borajimin Date: Thu, 9 Nov 2017 15:33:12 -0800 Subject: [PATCH 09/28] Got rid of Button Tool bar and Button group. --- frontend/components/SideBar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/SideBar.js b/frontend/components/SideBar.js index cd16ed7..639197e 100644 --- a/frontend/components/SideBar.js +++ b/frontend/components/SideBar.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { ButtonGroup, ButtonToolbar, Panel, Grid, Row, Col} from 'react-bootstrap'; +import { Panel, Grid, Row, Col} from 'react-bootstrap'; import SubmitPost from './SubmitPost'; import Login from './Login'; import Description from './Description'; From 85bc1ba386ab9c8ffb802182d478ba9174bbde0e Mon Sep 17 00:00:00 2001 From: borajimin Date: Thu, 9 Nov 2017 16:13:07 -0800 Subject: [PATCH 10/28] Working master --- frontend/actions/index.js | 42 ++++++++++++++--------------- frontend/components/NewPost.js | 9 +++++++ frontend/containers/AppContainer.js | 4 ++- frontend/containers/Root.dev.js | 8 +++--- frontend/reducers/index.js | 23 +++++++++------- server.js | 2 +- 6 files changed, 51 insertions(+), 37 deletions(-) diff --git a/frontend/actions/index.js b/frontend/actions/index.js index ae1160f..2af2d31 100644 --- a/frontend/actions/index.js +++ b/frontend/actions/index.js @@ -2,30 +2,30 @@ // import * as types from './types'; export function toggleLoginModal() { - return { - type: 'TOGGLE_LOGIN_MODAL' - }; + return { + type: 'TOGGLE_LOGIN_MODAL' + }; } export function loginUserClick(username, password) { - return { - type: 'LOGIN', - username: username, - password: password - } -}; + return { + type: 'LOGIN', + username: username, + password: password + }; +} export function registerUserClick(username, password, rpw) { - return { - type: 'REGISTER', - username: username, - password: password, - rpw: rpw - } -}; + return { + type: 'REGISTER', + username: username, + password: password, + rpw: rpw + }; +} -export function toggleSignUpClick(){ - return { - type: 'SIGN_UP' - } -}; +export function toggleSignUpClick() { + return { + type: 'SIGN_UP' + }; +} diff --git a/frontend/components/NewPost.js b/frontend/components/NewPost.js index 4256ffb..ec77755 100644 --- a/frontend/components/NewPost.js +++ b/frontend/components/NewPost.js @@ -37,6 +37,15 @@ class NewPost extends React.Component { + + + Links + + + + + + Select image diff --git a/frontend/containers/AppContainer.js b/frontend/containers/AppContainer.js index ca8afa2..16ed4a3 100644 --- a/frontend/containers/AppContainer.js +++ b/frontend/containers/AppContainer.js @@ -14,6 +14,8 @@ const AppContainer = ({ state, toggleLogin, loginUser, registerUser, toggleSignU return (
+ <Feed /> + <NewPost/> <SideBar toggleLogin={toggleLogin} loginUser={loginUser} registerUser={registerUser} @@ -43,7 +45,7 @@ const mapDispatchToProps = (dispatch) => { toggleLogin: () => {dispatch(toggleLoginModal());}, loginUser: (u, p) => {dispatch(loginUserClick(u, p));}, registerUser: (u, p) => {dispatch(registerUserClick(u, p));}, - toggleSignUp: () => {dispatch(toggleSignUpClick())} + toggleSignUp: () => {dispatch(toggleSignUpClick());} }; }; diff --git a/frontend/containers/Root.dev.js b/frontend/containers/Root.dev.js index af91423..a5a587c 100644 --- a/frontend/containers/Root.dev.js +++ b/frontend/containers/Root.dev.js @@ -13,13 +13,13 @@ export default function Root({ store }) { <HashRouter> <Switch> <Route exact path="/" component={AppContainer}/> - <Route exact path='/feed' component={Feed}/> - <Route exact path='/post/new' component={NewPost}/> + <Route exact path="/feed" component={Feed}/> + <Route exact path="/post/new" component={NewPost}/> </Switch> </HashRouter> </Provider> ); - +} Root.propTypes = { - store: PropTypes.object.isRequired + store: PropTypes.object.isRequired }; diff --git a/frontend/reducers/index.js b/frontend/reducers/index.js index 92fe5f5..50bc2a6 100644 --- a/frontend/reducers/index.js +++ b/frontend/reducers/index.js @@ -1,23 +1,26 @@ const axios = require('axios'); -function rootReducer(state = {name: 'Horizons', -isModalOpen: false, -description: "something", loggedIn: '', signUp: false}, action) { +function rootReducer(state = { + name: 'Horizons', + isModalOpen: false, + description: "something", + loggedIn: '', + signUp: false}, action) { switch (action.type) { case "TOGGLE_LOGIN_MODAL": return Object.assign({}, state, {isModalOpen: !state.isModalOpen}); case "LOGIN": axios.post('http://localhost:3000/api/login', { - username: action.username, - password: action.password - }) + username: action.username, + password: action.password + }); return state; case "Register": axios.post('http://localhost:3000/api/register', { - username: action.username, - password: action.password, - repeatedPassword: action.rpw - }) + username: action.username, + password: action.password, + repeatedPassword: action.rpw + }); return state; case "SIGN_UP": return Object.assign({}, state, {signUp: !state.signUp}); diff --git a/server.js b/server.js index 86ebeee..b908133 100644 --- a/server.js +++ b/server.js @@ -31,7 +31,7 @@ passport.use(new LocalStrategy(function(username, password, done) { sequelize.query(`SELECT * FROM users WHERE username = $1`, [username]) .then(user => { if(user.rows.length === 0){ - return done(null, false); + return done(null, false); } else { bcrypt.compare(password, user.rows[0].password, function(err, res) { if(res) { From 88cb70e97d2e7d5a8ffe247494aacec5ed3e05be Mon Sep 17 00:00:00 2001 From: pdelancy <pdelancy94@gmail.com> Date: Thu, 9 Nov 2017 16:18:18 -0800 Subject: [PATCH 11/28] Delete Sidebar.js --- frontend/components/Sidebar.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 frontend/components/Sidebar.js diff --git a/frontend/components/Sidebar.js b/frontend/components/Sidebar.js deleted file mode 100644 index e69de29..0000000 From b11927f9671b279c244b45a4fe27cfb058dfffe7 Mon Sep 17 00:00:00 2001 From: pdelancy <pdelancy94@gmail.com> Date: Thu, 9 Nov 2017 16:31:54 -0800 Subject: [PATCH 12/28] STABLE COMMIT post revert --- backend/routes.js | 72 +++++++++++++++++++++++++++-- frontend/components/Header.js | 46 ++++++++++++++++++ frontend/containers/AppContainer.js | 4 +- public/index.html | 1 - server.js | 2 +- 5 files changed, 116 insertions(+), 9 deletions(-) diff --git a/backend/routes.js b/backend/routes.js index 9dd2215..4d5a411 100644 --- a/backend/routes.js +++ b/backend/routes.js @@ -1,11 +1,73 @@ const express = require('express'); const router = express.Router(); +const { User } = require('../models'); +const bcrypt = require('bcrypt'); +let hashedPassword; -// YOUR API ROUTES HERE +module.exports = (passport) => { + // YOUR API ROUTES HERE + router.post('/register', (req, res) => { + User.findAll({where: {username: req.body.username}}) + .then(users => { + if(req.body.password === req.body.repeatPassword && !users[0]) { + bcrypt.hash(req.body.password, 10, (err, hash) => { + hashedPassword = hash; + User.create({ + username: req.body.username, + password: hashedPassword + }) + .then(() => { + res.json({success: true}); + }); + }); + } else { + res.json({success: false}); + } + }) + .catch((err)=>console.log(err)); + }); -// SAMPLE ROUTE -router.use('/users', (req, res) => { + router.post('/login', passport.authenticate('local', { + successRedirect: '/dashboard', + failureRedirect: '/login' + })); + + // router.use((req, res, next) => { + // if (! req.user) { + // res.redirect('/login'); + // } else { + // next(); + // } + // }); + + router.get('/logout', (req, res) => { + req.logout(); + res.redirect('/'); + }); + + router.get('/:username', (req, res) => { + User.findOne({where: {username: req.params.username}}) + .then((user) => { + if(user) { + console.log(user.dataValues); + res.json({success: true, user: Object.assign({}, user.dataValues, {password: null})}); + } else { + res.json({success: false, user: null}); + } + }); + }); + + router.get('/user', (req, res) => { + User.findOne({where: {username: req.user.username}}) + .then((user) => { + res.json({success: true, user: user.dataValues}); + }); + }); + + // SAMPLE ROUTE + router.use('/users', (req, res) => { res.json({ success: true }); -}); + }); -module.exports = router; + return router; +}; diff --git a/frontend/components/Header.js b/frontend/components/Header.js index e69de29..915b7b4 100644 --- a/frontend/components/Header.js +++ b/frontend/components/Header.js @@ -0,0 +1,46 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Navbar, Nav, NavDropdown, MenuItem } from 'react-bootstrap'; + +const Header = ( { name } ) => { + return ( + <Navbar fixedTop={true} fluid={true} style={{padding: '0px', margin: '0px'}}> + {/* <Navbar.Header> + <Navbar.Brand> */} + <div style={{width: '100%', backgroundColor: 'lightBlue', padding:'0px', display: 'flex', height: '100px', alignItems: 'center'}}> + <div style={{flex: 1, height:'100%', display: 'flex', alignItems: 'center', paddingLeft: '20px'}}> + <div> + <img src="https://www.acquia.com/sites/default/files/reddit_logo.png" style={{height: '80px', }}/> + </div> + </div> + <div style={{flex: 3, fontSize: '50px', color: 'white', textShadow: '2px 2px orange', fontFamily:"Arial, Sans-serif" }}> + R/ {name} + </div> + <div style={{flex: 4}}> + <Nav> + {/* <NavItem eventKey={1} href="#">Link</NavItem> + <NavItem eventKey={2} href="#">Link</NavItem> */} + <NavDropdown eventKey={3} title="Dropdown" id="basic-nav-dropdown"> + <MenuItem eventKey={3.1}>Action</MenuItem> + <MenuItem eventKey={3.2}>Another action</MenuItem> + <MenuItem eventKey={3.3}>Something else here</MenuItem> + <MenuItem divider /> + <MenuItem eventKey={3.4}>Separated link</MenuItem> + </NavDropdown> + </Nav> + </div> + </div> + + {/* </Navbar.Brand> + </Navbar.Header> */} + + </Navbar> + ); + }; + + Header.propTypes = { + name: PropTypes.string, + }; + + + export default Header; diff --git a/frontend/containers/AppContainer.js b/frontend/containers/AppContainer.js index 16ed4a3..004906e 100644 --- a/frontend/containers/AppContainer.js +++ b/frontend/containers/AppContainer.js @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { connect } from 'react-redux'; -import Title from '../components/Title'; +import Header from '../components/Header'; import DevTools from './DevTools'; import SideBar from '../components/SideBar'; import Feed from '../components/Feed'; @@ -13,7 +13,7 @@ import { toggleLoginModal, loginUserClick, registerUserClick, toggleSignUpClick const AppContainer = ({ state, toggleLogin, loginUser, registerUser, toggleSignUp }) => { return ( <div> - <Title name={name} /> + <Header name={name}/> <Feed /> <NewPost/> <SideBar toggleLogin={toggleLogin} diff --git a/public/index.html b/public/index.html index 5e940e3..a56a6f3 100644 --- a/public/index.html +++ b/public/index.html @@ -1,7 +1,6 @@ <!DOCTYPE html> <html> <head> - <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css"> <meta charset="utf-8"> <title>Node + React Starter diff --git a/server.js b/server.js index b908133..981976f 100644 --- a/server.js +++ b/server.js @@ -46,7 +46,7 @@ passport.use(new LocalStrategy(function(username, password, done) { app.use(passport.initialize()); app.use(passport.session()); -app.use('/api', api); +app.use('/api', api(passport)); app.listen(PORT, error => { error From 201ce4e4fb0a7f2a705094542ab4a1536879c903 Mon Sep 17 00:00:00 2001 From: pdelancy Date: Thu, 9 Nov 2017 17:11:39 -0800 Subject: [PATCH 13/28] Posts backend --- backend/routes.js | 138 ++++++++++++++++++++-------------- frontend/components/Header.js | 2 +- models.js | 80 ++++++++++---------- 3 files changed, 125 insertions(+), 95 deletions(-) diff --git a/backend/routes.js b/backend/routes.js index 4d5a411..2090b48 100644 --- a/backend/routes.js +++ b/backend/routes.js @@ -1,73 +1,99 @@ const express = require('express'); const router = express.Router(); -const { User } = require('../models'); +const { User, Post } = require('../models'); const bcrypt = require('bcrypt'); let hashedPassword; module.exports = (passport) => { // YOUR API ROUTES HERE - router.post('/register', (req, res) => { - User.findAll({where: {username: req.body.username}}) - .then(users => { - if(req.body.password === req.body.repeatPassword && !users[0]) { - bcrypt.hash(req.body.password, 10, (err, hash) => { - hashedPassword = hash; - User.create({ - username: req.body.username, - password: hashedPassword - }) - .then(() => { - res.json({success: true}); - }); - }); - } else { - res.json({success: false}); - } - }) - .catch((err)=>console.log(err)); - }); + router.post('/register', (req, res) => { + User.findAll({where: {username: req.body.username}}) + .then(users => { + if(req.body.password === req.body.repeatPassword && !users[0]) { + bcrypt.hash(req.body.password, 10, (err, hash) => { + hashedPassword = hash; + User.create({ + username: req.body.username, + password: hashedPassword + }) + .then(() => { + res.json({success: true}); + }); + }); + } else { + res.json({success: false}); + } + }) + .catch((err)=>console.log(err)); + }); + + router.post('/login', passport.authenticate('local', { + successRedirect: '/dashboard', + failureRedirect: '/login' + })); - router.post('/login', passport.authenticate('local', { - successRedirect: '/dashboard', - failureRedirect: '/login' - })); + // router.use((req, res, next) => { + // if (! req.user) { + // res.redirect('/login'); + // } else { + // next(); + // } + // }); - // router.use((req, res, next) => { - // if (! req.user) { - // res.redirect('/login'); - // } else { - // next(); - // } - // }); + router.get('/logout', (req, res) => { + req.logout(); + res.redirect('/'); + }); + + router.get('/:username', (req, res) => { + User.findOne({where: {username: req.params.username}}) + .then((user) => { + if(user) { + console.log(user.dataValues); + res.json({success: true, user: Object.assign({}, user.dataValues, {password: null})}); + } else { + res.json({success: false, user: null}); + } + }); + }); - router.get('/logout', (req, res) => { - req.logout(); - res.redirect('/'); - }); + router.get('/user', (req, res) => { + User.findOne({where: {username: req.user.username}}) + .then((user) => { + res.json({success: true, user: user.dataValues}); + }); + }); - router.get('/:username', (req, res) => { - User.findOne({where: {username: req.params.username}}) - .then((user) => { - if(user) { - console.log(user.dataValues); - res.json({success: true, user: Object.assign({}, user.dataValues, {password: null})}); - } else { - res.json({success: false, user: null}); - } + router.post('/post/new', (req, res) => { + Post.create({ + fk_post_id: req.body.postId, + img: req.body.img, + description: req.body.description, + fk_user_id: req.user.username, + title: req.body.title + }) + .then(() => { + res.json({success: true}); + }) + .catch((error)=>{ + res.json({success: false, error: error}); + }); }); - }); - router.get('/user', (req, res) => { - User.findOne({where: {username: req.user.username}}) - .then((user) => { - res.json({success: true, user: user.dataValues}); + router.get('/posts/all', (req, res) => { + Post.findAll({ + where: {fk_post_id: null} + }) + .then((posts) => { + console.log(posts); + res.json({success: true, posts: posts.dataValues}); + }); }); - }); - // SAMPLE ROUTE - router.use('/users', (req, res) => { - res.json({ success: true }); - }); + // SAMPLE ROUTE + router.use('/users', (req, res) => { + res.json({ success: true }); + }); - return router; + return router; }; diff --git a/frontend/components/Header.js b/frontend/components/Header.js index 915b7b4..e5d9392 100644 --- a/frontend/components/Header.js +++ b/frontend/components/Header.js @@ -14,7 +14,7 @@ const Header = ( { name } ) => {
- R/ {name} + R/ HORIZONS
-
+
R/ HORIZONS
-
- */}
From f8fe48b2730059de4fb0e3692e24bf8bcc7bd656 Mon Sep 17 00:00:00 2001 From: borajimin Date: Thu, 9 Nov 2017 19:03:59 -0800 Subject: [PATCH 15/28] connect newPost with backend --- backend/routes.js | 2 +- frontend/actions/index.js | 6 ++ frontend/components/Header.js | 2 +- frontend/components/NewPost.js | 125 +++++++++++++++++++--------- frontend/components/SideBar.js | 12 ++- frontend/components/SubmitPost.js | 34 +++++--- frontend/containers/AppContainer.js | 15 ++-- frontend/containers/Root.dev.js | 2 + frontend/index.js | 6 +- frontend/reducers/index.js | 23 ++++- package.json | 2 + 11 files changed, 165 insertions(+), 64 deletions(-) diff --git a/backend/routes.js b/backend/routes.js index 4d5a411..31cfb1d 100644 --- a/backend/routes.js +++ b/backend/routes.js @@ -28,7 +28,7 @@ module.exports = (passport) => { }); router.post('/login', passport.authenticate('local', { - successRedirect: '/dashboard', + successRedirect: '/', failureRedirect: '/login' })); diff --git a/frontend/actions/index.js b/frontend/actions/index.js index 2af2d31..aeee1ed 100644 --- a/frontend/actions/index.js +++ b/frontend/actions/index.js @@ -29,3 +29,9 @@ export function toggleSignUpClick() { type: 'SIGN_UP' }; } + +export function logoutUserClick() { + return { + type: 'LOG_OUT' + }; +} diff --git a/frontend/components/Header.js b/frontend/components/Header.js index 915b7b4..6b256be 100644 --- a/frontend/components/Header.js +++ b/frontend/components/Header.js @@ -14,7 +14,7 @@ const Header = ( { name } ) => {
- R/ {name} + R/ Horizons