A api/src/actions/user/login.rs => api/src/actions/user/login.rs +19 -0
@@ 0,0 1,19 @@
+/*
+ * This file is part of laurelin/api
+ * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
+ *
+ * Licensed under GPL-3.0-only.
+ * See LICENSE for licensing information.
+ */
+
+use diesel::PgConnection;
+use laurelin_shared::error::api::APIError;
+
+use crate::models::{User, UserCredentials};
+
+pub(crate) fn login(
+ conn: &mut PgConnection,
+ credentials: &UserCredentials,
+) -> Result<User, APIError> {
+ Err(APIError::UserInvalidCredentials)
+}
A api/src/actions/user/logout.rs => api/src/actions/user/logout.rs +0 -0
M api/src/actions/user/mod.rs => api/src/actions/user/mod.rs +4 -1
@@ 7,4 7,7 @@
*/
mod create;
-pub(crate) use create::*;
+pub(crate) use create::create;
+
+mod login;
+pub(crate) use login::login;
A api/src/handlers/user/login.rs => api/src/handlers/user/login.rs +49 -0
@@ 0,0 1,49 @@
+/*
+ * This file is part of laurelin/api
+ * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
+ *
+ * Licensed under GPL-3.0-only.
+ * See LICENSE for licensing information.
+ */
+
+use actix_session::Session;
+use actix_web::{post, web, HttpResponse, Responder};
+use laurelin_shared::error::api::APIError;
+
+use crate::{actions, models::UserCredentials, PgPool};
+
+#[post("/api/user/login")]
+pub(crate) async fn login(
+ pool: web::Data<PgPool>,
+ session: Session,
+ credentials: web::Json<UserCredentials>,
+) -> impl Responder {
+ let user = match web::block(move || {
+ let mut conn = match pool.get() {
+ Err(_) => return Err(APIError::DatabasePoolGetFailed),
+ Ok(conn) => conn,
+ };
+ actions::user::login(&mut conn, &credentials.0)
+ })
+ .await
+ {
+ Err(_) => {
+ // TODO: handle?
+ return HttpResponse::InternalServerError().json(APIError::Undefined);
+ }
+ Ok(user_res) => match user_res {
+ Err(err) => match err {
+ APIError::UserInvalidCredentials => {
+ return HttpResponse::Unauthorized().json(APIError::UserInvalidCredentials)
+ }
+ _ => return HttpResponse::InternalServerError().json(err),
+ },
+ Ok(user) => user,
+ },
+ };
+
+ match session.insert("user_id", user.id) {
+ Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
+ Ok(_) => HttpResponse::Ok().json(user),
+ }
+}
M api/src/handlers/user/mod.rs => api/src/handlers/user/mod.rs +5 -0
@@ 8,3 8,8 @@
mod create;
pub(crate) use create::*;
+
+mod login;
+pub(crate) use login::*;
+
+pub(crate) fn logout() {}
M api/src/main.rs => api/src/main.rs +9 -1
@@ 6,7 6,7 @@
* See LICENSE for licensing information.
*/
-use actix_session::{storage::RedisActorSessionStore, SessionMiddleware};
+use actix_session::{storage::RedisActorSessionStore, Session, SessionMiddleware};
use actix_web::{
cookie::Key, get, middleware::Logger, web, App, HttpResponse, HttpServer, Responder,
};
@@ 27,6 27,11 @@ async fn ping() -> impl Responder {
HttpResponse::Ok().body("pong")
}
+#[get("/api/ping_sec")]
+async fn ping_sec(session: Session) -> impl Responder {
+ HttpResponse::Ok().body("pong")
+}
+
fn run_migrations(conn: &mut PgConnection) {
conn.run_pending_migrations(MIGRATIONS).unwrap();
}
@@ 36,6 41,7 @@ mod schema;
mod actions;
mod handlers;
mod models;
+mod session;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
@@ 70,8 76,10 @@ async fn main() -> std::io::Result<()> {
.build(),
)
.service(ping)
+ .service(ping_sec)
.service(handlers::info)
.service(handlers::user::create)
+ .service(handlers::user::login)
})
.bind(("0.0.0.0", 8080))?
.run()
M api/src/models/user.rs => api/src/models/user.rs +6 -0
@@ 32,3 32,9 @@ pub(crate) struct InsertableUser {
pub email: String,
pub password: String,
}
+
+#[derive(Deserialize)]
+pub(crate) struct UserCredentials {
+ pub email: String,
+ pub password: String,
+}
A api/src/session.rs => api/src/session.rs +15 -0
@@ 0,0 1,15 @@
+/*
+ * This file is part of laurelin/api
+ * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
+ *
+ * Licensed under GPL-3.0-only.
+ * See LICENSE for licensing information.
+ */
+
+use actix_session::Session;
+use actix_web::HttpResponse;
+use laurelin_shared::error::api::APIError;
+
+pub(crate) fn validate_session(session: &Session) -> Result<String, HttpResponse> {
+ Err(HttpResponse::Unauthorized().json(APIError::NotAuthorized))
+}