forked from Roflin/gamenight
Added Login and Register handlers for actix backend
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use std::fmt::{Display, Formatter, Result};
|
||||
use actix_web::{ResponseError, error::BlockingError};
|
||||
use actix_web::{ResponseError, error::BlockingError, HttpResponse, http::{header::ContentType, StatusCode}};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use validator::ValidationErrors;
|
||||
|
||||
@@ -7,22 +7,32 @@ use crate::schema::error::DatabaseError;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct ApiError {
|
||||
pub error: String
|
||||
#[serde(skip_serializing)]
|
||||
pub status: u16,
|
||||
pub message: String
|
||||
}
|
||||
|
||||
impl Display for ApiError {
|
||||
// This trait requires `fmt` with this exact signature.
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
write!(f, "{}", self.error)
|
||||
write!(f, "{}", self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResponseError for ApiError { }
|
||||
impl ResponseError for ApiError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::build(StatusCode::from_u16(self.status).unwrap())
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&self).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DatabaseError> for ApiError {
|
||||
fn from(value: DatabaseError) -> Self {
|
||||
ApiError {
|
||||
error: value.0
|
||||
//Todo, split this in unrecoverable and schema error
|
||||
status: 500,
|
||||
message: value.0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +40,8 @@ impl From<DatabaseError> for ApiError {
|
||||
impl From<BlockingError> for ApiError {
|
||||
fn from(value: BlockingError) -> Self {
|
||||
ApiError {
|
||||
error: value.to_string()
|
||||
status: 500,
|
||||
message: value.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,15 +49,17 @@ impl From<BlockingError> for ApiError {
|
||||
impl From<serde_json::Error> for ApiError {
|
||||
fn from(value: serde_json::Error) -> Self {
|
||||
ApiError {
|
||||
error: value.to_string()
|
||||
status: 500,
|
||||
message: value.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<jsonwebtoken::errors::Error> for ApiError {
|
||||
fn from(value: jsonwebtoken::errors::Error) -> Self {
|
||||
ApiError {
|
||||
error: value.to_string()
|
||||
ApiError {
|
||||
status: 500,
|
||||
message: value.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,7 +67,8 @@ impl From<jsonwebtoken::errors::Error> for ApiError {
|
||||
impl From<ValidationErrors> for ApiError {
|
||||
fn from(value: ValidationErrors) -> Self {
|
||||
ApiError {
|
||||
error: value.to_string()
|
||||
status: 422,
|
||||
message: value.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use serde::{Serialize, Deserialize};
|
||||
use uuid::Uuid;
|
||||
use validator::ValidateArgs;
|
||||
use crate::DbPool;
|
||||
use crate::request::request_data::{Login, Register};
|
||||
use crate::request::requests::{Login, Register};
|
||||
use crate::request::error::ApiError;
|
||||
use crate::request::responses::LoginResponse;
|
||||
use crate::schema::user::Role;
|
||||
@@ -83,6 +83,7 @@ pub async fn register(pool: web::Data<DbPool>, register_data: web::Json<Register
|
||||
let mut conn1 = pool.get().expect("couldn't get db connection from pool");
|
||||
let mut conn2 = pool.get().expect("couldn't get db connection from pool");
|
||||
|
||||
|
||||
let _validation_result = web::block(move || {
|
||||
data1.validate_args((&mut conn1, &mut conn2))
|
||||
}).await??;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
mod request_data;
|
||||
mod requests;
|
||||
mod responses;
|
||||
mod handler;
|
||||
mod error;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod user;
|
||||
pub mod error;
|
||||
pub mod schema;
|
||||
|
||||
pub use user::login;
|
||||
pub use user::register;
|
||||
pub use user::register;
|
||||
|
||||
80
backend-actix/src/schema/schema.rs
Normal file
80
backend-actix/src/schema/schema.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
// @generated automatically by Diesel CLI.
|
||||
|
||||
pub mod sql_types {
|
||||
#[derive(diesel::sql_types::SqlType)]
|
||||
#[diesel(postgres_type(name = "role"))]
|
||||
pub struct Role;
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
gamenight (id) {
|
||||
id -> Uuid,
|
||||
name -> Varchar,
|
||||
datetime -> Timestamptz,
|
||||
owner_id -> Uuid,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
gamenight_gamelist (gamenight_id, game_id) {
|
||||
gamenight_id -> Uuid,
|
||||
game_id -> Uuid,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
gamenight_participants (gamenight_id, user_id) {
|
||||
gamenight_id -> Uuid,
|
||||
user_id -> Uuid,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
known_games (id) {
|
||||
id -> Uuid,
|
||||
name -> Varchar,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
pwd (user_id) {
|
||||
user_id -> Uuid,
|
||||
password -> Varchar,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
registration_tokens (id) {
|
||||
id -> Uuid,
|
||||
token -> Bpchar,
|
||||
single_use -> Bool,
|
||||
expires -> Nullable<Timestamptz>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
use diesel::sql_types::*;
|
||||
use super::sql_types::Role;
|
||||
|
||||
users (id) {
|
||||
id -> Uuid,
|
||||
username -> Varchar,
|
||||
email -> Varchar,
|
||||
role -> Role,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::joinable!(gamenight -> users (owner_id));
|
||||
diesel::joinable!(gamenight_gamelist -> known_games (game_id));
|
||||
diesel::joinable!(gamenight_participants -> users (user_id));
|
||||
diesel::joinable!(pwd -> users (user_id));
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
gamenight,
|
||||
gamenight_gamelist,
|
||||
gamenight_participants,
|
||||
known_games,
|
||||
pwd,
|
||||
registration_tokens,
|
||||
users,
|
||||
);
|
||||
@@ -1,7 +1,7 @@
|
||||
use diesel::Connection;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use uuid::Uuid;
|
||||
use diesel::{PgConnection, ExpressionMethods, QueryDsl, RunQueryDsl, table, Insertable, Queryable};
|
||||
use diesel::{PgConnection, ExpressionMethods, QueryDsl, RunQueryDsl, Insertable, Queryable};
|
||||
use diesel_derive_enum::DbEnum;
|
||||
use argon2::password_hash::SaltString;
|
||||
use argon2::PasswordHash;
|
||||
@@ -11,6 +11,7 @@ use argon2::{
|
||||
Argon2,
|
||||
};
|
||||
use validator::ValidationError;
|
||||
use super::schema::{pwd, users};
|
||||
|
||||
pub use super::error::DatabaseError;
|
||||
|
||||
@@ -30,10 +31,11 @@ pub struct User {
|
||||
pub role: Role,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, DbEnum, Clone, Copy, PartialEq)]
|
||||
#[derive(DbEnum, Debug, Serialize, Deserialize, Clone, Copy, PartialEq)]
|
||||
#[ExistingTypePath = "crate::schema::schema::sql_types::Role"]
|
||||
pub enum Role {
|
||||
Admin,
|
||||
User,
|
||||
User
|
||||
}
|
||||
|
||||
pub struct LoginUser {
|
||||
@@ -59,23 +61,6 @@ pub struct Register {
|
||||
pub password: String
|
||||
}
|
||||
|
||||
|
||||
table! {
|
||||
users(id) {
|
||||
id -> diesel::sql_types::Uuid,
|
||||
username -> VarChar,
|
||||
email -> VarChar,
|
||||
role -> crate::schema::user::RoleMapping,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
pwd(user_id) {
|
||||
user_id -> diesel::sql_types::Uuid,
|
||||
password -> VarChar,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn login(conn: &mut PgConnection, user: LoginUser) -> Result<Option<User>, DatabaseError> {
|
||||
let id: Uuid = users::table
|
||||
.filter(users::username.eq(&user.username))
|
||||
|
||||
Reference in New Issue
Block a user