From 41eacfc99948ecac8c2e4bf4167f66a1e1aac236 Mon Sep 17 00:00:00 2001 From: JP1998 Date: Mon, 8 Apr 2019 09:21:37 +0200 Subject: [PATCH 1/8] Add first prototype of the restriction of content --- js/CommonComponents.js | 145 ++++++++++++++++++++++++++++++++++++++++- pages/create.js | 25 +++---- pages/login.js | 94 +------------------------- 3 files changed, 157 insertions(+), 107 deletions(-) diff --git a/js/CommonComponents.js b/js/CommonComponents.js index 87791dd..3fa9cad 100644 --- a/js/CommonComponents.js +++ b/js/CommonComponents.js @@ -2,20 +2,29 @@ import { Badge, Button, ButtonGroup, + Card, + CardBody, + Container, Collapse, + Form, + FormGroup, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, - NavLink + NavLink, + Input, + Label } from 'reactstrap'; +import Head from 'next/head'; + import { connect } from 'react-redux'; import React from 'react'; -import { logout } from './api'; +import { login, logout } from './api'; export function BigImage(props) { return ( @@ -95,7 +104,6 @@ class InvisibleLoginLogoutButtons extends React.Component { ); } } - } const mapStateToLoginLogoutButtonProperties = (state) => { @@ -124,3 +132,134 @@ export function Footer() { ); } + +class PrivateSignedInEnforcer extends React.Component { + + render() { + const { isSignedIn, children } = this.props; + + if(isSignedIn) { + return children; + } else { + return ( +
+ + Anmeldung + + +
+ +
+
+
+ ); + } + } +} + +const mapStateToSignedInEnforcerProperties = (state) => { + const { isSignedIn } = state.userinfo; + return { isSignedIn }; +} + +export const SignedInEnforcer = connect( + mapStateToSignedInEnforcerProperties +)(PrivateSignedInEnforcer); + +export function Login(props) { + return ( + + + +

Login

+ + + +
+
+
+ ); +} + +class LoginErrorList extends React.Component { + render() { + const { error, errorMessages } = this.props; + if(error) { + return ( + + ); + } else { + return null; + } + } +} + +const mapStateToErrorMessages = (state) => { + const { errorMessages, error } = state.userinfo; + return { errorMessages, error }; +}; + +const VisibleLoginErrorList = connect( + mapStateToErrorMessages +)(LoginErrorList); + + +class LoginForm extends React.Component { + + constructor(props) { + super(props); + + this.state = { + email : '', + password : '' + }; + } + + render() { + return ( +
+ + + + + + + + + + + + ); + } + + handlePasswordInput(input) { + this.setState({ password : input.target.value }); + } + + handleEmailInput(input) { + this.setState({ email : input.target.value }); + } +} + +function Hint(props) { + if(props.hint != null) { + return ( +

{ props.hint }

+ ); + } +} diff --git a/pages/create.js b/pages/create.js index b1606f4..79e5c33 100644 --- a/pages/create.js +++ b/pages/create.js @@ -1,6 +1,6 @@ import Head from 'next/head'; import '../static/everypage.css'; -import { Footer, TurniereNavigation } from '../js/CommonComponents'; +import { Footer, TurniereNavigation, SignedInEnforcer } from '../js/CommonComponents'; import React from 'react'; import { @@ -17,7 +17,8 @@ import { } from 'reactstrap'; import { - verifyCredentials + verifyCredentials, + getState } from '../js/api'; import EditableStringList from '../js/EditableStringList'; @@ -30,16 +31,18 @@ export default class CreatePage extends React.Component { render() { return ( -
- - Turnier erstellen: turnie.re - - -
- + +
+ + Turnier erstellen: turnie.re + + +
+ +
+
-
-
+ ); } } diff --git a/pages/login.js b/pages/login.js index 1a58e49..aa43fa5 100644 --- a/pages/login.js +++ b/pages/login.js @@ -1,10 +1,7 @@ import Head from 'next/head'; import '../static/everypage.css'; -import {Footer, TurniereNavigation} from '../js/CommonComponents'; +import { Footer, TurniereNavigation, Login } from '../js/CommonComponents'; import React from 'react'; -import { Button, Card, CardBody, Container, Form, FormGroup, Input, Label } from 'reactstrap'; -import { login } from '../js/api'; -import { connect } from 'react-redux'; import { verifyCredentials @@ -31,92 +28,3 @@ export default class LoginPage extends React.Component { ); } } - -function Login() { - return ( - - - -

Login

- - -
-
-
- ); -} - -class LoginErrorList extends React.Component { - render() { - const { error, errorMessages } = this.props; - if(error) { - return ( -
    - { errorMessages.map((message, index) => -
  • - - {message} -
  • - - ) } -
- ); - } else { - return null; - } - } -} - -const mapStateToErrorMessages = (state) => { - const { errorMessages, error } = state.userinfo; - return { errorMessages, error }; -}; - -const VisibleLoginErrorList = connect( - mapStateToErrorMessages -)(LoginErrorList); - - -class LoginForm extends React.Component { - - constructor(props) { - super(props); - - this.state = { - email : '', - password : '' - }; - } - - render() { - return ( -
- - - - - - - - - - - - ); - } - - handlePasswordInput(input) { - this.setState({ password : input.target.value }); - } - - handleEmailInput(input) { - this.setState({ email : input.target.value }); - } -} \ No newline at end of file From 7c40ba0e617b5932559c39fb879d0de6372e04e8 Mon Sep 17 00:00:00 2001 From: JP1998 Date: Mon, 8 Apr 2019 09:22:49 +0200 Subject: [PATCH 2/8] Fix a bug with the original sign in page not rendering --- js/CommonComponents.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/CommonComponents.js b/js/CommonComponents.js index 3fa9cad..6bd133f 100644 --- a/js/CommonComponents.js +++ b/js/CommonComponents.js @@ -261,5 +261,7 @@ function Hint(props) { return (

{ props.hint }

); + } else { + return null; } } From 4dc55a93d26c682edaaa5bbd03353cc8af89dbe1 Mon Sep 17 00:00:00 2001 From: JP1998 Date: Mon, 8 Apr 2019 09:43:42 +0200 Subject: [PATCH 3/8] Remove the edit button from tournaments that the user is not the owner of --- pages/tournament.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/pages/tournament.js b/pages/tournament.js index 40753f5..f155262 100644 --- a/pages/tournament.js +++ b/pages/tournament.js @@ -22,6 +22,7 @@ import 'bootstrap/dist/css/bootstrap.min.css'; import {BigImage, Footer, TurniereNavigation} from '../js/CommonComponents.js'; import '../static/everypage.css'; import '../static/css/tournament.css'; +import { connect } from 'react-redux'; import { getRequest, @@ -38,7 +39,7 @@ class TournamentPage extends React.Component { return (
- Turnier bearbeiten +

{description}

@@ -57,6 +58,27 @@ class TournamentPage extends React.Component { } } +function PrivateEditButton(props) { + const { id, ownerName, isSignedIn, username } = props; + + if(isSignedIn && ownerName === username) { + return ( + Turnier bearbeiten + ); + } else { + return null; + } +} + +function mapStateToEditButtonProperties(state) { + const { isSignedIn, username } = state.userinfo; + return { isSignedIn, username }; +} + +const EditButton = connect( + mapStateToEditButtonProperties +)(PrivateEditButton); + function getLevelName(levelNumber) { const names = ['Finale', 'Halbfinale', 'Viertelfinale', 'Achtelfinale']; if(levelNumber < names.length){ From 110f862bc3771c75d79b6572983b58737961700b Mon Sep 17 00:00:00 2001 From: JP1998 Date: Mon, 8 Apr 2019 10:20:31 +0200 Subject: [PATCH 4/8] Change the SignedInEnforcer to a more flexible and versatile UserRestrictor --- js/CommonComponents.js | 65 ++++++++++++++++++++++++++---------------- pages/create.js | 55 ++++++++++++++++++++++++++--------- 2 files changed, 82 insertions(+), 38 deletions(-) diff --git a/js/CommonComponents.js b/js/CommonComponents.js index 6bd133f..3e55f9f 100644 --- a/js/CommonComponents.js +++ b/js/CommonComponents.js @@ -133,39 +133,56 @@ export function Footer() { ); } -class PrivateSignedInEnforcer extends React.Component { +/** + * This component works just like a switch statement, although the conditions of the first items + * are checked first, and the first component with a condition that is true will be shown. + * + * For single conditions and options any kind of component can be taken, while the Option-component + * is dedicated for this job. The only important thing is that this component has to have a condition property. + * + * You should also give a default option with a condition that always evaluates to true. + * + * A quick example would be some content that is only to be shown when the user is logged in: + * + * function SomeRestrictedContent(props) { + * const { isSignedIn } = props; + * + * return ( + * + * + * + * + * ); + * } + * + * In the example you'll have to note that the default option is at the bottom of all the options + * since it would always be taken otherwise (the options' conditions are checked from top to bottom) + */ +export class UserRestrictor extends React.Component { render() { - const { isSignedIn, children } = this.props; + const { children } = this.props; - if(isSignedIn) { - return children; - } else { - return ( -
- - Anmeldung - - -
- -
-
-
- ); + for(var i in children) { + var c = children[i]; + + if(c.props.condition) { + return c; + } } + + return null; } } -const mapStateToSignedInEnforcerProperties = (state) => { - const { isSignedIn } = state.userinfo; - return { isSignedIn }; +export function Option(props) { + return props.children; } -export const SignedInEnforcer = connect( - mapStateToSignedInEnforcerProperties -)(PrivateSignedInEnforcer); - export function Login(props) { return ( diff --git a/pages/create.js b/pages/create.js index 79e5c33..fed72a3 100644 --- a/pages/create.js +++ b/pages/create.js @@ -1,7 +1,8 @@ import Head from 'next/head'; import '../static/everypage.css'; -import { Footer, TurniereNavigation, SignedInEnforcer } from '../js/CommonComponents'; +import { Footer, TurniereNavigation, UserRestrictor, Option, Login } from '../js/CommonComponents'; import React from 'react'; +import { connect } from 'react-redux'; import { Button, @@ -23,30 +24,56 @@ import { import EditableStringList from '../js/EditableStringList'; -export default class CreatePage extends React.Component { +class PrivateCreatePage extends React.Component { componentDidMount() { verifyCredentials(); } render() { + const { isSignedIn } = this.props; + return ( - -
- - Turnier erstellen: turnie.re - - -
- + +
- + + + ); } -} +} +function mapStateToCreatePageProperties(state) { + const { isSignedIn } = state.userinfo; + return { isSignedIn }; +} + +const CreatePage = connect( + mapStateToCreatePageProperties +)(PrivateCreatePage); + +export default CreatePage; function CreateTournamentCard() { return ( From 8796bbf553a7f0f7571631993536e746f95f13a5 Mon Sep 17 00:00:00 2001 From: JP1998 Date: Mon, 8 Apr 2019 10:51:11 +0200 Subject: [PATCH 5/8] Add several restrictions to the edit tournament page --- js/api.js | 2 ++ pages/tournament-edit.js | 76 ++++++++++++++++++++++++++++------------ 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/js/api.js b/js/api.js index 83f281b..92b9753 100644 --- a/js/api.js +++ b/js/api.js @@ -57,6 +57,7 @@ const defaultstate_tournamentinfo = { description : '', id : -1, name : '', + ownerUsername : '', isPublic : '', stages: [], teams : [] @@ -272,6 +273,7 @@ const reducer_tournamentinfo = (state = defaultstate_tournamentinfo, action) => description : action.parameters.description, id : action.parameters.id, name : action.parameters.name, + ownerUsername : action.parameters.owner_username, isPublic : action.parameters.public, stages: action.parameters.stages, teams : action.parameters.teams diff --git a/pages/tournament-edit.js b/pages/tournament-edit.js index 0c89d91..6d1a9f2 100644 --- a/pages/tournament-edit.js +++ b/pages/tournament-edit.js @@ -5,7 +5,7 @@ import { connect } from 'react-redux'; import { notify } from 'react-notify-toast'; import { requestTournament } from '../js/api'; -import { BigImage, Footer, TurniereNavigation } from '../js/CommonComponents.js'; +import { BigImage, Footer, TurniereNavigation, Login, UserRestrictor, Option } from '../js/CommonComponents.js'; import { ErrorPageComponent } from '../js/components/ErrorComponents.js'; import { @@ -42,7 +42,10 @@ class EditTournamentPage extends React.Component { verifyCredentials(); requestTournament(this.props.query.code, () => { this.setState({ validCode: true }); - this._edittournamentcontent.notifyOfContentUpdate(); + + if(this._edittournamentcontent != null) { + this._edittournamentcontent.notifyOfContentUpdate(); + } }, () => { this.setState({ validCode: false }); }); @@ -50,33 +53,60 @@ class EditTournamentPage extends React.Component { render() { const { validCode } = this.state; - const { name } = this.props; + const { tournamentname, ownerUsername, isSignedIn, username } = this.props; - if(validCode) { - return ( -
- - Turnie.re - Turnier bearbeiten - - - + return ( + +
+ + + + + + ); } } function mapStateToTournamentInfo(state) { - const { name } = state.tournamentinfo; - return { name }; + const { tournamentname, ownerUsername } = state.tournamentinfo; + const { isSignedIn, username } = state.userinfo; + return { tournamentname, ownerUsername, isSignedIn, username }; } export default connect( From cbe5343a64c75847e9e8ad597ebc617ec8337ba3 Mon Sep 17 00:00:00 2001 From: JP1998 Date: Mon, 8 Apr 2019 11:08:43 +0200 Subject: [PATCH 6/8] Resolve any errors in the syntax --- .gitignore | 3 ++- js/CommonComponents.js | 2 -- pages/create.js | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index f3be5cb..3d060ad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /.next/ /node_modules/ -/.idea \ No newline at end of file +/.idea +check-syntax.sh diff --git a/js/CommonComponents.js b/js/CommonComponents.js index 3e55f9f..b32d412 100644 --- a/js/CommonComponents.js +++ b/js/CommonComponents.js @@ -17,8 +17,6 @@ import { Input, Label } from 'reactstrap'; -import Head from 'next/head'; - import { connect } from 'react-redux'; diff --git a/pages/create.js b/pages/create.js index fed72a3..3a25a0b 100644 --- a/pages/create.js +++ b/pages/create.js @@ -18,8 +18,7 @@ import { } from 'reactstrap'; import { - verifyCredentials, - getState + verifyCredentials } from '../js/api'; import EditableStringList from '../js/EditableStringList'; From a8fec087b7bf4609933be802a6d77684a4a27c71 Mon Sep 17 00:00:00 2001 From: JP1998 Date: Mon, 8 Apr 2019 11:16:58 +0200 Subject: [PATCH 7/8] Edit the appearance of the errors in the edit tournament page --- pages/tournament-edit.js | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/pages/tournament-edit.js b/pages/tournament-edit.js index 6d1a9f2..7ddccad 100644 --- a/pages/tournament-edit.js +++ b/pages/tournament-edit.js @@ -70,18 +70,9 @@ class EditTournamentPage extends React.Component {
- From fb93feed457a9fde8e3e2f93c6d8d2e583898ca6 Mon Sep 17 00:00:00 2001 From: JP1998 Date: Mon, 8 Apr 2019 11:41:48 +0200 Subject: [PATCH 8/8] Make the tournament page correctly handle status codes from the backend --- js/components/ErrorComponents.js | 2 +- pages/tournament-edit.js | 2 +- pages/tournament.js | 46 ++++++++++++++++---------------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/js/components/ErrorComponents.js b/js/components/ErrorComponents.js index d33190b..2e84ee9 100644 --- a/js/components/ErrorComponents.js +++ b/js/components/ErrorComponents.js @@ -26,7 +26,7 @@ export class ErrorPageComponent extends React.Component { } } -function ErrorPage(props){ +export function ErrorPage(props){ return (
diff --git a/pages/tournament-edit.js b/pages/tournament-edit.js index 7ddccad..1d147c1 100644 --- a/pages/tournament-edit.js +++ b/pages/tournament-edit.js @@ -34,7 +34,7 @@ class EditTournamentPage extends React.Component { super(props); this.state = { - validCode: true + validCode: false }; } diff --git a/pages/tournament.js b/pages/tournament.js index f155262..779a0ba 100644 --- a/pages/tournament.js +++ b/pages/tournament.js @@ -18,6 +18,7 @@ import { Row, Table } from 'reactstrap'; +import { ErrorPageComponent } from '../js/components/ErrorComponents.js'; import 'bootstrap/dist/css/bootstrap.min.css'; import {BigImage, Footer, TurniereNavigation} from '../js/CommonComponents.js'; import '../static/everypage.css'; @@ -88,16 +89,6 @@ function getLevelName(levelNumber) { } } -function TournamentContainer(props) { - const { tournament } = props.data; - - if (tournament === null) { - return null; - } else { - return ; - } -} - function Stage(props) { return (
@@ -393,25 +384,34 @@ class Main extends React.Component { getRequest(getState(), '/tournaments/' + code) .then(response => { - this.setState({tournament: convertTournament(response.data)}); + this.setState({ status : response.status, tournament : convertTournament(response.data)}); }) - .catch(() => { /* TODO: Show some kind of error or smth */ }); + .catch((err) => { + this.setState({ status : err.response.status }); + }); } render() { const tournamentName = this.state.tournament === null ? 'Turnier' : this.state.tournament.name; - return ( -
- - {tournamentName}: turnie.re - - - - -
-
- ); + + const { status, tournament } = this.state; + + if (status == 200) { + return ( +
+ + {tournamentName}: turnie.re + + + + +
+
+ ); + } else { + return ; + } } }