mirror of
https://github.com/danbulant/Portfolio
synced 2026-05-27 05:51:56 +00:00
Merge pull request #26 from EETagent/guards_routes_upload
WIP: Guards & Routes
This commit is contained in:
commit
eb04334081
19 changed files with 251 additions and 110 deletions
|
|
@ -1,27 +0,0 @@
|
||||||
use portfolio_core::sea_orm::prelude::Uuid;
|
|
||||||
use rocket::http::Status;
|
|
||||||
use rocket::outcome::Outcome;
|
|
||||||
use rocket::request::{FromRequest, Request};
|
|
||||||
|
|
||||||
|
|
||||||
pub struct UUIDCookie(Uuid);
|
|
||||||
|
|
||||||
impl UUIDCookie {
|
|
||||||
pub fn value(self) -> Uuid {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rocket::async_trait]
|
|
||||||
impl<'r> FromRequest<'r> for UUIDCookie {
|
|
||||||
type Error = Status;
|
|
||||||
async fn from_request(req: &'r Request<'_>) -> Outcome<UUIDCookie, (Status, Status), ()> {
|
|
||||||
let session_id = req.cookies().get("id").unwrap().name_value().1;
|
|
||||||
println!("session_id: {}", session_id);
|
|
||||||
|
|
||||||
match Uuid::parse_str(&session_id) {
|
|
||||||
Ok(uuid) => Outcome::Success(UUIDCookie(uuid)),
|
|
||||||
Err(_) => return Outcome::Failure((Status::BadRequest, Status::BadRequest)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
pub mod candidate_refresh_token;
|
|
||||||
43
api/src/guards/data/letter.rs
Normal file
43
api/src/guards/data/letter.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
use rocket::data::{self, Data, FromData, ToByteUnit};
|
||||||
|
use rocket::http::{ContentType, Status};
|
||||||
|
use rocket::outcome::Outcome;
|
||||||
|
use rocket::request::Request;
|
||||||
|
|
||||||
|
struct Letter(Vec<u8>);
|
||||||
|
|
||||||
|
impl Into<Vec<u8>> for Letter {
|
||||||
|
fn into(self) -> Vec<u8> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rocket::async_trait]
|
||||||
|
impl<'r> FromData<'r> for Letter {
|
||||||
|
type Error = Option<String>;
|
||||||
|
|
||||||
|
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
|
||||||
|
let content_type_pdf = ContentType::new("application", "application/pdf");
|
||||||
|
|
||||||
|
if req.content_type() != Some(&content_type_pdf) {
|
||||||
|
return Outcome::Failure((Status::BadRequest, None))
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = data.open(11.megabytes());
|
||||||
|
|
||||||
|
let data_bytes = data.into_bytes().await.unwrap();
|
||||||
|
|
||||||
|
if !data_bytes.is_complete() {
|
||||||
|
// TODO: Over limit
|
||||||
|
}
|
||||||
|
|
||||||
|
let data_bytes = data_bytes.into_inner();
|
||||||
|
|
||||||
|
let is_pdf = portfolio_core::filetype::filetype_is_pdf(&data_bytes);
|
||||||
|
|
||||||
|
if !is_pdf {
|
||||||
|
// TODO: Not PDF
|
||||||
|
}
|
||||||
|
|
||||||
|
Outcome::Success(Letter(data_bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
2
api/src/guards/data/mod.rs
Normal file
2
api/src/guards/data/mod.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod portfolio;
|
||||||
|
pub mod letter;
|
||||||
43
api/src/guards/data/portfolio.rs
Normal file
43
api/src/guards/data/portfolio.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
use rocket::data::{self, Data, FromData, ToByteUnit};
|
||||||
|
use rocket::http::{ContentType, Status};
|
||||||
|
use rocket::outcome::Outcome;
|
||||||
|
use rocket::request::Request;
|
||||||
|
|
||||||
|
struct Portfolio(Vec<u8>);
|
||||||
|
|
||||||
|
impl Into<Vec<u8>> for Portfolio {
|
||||||
|
fn into(self) -> Vec<u8> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rocket::async_trait]
|
||||||
|
impl<'r> FromData<'r> for Portfolio {
|
||||||
|
type Error = Option<String>;
|
||||||
|
|
||||||
|
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
|
||||||
|
let content_type_zip = ContentType::new("application", "application/zip");
|
||||||
|
|
||||||
|
if req.content_type() != Some(&content_type_zip) {
|
||||||
|
return Outcome::Failure((Status::BadRequest, None))
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = data.open(101.megabytes());
|
||||||
|
|
||||||
|
let data_bytes = data.into_bytes().await.unwrap();
|
||||||
|
|
||||||
|
if !data_bytes.is_complete() {
|
||||||
|
// TODO: Over limit
|
||||||
|
}
|
||||||
|
|
||||||
|
let data_bytes = data_bytes.into_inner();
|
||||||
|
|
||||||
|
let is_zip = portfolio_core::filetype::filetype_is_zip(&data_bytes);
|
||||||
|
|
||||||
|
if !is_zip {
|
||||||
|
// TODO: Not ZIP
|
||||||
|
}
|
||||||
|
|
||||||
|
Outcome::Success(Portfolio(data_bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
2
api/src/guards/mod.rs
Normal file
2
api/src/guards/mod.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod data;
|
||||||
|
pub mod request;
|
||||||
1
api/src/guards/request/mod.rs
Normal file
1
api/src/guards/request/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod session_auth;
|
||||||
38
api/src/guards/request/session_auth.rs
Normal file
38
api/src/guards/request/session_auth.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
use entity::candidate::Model as Candidate;
|
||||||
|
use portfolio_core::sea_orm::prelude::Uuid;
|
||||||
|
use portfolio_core::services::candidate_service::CandidateService;
|
||||||
|
use rocket::http::Status;
|
||||||
|
use rocket::outcome::Outcome;
|
||||||
|
use rocket::request::{FromRequest, Request};
|
||||||
|
|
||||||
|
use crate::pool::Db;
|
||||||
|
|
||||||
|
pub struct SessionAuth(Candidate);
|
||||||
|
|
||||||
|
impl Into<Candidate> for SessionAuth {
|
||||||
|
fn into(self) -> Candidate {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rocket::async_trait]
|
||||||
|
impl<'r> FromRequest<'r> for SessionAuth {
|
||||||
|
type Error = Option<String>;
|
||||||
|
async fn from_request(req: &'r Request<'_>) -> Outcome<SessionAuth, (Status, Self::Error), ()> {
|
||||||
|
let session_id = req.cookies().get("id").unwrap().name_value().1;
|
||||||
|
let conn = &req.rocket().state::<Db>().unwrap().conn;
|
||||||
|
|
||||||
|
let uuid = match Uuid::parse_str(&session_id) {
|
||||||
|
Ok(uuid) => uuid,
|
||||||
|
Err(_) => return Outcome::Failure((Status::BadRequest, None)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let session = CandidateService::auth_user_session(conn, uuid).await;
|
||||||
|
|
||||||
|
match session {
|
||||||
|
Ok(model) => Outcome::Success(SessionAuth(model)),
|
||||||
|
Err(_) => Outcome::Failure((Status::Unauthorized, None)),
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ extern crate rocket;
|
||||||
|
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
|
use guards::request::session_auth::SessionAuth;
|
||||||
use portfolio_core::error::ServiceError;
|
use portfolio_core::error::ServiceError;
|
||||||
use portfolio_core::services::candidate_service::CandidateService;
|
use portfolio_core::services::candidate_service::CandidateService;
|
||||||
use requests::{LoginRequest, RegisterRequest};
|
use requests::{LoginRequest, RegisterRequest};
|
||||||
|
|
@ -18,8 +19,9 @@ use sea_orm_rocket::{Connection, Database};
|
||||||
|
|
||||||
|
|
||||||
mod pool;
|
mod pool;
|
||||||
mod guard;
|
mod guards;
|
||||||
mod requests;
|
mod requests;
|
||||||
|
mod routes;
|
||||||
|
|
||||||
use pool::Db;
|
use pool::Db;
|
||||||
|
|
||||||
|
|
@ -28,8 +30,6 @@ pub use entity::candidate::Entity as Candidate;
|
||||||
|
|
||||||
use portfolio_core::crypto::random_8_char_string;
|
use portfolio_core::crypto::random_8_char_string;
|
||||||
|
|
||||||
use crate::guard::candidate_refresh_token::UUIDCookie;
|
|
||||||
|
|
||||||
fn custom_err_from_service_err(service_err: ServiceError) -> Custom<String> {
|
fn custom_err_from_service_err(service_err: ServiceError) -> Custom<String> {
|
||||||
Custom(Status::from_code(service_err.0.code).unwrap_or_default(), service_err.1.to_string())
|
Custom(Status::from_code(service_err.0.code).unwrap_or_default(), service_err.1.to_string())
|
||||||
}
|
}
|
||||||
|
|
@ -49,15 +49,9 @@ async fn create(conn: Connection<'_, Db>, post_form: Json<RegisterRequest>) -> R
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/whoami")]
|
#[get("/whoami")]
|
||||||
async fn validate(conn: Connection<'_, Db>, uuid_cookie: Result<UUIDCookie, Status>) -> Result<String, Custom<String>> {
|
async fn validate(session: SessionAuth) -> Result<String, Custom<String>> {
|
||||||
let db = conn.into_inner();
|
let candidate: entity::candidate::Model = session.into();
|
||||||
let user = CandidateService::auth_user_session(db, uuid_cookie.ok().unwrap().value()).await;
|
Ok(candidate.application.to_string())
|
||||||
|
|
||||||
|
|
||||||
match user {
|
|
||||||
Ok(user) => Ok(user.application.to_string()),
|
|
||||||
Err(err) => Err(custom_err_from_service_err(err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/login", data = "<login_form>")]
|
#[post("/login", data = "<login_form>")]
|
||||||
|
|
|
||||||
0
api/src/routes/mod.rs
Normal file
0
api/src/routes/mod.rs
Normal file
2
core/src/database/mod.rs
Normal file
2
core/src/database/mod.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod mutation;
|
||||||
|
pub mod query;
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
|
use crate::Mutation;
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
||||||
use chrono::{Utc, Duration};
|
use ::entity::candidate;
|
||||||
use ::entity::{candidate, session};
|
use sea_orm::{*};
|
||||||
use sea_orm::{*, prelude::Uuid};
|
use crate::{crypto::{hash_password, self}};
|
||||||
use crate::crypto::{hash_password, self};
|
|
||||||
|
|
||||||
pub struct Mutation;
|
|
||||||
|
|
||||||
impl Mutation {
|
impl Mutation {
|
||||||
pub async fn create_candidate(
|
pub async fn create_candidate(
|
||||||
|
|
@ -37,36 +35,6 @@ impl Mutation {
|
||||||
.insert(db)
|
.insert(db)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn insert_session(
|
|
||||||
db: &DbConn,
|
|
||||||
user_id: i32,
|
|
||||||
random_uuid: Uuid,
|
|
||||||
ip_addr: String,
|
|
||||||
) -> Result<session::Model, DbErr> {
|
|
||||||
session::ActiveModel {
|
|
||||||
id: Set(random_uuid),
|
|
||||||
user_id: Set(user_id),
|
|
||||||
ip_address: Set(ip_addr),
|
|
||||||
created_at: Set(Utc::now().naive_local()),
|
|
||||||
expires_at: Set(Utc::now().naive_local().checked_add_signed(Duration::days(1)).unwrap()),
|
|
||||||
}
|
|
||||||
.insert(db)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn delete_session(
|
|
||||||
db: &DbConn,
|
|
||||||
session_id: Uuid
|
|
||||||
) -> Result<DeleteResult, DbErr> {
|
|
||||||
session::ActiveModel {
|
|
||||||
id: Set(session_id),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
.delete(db)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
4
core/src/database/mutation/mod.rs
Normal file
4
core/src/database/mutation/mod.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
pub struct Mutation;
|
||||||
|
|
||||||
|
pub mod session;
|
||||||
|
pub mod candidate;
|
||||||
37
core/src/database/mutation/session.rs
Normal file
37
core/src/database/mutation/session.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
use chrono::{Utc, Duration};
|
||||||
|
use ::entity::session;
|
||||||
|
use sea_orm::{*, prelude::Uuid};
|
||||||
|
|
||||||
|
use crate::Mutation;
|
||||||
|
|
||||||
|
|
||||||
|
impl Mutation {
|
||||||
|
pub async fn insert_session(
|
||||||
|
db: &DbConn,
|
||||||
|
user_id: i32,
|
||||||
|
random_uuid: Uuid,
|
||||||
|
ip_addr: String,
|
||||||
|
) -> Result<session::Model, DbErr> {
|
||||||
|
session::ActiveModel {
|
||||||
|
id: Set(random_uuid),
|
||||||
|
user_id: Set(user_id),
|
||||||
|
ip_address: Set(ip_addr),
|
||||||
|
created_at: Set(Utc::now().naive_local()),
|
||||||
|
expires_at: Set(Utc::now()
|
||||||
|
.naive_local()
|
||||||
|
.checked_add_signed(Duration::days(1))
|
||||||
|
.unwrap()),
|
||||||
|
}
|
||||||
|
.insert(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_session(db: &DbConn, session_id: Uuid) -> Result<DeleteResult, DbErr> {
|
||||||
|
session::ActiveModel {
|
||||||
|
id: Set(session_id),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.delete(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,33 +1,22 @@
|
||||||
use ::entity::{candidate, candidate::Entity as Candidate};
|
use crate::Query;
|
||||||
use ::entity::{session, session::Entity as Session};
|
|
||||||
use sea_orm::*;
|
|
||||||
use sea_orm::prelude::Uuid;
|
|
||||||
|
|
||||||
pub struct Query;
|
use ::entity::{candidate, candidate::Entity as Candidate};
|
||||||
|
use sea_orm::*;
|
||||||
|
|
||||||
impl Query {
|
impl Query {
|
||||||
pub async fn find_candidate_by_id(db: &DbConn, id: i32) -> Result<Option<candidate::Model>, DbErr> {
|
pub async fn find_candidate_by_id(
|
||||||
|
db: &DbConn,
|
||||||
|
id: i32,
|
||||||
|
) -> Result<Option<candidate::Model>, DbErr> {
|
||||||
Candidate::find_by_id(id).one(db).await
|
Candidate::find_by_id(id).one(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_session_by_uuid(db: &DbConn, uuid: Uuid) -> Result<Option<session::Model>, DbErr> {
|
|
||||||
Session::find_by_id(uuid).one(db).await
|
|
||||||
}
|
|
||||||
|
|
||||||
// find session by user id
|
|
||||||
pub async fn find_sessions_by_user_id(db: &DbConn, user_id: i32) -> Result<Vec<session::Model>, DbErr> {
|
|
||||||
Session::find()
|
|
||||||
.filter(session::Column::UserId.eq(user_id))
|
|
||||||
.all(db)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use sea_orm::{DbConn, Set, ActiveModelTrait};
|
|
||||||
use entity::candidate;
|
use entity::candidate;
|
||||||
use sea_orm::{Schema, Database, DbBackend, sea_query::TableCreateStatement, ConnectionTrait};
|
use sea_orm::{sea_query::TableCreateStatement, ConnectionTrait, Database, DbBackend, Schema};
|
||||||
|
use sea_orm::{ActiveModelTrait, DbConn, Set};
|
||||||
|
|
||||||
use crate::Query;
|
use crate::Query;
|
||||||
|
|
||||||
|
|
@ -38,7 +27,9 @@ mod tests {
|
||||||
|
|
||||||
let schema = Schema::new(DbBackend::Sqlite);
|
let schema = Schema::new(DbBackend::Sqlite);
|
||||||
let stmt: TableCreateStatement = schema.create_table_from_entity(candidate::Entity);
|
let stmt: TableCreateStatement = schema.create_table_from_entity(candidate::Entity);
|
||||||
db.execute(db.get_database_backend().build(&stmt)).await.unwrap();
|
db.execute(db.get_database_backend().build(&stmt))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
db
|
db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,7 +50,9 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let candidate = Query::find_candidate_by_id(&db, candidate.application).await.unwrap();
|
let candidate = Query::find_candidate_by_id(&db, candidate.application)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
assert!(candidate.is_some());
|
assert!(candidate.is_some());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
4
core/src/database/query/mod.rs
Normal file
4
core/src/database/query/mod.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
pub struct Query;
|
||||||
|
|
||||||
|
pub mod candidate;
|
||||||
|
pub mod session;
|
||||||
37
core/src/database/query/session.rs
Normal file
37
core/src/database/query/session.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
use crate::Query;
|
||||||
|
|
||||||
|
use ::entity::{session, session::Entity as Session};
|
||||||
|
use sea_orm::*;
|
||||||
|
use sea_orm::prelude::Uuid;
|
||||||
|
|
||||||
|
impl Query {
|
||||||
|
pub async fn find_session_by_uuid(db: &DbConn, uuid: Uuid) -> Result<Option<session::Model>, DbErr> {
|
||||||
|
Session::find_by_id(uuid).one(db).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// find session by user id
|
||||||
|
pub async fn find_sessions_by_user_id(db: &DbConn, user_id: i32) -> Result<Vec<session::Model>, DbErr> {
|
||||||
|
Session::find()
|
||||||
|
.filter(session::Column::UserId.eq(user_id))
|
||||||
|
.all(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use sea_orm::DbConn;
|
||||||
|
use entity::candidate;
|
||||||
|
use sea_orm::{Schema, Database, DbBackend, sea_query::TableCreateStatement, ConnectionTrait};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
async fn get_memory_sqlite_connection() -> DbConn {
|
||||||
|
let base_url = "sqlite::memory:";
|
||||||
|
let db: DbConn = Database::connect(base_url).await.unwrap();
|
||||||
|
|
||||||
|
let schema = Schema::new(DbBackend::Sqlite);
|
||||||
|
let stmt: TableCreateStatement = schema.create_table_from_entity(candidate::Entity);
|
||||||
|
db.execute(db.get_database_backend().build(&stmt)).await.unwrap();
|
||||||
|
db
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
mod mutation;
|
pub mod database;
|
||||||
mod query;
|
|
||||||
pub mod crypto;
|
pub mod crypto;
|
||||||
pub mod filetype;
|
pub mod filetype;
|
||||||
pub mod services;
|
pub mod services;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
pub use mutation::*;
|
pub use database::mutation::*;
|
||||||
pub use query::*;
|
pub use database::query::*;
|
||||||
|
|
||||||
pub use sea_orm;
|
pub use sea_orm;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use crate::{crypto::{self}, Query, error::{ServiceError, USER_NOT_FOUND_ERROR, I
|
||||||
pub struct CandidateService;
|
pub struct CandidateService;
|
||||||
|
|
||||||
impl CandidateService {
|
impl CandidateService {
|
||||||
|
/// Delete n old sessions for user
|
||||||
async fn delete_old_sessions(db: &DatabaseConnection, user_id: i32, keep_n_recent: usize) -> Result<(), ServiceError> {
|
async fn delete_old_sessions(db: &DatabaseConnection, user_id: i32, keep_n_recent: usize) -> Result<(), ServiceError> {
|
||||||
let mut sessions = Query::find_sessions_by_user_id(db, user_id).await.unwrap();
|
let mut sessions = Query::find_sessions_by_user_id(db, user_id).await.unwrap();
|
||||||
|
|
||||||
|
|
@ -21,6 +22,7 @@ impl CandidateService {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Authenticate user by application id and password and generate a new session
|
||||||
pub async fn new_session(db: &DatabaseConnection, user_id: i32, password: String, ip_addr: String) -> Result<String, ServiceError> {
|
pub async fn new_session(db: &DatabaseConnection, user_id: i32, password: String, ip_addr: String) -> Result<String, ServiceError> {
|
||||||
let candidate = match Query::find_candidate_by_id(db, user_id).await {
|
let candidate = match Query::find_candidate_by_id(db, user_id).await {
|
||||||
Ok(candidate) => match candidate {
|
Ok(candidate) => match candidate {
|
||||||
|
|
@ -40,10 +42,8 @@ impl CandidateService {
|
||||||
Err(_) => {return Err(INVALID_CREDENTIALS_ERROR)}
|
Err(_) => {return Err(INVALID_CREDENTIALS_ERROR)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO delete old sessions?
|
|
||||||
|
|
||||||
|
// user is authenticated, generate a new session
|
||||||
// user is authenticated, generate a session
|
|
||||||
let random_uuid: Uuid = Uuid::new_v4();
|
let random_uuid: Uuid = Uuid::new_v4();
|
||||||
|
|
||||||
let session = match Mutation::insert_session(db, user_id, random_uuid, ip_addr).await {
|
let session = match Mutation::insert_session(db, user_id, random_uuid, ip_addr).await {
|
||||||
|
|
@ -57,6 +57,8 @@ impl CandidateService {
|
||||||
Ok(session.id.to_string())
|
Ok(session.id.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Authenticate user by session id
|
||||||
|
/// Return user model if session is valid
|
||||||
pub async fn auth_user_session(db: &DatabaseConnection, uuid: Uuid) -> Result<candidate::Model, ServiceError> {
|
pub async fn auth_user_session(db: &DatabaseConnection, uuid: Uuid) -> Result<candidate::Model, ServiceError> {
|
||||||
let session = match Query::find_session_by_uuid(db, uuid).await {
|
let session = match Query::find_session_by_uuid(db, uuid).await {
|
||||||
Ok(session) => match session {
|
Ok(session) => match session {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue