From 0a2c180d6aea6eff758c9857dd2b8ad1c57ef699 Mon Sep 17 00:00:00 2001 From: Felix Hamme Date: Wed, 8 May 2019 09:40:00 +0200 Subject: [PATCH 01/10] Replace hardcoded backend url with environment variable (works only server-side) (required client-side tough, so it doesn't work (wait till next commit, Thor77 has a lovely fix for that)) (This commit was definitely not changed because I nagged about it wasn't working...) --- js/api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/api.js b/js/api.js index fba72d9..3758752 100644 --- a/js/api.js +++ b/js/api.js @@ -10,7 +10,7 @@ import { errorMessages } from './constants'; const axios = require('axios'); -const api_url = 'https://api.turnie.re'; +const api_url = process.env.REACT_APP_TURNIERE_API_URL; const actiontypes_userinfo = { 'REGISTER' : 'REGISTER', From e858200a7a8166a8261e0aa7f4e049a101785aa0 Mon Sep 17 00:00:00 2001 From: Thor77 Date: Wed, 8 May 2019 10:54:00 +0200 Subject: [PATCH 02/10] Fix envvar problem --- js/api.js | 379 +++++++++++++++++++++++++------------------------ next.config.js | 5 +- 2 files changed, 195 insertions(+), 189 deletions(-) diff --git a/js/api.js b/js/api.js index 3758752..54fd91f 100644 --- a/js/api.js +++ b/js/api.js @@ -8,9 +8,12 @@ import thunkMiddleware from 'redux-thunk'; import { errorMessages } from './constants'; -const axios = require('axios'); +import getConfig from 'next/config'; +const { publicRuntimeConfig } = getConfig(); -const api_url = process.env.REACT_APP_TURNIERE_API_URL; +const api_url = publicRuntimeConfig.api_url; + +const axios = require('axios'); const actiontypes_userinfo = { 'REGISTER' : 'REGISTER', @@ -20,7 +23,7 @@ const actiontypes_userinfo = { 'LOGIN' : 'LOGIN', 'LOGIN_RESULT_SUCCESS' : 'LOGIN_RESULT_SUCCESS', 'LOGIN_RESULT_ERROR' : 'LOGIN_RESULT_ERROR', - + 'LOGOUT' : 'LOGOUT', 'VERIFY_CREDENTIALS' : 'VERIFY_CREDENTIALS', @@ -147,215 +150,215 @@ function checkForAuthenticationHeaders(response) { const reducer_userinfo = (state = defaultstate_userinfo, action) => { switch(action.type) { - case actiontypes_userinfo.REGISTER: - postRequest(action.state, '/users', { - 'username' : action.parameters.username, - 'email' : action.parameters.email, - 'password' : action.parameters.password - }).then((resp) => { - __store.dispatch({ - type : actiontypes_userinfo.REGISTER_RESULT_SUCCESS - }); - storeOptionalToken(resp); - }).catch((error) => { - if (error.response) { + case actiontypes_userinfo.REGISTER: + postRequest(action.state, '/users', { + 'username' : action.parameters.username, + 'email' : action.parameters.email, + 'password' : action.parameters.password + }).then((resp) => { __store.dispatch({ - 'type' : actiontypes_userinfo.REGISTER_RESULT_ERROR, - 'parameters' : { - 'errorMessages' : error.response.data.errors.full_messages - } + type : actiontypes_userinfo.REGISTER_RESULT_SUCCESS }); - storeOptionalToken(error.response); - } else { - __store.dispatch({ - 'type' : actiontypes_userinfo.REGISTER_RESULT_ERROR, - 'parameters' : { - 'errorMessages' : [ - errorMessages['registration_errorunknown']['en'] - ] - } - }); - } - }); - return Object.assign({}, state, {}); - case actiontypes_userinfo.REGISTER_RESULT_SUCCESS: - return Object.assign({}, state, { - error : false, - errorMessages : [] - }); - case actiontypes_userinfo.REGISTER_RESULT_ERROR: - return Object.assign({}, state, { - error : true, - errorMessages : action.parameters.errorMessages - }); - case actiontypes_userinfo.LOGIN: - postRequest(action.state, '/users/sign_in', { - email : action.parameters.email, - password : action.parameters.password - }).then((resp) => { - __store.dispatch({ - type : actiontypes_userinfo.LOGIN_RESULT_SUCCESS, - parameters : { - username : resp.data.username, - successCallback: action.parameters.successCallback + storeOptionalToken(resp); + }).catch((error) => { + if (error.response) { + __store.dispatch({ + 'type' : actiontypes_userinfo.REGISTER_RESULT_ERROR, + 'parameters' : { + 'errorMessages' : error.response.data.errors.full_messages + } + }); + storeOptionalToken(error.response); + } else { + __store.dispatch({ + 'type' : actiontypes_userinfo.REGISTER_RESULT_ERROR, + 'parameters' : { + 'errorMessages' : [ + errorMessages['registration_errorunknown']['en'] + ] + } + }); } }); - storeOptionalToken(resp); - }).catch((error) => { - if(error.response) { + return Object.assign({}, state, {}); + case actiontypes_userinfo.REGISTER_RESULT_SUCCESS: + return Object.assign({}, state, { + error : false, + errorMessages : [] + }); + case actiontypes_userinfo.REGISTER_RESULT_ERROR: + return Object.assign({}, state, { + error : true, + errorMessages : action.parameters.errorMessages + }); + case actiontypes_userinfo.LOGIN: + postRequest(action.state, '/users/sign_in', { + email : action.parameters.email, + password : action.parameters.password + }).then((resp) => { __store.dispatch({ - 'type' : actiontypes_userinfo.LOGIN_RESULT_ERROR, - 'parameters' : { - 'errorMessages' : error.response.data.errors + type : actiontypes_userinfo.LOGIN_RESULT_SUCCESS, + parameters : { + username : resp.data.username, + successCallback: action.parameters.successCallback } }); - storeOptionalToken(error.response); - } else { - __store.dispatch({ - 'type' : actiontypes_userinfo.LOGIN_RESULT_ERROR, - 'parameters' : { - 'errorMessages' : [ errorMessages['login_errorunknown']['en'] ] - } - }); - } - }); - return Object.assign({}, state, {}); - case actiontypes_userinfo.LOGIN_RESULT_SUCCESS: - action.parameters.successCallback(action.parameters.username); - return Object.assign({}, state, { - isSignedIn : true, - error : false, - errorMessages : [], - username : action.parameters.username, - }); - case actiontypes_userinfo.LOGIN_RESULT_ERROR: - return Object.assign({}, state, { - error : true, - errorMessages : action.parameters.errorMessages - }); - case actiontypes_userinfo.LOGOUT: - deleteRequest(action.state, '/users/sign_out').then(() => { - action.parameters.successCallback(); - __store.dispatch({ type : actiontypes_userinfo.CLEAR }); - }).catch(() => { - __store.dispatch({ type : actiontypes_userinfo.CLEAR }); - }); - return Object.assign({}, state, {}); - case actiontypes_userinfo.STORE_AUTH_HEADERS: - return Object.assign({}, state, { - accesstoken : action.parameters.accesstoken, - client : action.parameters.client, - expiry : action.parameters.expiry, - uid : action.parameters.uid - }); - case actiontypes_userinfo.VERIFY_CREDENTIALS: - getRequest(action.state, '/users/validate_token').then((resp) => { - storeOptionalToken(resp); - }).catch(() => { - __store.dispatch({ type: actiontypes_userinfo.CLEAR }); - }); - return Object.assign({}, state, {}); - case actiontypes_userinfo.REHYDRATE: - return Object.assign({}, state, action.parameters, { error: false, errorMessages: [] }); - case actiontypes_userinfo.CLEAR: - return Object.assign({}, state, { - isSignedIn : false, - username : null, - error : false, - errorMessages : [], + storeOptionalToken(resp); + }).catch((error) => { + if(error.response) { + __store.dispatch({ + 'type' : actiontypes_userinfo.LOGIN_RESULT_ERROR, + 'parameters' : { + 'errorMessages' : error.response.data.errors + } + }); + storeOptionalToken(error.response); + } else { + __store.dispatch({ + 'type' : actiontypes_userinfo.LOGIN_RESULT_ERROR, + 'parameters' : { + 'errorMessages' : [ errorMessages['login_errorunknown']['en'] ] + } + }); + } + }); + return Object.assign({}, state, {}); + case actiontypes_userinfo.LOGIN_RESULT_SUCCESS: + action.parameters.successCallback(action.parameters.username); + return Object.assign({}, state, { + isSignedIn : true, + error : false, + errorMessages : [], + username : action.parameters.username, + }); + case actiontypes_userinfo.LOGIN_RESULT_ERROR: + return Object.assign({}, state, { + error : true, + errorMessages : action.parameters.errorMessages + }); + case actiontypes_userinfo.LOGOUT: + deleteRequest(action.state, '/users/sign_out').then(() => { + action.parameters.successCallback(); + __store.dispatch({ type : actiontypes_userinfo.CLEAR }); + }).catch(() => { + __store.dispatch({ type : actiontypes_userinfo.CLEAR }); + }); + return Object.assign({}, state, {}); + case actiontypes_userinfo.STORE_AUTH_HEADERS: + return Object.assign({}, state, { + accesstoken : action.parameters.accesstoken, + client : action.parameters.client, + expiry : action.parameters.expiry, + uid : action.parameters.uid + }); + case actiontypes_userinfo.VERIFY_CREDENTIALS: + getRequest(action.state, '/users/validate_token').then((resp) => { + storeOptionalToken(resp); + }).catch(() => { + __store.dispatch({ type: actiontypes_userinfo.CLEAR }); + }); + return Object.assign({}, state, {}); + case actiontypes_userinfo.REHYDRATE: + return Object.assign({}, state, action.parameters, { error: false, errorMessages: [] }); + case actiontypes_userinfo.CLEAR: + return Object.assign({}, state, { + isSignedIn : false, + username : null, + error : false, + errorMessages : [], - accesstoken : null, - client : null, - expiry : null, - uid : null - }); - default: return state; + accesstoken : null, + client : null, + expiry : null, + uid : null + }); + default: return state; } }; const reducer_tournamentinfo = (state = defaultstate_tournamentinfo, action) => { switch(action.type) { - case actiontypes_tournamentinfo.CREATE_TOURNAMENT: - postRequest(action.state, '/tournaments', action.parameters.tournament).then((resp) => { - storeOptionalToken(resp); - action.parameters.successCallback(); - }).catch(() => { - action.parameters.errorCallback(); - }); - return Object.assign({}, state, {}); - case actiontypes_tournamentinfo.REQUEST_TOURNAMENT: - getRequest(action.state, '/tournaments/' + action.parameters.code).then((resp) => { - __store.dispatch({ - type: actiontypes_tournamentinfo.REQUEST_TOURNAMENT_SUCCESS, - parameters: resp.data + case actiontypes_tournamentinfo.CREATE_TOURNAMENT: + postRequest(action.state, '/tournaments', action.parameters.tournament).then((resp) => { + storeOptionalToken(resp); + action.parameters.successCallback(); + }).catch(() => { + action.parameters.errorCallback(); }); - storeOptionalToken(resp); - action.parameters.successCallback(); - }).catch(() => { - action.parameters.errorCallback(); - }); - return Object.assign({}, state, {}); - case actiontypes_tournamentinfo.REQUEST_TOURNAMENT_SUCCESS: - return Object.assign({}, state, { - code : action.parameters.code, - 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 - }); - case actiontypes_tournamentinfo.MODIFY_TOURNAMENT: - patchRequest(action.state, '/teams/' + action.parameters.teamid, { - name: action.parameters.name - }).then((resp) => { - storeOptionalToken(resp); - action.parameters.onSuccess(); - }).catch((error) => { - if(error.response) { - storeOptionalToken(error.response); - } - action.parameters.onError(); - }); - return Object.assign({}, state, {}); - case actiontypes_tournamentinfo.MODIFY_TOURNAMENT_SUCCESS: + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.REQUEST_TOURNAMENT: + getRequest(action.state, '/tournaments/' + action.parameters.code).then((resp) => { + __store.dispatch({ + type: actiontypes_tournamentinfo.REQUEST_TOURNAMENT_SUCCESS, + parameters: resp.data + }); + storeOptionalToken(resp); + action.parameters.successCallback(); + }).catch(() => { + action.parameters.errorCallback(); + }); + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.REQUEST_TOURNAMENT_SUCCESS: + return Object.assign({}, state, { + code : action.parameters.code, + 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 + }); + case actiontypes_tournamentinfo.MODIFY_TOURNAMENT: + patchRequest(action.state, '/teams/' + action.parameters.teamid, { + name: action.parameters.name + }).then((resp) => { + storeOptionalToken(resp); + action.parameters.onSuccess(); + }).catch((error) => { + if(error.response) { + storeOptionalToken(error.response); + } + action.parameters.onError(); + }); + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.MODIFY_TOURNAMENT_SUCCESS: - return Object.assign({}, state, {}); - case actiontypes_tournamentinfo.MODIFY_TOURNAMENT_ERROR: + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.MODIFY_TOURNAMENT_ERROR: - return Object.assign({}, state, {}); - case actiontypes_tournamentinfo.REHYDRATE: + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.REHYDRATE: - return Object.assign({}, state, {}); - case actiontypes_tournamentinfo.CLEAR: + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.CLEAR: - return Object.assign({}, state, {}); - default: return state; + return Object.assign({}, state, {}); + default: return state; } }; const reducer_tournamentlist = (state = defaultstate_tournamentlist, action) => { switch (action.type) { - case actiontypes_tournamentlist.FETCH: - getRequest(action.state, '/tournaments?type=' + action.parameters.type).then((resp) => { - __store.dispatch({ - type: actiontypes_tournamentlist.FETCH_SUCCESS, - parameters: resp.data + case actiontypes_tournamentlist.FETCH: + getRequest(action.state, '/tournaments?type=' + action.parameters.type).then((resp) => { + __store.dispatch({ + type: actiontypes_tournamentlist.FETCH_SUCCESS, + parameters: resp.data + }); + storeOptionalToken(resp); + action.parameters.successCallback(resp.data); + }).catch((error) => { + if(error.response) { + storeOptionalToken(error.response); + } + action.parameters.errorCallback(); }); - storeOptionalToken(resp); - action.parameters.successCallback(resp.data); - }).catch((error) => { - if(error.response) { - storeOptionalToken(error.response); - } - action.parameters.errorCallback(); - }); - return state; - case actiontypes_tournamentlist.FETCH_SUCCESS: - return Object.assign({}, state, {tournaments: action.parameters}); - default: - return state; + return state; + case actiontypes_tournamentlist.FETCH_SUCCESS: + return Object.assign({}, state, {tournaments: action.parameters}); + default: + return state; } }; diff --git a/next.config.js b/next.config.js index f332296..71ffa80 100644 --- a/next.config.js +++ b/next.config.js @@ -1,3 +1,6 @@ const withCSS = require('@zeit/next-css'); -module.exports = withCSS(); \ No newline at end of file +module.exports = withCSS(); +module.exports.publicRuntimeConfig = { + api_url: process.env.API_URL +}; From 91f7063887e90336f383470761da650d7996f397 Mon Sep 17 00:00:00 2001 From: Felix Hamme Date: Wed, 8 May 2019 13:31:50 +0200 Subject: [PATCH 03/10] Rename environment variable API_URL to TURNIERE_API_URL --- next.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/next.config.js b/next.config.js index 71ffa80..bc76b7e 100644 --- a/next.config.js +++ b/next.config.js @@ -2,5 +2,5 @@ const withCSS = require('@zeit/next-css'); module.exports = withCSS(); module.exports.publicRuntimeConfig = { - api_url: process.env.API_URL + api_url: process.env.TURNIERE_API_URL }; From 9a84dcb5085d439b81d7e81ed2f2dd4f64775df2 Mon Sep 17 00:00:00 2001 From: Felix Hamme Date: Wed, 8 May 2019 13:34:40 +0200 Subject: [PATCH 04/10] Run the server on port 80 if in production mode, otherwise on port 3000 --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 188d268..7bcbecc 100644 --- a/server.js +++ b/server.js @@ -8,7 +8,7 @@ const handle = app.getRequestHandler(); app.prepare() .then(() => { const server = express(); - + server.get('/t/:code', (req, res) => { const actualPage = '/tournament'; const queryParam = { code: req.params.code }; @@ -31,7 +31,7 @@ app.prepare() return handle(req, res); }); - server.listen(3000, (err) => { + server.listen(dev ? 3000 : 80, (err) => { if (err) throw err; }); }) From 88d4f1dae8c6e036c7f8f52e653f05acc72d085d Mon Sep 17 00:00:00 2001 From: Felix Hamme Date: Wed, 8 May 2019 13:36:45 +0200 Subject: [PATCH 05/10] Create Dockerfile (the image is quite big, but it works) --- .dockerignore | 3 +++ Dockerfile | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7001e78 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +node_modules/** +.next/** +.idea/** \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..25205cb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM node:8-alpine + +COPY js /srv/js +COPY pages /srv/pages +COPY static /srv/static +COPY next.config.js package.json package-lock.json server.js style.css yarn.lock /srv/ +WORKDIR /srv +RUN yarn install +RUN yarn build + +EXPOSE 80 +ENV TURNIERE_API_URL=https://api.turnie.re +CMD yarn start \ No newline at end of file From 6b4e0c36a59eabd314addf93dd3d9a18662fac99 Mon Sep 17 00:00:00 2001 From: Felix Hamme Date: Wed, 8 May 2019 13:37:29 +0200 Subject: [PATCH 06/10] update README.md --- README.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fde2c49..f75e18a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ # turniere-frontend -## Prerequisites +## Development Setup +### Prerequisites You'll need Node.js and a package manager for Node.js (like npm or Yarn; We recommend Yarn) installed on your system in order to run this program. You can see how to install Node.js [here](https://nodejs.org/en/). -## Setup the project +### Setup the Project First of course you'll need to clone this repository: @@ -18,8 +19,18 @@ Afterwards you'll have to install the used libraries using following command: $ yarn install ``` -Afterwards you may simply run the developer version of the project: +Then you can run the development server by executing: +``` +$ TURNIERE_API_URL=https://api.example.com yarn run dev +``` +The environment variable `TURNIERE_API_URL` must contain an valid url to a [turniere backend server](https://github.com/turniere/turniere-backend). + +In production environment the server runs on port 80, otherwise on port 3000. + +## Production Setup: Build the Docker Container ``` -$ yarn run dev +$ docker build -t turniere-frontend:latest . ``` + +The built container exposes port 80. \ No newline at end of file From f4cf04ad251f6cb3a13d2601a911415f573c3b12 Mon Sep 17 00:00:00 2001 From: Felix Hamme Date: Wed, 8 May 2019 13:59:11 +0200 Subject: [PATCH 07/10] Formatting: satisfy Hound --- js/api.js | 374 +++++++++++++++++++++++++++--------------------------- 1 file changed, 187 insertions(+), 187 deletions(-) diff --git a/js/api.js b/js/api.js index 54fd91f..d1222e9 100644 --- a/js/api.js +++ b/js/api.js @@ -150,215 +150,215 @@ function checkForAuthenticationHeaders(response) { const reducer_userinfo = (state = defaultstate_userinfo, action) => { switch(action.type) { - case actiontypes_userinfo.REGISTER: - postRequest(action.state, '/users', { - 'username' : action.parameters.username, - 'email' : action.parameters.email, - 'password' : action.parameters.password - }).then((resp) => { + case actiontypes_userinfo.REGISTER: + postRequest(action.state, '/users', { + 'username' : action.parameters.username, + 'email' : action.parameters.email, + 'password' : action.parameters.password + }).then((resp) => { + __store.dispatch({ + type : actiontypes_userinfo.REGISTER_RESULT_SUCCESS + }); + storeOptionalToken(resp); + }).catch((error) => { + if (error.response) { __store.dispatch({ - type : actiontypes_userinfo.REGISTER_RESULT_SUCCESS - }); - storeOptionalToken(resp); - }).catch((error) => { - if (error.response) { - __store.dispatch({ - 'type' : actiontypes_userinfo.REGISTER_RESULT_ERROR, - 'parameters' : { - 'errorMessages' : error.response.data.errors.full_messages - } - }); - storeOptionalToken(error.response); - } else { - __store.dispatch({ - 'type' : actiontypes_userinfo.REGISTER_RESULT_ERROR, - 'parameters' : { - 'errorMessages' : [ - errorMessages['registration_errorunknown']['en'] - ] - } - }); - } - }); - return Object.assign({}, state, {}); - case actiontypes_userinfo.REGISTER_RESULT_SUCCESS: - return Object.assign({}, state, { - error : false, - errorMessages : [] - }); - case actiontypes_userinfo.REGISTER_RESULT_ERROR: - return Object.assign({}, state, { - error : true, - errorMessages : action.parameters.errorMessages - }); - case actiontypes_userinfo.LOGIN: - postRequest(action.state, '/users/sign_in', { - email : action.parameters.email, - password : action.parameters.password - }).then((resp) => { - __store.dispatch({ - type : actiontypes_userinfo.LOGIN_RESULT_SUCCESS, - parameters : { - username : resp.data.username, - successCallback: action.parameters.successCallback + 'type' : actiontypes_userinfo.REGISTER_RESULT_ERROR, + 'parameters' : { + 'errorMessages' : error.response.data.errors.full_messages } }); - storeOptionalToken(resp); - }).catch((error) => { - if(error.response) { - __store.dispatch({ - 'type' : actiontypes_userinfo.LOGIN_RESULT_ERROR, - 'parameters' : { - 'errorMessages' : error.response.data.errors - } - }); - storeOptionalToken(error.response); - } else { - __store.dispatch({ - 'type' : actiontypes_userinfo.LOGIN_RESULT_ERROR, - 'parameters' : { - 'errorMessages' : [ errorMessages['login_errorunknown']['en'] ] - } - }); + storeOptionalToken(error.response); + } else { + __store.dispatch({ + 'type' : actiontypes_userinfo.REGISTER_RESULT_ERROR, + 'parameters' : { + 'errorMessages' : [ + errorMessages['registration_errorunknown']['en'] + ] + } + }); + } + }); + return Object.assign({}, state, {}); + case actiontypes_userinfo.REGISTER_RESULT_SUCCESS: + return Object.assign({}, state, { + error : false, + errorMessages : [] + }); + case actiontypes_userinfo.REGISTER_RESULT_ERROR: + return Object.assign({}, state, { + error : true, + errorMessages : action.parameters.errorMessages + }); + case actiontypes_userinfo.LOGIN: + postRequest(action.state, '/users/sign_in', { + email : action.parameters.email, + password : action.parameters.password + }).then((resp) => { + __store.dispatch({ + type : actiontypes_userinfo.LOGIN_RESULT_SUCCESS, + parameters : { + username : resp.data.username, + successCallback: action.parameters.successCallback } }); - return Object.assign({}, state, {}); - case actiontypes_userinfo.LOGIN_RESULT_SUCCESS: - action.parameters.successCallback(action.parameters.username); - return Object.assign({}, state, { - isSignedIn : true, - error : false, - errorMessages : [], - username : action.parameters.username, - }); - case actiontypes_userinfo.LOGIN_RESULT_ERROR: - return Object.assign({}, state, { - error : true, - errorMessages : action.parameters.errorMessages - }); - case actiontypes_userinfo.LOGOUT: - deleteRequest(action.state, '/users/sign_out').then(() => { - action.parameters.successCallback(); - __store.dispatch({ type : actiontypes_userinfo.CLEAR }); - }).catch(() => { - __store.dispatch({ type : actiontypes_userinfo.CLEAR }); - }); - return Object.assign({}, state, {}); - case actiontypes_userinfo.STORE_AUTH_HEADERS: - return Object.assign({}, state, { - accesstoken : action.parameters.accesstoken, - client : action.parameters.client, - expiry : action.parameters.expiry, - uid : action.parameters.uid - }); - case actiontypes_userinfo.VERIFY_CREDENTIALS: - getRequest(action.state, '/users/validate_token').then((resp) => { - storeOptionalToken(resp); - }).catch(() => { - __store.dispatch({ type: actiontypes_userinfo.CLEAR }); - }); - return Object.assign({}, state, {}); - case actiontypes_userinfo.REHYDRATE: - return Object.assign({}, state, action.parameters, { error: false, errorMessages: [] }); - case actiontypes_userinfo.CLEAR: - return Object.assign({}, state, { - isSignedIn : false, - username : null, - error : false, - errorMessages : [], + storeOptionalToken(resp); + }).catch((error) => { + if(error.response) { + __store.dispatch({ + 'type' : actiontypes_userinfo.LOGIN_RESULT_ERROR, + 'parameters' : { + 'errorMessages' : error.response.data.errors + } + }); + storeOptionalToken(error.response); + } else { + __store.dispatch({ + 'type' : actiontypes_userinfo.LOGIN_RESULT_ERROR, + 'parameters' : { + 'errorMessages' : [ errorMessages['login_errorunknown']['en'] ] + } + }); + } + }); + return Object.assign({}, state, {}); + case actiontypes_userinfo.LOGIN_RESULT_SUCCESS: + action.parameters.successCallback(action.parameters.username); + return Object.assign({}, state, { + isSignedIn : true, + error : false, + errorMessages : [], + username : action.parameters.username, + }); + case actiontypes_userinfo.LOGIN_RESULT_ERROR: + return Object.assign({}, state, { + error : true, + errorMessages : action.parameters.errorMessages + }); + case actiontypes_userinfo.LOGOUT: + deleteRequest(action.state, '/users/sign_out').then(() => { + action.parameters.successCallback(); + __store.dispatch({ type : actiontypes_userinfo.CLEAR }); + }).catch(() => { + __store.dispatch({ type : actiontypes_userinfo.CLEAR }); + }); + return Object.assign({}, state, {}); + case actiontypes_userinfo.STORE_AUTH_HEADERS: + return Object.assign({}, state, { + accesstoken : action.parameters.accesstoken, + client : action.parameters.client, + expiry : action.parameters.expiry, + uid : action.parameters.uid + }); + case actiontypes_userinfo.VERIFY_CREDENTIALS: + getRequest(action.state, '/users/validate_token').then((resp) => { + storeOptionalToken(resp); + }).catch(() => { + __store.dispatch({ type: actiontypes_userinfo.CLEAR }); + }); + return Object.assign({}, state, {}); + case actiontypes_userinfo.REHYDRATE: + return Object.assign({}, state, action.parameters, { error: false, errorMessages: [] }); + case actiontypes_userinfo.CLEAR: + return Object.assign({}, state, { + isSignedIn : false, + username : null, + error : false, + errorMessages : [], - accesstoken : null, - client : null, - expiry : null, - uid : null - }); - default: return state; + accesstoken : null, + client : null, + expiry : null, + uid : null + }); + default: return state; } }; const reducer_tournamentinfo = (state = defaultstate_tournamentinfo, action) => { switch(action.type) { - case actiontypes_tournamentinfo.CREATE_TOURNAMENT: - postRequest(action.state, '/tournaments', action.parameters.tournament).then((resp) => { - storeOptionalToken(resp); - action.parameters.successCallback(); - }).catch(() => { - action.parameters.errorCallback(); + case actiontypes_tournamentinfo.CREATE_TOURNAMENT: + postRequest(action.state, '/tournaments', action.parameters.tournament).then((resp) => { + storeOptionalToken(resp); + action.parameters.successCallback(); + }).catch(() => { + action.parameters.errorCallback(); + }); + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.REQUEST_TOURNAMENT: + getRequest(action.state, '/tournaments/' + action.parameters.code).then((resp) => { + __store.dispatch({ + type: actiontypes_tournamentinfo.REQUEST_TOURNAMENT_SUCCESS, + parameters: resp.data }); - return Object.assign({}, state, {}); - case actiontypes_tournamentinfo.REQUEST_TOURNAMENT: - getRequest(action.state, '/tournaments/' + action.parameters.code).then((resp) => { - __store.dispatch({ - type: actiontypes_tournamentinfo.REQUEST_TOURNAMENT_SUCCESS, - parameters: resp.data - }); - storeOptionalToken(resp); - action.parameters.successCallback(); - }).catch(() => { - action.parameters.errorCallback(); - }); - return Object.assign({}, state, {}); - case actiontypes_tournamentinfo.REQUEST_TOURNAMENT_SUCCESS: - return Object.assign({}, state, { - code : action.parameters.code, - 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 - }); - case actiontypes_tournamentinfo.MODIFY_TOURNAMENT: - patchRequest(action.state, '/teams/' + action.parameters.teamid, { - name: action.parameters.name - }).then((resp) => { - storeOptionalToken(resp); - action.parameters.onSuccess(); - }).catch((error) => { - if(error.response) { - storeOptionalToken(error.response); - } - action.parameters.onError(); - }); - return Object.assign({}, state, {}); - case actiontypes_tournamentinfo.MODIFY_TOURNAMENT_SUCCESS: + storeOptionalToken(resp); + action.parameters.successCallback(); + }).catch(() => { + action.parameters.errorCallback(); + }); + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.REQUEST_TOURNAMENT_SUCCESS: + return Object.assign({}, state, { + code : action.parameters.code, + 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 + }); + case actiontypes_tournamentinfo.MODIFY_TOURNAMENT: + patchRequest(action.state, '/teams/' + action.parameters.teamid, { + name: action.parameters.name + }).then((resp) => { + storeOptionalToken(resp); + action.parameters.onSuccess(); + }).catch((error) => { + if(error.response) { + storeOptionalToken(error.response); + } + action.parameters.onError(); + }); + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.MODIFY_TOURNAMENT_SUCCESS: - return Object.assign({}, state, {}); - case actiontypes_tournamentinfo.MODIFY_TOURNAMENT_ERROR: + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.MODIFY_TOURNAMENT_ERROR: - return Object.assign({}, state, {}); - case actiontypes_tournamentinfo.REHYDRATE: + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.REHYDRATE: - return Object.assign({}, state, {}); - case actiontypes_tournamentinfo.CLEAR: + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.CLEAR: - return Object.assign({}, state, {}); - default: return state; + return Object.assign({}, state, {}); + default: return state; } }; const reducer_tournamentlist = (state = defaultstate_tournamentlist, action) => { switch (action.type) { - case actiontypes_tournamentlist.FETCH: - getRequest(action.state, '/tournaments?type=' + action.parameters.type).then((resp) => { - __store.dispatch({ - type: actiontypes_tournamentlist.FETCH_SUCCESS, - parameters: resp.data - }); - storeOptionalToken(resp); - action.parameters.successCallback(resp.data); - }).catch((error) => { - if(error.response) { - storeOptionalToken(error.response); - } - action.parameters.errorCallback(); + case actiontypes_tournamentlist.FETCH: + getRequest(action.state, '/tournaments?type=' + action.parameters.type).then((resp) => { + __store.dispatch({ + type: actiontypes_tournamentlist.FETCH_SUCCESS, + parameters: resp.data }); - return state; - case actiontypes_tournamentlist.FETCH_SUCCESS: - return Object.assign({}, state, {tournaments: action.parameters}); - default: - return state; + storeOptionalToken(resp); + action.parameters.successCallback(resp.data); + }).catch((error) => { + if(error.response) { + storeOptionalToken(error.response); + } + action.parameters.errorCallback(); + }); + return state; + case actiontypes_tournamentlist.FETCH_SUCCESS: + return Object.assign({}, state, {tournaments: action.parameters}); + default: + return state; } }; From d6abcf403e135fcdf9182da619fd6d5e2ce0ae11 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 8 May 2019 14:11:23 +0200 Subject: [PATCH 08/10] Exclude more in .dockerignore Co-Authored-By: betanummeric <40263343+betanummeric@users.noreply.github.com> --- .dockerignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index 7001e78..1e7b011 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,6 @@ node_modules/** .next/** -.idea/** \ No newline at end of file +.idea/** +README.md +.hound.yml +.gitignore From db88a4289709307f6fcb43d16e9390f5ee9717ef Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 8 May 2019 14:19:21 +0200 Subject: [PATCH 09/10] Update README.md: tagging latest is redundant Co-Authored-By: betanummeric <40263343+betanummeric@users.noreply.github.com> --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f75e18a..1ac9816 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ In production environment the server runs on port 80, otherwise on port 3000. ## Production Setup: Build the Docker Container ``` -$ docker build -t turniere-frontend:latest . +$ docker build -t turniere-frontend . ``` -The built container exposes port 80. \ No newline at end of file +The built container exposes port 80. From 482c500d9f4c5e31ecc375f59927278f5a0f07c4 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 8 May 2019 14:25:47 +0200 Subject: [PATCH 10/10] Use multistage build in Dockerfile to shrink image size Co-Authored-By: betanummeric <40263343+betanummeric@users.noreply.github.com> --- Dockerfile | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 25205cb..bffce91 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,19 @@ -FROM node:8-alpine - +### STAGE 1: Build ### +FROM node:8-alpine as build +WORKDIR /srv COPY js /srv/js COPY pages /srv/pages COPY static /srv/static COPY next.config.js package.json package-lock.json server.js style.css yarn.lock /srv/ -WORKDIR /srv RUN yarn install RUN yarn build +RUN yarn cache clean +### STAGE 2: Productive Container ### +FROM alpine +WORKDIR /srv +COPY --from=build /srv /srv +RUN apk --no-cache add yarn && rm -rf /var/cache/apk/* EXPOSE 80 ENV TURNIERE_API_URL=https://api.turnie.re CMD yarn start \ No newline at end of file