1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
use crate::auth::Auth; use crate::config::AppState; use crate::db::{self, users::UserCreationError}; use crate::errors::{Errors, FieldValidator}; use rocket::State; use rocket_contrib::json::{Json, JsonValue}; use serde::Deserialize; use validator::Validate; #[derive(Deserialize)] pub struct NewUser { user: NewUserData, } #[derive(Deserialize, Validate)] struct NewUserData { #[validate(length(min = 1))] username: Option<String>, #[validate(email)] email: Option<String>, #[validate(length(min = 8))] password: Option<String>, } #[post("/users", format = "json", data = "<new_user>")] pub fn post_users( new_user: Json<NewUser>, conn: db::Conn, state: State<AppState>, ) -> Result<JsonValue, Errors> { let new_user = new_user.into_inner().user; let mut extractor = FieldValidator::validate(&new_user); let username = extractor.extract("username", new_user.username); let email = extractor.extract("email", new_user.email); let password = extractor.extract("password", new_user.password); extractor.check()?; db::users::create(&conn, &username, &email, &password) .map(|user| json!({ "user": user.to_user_auth(&state.secret) })) .map_err(|error| { let field = match error { UserCreationError::DuplicatedEmail => "email", UserCreationError::DuplicatedUsername => "username", }; Errors::new(&[(field, "has already been taken")]) }) } #[derive(Deserialize)] pub struct LoginUser { user: LoginUserData, } #[derive(Deserialize)] struct LoginUserData { email: Option<String>, password: Option<String>, } #[post("/users/login", format = "json", data = "<user>")] pub fn post_users_login( user: Json<LoginUser>, conn: db::Conn, state: State<AppState>, ) -> Result<JsonValue, Errors> { let user = user.into_inner().user; let mut extractor = FieldValidator::default(); let email = extractor.extract("email", user.email); let password = extractor.extract("password", user.password); extractor.check()?; db::users::login(&conn, &email, &password) .map(|user| json!({ "user": user.to_user_auth(&state.secret) })) .ok_or_else(|| Errors::new(&[("email or password", "is invalid")])) } #[get("/user")] pub fn get_user(auth: Auth, conn: db::Conn, state: State<AppState>) -> Option<JsonValue> { db::users::find(&conn, auth.id).map(|user| json!({ "user": user.to_user_auth(&state.secret) })) } #[derive(Deserialize)] pub struct UpdateUser { user: db::users::UpdateUserData, } #[put("/user", format = "json", data = "<user>")] pub fn put_user( user: Json<UpdateUser>, auth: Auth, conn: db::Conn, state: State<AppState>, ) -> Option<JsonValue> { db::users::update(&conn, auth.id, &user.user) .map(|user| json!({ "user": user.to_user_auth(&state.secret) })) }