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.
Dependencies
- [2]
5UNA2DEAroutes: 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]
KFVJ3KMWfrontend: 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
use crate::models;use crate::models::users::User; - replacement in src/users.rs at line 35
let mut new_user = models::User {let mut new_user = User { - replacement in src/users.rs at line 75
match models::User::authenticate(db, user.user_name.clone(), user.password.clone()).await {match User::authenticate(db, user.user_name.clone(), user.password.clone()).await { - replacement in src/users.rs at line 101
fn set_user_cookie(jar: &CookieJar<'_>, user: models::User) {fn set_user_cookie(jar: &CookieJar<'_>, user: User) { - replacement in src/models/mod.rs at line 1
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 idOk(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;