initial-frontend-work #2
@ -24,13 +24,20 @@ pub enum ApiResponseVariant {
 | 
				
			|||||||
    //    Flash(Flash<Redirect>)
 | 
					    //    Flash(Flash<Redirect>)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct UserWithToken {
 | 
				
			||||||
 | 
					    #[serde(flatten)]
 | 
				
			||||||
 | 
					    pub user: schema::User,
 | 
				
			||||||
 | 
					    pub jwt: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug)]
 | 
					#[derive(Serialize, Deserialize, Debug)]
 | 
				
			||||||
struct ApiResponse {
 | 
					struct ApiResponse {
 | 
				
			||||||
    result: Cow<'static, str>,
 | 
					    result: Cow<'static, str>,
 | 
				
			||||||
    #[serde(skip_serializing_if = "Option::is_none")]
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
    message: Option<Cow<'static, str>>,
 | 
					    message: Option<Cow<'static, str>>,
 | 
				
			||||||
    #[serde(skip_serializing_if = "Option::is_none")]
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
    jwt: Option<Cow<'static, str>>,
 | 
					    user: Option<UserWithToken>,
 | 
				
			||||||
    #[serde(skip_serializing_if = "Option::is_none")]
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
    gamenights: Option<Vec<schema::GameNight>>,
 | 
					    gamenights: Option<Vec<schema::GameNight>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -42,7 +49,7 @@ impl ApiResponse {
 | 
				
			|||||||
    const SUCCES: Self = Self {
 | 
					    const SUCCES: Self = Self {
 | 
				
			||||||
        result: Self::SUCCES_RESULT,
 | 
					        result: Self::SUCCES_RESULT,
 | 
				
			||||||
        message: None,
 | 
					        message: None,
 | 
				
			||||||
        jwt: None,
 | 
					        user: None,
 | 
				
			||||||
        gamenights: None,
 | 
					        gamenights: None,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -50,16 +57,19 @@ impl ApiResponse {
 | 
				
			|||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            result: Self::FAILURE_RESULT,
 | 
					            result: Self::FAILURE_RESULT,
 | 
				
			||||||
            message: Some(Cow::Owned(message)),
 | 
					            message: Some(Cow::Owned(message)),
 | 
				
			||||||
            jwt: None,
 | 
					            user: None,
 | 
				
			||||||
            gamenights: None,
 | 
					            gamenights: None,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn login_response(jwt: String) -> Self {
 | 
					    fn login_response(user: schema::User, jwt: String) -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            result: Self::SUCCES_RESULT,
 | 
					            result: Self::SUCCES_RESULT,
 | 
				
			||||||
            message: None,
 | 
					            message: None,
 | 
				
			||||||
            jwt: Some(Cow::Owned(jwt)),
 | 
					            user: Some(UserWithToken {
 | 
				
			||||||
 | 
					                user: user,
 | 
				
			||||||
 | 
					                jwt: jwt
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
            gamenights: None,
 | 
					            gamenights: None,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -68,7 +78,7 @@ impl ApiResponse {
 | 
				
			|||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            result: Self::SUCCES_RESULT,
 | 
					            result: Self::SUCCES_RESULT,
 | 
				
			||||||
            message: None,
 | 
					            message: None,
 | 
				
			||||||
            jwt: None,
 | 
					            user: None,
 | 
				
			||||||
            gamenights: Some(gamenights),
 | 
					            gamenights: Some(gamenights),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -190,10 +200,11 @@ pub async fn login_post_json(
 | 
				
			|||||||
                ))));
 | 
					                ))));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let user = login_result.user.unwrap();
 | 
				
			||||||
            let my_claims = Claims {
 | 
					            let my_claims = Claims {
 | 
				
			||||||
                exp: Utc::now().timestamp() + chrono::Duration::days(7).num_seconds(),
 | 
					                exp: Utc::now().timestamp() + chrono::Duration::days(7).num_seconds(),
 | 
				
			||||||
                uid: login_result.id.unwrap(),
 | 
					                uid: user.id,
 | 
				
			||||||
                role: login_result.role.unwrap(),
 | 
					                role: user.role,
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let secret = &config.inner().jwt_secret;
 | 
					            let secret = &config.inner().jwt_secret;
 | 
				
			||||||
@ -202,7 +213,7 @@ pub async fn login_post_json(
 | 
				
			|||||||
                &my_claims,
 | 
					                &my_claims,
 | 
				
			||||||
                &EncodingKey::from_secret(secret.as_bytes()),
 | 
					                &EncodingKey::from_secret(secret.as_bytes()),
 | 
				
			||||||
            ) {
 | 
					            ) {
 | 
				
			||||||
                Ok(token) => ApiResponseVariant::Value(json!(ApiResponse::login_response(token))),
 | 
					                Ok(token) => ApiResponseVariant::Value(json!(ApiResponse::login_response(user, token))),
 | 
				
			||||||
                Err(error) => {
 | 
					                Err(error) => {
 | 
				
			||||||
                    ApiResponseVariant::Value(json!(ApiResponse::error(error.to_string())))
 | 
					                    ApiResponseVariant::Value(json!(ApiResponse::error(error.to_string())))
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
				
			|||||||
@ -175,25 +175,19 @@ pub async fn login(conn: DbConn, login: Login) -> Result<LoginResult, DatabaseEr
 | 
				
			|||||||
            .verify_password(&login.password.as_bytes(), &parsed_hash)
 | 
					            .verify_password(&login.password.as_bytes(), &parsed_hash)
 | 
				
			||||||
            .is_ok()
 | 
					            .is_ok()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            let role: Role = match user::table
 | 
					            let user: User = match user::table.find(id).first(c) {
 | 
				
			||||||
                .filter(user::id.eq(id))
 | 
					                Ok(user) => user,
 | 
				
			||||||
                .select(user::role)
 | 
					                Err(error) => return Err(DatabaseError::Query(error.to_string()))
 | 
				
			||||||
                .first(c)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Ok(role) => role,
 | 
					 | 
				
			||||||
                Err(error) => return Err(DatabaseError::Query(error.to_string())),
 | 
					 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Ok(LoginResult {
 | 
					            Ok(LoginResult {
 | 
				
			||||||
                result: true,
 | 
					                result: true,
 | 
				
			||||||
                id: Some(id),
 | 
					                user : Some(user)
 | 
				
			||||||
                role: Some(role),
 | 
					 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            Ok(LoginResult {
 | 
					            Ok(LoginResult {
 | 
				
			||||||
                result: false,
 | 
					                result: false,
 | 
				
			||||||
                id: None,
 | 
					                user: None
 | 
				
			||||||
                role: None,
 | 
					 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
@ -251,7 +245,7 @@ pub async fn run_migrations(rocket: Rocket<Build>) -> Rocket<Build> {
 | 
				
			|||||||
    rocket
 | 
					    rocket
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Serialize, Deserialize, DbEnum, Clone)]
 | 
					#[derive(Debug, Serialize, Deserialize, DbEnum, Clone, Copy)]
 | 
				
			||||||
pub enum Role {
 | 
					pub enum Role {
 | 
				
			||||||
    Admin,
 | 
					    Admin,
 | 
				
			||||||
    User,
 | 
					    User,
 | 
				
			||||||
@ -318,6 +312,5 @@ pub struct Login {
 | 
				
			|||||||
#[derive(Serialize, Deserialize, Debug)]
 | 
					#[derive(Serialize, Deserialize, Debug)]
 | 
				
			||||||
pub struct LoginResult {
 | 
					pub struct LoginResult {
 | 
				
			||||||
    pub result: bool,
 | 
					    pub result: bool,
 | 
				
			||||||
    pub id: Option<i32>,
 | 
					    pub user: Option<User>,
 | 
				
			||||||
    pub role: Option<Role>,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,3 @@
 | 
				
			|||||||
import logo from './logo.svg';
 | 
					 | 
				
			||||||
import './App.css';
 | 
					import './App.css';
 | 
				
			||||||
import React, { useState, useEffect } from 'react';
 | 
					import React, { useState, useEffect } from 'react';
 | 
				
			||||||
import MenuBar from './components/MenuBar';
 | 
					import MenuBar from './components/MenuBar';
 | 
				
			||||||
@ -6,10 +5,11 @@ import Login from './components/Login';
 | 
				
			|||||||
import Gamenights from './components/Gamenights'
 | 
					import Gamenights from './components/Gamenights'
 | 
				
			||||||
import AddGameNight from './components/AddGameNight'
 | 
					import AddGameNight from './components/AddGameNight'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const localStorageUserKey = 'user';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function App() {
 | 
					function App() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [user, setUser] = useState(null);
 | 
					  const [user, setUser] = useState(null);
 | 
				
			||||||
  const [token, setToken] = useState(null);
 | 
					 | 
				
			||||||
  const [gamenights, setGamenights] = useState([]);
 | 
					  const [gamenights, setGamenights] = useState([]);
 | 
				
			||||||
  const [flashData, setFlashData] = useState({});
 | 
					  const [flashData, setFlashData] = useState({});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -23,7 +23,8 @@ function App() {
 | 
				
			|||||||
      .then(response => response.json())
 | 
					      .then(response => response.json())
 | 
				
			||||||
      .then(data => {
 | 
					      .then(data => {
 | 
				
			||||||
        if(data.result === "Ok") {
 | 
					        if(data.result === "Ok") {
 | 
				
			||||||
          setToken(data.jwt);
 | 
					          setUser(data.user);
 | 
				
			||||||
 | 
					          localStorage.setItem(localStorageUserKey, JSON.stringify(data.user));
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          setFlashData({
 | 
					          setFlashData({
 | 
				
			||||||
            type: "Error",
 | 
					            type: "Error",
 | 
				
			||||||
@ -34,17 +35,17 @@ function App() {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleAddGameNight = (input) => {
 | 
					  const handleAddGameNight = (input) => {
 | 
				
			||||||
    if (token !== null) {
 | 
					    if (user !== null) {
 | 
				
			||||||
      const requestOptions = {
 | 
					      const requestOptions = {
 | 
				
			||||||
        method: 'POST',
 | 
					        method: 'POST',
 | 
				
			||||||
        headers: {
 | 
					        headers: {
 | 
				
			||||||
          'Content-Type': 'application/json',
 | 
					          'Content-Type': 'application/json',
 | 
				
			||||||
          'Authorization': `Bearer ${token}`
 | 
					          'Authorization': `Bearer ${user.jwt}`
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        body: JSON.stringify(input)
 | 
					        body: JSON.stringify(input)
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      fetch('api/gamenight', requestOptions)
 | 
					      return fetch('api/gamenight', requestOptions)
 | 
				
			||||||
        .then(response => response.json())
 | 
					        .then(response => response.json())
 | 
				
			||||||
        .then(data => {
 | 
					        .then(data => {
 | 
				
			||||||
          if(data.result !== "Ok") {
 | 
					          if(data.result !== "Ok") {
 | 
				
			||||||
@ -52,24 +53,25 @@ function App() {
 | 
				
			|||||||
              type: "Error",
 | 
					              type: "Error",
 | 
				
			||||||
              message: data.message
 | 
					              message: data.message
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            setToken(token);
 | 
					            setUser({ ...user });
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        });
 | 
					        })
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const onLogout = () => {
 | 
					  const onLogout = () => {
 | 
				
			||||||
    setUser(null);
 | 
					    setUser(null);
 | 
				
			||||||
    setToken(null);
 | 
					    localStorage.removeItem(localStorageUserKey);
 | 
				
			||||||
  }
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (token !== null) {
 | 
					    if (user !== null) {
 | 
				
			||||||
      const requestOptions = {
 | 
					      const requestOptions = {
 | 
				
			||||||
        method: 'GET',
 | 
					        method: 'GET',
 | 
				
			||||||
        headers: { 'Authorization': `Bearer ${token}` },
 | 
					        headers: { 'Authorization': `Bearer ${user.jwt}` },
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
      fetch('api/gamenights', requestOptions)
 | 
					      fetch('api/gamenights', requestOptions)
 | 
				
			||||||
        .then(response => response.json())
 | 
					        .then(response => response.json())
 | 
				
			||||||
@ -84,9 +86,13 @@ function App() {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  }, [user])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if(token === null) {
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    setUser(JSON.parse(localStorage.getItem(localStorageUserKey)));
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if(user === null) {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className="App">
 | 
					      <div className="App">
 | 
				
			||||||
        <Login onChange={handleLogin}/>
 | 
					        <Login onChange={handleLogin}/>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import React, { useState } from 'react';
 | 
					import React, { useEffect, useState } from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function AddGameNight(props) {
 | 
					function AddGameNight(props) {
 | 
				
			||||||
  const [expanded, setExpanded] = useState(false);
 | 
					  const [expanded, setExpanded] = useState(false);
 | 
				
			||||||
@ -9,6 +9,12 @@ function AddGameNight(props) {
 | 
				
			|||||||
    props.onChange({
 | 
					    props.onChange({
 | 
				
			||||||
      game: gameName,
 | 
					      game: gameName,
 | 
				
			||||||
      datetime: date
 | 
					      datetime: date
 | 
				
			||||||
 | 
					    }).then((result) => {
 | 
				
			||||||
 | 
					      if(result) {
 | 
				
			||||||
 | 
					        setExpanded(false);
 | 
				
			||||||
 | 
					        setGameName("");
 | 
				
			||||||
 | 
					        setDate(null);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    event.preventDefault();
 | 
					    event.preventDefault();
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@ -21,6 +27,13 @@ function AddGameNight(props) {
 | 
				
			|||||||
    setDate(event.target.value);
 | 
					    setDate(event.target.value);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if(!expanded) {
 | 
				
			||||||
 | 
					      setGameName("");
 | 
				
			||||||
 | 
					      setDate(null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [expanded]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if(expanded) {
 | 
					  if(expanded) {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className="Add-GameNight">
 | 
					      <div className="Add-GameNight">
 | 
				
			||||||
@ -32,20 +45,20 @@ function AddGameNight(props) {
 | 
				
			|||||||
            <input id="gamename" name="gamename" type="text"
 | 
					            <input id="gamename" name="gamename" type="text"
 | 
				
			||||||
              value={gameName}
 | 
					              value={gameName}
 | 
				
			||||||
              onChange={handleNameChange} />
 | 
					              onChange={handleNameChange} />
 | 
				
			||||||
            <label for="date">date:</label>
 | 
					            <label for="datetime">date:</label>
 | 
				
			||||||
            <input id="date" name="date" type="date"
 | 
					            <input id="datetime" name="datetime" type="datetime-local"
 | 
				
			||||||
              value={date}
 | 
					              value={date}
 | 
				
			||||||
              onChange={handleDateChange} />
 | 
					              onChange={handleDateChange} />
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
            <input type="submit" value="Submit" />
 | 
					            <input type="submit" value="Submit" />
 | 
				
			||||||
          </fieldset>
 | 
					          </fieldset>
 | 
				
			||||||
        </form>
 | 
					        </form>
 | 
				
			||||||
        <button onClick={() => {setExpanded(false)}}>Expand</button>
 | 
					        <button onClick={() => setExpanded(false)}>Discard</button>
 | 
				
			||||||
      </div>        
 | 
					      </div>        
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <button onClick={() => {setExpanded(true)}}>Expand</button>
 | 
					      <button onClick={() => setExpanded(true)}>Expand</button>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,14 +2,10 @@ import React from 'react';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function Gamenights(props) {
 | 
					function Gamenights(props) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  console.log(props.gamenights);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let gamenights = props.gamenights.map(g => 
 | 
					  let gamenights = props.gamenights.map(g => 
 | 
				
			||||||
    (<li>{g.game}</li>)
 | 
					    (<li>{g.game}</li>)
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  console.log(gamenights);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <ul>
 | 
					    <ul>
 | 
				
			||||||
      {gamenights}
 | 
					      {gamenights}
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ function MenuBar(props) {
 | 
				
			|||||||
        <a>Gamenight</a>
 | 
					        <a>Gamenight</a>
 | 
				
			||||||
      </li>
 | 
					      </li>
 | 
				
			||||||
      <li>
 | 
					      <li>
 | 
				
			||||||
        <a>User: {props.user}</a>
 | 
					        <a>User: {props.user.username}</a>
 | 
				
			||||||
      </li>
 | 
					      </li>
 | 
				
			||||||
      <li>
 | 
					      <li>
 | 
				
			||||||
        <button onClick={props.onLogout}>Logout</button>
 | 
					        <button onClick={props.onLogout}>Logout</button>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user