Can create a family
This commit is contained in:
parent
e6c896efa2
commit
f54dfde7f7
@ -14,18 +14,18 @@ CREATE TABLE users (
|
|||||||
admin BOOLEAN NOT NULL DEFAULT FALSE
|
admin BOOLEAN NOT NULL DEFAULT FALSE
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE families(
|
CREATE TABLE families (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
time_create BIGINT NOT NULL,
|
time_create BIGINT NOT NULL,
|
||||||
name VARCHAR(30) NOT NULL,
|
name VARCHAR(30) NOT NULL,
|
||||||
invitation_code VARCHAR(7) NOT NULL
|
invitation_code VARCHAR(7) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE memberships(
|
CREATE TABLE memberships (
|
||||||
user_id integer NOT NULL REFERENCES users,
|
user_id integer NOT NULL REFERENCES users,
|
||||||
family_id integer NOT NULL REFERENCES families,
|
family_id integer NOT NULL REFERENCES families,
|
||||||
time_create BIGINT NOT NULL,
|
time_create BIGINT NOT NULL,
|
||||||
is_admin BOOLEAN NOT NULL DEFAULT TRUE,
|
is_admin BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
|
||||||
PRIMARY KEY(user_id, family_id)
|
PRIMARY KEY(user_id, family_id)
|
||||||
);
|
);
|
@ -22,6 +22,7 @@ pub struct StaticConstraints {
|
|||||||
pub mail_len: SizeConstraint,
|
pub mail_len: SizeConstraint,
|
||||||
pub user_name_len: SizeConstraint,
|
pub user_name_len: SizeConstraint,
|
||||||
pub password_len: SizeConstraint,
|
pub password_len: SizeConstraint,
|
||||||
|
pub family_name_len: SizeConstraint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for StaticConstraints {
|
impl Default for StaticConstraints {
|
||||||
@ -30,6 +31,7 @@ impl Default for StaticConstraints {
|
|||||||
mail_len: SizeConstraint::new(5, 255),
|
mail_len: SizeConstraint::new(5, 255),
|
||||||
user_name_len: SizeConstraint::new(3, 30),
|
user_name_len: SizeConstraint::new(3, 30),
|
||||||
password_len: SizeConstraint::new(8, 255),
|
password_len: SizeConstraint::new(8, 255),
|
||||||
|
family_name_len: SizeConstraint::new(3, 30),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,3 +44,6 @@ pub const ACCOUNT_DELETE_TOKEN_DURATION: Duration = Duration::from_secs(3600 * 1
|
|||||||
|
|
||||||
/// OpenID state duration
|
/// OpenID state duration
|
||||||
pub const OPEN_ID_STATE_DURATION: Duration = Duration::from_secs(3600);
|
pub const OPEN_ID_STATE_DURATION: Duration = Duration::from_secs(3600);
|
||||||
|
|
||||||
|
/// Length of family invitation code
|
||||||
|
pub const FAMILY_INVITATION_CODE_LEN: usize = 7;
|
||||||
|
24
geneit_backend/src/controllers/families_controller.rs
Normal file
24
geneit_backend/src/controllers/families_controller.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use crate::constants::StaticConstraints;
|
||||||
|
use crate::controllers::HttpResult;
|
||||||
|
use crate::services::families_service;
|
||||||
|
use crate::services::login_token_service::LoginToken;
|
||||||
|
use actix_web::{web, HttpResponse};
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize)]
|
||||||
|
pub struct CreateFamilyReq {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new family
|
||||||
|
pub async fn create(req: web::Json<CreateFamilyReq>, token: LoginToken) -> HttpResult {
|
||||||
|
if !StaticConstraints::default()
|
||||||
|
.family_name_len
|
||||||
|
.validate(&req.name)
|
||||||
|
{
|
||||||
|
return Ok(HttpResponse::BadRequest().body("Invalid family name!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let family = families_service::create(&req.name, token.user_id).await?;
|
||||||
|
|
||||||
|
Ok(HttpResponse::Created().json(family))
|
||||||
|
}
|
@ -5,8 +5,9 @@ use actix_web::HttpResponse;
|
|||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
|
|
||||||
pub mod auth_controller;
|
pub mod auth_controller;
|
||||||
|
pub mod families_controller;
|
||||||
pub mod server_controller;
|
pub mod server_controller;
|
||||||
pub mod user_controller;
|
pub mod users_controller;
|
||||||
|
|
||||||
/// Custom error to ease controller writing
|
/// Custom error to ease controller writing
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -3,7 +3,9 @@ use actix_remote_ip::RemoteIPConfig;
|
|||||||
use actix_web::middleware::Logger;
|
use actix_web::middleware::Logger;
|
||||||
use actix_web::{web, App, HttpServer};
|
use actix_web::{web, App, HttpServer};
|
||||||
use geneit_backend::app_config::AppConfig;
|
use geneit_backend::app_config::AppConfig;
|
||||||
use geneit_backend::controllers::{auth_controller, server_controller, user_controller};
|
use geneit_backend::controllers::{
|
||||||
|
auth_controller, families_controller, server_controller, users_controller,
|
||||||
|
};
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
@ -63,26 +65,31 @@ async fn main() -> std::io::Result<()> {
|
|||||||
)
|
)
|
||||||
.route("/auth/logout", web::get().to(auth_controller::logout))
|
.route("/auth/logout", web::get().to(auth_controller::logout))
|
||||||
// User controller
|
// User controller
|
||||||
.route("/user/info", web::get().to(user_controller::auth_info))
|
.route("/user/info", web::get().to(users_controller::auth_info))
|
||||||
.route(
|
.route(
|
||||||
"/user/update_profile",
|
"/user/update_profile",
|
||||||
web::post().to(user_controller::update_profile),
|
web::post().to(users_controller::update_profile),
|
||||||
)
|
)
|
||||||
.route(
|
.route(
|
||||||
"/user/replace_password",
|
"/user/replace_password",
|
||||||
web::post().to(user_controller::replace_password),
|
web::post().to(users_controller::replace_password),
|
||||||
)
|
)
|
||||||
.route(
|
.route(
|
||||||
"/user/request_delete",
|
"/user/request_delete",
|
||||||
web::get().to(user_controller::request_delete_account),
|
web::get().to(users_controller::request_delete_account),
|
||||||
)
|
)
|
||||||
.route(
|
.route(
|
||||||
"/user/check_delete_token",
|
"/user/check_delete_token",
|
||||||
web::post().to(user_controller::check_delete_token),
|
web::post().to(users_controller::check_delete_token),
|
||||||
)
|
)
|
||||||
.route(
|
.route(
|
||||||
"/user/delete_account",
|
"/user/delete_account",
|
||||||
web::post().to(user_controller::delete_account),
|
web::post().to(users_controller::delete_account),
|
||||||
|
)
|
||||||
|
// Families controller
|
||||||
|
.route(
|
||||||
|
"/family/create",
|
||||||
|
web::post().to(families_controller::create),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.bind(AppConfig::get().listen_address.as_str())?
|
.bind(AppConfig::get().listen_address.as_str())?
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::schema::users;
|
use crate::schema::{families, memberships, users};
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
|
||||||
/// User ID holder
|
/// User ID holder
|
||||||
@ -51,3 +51,46 @@ pub struct NewUser<'a> {
|
|||||||
pub email: &'a str,
|
pub email: &'a str,
|
||||||
pub time_create: i64,
|
pub time_create: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Family ID holder
|
||||||
|
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct FamilyID(pub i32);
|
||||||
|
|
||||||
|
#[derive(Queryable, Debug, serde::Serialize)]
|
||||||
|
pub struct Family {
|
||||||
|
pub id: i32,
|
||||||
|
pub time_create: i64,
|
||||||
|
pub name: String,
|
||||||
|
pub invitation_code: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Family {
|
||||||
|
pub fn id(&self) -> FamilyID {
|
||||||
|
FamilyID(self.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Insertable)]
|
||||||
|
#[diesel(table_name = families)]
|
||||||
|
pub struct NewFamily<'a> {
|
||||||
|
pub name: &'a str,
|
||||||
|
pub invitation_code: String,
|
||||||
|
pub time_create: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Queryable, Debug, serde::Serialize)]
|
||||||
|
pub struct Membership {
|
||||||
|
user_id: i32,
|
||||||
|
family_id: i32,
|
||||||
|
time_create: i64,
|
||||||
|
is_admin: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Insertable)]
|
||||||
|
#[diesel(table_name = memberships)]
|
||||||
|
pub struct NewMembership {
|
||||||
|
pub user_id: i32,
|
||||||
|
pub family_id: i32,
|
||||||
|
pub time_create: i64,
|
||||||
|
pub is_admin: bool,
|
||||||
|
}
|
||||||
|
@ -38,8 +38,4 @@ diesel::table! {
|
|||||||
diesel::joinable!(memberships -> families (family_id));
|
diesel::joinable!(memberships -> families (family_id));
|
||||||
diesel::joinable!(memberships -> users (user_id));
|
diesel::joinable!(memberships -> users (user_id));
|
||||||
|
|
||||||
diesel::allow_tables_to_appear_in_same_query!(
|
diesel::allow_tables_to_appear_in_same_query!(families, memberships, users,);
|
||||||
families,
|
|
||||||
memberships,
|
|
||||||
users,
|
|
||||||
);
|
|
||||||
|
46
geneit_backend/src/services/families_service.rs
Normal file
46
geneit_backend/src/services/families_service.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use crate::connections::db_connection;
|
||||||
|
use crate::constants::FAMILY_INVITATION_CODE_LEN;
|
||||||
|
use crate::models::{Family, FamilyID, Membership, NewFamily, NewMembership, UserID};
|
||||||
|
use crate::schema::{families, memberships};
|
||||||
|
use crate::utils::string_utils::rand_str;
|
||||||
|
use crate::utils::time_utils::time;
|
||||||
|
use diesel::RunQueryDsl;
|
||||||
|
|
||||||
|
/// Create a new family, with an initial administrator
|
||||||
|
pub async fn create(name: &str, user_id: UserID) -> anyhow::Result<Family> {
|
||||||
|
let family = db_connection::execute(|conn| {
|
||||||
|
let res: Family = diesel::insert_into(families::table)
|
||||||
|
.values(&NewFamily {
|
||||||
|
name: name.trim(),
|
||||||
|
invitation_code: rand_str(FAMILY_INVITATION_CODE_LEN),
|
||||||
|
time_create: time() as i64,
|
||||||
|
})
|
||||||
|
.get_result(conn)?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
add_member(family.id(), user_id, true).await?;
|
||||||
|
|
||||||
|
Ok(family)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a member to a family
|
||||||
|
pub async fn add_member(
|
||||||
|
family_id: FamilyID,
|
||||||
|
user_id: UserID,
|
||||||
|
admin: bool,
|
||||||
|
) -> anyhow::Result<Membership> {
|
||||||
|
db_connection::execute(|conn| {
|
||||||
|
let res = diesel::insert_into(memberships::table)
|
||||||
|
.values(&NewMembership {
|
||||||
|
user_id: user_id.0,
|
||||||
|
family_id: family_id.0,
|
||||||
|
time_create: time() as i64,
|
||||||
|
is_admin: admin,
|
||||||
|
})
|
||||||
|
.get_result(conn)?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
})
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
//! # Backend services
|
//! # Backend services
|
||||||
|
|
||||||
|
pub mod families_service;
|
||||||
pub mod login_token_service;
|
pub mod login_token_service;
|
||||||
pub mod mail_service;
|
pub mod mail_service;
|
||||||
pub mod openid_service;
|
pub mod openid_service;
|
||||||
|
Loading…
Reference in New Issue
Block a user