doido_auth/controllers/
sessions.rs1use crate::handlers::{authenticate, sign_in, sign_out};
4use crate::user::AuthUser;
5use doido_auth_macros::auth_controller;
6use doido_controller::respond::Format;
7use doido_core::Result;
8use doido_model::password::HasSecurePassword;
9use serde::Deserialize;
10use serde::Serialize;
11use std::marker::PhantomData;
12
13pub struct AuthSessions<U>(PhantomData<U>);
15
16#[derive(Debug, Deserialize)]
17pub struct SignInForm {
18 pub email: String,
19 pub password: String,
20}
21
22#[auth_controller]
23impl<U> AuthSessions<U>
24where
25 U: AuthUser + HasSecurePassword + Serialize + Send + Sync + 'static,
26{
27 pub async fn new(ctx: doido_controller::Context) -> doido_controller::Response {
29 ctx.render("auth/sign_in", serde_json::json!({}))
30 }
31
32 pub async fn create(mut ctx: doido_controller::Context) -> Result<doido_controller::Response> {
34 let json = ctx.negotiated_format() == Format::Json;
35 let form: SignInForm = if json {
36 ctx.body_json().await?
37 } else {
38 ctx.form().await?
39 };
40
41 match authenticate::<U>(ctx.db(), &form.email, &form.password).await {
42 Ok(user) => {
43 sign_in(ctx, &user)?;
44 if json {
45 Ok(ctx.json(user))
46 } else {
47 Ok(ctx.redirect_to("/"))
48 }
49 }
50 Err(_) if json => Ok(ctx.status(401)),
51 Err(_) => Ok(ctx.render(
52 "auth/sign_in",
53 serde_json::json!({ "error": "Invalid email or password" }),
54 )),
55 }
56 }
57
58 pub async fn destroy(mut ctx: doido_controller::Context) -> Result<doido_controller::Response> {
60 sign_out(ctx)?;
61 if ctx.negotiated_format() == Format::Json {
62 Ok(ctx.status(204))
63 } else {
64 Ok(ctx.redirect_to("/"))
65 }
66 }
67}