From 31a59f56bab9fd1e3f067662f95c1fc9667f9255 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Fri, 10 May 2019 13:11:07 +1000 Subject: [PATCH] Viewing profiles works, profiles not yet created --- public/styles/shared.css | 12 +- server/index.js | 4 + server/profiles.js | 44 ++++++ sql/create_database_structure.sql | 17 +++ sql/drop_everything.sql | 3 +- src/components/app.jsx | 2 + src/components/pages/home.jsx | 5 +- src/components/pages/profile.jsx | 221 ++++++++++++++++++++++++++++++ 8 files changed, 300 insertions(+), 8 deletions(-) create mode 100644 server/profiles.js create mode 100644 src/components/pages/profile.jsx diff --git a/public/styles/shared.css b/public/styles/shared.css index 0c5c646..f368fbd 100644 --- a/public/styles/shared.css +++ b/public/styles/shared.css @@ -110,8 +110,8 @@ footer { /* custom styling */ -/* Homepage structure */ -.homePage { +/* SidePanelPage structure */ +.sidePanelPage { flex: 1; display: flex; flex-direction: row; @@ -120,14 +120,14 @@ footer { } @media screen and (max-width: 480px) { - .homePage { + .sidePanelPage { flex-direction: column; } } /* left panel */ .sidePanel { - flex: 1; + flex: 0 1 auto; display: flex; flex-direction: column; justify-content: flex-start; @@ -173,6 +173,10 @@ footer { /* New panel */ .newsPanel { margin-left: 15px; + flex: 1; + display: flex; + flex-direction: column; + justify-content: flex-start; } /* bits and pieces */ diff --git a/server/index.js b/server/index.js index 18ef27a..f5d091a 100644 --- a/server/index.js +++ b/server/index.js @@ -24,6 +24,10 @@ app.post('/passwordchange', accounts.passwordChange(connection)); app.post('/passwordrecover', accounts.passwordRecover(connection)); app.post('/passwordreset', accounts.passwordReset(connection)); +//handle profiles +let profiles = require('./profiles.js'); +app.post('/profilerequest', profiles.profileRequest(connection)); + //static directories app.use('/styles', express.static(path.resolve(__dirname + '/../public/styles')) ); diff --git a/server/profiles.js b/server/profiles.js new file mode 100644 index 0000000..68daf30 --- /dev/null +++ b/server/profiles.js @@ -0,0 +1,44 @@ +//environment variables +require('dotenv').config(); + +//libraries +let formidable = require('formidable'); + +function profileRequest(connection) { + return (req, res) => { + //formidable handles forms + let form = formidable.IncomingForm(); + + //parse form + form.parse(req, (err, fields) => { + if (err) throw err; + + //TODO: do something with the id and token provided + + let query = 'SELECT * FROM profiles WHERE accountId IN (SELECT accounts.id FROM accounts WHERE username = ?);'; + connection.query(query, [fields.username], (err, results) => { + if (err) throw err; + + if (results.length !== 1) { + res.status(400).write(`Failed to find that profile: ${fields.username}`); + res.end(); + return; + } + + res.status(200).json({ + username: fields.username, + gold: results[0].gold, + recruits: results[0].recruits, + soldiers: results[0].soldiers, + spies: results[0].spies, + scientists: results[0].scientists + }); + res.end(); + }); + }); + }; +} + +module.exports = { + profileRequest: profileRequest +} \ No newline at end of file diff --git a/sql/create_database_structure.sql b/sql/create_database_structure.sql index 417253e..c0996c8 100644 --- a/sql/create_database_structure.sql +++ b/sql/create_database_structure.sql @@ -1,3 +1,4 @@ +# account system CREATE TABLE IF NOT EXISTS signups ( email VARCHAR(320) UNIQUE, username VARCHAR(100) UNIQUE, @@ -34,5 +35,21 @@ CREATE TABLE IF NOT EXISTS passwordRecover ( accountId INTEGER UNSIGNED UNIQUE, token INTEGER DEFAULT 0, + CONSTRAINT FOREIGN KEY fk_accountId(accountId) REFERENCES accounts(id) ON UPDATE CASCADE ON DELETE CASCADE +); + +#profile system +CREATE TABLE IF NOT EXISTS profiles ( + id INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY UNIQUE, + td TIMESTAMP DEFAULT CURRENT_TIMESTAMP(), + + accountId INTEGER UNSIGNED UNIQUE, + + gold INTEGER DEFAULT 0, + recruits INTEGER DEFAULT 0, + soldiers INTEGER DEFAULT 0, + spies INTEGER DEFAULT 0, + scientists INTEGER DEFAULT 0, + CONSTRAINT FOREIGN KEY fk_accountId(accountId) REFERENCES accounts(id) ON UPDATE CASCADE ON DELETE CASCADE ); \ No newline at end of file diff --git a/sql/drop_everything.sql b/sql/drop_everything.sql index 847ec52..6179bad 100644 --- a/sql/drop_everything.sql +++ b/sql/drop_everything.sql @@ -1,4 +1,5 @@ DROP TABLE signups; DROP TABLE accounts; DROP TABLE sessions; -#DROP TABLE profiles; +DROP TABLE passwordRecover; +DROP TABLE profiles; diff --git a/src/components/app.jsx b/src/components/app.jsx index f40d848..f6abbd6 100644 --- a/src/components/app.jsx +++ b/src/components/app.jsx @@ -3,6 +3,7 @@ import { BrowserRouter, Switch, Route } from 'react-router-dom'; //include pages import Home from './pages/home.jsx'; +import Profile from './pages/profile.jsx'; import PasswordReset from './pages/password_reset.jsx' import PageNotFound from './pages/page_not_found.jsx'; @@ -21,6 +22,7 @@ export default class App extends React.Component { + diff --git a/src/components/pages/home.jsx b/src/components/pages/home.jsx index 58afdd7..514693e 100644 --- a/src/components/pages/home.jsx +++ b/src/components/pages/home.jsx @@ -39,9 +39,8 @@ class Home extends React.Component { return (

KINGDOM BATTLES!

-
+
-

News

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

@@ -85,7 +84,7 @@ class Home extends React.Component { //finally return the side panel return (
-

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+

Go to your profile

diff --git a/src/components/pages/profile.jsx b/src/components/pages/profile.jsx new file mode 100644 index 0000000..82fd5b0 --- /dev/null +++ b/src/components/pages/profile.jsx @@ -0,0 +1,221 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { withRouter, Link } from 'react-router-dom'; +import PropTypes from 'prop-types'; +import queryString from 'query-string'; + +//panels +import Logout from '../panels/logout.jsx'; +import PasswordChange from '../panels/password_change.jsx'; + +class Profile extends React.Component { + constructor(props) { + super(props); + this.state = { + params: queryString.parse(props.location.search), + username: '', + gold: 0, + recruits: 0, + soldiers: 0, + spies: 0, + scientists: 0, + warning: '' + }; + } + + componentWillMount() { + this.requestProfileData(this.state.params.username ? this.state.params.username : this.props.username); + } + + render() { + let warningStyle = { + display: this.state.warning.length > 0 ? 'flex' : 'none' + }; + + //side panel stuff + let SidePanel; + + if (this.props.id) { + if (this.props.username === this.state.username) { + SidePanel = this.MyProfileSidePanel.bind(this); + } else { + SidePanel = this.NotMyProfileSidePanel.bind(this); + } + } else { //logged out + SidePanel = this.LoggedOutSidePanel.bind(this); + } + + //main panel + let MainPanel; + + if (this.state.username != '') { + MainPanel = () => { + return ( +
+

Username: {this.state.username}

+

Gold: {this.state.gold}

+

Recruits: {this.state.recruits}

+

Soldiers: {this.state.soldiers}

+

Spies: {this.state.spies}

+

Scientists: {this.state.scientists}

+
+ ); + } + } else { + MainPanel = () => { + return ( +
+

No profile found!

+
+ ); + } + } + + return ( +
+

KINGDOM BATTLES!

+ +
+ +
+
+

{this.state.warning}

+
+ + +
+
+
+ ); + } + + //gameplay functions + requestProfileData(username) { + if (username === undefined || username === '') { + return; + } + + //request this profile's info, using my credentials + let formData = new FormData(); + + formData.append('id', this.props.id); + formData.append('token', this.props.token); + + formData.append('username', username); + + //build the XHR + let xhr = new XMLHttpRequest(); + xhr.onreadystatechange = () => { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + let json = JSON.parse(xhr.responseText); + this.storeProfile( + json.username, + json.gold, + json.recruits, + json.soldiers, + json.spies, + json.scientists + ); + } + else if (xhr.status === 400) { + this.setWarning(xhr.responseText); + } + else if (xhr.status === 404) { + this.props.history.push('/404'); + } + } + } + + //send + xhr.open('POST', '/profilerequest', true); + xhr.send(formData); + } + + storeProfile(username, gold, recruits, soldiers, spies, scientists) { + this.setState({ + username: username, + gold: gold, + recruits: recruits, + soldiers: soldiers, + spies: spies, + scientists: scientists + }); + } + + //panel functions + MyProfileSidePanel() { + //build the password change panel + let PasswordChangePanel; + + if (!this.state.changedPassword) { + PasswordChangePanel = () => { + return ( { this.setState({changedPassword: true}) }} />); + } + } else { + PasswordChangePanel = () => { + return (

Password changed!

); + } + } + + //finally return the side panel + return ( +
+

Return home

+ + +
+ ); + } + + NotMyProfileSidePanel() { + //finally return the side panel + return ( +
+

Return home

+

Go to { e.preventDefault(); this.requestProfileData(this.props.username); }}>your profile

+ +
+ ); + } + + LoggedOutSidePanel() { + return ( +
+

Return home

+
+ ); + } + + setWarning(s) { + this.setState({ + warning: s + }); + } +} + +Profile.propTypes = { + id: PropTypes.number.isRequired, + email: PropTypes.string.isRequired, + username: PropTypes.string.isRequired, + token: PropTypes.number.isRequired +}; + +function mapStoreToProps(store) { + return { + id: store.account.id, + email: store.account.email, + username: store.account.username, + token: store.account.token + } +} + +function mapDispatchToProps(dispatch) { + return { + // + } +} + +Profile = connect(mapStoreToProps, mapDispatchToProps)(Profile); + +export default withRouter(Profile); \ No newline at end of file