Browse Source

added user management. working on user list.

Tomi Cvetic 6 years ago
parent
commit
50a0172841

+ 1 - 0
client/package.json

@@ -2,6 +2,7 @@
   "name": "sztm-excel",
   "version": "0.1.0",
   "private": true,
+  "proxy": "http://localhost:3002/",
   "dependencies": {
     "babel-core": "^6.25.0",
     "babel-polyfill": "^6.23.0",

+ 2 - 1
client/public/index.html

@@ -22,6 +22,7 @@
     <title>SZTM Excel</title>
   </head>
   <body>
+    <!--
     <header>
       <nav>
         <a href="players/">Spieler</a> |
@@ -69,7 +70,7 @@
       </article>
     </main>
     <footer></footer>
-
+-->
     <noscript>
       You need to enable JavaScript to run this app.
     </noscript>

+ 41 - 0
client/src/layout/components/AppLayout.js

@@ -2,14 +2,44 @@ import React from 'react'
 import { Tabs, Tab } from 'react-bootstrap'
 
 class AppLayout extends React.Component {
+
+  constructor () {
+    super()
+    this.handleSubmit = this.handleSubmit.bind(this)
+  }
+
+  handleSubmit (event) {
+    event.preventDefault()
+    console.log(this.props.state.usersActions)
+    const { loginRequest } = this.props.state.usersActions
+    const data = {
+      username: this.username.value,
+      password: this.password.value
+    }
+    console.log(data)
+    loginRequest(data)
+    //const { fileUploadStart } = this.props.actions
+    //const { files } = this.playerListFile
+    // if (files.length === 0) {
+    //   alertAdd({ type: 'info', text: 'Datei entfernt' })
+    //   return
+    // }
+    // if (files.length > 1) {
+    //   alertAdd({ type: 'warning', text: 'Mehrere Dateien gesendet. Nur die erste wird verarbeitet.' })
+    // }
+  }
+
   render () {
     const { state } = this.props
     const { activeTab } = this.props.state.layout
     const { changeTab } = this.props.state.layoutActions
     const { PlayerList, MatchList, StartPage, UserList } = this.props.components
 
+    const { token, tokenData } = state.users
+
     return (
       <div>
+      {(tokenData) ? (
         <Tabs activeKey={activeTab} onSelect={changeTab} id='layout-tabs'>
           <Tab eventKey={0} title='Setup'>
             <StartPage {...state} />
@@ -26,6 +56,17 @@ class AppLayout extends React.Component {
           <Tab eventKey={4} title='Spielplan' />
           <Tab eventKey={5} title='Zahlliste' />
         </Tabs>
+       ) : (
+        <div>
+          <form ref='loginForm' onSubmit={this.handleSubmit}>
+            <label>Benutzername</label>
+            <input type='text' id='username' ref={(input) => {this.username = input}}/>
+            <label>Passwort</label>
+            <input type='password' id='password' ref={(input) => {this.password = input}}/>
+            <input type='submit' />
+          </form>
+        </div>
+       )}
       </div>
     )
   }

+ 22 - 2
client/src/users/components/UserList.js

@@ -2,18 +2,38 @@ import React from 'react'
 
 class UserList extends React.Component {
   render () {
+    const state = this.props.state.users
+    const actions = this.props.state.usersActions
+    if (state.tokenData) {
+      actions.getUserList()
+    }
+    let user = null
+
     return (
       <div>
+        <form>
+          <h2>{(user) ? "Benutzer editieren": "Neuer Benutzer"}</h2>
+          {user ? <input type="hidden" key="userid" value={user._id} ref={(input) => {this.name = input}} id="userid"/> : ""}
+          <label htmlFor="name">Name</label>
+          <input type="input" ref={(input) => {this.name = input}} id="name"></input>
+          <label htmlFor="username">Benutzername</label>
+          <input type="input" ref={(input) => {this.username = input}} id="username"></input>
+          <label htmlFor="password">Passwort</label>
+          <input type="password" ref={(input) => {this.password = input}} id="password"></input>
+          <input type="submit" value={user ? "Aenderungen speichern" : "Benutzer anlegen"} />
+        </form>
         <table>
           <thead>
             <tr>
-              <th></th>
+              <th>Name</th><th>Benutzername</th><th>Aktionen</th>
             </tr>
           </thead>
           <tbody>
+            {state.users ? state.users.forEach(user => {
             <tr>
-              <td></td>
+              <td>{user.name}</td><td>{user.username}</td><td><a>editieren</a><a>loeschen</a></td>
             </tr>
+            }) : null}
           </tbody>
         </table>
       </div>

+ 139 - 42
client/src/users/state.js

@@ -1,51 +1,148 @@
 /** @module users/state */
+import { call, put, takeEvery } from 'redux-saga/effects'
+import jwt from 'jwt-simple'
 
 /**
- * state.js
- *
- * Collection of everything which has to do with state changes.
- **/
+* state.js
+*
+* Collection of everything which has to do with state changes.
+**/
 
 /** actionTypes define what actions are handeled by the reducer. */
 export const actions = {
-    addUser: page => {
-      return {
-        type: 'TABLE_CHANGE_PAGINATION_PAGE',
-        page
-      }
-    },
-    deleteUser: items => {
-      return {
-        type: 'TABLE_CHANGE_PAGINATION_ITEMS',
-        items
-      }
+    loginRequest: (data) => {
+        return {
+            type: 'USER/LOGIN_REQUEST',
+            data
+        }
+    },
+    loginSuccess: (token) => {
+        return {
+            type: 'USER/LOGIN_SUCCESS',
+            token
+        }
+    },
+    loginFailure: () => {
+        return {
+            type: 'USER/LOGIN_FAILURE'
+        }
+    },
+    getUserList: () => {
+        return {
+            type: 'USER/GET_USER_LIST'
+        }
+    },
+    userListSuccess: (users) => {
+        return {
+            type: 'USER/GET_USER_LIST_SUCCESS',
+            users
+        }
+    },
+    userListFailure: () => {
+        return {
+            type: 'USER/GET_USER_LIST_FAILURE'
+        }
+    },
+    addUserRequest: (data) => {
+        return {
+            type: 'USER/ADD_REQUEST',
+            data
+        }
+    },
+    addUserSuccess: (data) => {
+        return {
+            type: 'USER/ADD_SUCCESS',
+            data
+        }
+    },
+    addUserFailure: () => {
+        return {
+            type: 'USER/ADD_FAILURE'
+        }
     }
-  }
-  console.log('State actions', actions)
-  
-  /** state definition */
-  export const state = {
-    users: {}
-  }
-  console.log('State state', state)
-  
-  /** reducer is called by the redux dispatcher and handles all component actions */
-  export function reducer (state = [], action) {
-    let pagination
+}
+console.log('State actions', actions)
+
+/** state definition */
+export const state = {
+    loginRequested: false,
+    users: {},
+    token: null,
+    tokenData: null
+}
+console.log('State state', state)
+
+/** reducer is called by the redux dispatcher and handles all component actions */
+export function reducer (state = [], action) {
     switch (action.type) {
-      case 'TABLE_CHANGE_PAGINATION_PAGE':
-        pagination = { ...state.pagination }
-        pagination.activePage = action.page
-        return { ...state, pagination }
-      case 'TABLE_CHANGE_PAGINATION_ITEMS':
-        pagination = { ...state.pagination }
-        pagination.items = action.items
-        return { ...state, pagination }
-      default:
-        return state
+        case 'USER/LOGIN_REQUEST':
+            return { ...state, loginRequested: true }
+        case 'USER/LOGIN_SUCCESS':
+            const tokenData = action.token ? jwt.decode(action.token, null, true) : null
+            console.log(tokenData)
+            return { ...state, loginRequested: false, token: action.token, tokenData }
+        case 'USER/LOGIN_FAILURE':
+            return { ...state, loginRequested: false }
+        case 'USER/GET_USER_LIST':
+            return { ...state }
+        case 'USER/GET_USER_LIST_SUCCESS':
+            return { ...state, users: action.users }
+        case 'USER/GET_USER_LIST_FAILURE':
+            return { ...state }
+        default:
+            return state
+    }
+}
+
+function * login (action) {
+    try {
+        console.log('User login requested', action.data)
+        const response = yield call(fetch, 'http://localhost:3002/authenticate/login', {
+            method: 'POST',
+            headers: {
+                'Content-Type': 'application/json'
+            },
+            body: JSON.stringify(action.data)
+        })
+        const responseJson = yield response.json()
+        if (response.status != 200) {
+            console.log(responseJson.msg)
+            throw new Error(responseJson.msg)
+        }
+        console.log('User login success!', actions.loginSuccess(responseJson.token))
+        yield put(actions.loginSuccess(responseJson.token))
+    } catch (error) {
+        console.log('User login failure!', actions.loginFailure(error))
+        yield put(actions.loginFailure(error))
     }
-  }
-  
-  /** sagas are asynchronous workers (JS generators) to handle the state. */
-  export function * saga () {}
-  
+}
+
+function * getUserList (action) {
+    try {
+        console.log('User list requested')
+        const response = yield call(fetch, 'http://localhost:3002/api/users', {
+            method: 'GET',
+            headers: {
+                'Content-Type': 'application/json',
+                'x-access-token': action.token
+            },
+        })
+        const responseJson = yield response.json()
+        if (response.status != 200) {
+            console.log(responseJson.msg)
+            throw new Error(responseJson.msg)
+        }
+        console.log('Get user list success!', actions.userListFailure(responseJson.users))
+        yield put(actions.userListFailure(responseJson.users))
+    } catch (error) {
+        console.log('Get user list failure!', actions.userListFailure(error))
+        yield put(actions.userListFailure(error.toString()))
+    }
+}
+
+/** sagas are asynchronous workers (JS generators) to handle the state. */
+export function * saga () {
+    console.log('User saga started.')
+    yield takeEvery('USER/LOGIN_REQUEST', login)
+    yield takeEvery('USER/GET_USER_LIST', getUserList)
+}

+ 12 - 13
server/src/restServer/routes/authenticate.js

@@ -43,9 +43,8 @@ authenticate.post('/login', (req, res) => {
   console.log("Trying to log in.")
   const { username, password } = req.body
   if (!username || !password) {
-    return res.status(400).json({ 
-      success: false, 
-      msg: 'Parameters name and password are required' 
+    return res.status(400).json({
+      msg: 'Parameters username and password are required' 
     })
   }
 
@@ -53,30 +52,26 @@ authenticate.post('/login', (req, res) => {
     console.log('hoppla!')
     if (err) {
       return res.status(400).json({ 
-        success: false, 
         msg: err.toString() 
       })
     }
     if (!user) {
       return res.status(400).json({ 
-        success: false, 
         msg: 'Authentication failed. User not found.' 
       })
     }
     console.log(password, user)
     if (!bcrypt.compareSync(password, user.password)) {
       return res.status(400).json({ 
-        success: false, 
         msg: 'Authentication failed. Wrong password' 
       })
     } else {
       const token = jwt.encode({
-        exp: Math.floor(Date.now() / 1000) + 24*60*60,
-        data: user
+        exp: Date.now() + 24*60*60*1000,
+        data: { username: user.username, name: user.name }
       }, config.secret)
       return res.json({ 
-        success: true, 
-        token 
+        token
       })
     }
   })
@@ -91,13 +86,17 @@ verify.use( (req, res, next) => {
   if (token) {
 
     const decoded = jwt.decode(token, config.secret)
+    if (decoded.exp < Date.now()) {
+      return res.status(403).json({
+        msg: 'Token expired.'
+      })
+    }
     req.decoded = decoded
     next()
 
   } else {
-    return res.status(403).send({
-      success: false,
-      message: 'No token provided.'
+    return res.status(403).json({
+      msg: 'No token provided.'
     })
   }
 })

+ 0 - 15
server/src/restServer/routes/users.js

@@ -8,14 +8,12 @@ users.get('/', (req, res) => {
   dbUsers.exec((err, users) => {
       if (err) {
         res.status(400).json({
-            success: false,
             msg: err.toString()
         })
         return
       }
 
       return res.json({
-          success: true,
           users: JSON.stringify(users)
       })
   })
@@ -26,7 +24,6 @@ users.get('/:username', (req, res) => {
 
     if (!username) {
         res.status(400).json({
-            success: false,
             msg: 'Parameter username is required'
         })
         return
@@ -36,14 +33,12 @@ users.get('/:username', (req, res) => {
     dbUser.exec((err, user) => {
         if (err) {
             res.status(400).json({
-                success: false,
                 msg: err.toString()
             })
             return
         }
 
         return res.json({
-            success: true,
             user: JSON.stringify(user)
         })
     })
@@ -55,7 +50,6 @@ users.post('/', (req, res) => {
   // return, if username or password are missing
   if (!username || !name || !password) {
     res.status(400).json({
-      success: false,
       msg: 'Parameters username, name and password are required'
     })
     return
@@ -68,13 +62,11 @@ users.post('/', (req, res) => {
   user.save((err) => {
       if (err) {
         res.status(400).json({
-            success: false,
             msg: err.toString()
         })
         return
       }
       res.json({
-        success: true,
         user_id: user._id
       })
   })
@@ -86,7 +78,6 @@ users.put('/', (req, res) => {
     // return, if username or password are missing
     if (!username || !name || !password) {
       res.status(400).json({
-        success: false,
         msg: 'Parameters username, name and password are required'
       })
       return
@@ -97,13 +88,11 @@ users.put('/', (req, res) => {
         user.save((err) => {
             if (err) {
               res.status(400).json({
-                  success: false,
                   msg: err.toString()
               })
               return
             }
             res.json({
-              success: true,
               user_id: user._id
             })
         })
@@ -116,14 +105,12 @@ users.delete('/:username', (req, res) => {
     User.findOne({ username }, (err, user) => {
         if (err) {
             res.status(400).json({
-                success: false,
                 msg: err.toString()
             })
             return
         }
         if (!user) {
             res.status(400).json({
-                success: false,
                 msg: "User not found."
             })
             return
@@ -131,13 +118,11 @@ users.delete('/:username', (req, res) => {
         User.deleteOne({ username }, (err) => {
             if (err) {
                 res.status(400).json({
-                    success: false,
                     msg: err.toString()
                 })
                 return
             }
             res.json({
-                success: true
             })
         })
     })