models: Put User model in their own file Before adding a next model, let's start organizing the code a little, to make extending easier.

zj
Sep 7, 2021, 12:20 PM
T7TT5B4G3RBWVEG3BK6TPZQJJ3PSBBUZZCNBUM5KWYPVVPJ2VKAAC

Dependencies

  • [2] 5UNA2DEA routes: Register and authenticate users Allow users to sign up, and sign in/sign out. The routes are added, though the design of the pages is very bare bones still, it's hard to go through the full flow to demo. On the server side: Passwords are stored encrypted in the database with salts. This uses the PG encrypt tooling to prevent against bugs and maintainance costs on this project. When a user is signed in, the user ID is set in a private cookie. Rocket has Guards for routes, which has not been implemented yet for this project.
  • [3] KFVJ3KMW frontend: Introduce navigation bar Minor changes to the front-end mostly, to allow users to register, sign in, and sign out. The sign out route is changed to a GET endpoint, as links in HTML cannot DELETE.

Change contents

  • replacement in src/users.rs at line 10
    [2.2524][2.2524:2543]()
    use crate::models;
    [2.2524]
    [2.2543]
    use crate::models::users::User;
  • replacement in src/users.rs at line 35
    [2.3208][2.3208:3246]()
    let mut new_user = models::User {
    [2.3208]
    [2.3246]
    let mut new_user = User {
  • replacement in src/users.rs at line 75
    [2.4338][2.4338:4434]()
    match models::User::authenticate(db, user.user_name.clone(), user.password.clone()).await {
    [2.4338]
    [2.4434]
    match User::authenticate(db, user.user_name.clone(), user.password.clone()).await {
  • replacement in src/users.rs at line 101
    [2.5152][2.5152:5214]()
    fn set_user_cookie(jar: &CookieJar<'_>, user: models::User) {
    [2.5152]
    [2.5214]
    fn set_user_cookie(jar: &CookieJar<'_>, user: User) {
  • replacement in src/models/mod.rs at line 1
    [2.6665][2.6666:8001]()
    use crate::database::Database;
    use rocket::State;
    use sqlx::{query, query_as};
    use rocket::serde::{Deserialize, Serialize};
    #[derive(Debug, Clone, Deserialize, Serialize)]
    #[serde(crate = "rocket::serde")]
    pub struct User {
    pub id: i32,
    pub name: String,
    pub email: String,
    #[serde(skip_deserializing)]
    pub password: String,
    }
    impl User {
    pub async fn create(&self, db: &State<Database>) -> Result<i32, sqlx::Error> {
    let result = query!(
    "INSERT INTO users (name, email, password) VALUES ($1, $2, crypt($3, gen_salt('bf'))) RETURNING id",
    &self.name,
    &self.email.to_lowercase(),
    &self.password
    )
    .fetch_one(&**db)
    .await?;
    // TODO when I figure out Rust, update self with this id
    Ok(result.id)
    }
    /// Validates a user and password combination, returns a User struct when
    /// valid.
    pub async fn authenticate(
    db: &State<Database>,
    name: String,
    password: String,
    ) -> Result<Option<User>, sqlx::Error> {
    let result = query_as!(
    User,
    "SELECT * FROM users WHERE name = $1 AND password = crypt($2, password)",
    name,
    password
    )
    .fetch_optional(&**db)
    .await?;
    Ok(result)
    }
    }
    [2.6665]
    pub mod users;