Ready to implement photos management
This commit is contained in:
		
							
								
								
									
										97
									
								
								geneit_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										97
									
								
								geneit_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -83,6 +83,44 @@ dependencies = [
 | 
			
		||||
 "syn 1.0.109",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "actix-multipart"
 | 
			
		||||
version = "0.6.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "dee489e3c01eae4d1c35b03c4493f71cb40d93f66b14558feb1b1a807671cc4e"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "actix-multipart-derive",
 | 
			
		||||
 "actix-utils",
 | 
			
		||||
 "actix-web",
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "derive_more",
 | 
			
		||||
 "futures-core",
 | 
			
		||||
 "futures-util",
 | 
			
		||||
 "httparse",
 | 
			
		||||
 "local-waker",
 | 
			
		||||
 "log",
 | 
			
		||||
 "memchr",
 | 
			
		||||
 "mime",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "serde_plain",
 | 
			
		||||
 "tempfile",
 | 
			
		||||
 "tokio",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "actix-multipart-derive"
 | 
			
		||||
version = "0.6.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "2ec592f234db8a253cf80531246a4407c8a70530423eea80688a6c5a44a110e7"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "darling 0.14.4",
 | 
			
		||||
 "parse-size",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 1.0.109",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "actix-remote-ip"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
@@ -700,14 +738,38 @@ dependencies = [
 | 
			
		||||
 "memchr",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "darling"
 | 
			
		||||
version = "0.14.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "darling_core 0.14.4",
 | 
			
		||||
 "darling_macro 0.14.4",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "darling"
 | 
			
		||||
version = "0.20.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "darling_core",
 | 
			
		||||
 "darling_macro",
 | 
			
		||||
 "darling_core 0.20.3",
 | 
			
		||||
 "darling_macro 0.20.3",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "darling_core"
 | 
			
		||||
version = "0.14.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "fnv",
 | 
			
		||||
 "ident_case",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "strsim",
 | 
			
		||||
 "syn 1.0.109",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -724,13 +786,24 @@ dependencies = [
 | 
			
		||||
 "syn 2.0.23",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "darling_macro"
 | 
			
		||||
version = "0.14.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "darling_core 0.14.4",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 1.0.109",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "darling_macro"
 | 
			
		||||
version = "0.20.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "darling_core",
 | 
			
		||||
 "darling_core 0.20.3",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.23",
 | 
			
		||||
]
 | 
			
		||||
@@ -1057,6 +1130,7 @@ name = "geneit_backend"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "actix-cors",
 | 
			
		||||
 "actix-multipart",
 | 
			
		||||
 "actix-remote-ip",
 | 
			
		||||
 "actix-web",
 | 
			
		||||
 "anyhow",
 | 
			
		||||
@@ -1701,6 +1775,12 @@ dependencies = [
 | 
			
		||||
 "windows-targets",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "parse-size"
 | 
			
		||||
version = "1.0.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "paste"
 | 
			
		||||
version = "1.0.13"
 | 
			
		||||
@@ -2166,6 +2246,15 @@ dependencies = [
 | 
			
		||||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_plain"
 | 
			
		||||
version = "1.0.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "d6018081315db179d0ce57b1fe4b62a12a0028c9cf9bbef868c9cf477b3c34ae"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_urlencoded"
 | 
			
		||||
version = "0.7.1"
 | 
			
		||||
@@ -2200,7 +2289,7 @@ version = "3.1.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ea3cee93715c2e266b9338b7544da68a9f24e227722ba482bd1c024367c77c65"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "darling",
 | 
			
		||||
 "darling 0.20.3",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.23",
 | 
			
		||||
 
 | 
			
		||||
@@ -13,11 +13,12 @@ lazy_static = "1.4.0"
 | 
			
		||||
anyhow = "1.0.71"
 | 
			
		||||
actix-web = "4.3.1"
 | 
			
		||||
actix-cors = "0.6.4"
 | 
			
		||||
actix-multipart = "0.6.0"
 | 
			
		||||
actix-remote-ip = "0.1.0"
 | 
			
		||||
futures-util = "0.3.28"
 | 
			
		||||
diesel = { version = "2.0.4", features = ["postgres"] }
 | 
			
		||||
serde = { version = "1.0.163", features = ["derive"] }
 | 
			
		||||
serde_json = "1.0.96"
 | 
			
		||||
actix-remote-ip = "0.1.0"
 | 
			
		||||
mailchecker = "5.0.9"
 | 
			
		||||
redis = "0.23.0"
 | 
			
		||||
lettre = "0.10.4"
 | 
			
		||||
@@ -27,4 +28,4 @@ light-openid = "1.0.1"
 | 
			
		||||
thiserror = "1.0.40"
 | 
			
		||||
serde_with = "3.1.0"
 | 
			
		||||
rust_iso3166 = "0.1.10"
 | 
			
		||||
rust-s3 = "0.33.0"
 | 
			
		||||
rust-s3 = "0.33.0"
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
DROP view if EXISTS families_memberships ;
 | 
			
		||||
DROP table IF EXISTS couples;
 | 
			
		||||
DROP table IF EXISTS members;
 | 
			
		||||
DROP table IF EXISTS photos;
 | 
			
		||||
DROP table IF EXISTS memberships ;
 | 
			
		||||
DROP table IF EXISTS families;
 | 
			
		||||
DROP table IF EXISTS users;
 | 
			
		||||
@@ -30,13 +30,22 @@ CREATE TABLE memberships (
 | 
			
		||||
    PRIMARY KEY(user_id, family_id)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE photos (
 | 
			
		||||
    id SERIAL PRIMARY KEY,
 | 
			
		||||
    time_create VARCHAR(130) NOT NULL,
 | 
			
		||||
    mime_type VARCHAR(150) NOT NULL,
 | 
			
		||||
    sha512 VARCHAR(130) NOT NULL,
 | 
			
		||||
    file_size INTEGER NOT NULL,
 | 
			
		||||
    thumb_sha512 VARCHAR(130) NOT NULL
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE members (
 | 
			
		||||
    id SERIAL PRIMARY KEY,
 | 
			
		||||
    family_id integer NOT NULL REFERENCES families,
 | 
			
		||||
    first_name VARCHAR(30) NULL,
 | 
			
		||||
    last_name VARCHAR(30) NULL,
 | 
			
		||||
    birth_last_name VARCHAR(30) NULL,
 | 
			
		||||
    photo_id VARCHAR(255) NULL,
 | 
			
		||||
    photo_id INTEGER NULL REFERENCES photos ON DELETE SET NULL,
 | 
			
		||||
    email VARCHAR(255) NULL,
 | 
			
		||||
    phone VARCHAR(30) NULL,
 | 
			
		||||
    address VARCHAR (155) NULL,
 | 
			
		||||
@@ -60,7 +69,7 @@ CREATE TABLE members (
 | 
			
		||||
CREATE TABLE couples (
 | 
			
		||||
    wife integer NOT NULL REFERENCES members,
 | 
			
		||||
    husband integer NOT NULL REFERENCES members,
 | 
			
		||||
    photo_id VARCHAR(255) NULL,
 | 
			
		||||
    photo_id INTEGER NULL REFERENCES photos ON DELETE SET NULL,
 | 
			
		||||
    wedding_year smallint NULL,
 | 
			
		||||
    wedding_month smallint NULL,
 | 
			
		||||
    wedding_day smallint NULL,
 | 
			
		||||
 
 | 
			
		||||
@@ -141,6 +141,10 @@ pub struct AppConfig {
 | 
			
		||||
    /// S3 skip auto create bucket if not existing
 | 
			
		||||
    #[arg(long, env)]
 | 
			
		||||
    pub s3_skip_auto_create_bucket: bool,
 | 
			
		||||
 | 
			
		||||
    /// Directory where temporary files are stored
 | 
			
		||||
    #[arg(long, env, default_value = "/tmp")]
 | 
			
		||||
    pub temp_dir: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
lazy_static::lazy_static! {
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,13 @@ impl NumberValueConstraint {
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, serde::Serialize)]
 | 
			
		||||
pub struct StaticConstraints {
 | 
			
		||||
    pub date_year: NumberValueConstraint,
 | 
			
		||||
    pub date_month: NumberValueConstraint,
 | 
			
		||||
    pub date_day: NumberValueConstraint,
 | 
			
		||||
 | 
			
		||||
    pub photo_allowed_types: &'static [&'static str],
 | 
			
		||||
    pub photo_max_size: usize,
 | 
			
		||||
 | 
			
		||||
    pub mail_len: SizeConstraint,
 | 
			
		||||
    pub user_name_len: SizeConstraint,
 | 
			
		||||
    pub password_len: SizeConstraint,
 | 
			
		||||
@@ -53,15 +60,18 @@ pub struct StaticConstraints {
 | 
			
		||||
    pub member_country: SizeConstraint,
 | 
			
		||||
    pub member_sex: SizeConstraint,
 | 
			
		||||
    pub member_note: SizeConstraint,
 | 
			
		||||
 | 
			
		||||
    pub date_year: NumberValueConstraint,
 | 
			
		||||
    pub date_month: NumberValueConstraint,
 | 
			
		||||
    pub date_day: NumberValueConstraint,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for StaticConstraints {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            date_year: NumberValueConstraint::new(1, 2050),
 | 
			
		||||
            date_month: NumberValueConstraint::new(1, 12),
 | 
			
		||||
            date_day: NumberValueConstraint::new(1, 31),
 | 
			
		||||
 | 
			
		||||
            photo_allowed_types: &ALLOWED_PHOTOS_MIMETYPES,
 | 
			
		||||
            photo_max_size: PHOTOS_MAX_SIZE,
 | 
			
		||||
 | 
			
		||||
            mail_len: SizeConstraint::new(5, 255),
 | 
			
		||||
            user_name_len: SizeConstraint::new(3, 30),
 | 
			
		||||
            password_len: SizeConstraint::new(8, 255),
 | 
			
		||||
@@ -81,9 +91,6 @@ impl Default for StaticConstraints {
 | 
			
		||||
            member_country: SizeConstraint::new(0, 2),
 | 
			
		||||
            member_sex: SizeConstraint::new(0, 1),
 | 
			
		||||
            member_note: SizeConstraint::new(0, 35000),
 | 
			
		||||
            date_year: NumberValueConstraint::new(1, 2050),
 | 
			
		||||
            date_month: NumberValueConstraint::new(1, 12),
 | 
			
		||||
            date_day: NumberValueConstraint::new(1, 31),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -108,3 +115,16 @@ pub const AUTH_TOKEN_MAX_INACTIVITY: Duration = Duration::from_secs(3600);
 | 
			
		||||
 | 
			
		||||
/// Length of family invitation code
 | 
			
		||||
pub const FAMILY_INVITATION_CODE_LEN: usize = 7;
 | 
			
		||||
 | 
			
		||||
/// Allowed photos mimetypes
 | 
			
		||||
pub const ALLOWED_PHOTOS_MIMETYPES: [&str; 6] = [
 | 
			
		||||
    "image/jpeg",
 | 
			
		||||
    "image/png",
 | 
			
		||||
    "image/gif",
 | 
			
		||||
    "image/bmp",
 | 
			
		||||
    "image/webp",
 | 
			
		||||
    "image/vnd.microsoft.icon",
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
/// Uploaded photos max size
 | 
			
		||||
pub const PHOTOS_MAX_SIZE: usize = 10 * 1000 * 1000;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,8 @@ use crate::extractors::member_extractor::FamilyAndMemberInPath;
 | 
			
		||||
use crate::models::{Member, MemberID, Sex};
 | 
			
		||||
use crate::services::members_service;
 | 
			
		||||
use crate::utils::countries_utils;
 | 
			
		||||
use actix_multipart::form::tempfile::TempFile;
 | 
			
		||||
use actix_multipart::form::MultipartForm;
 | 
			
		||||
use actix_web::{web, HttpResponse};
 | 
			
		||||
 | 
			
		||||
serde_with::with_prefix!(prefix_birth "birth_");
 | 
			
		||||
@@ -292,3 +294,17 @@ pub async fn delete(m: FamilyAndMemberInPath) -> HttpResult {
 | 
			
		||||
    members_service::delete(&m).await?;
 | 
			
		||||
    Ok(HttpResponse::Ok().finish())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, MultipartForm)]
 | 
			
		||||
pub struct UploadPhotoForm {
 | 
			
		||||
    #[multipart(rename = "photo")]
 | 
			
		||||
    photo: TempFile,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Upload a new photo for a user
 | 
			
		||||
pub async fn set_photo(
 | 
			
		||||
    _m: FamilyAndMemberInPath,
 | 
			
		||||
    MultipartForm(_form): MultipartForm<UploadPhotoForm>,
 | 
			
		||||
) -> HttpResult {
 | 
			
		||||
    todo!()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
use actix_cors::Cors;
 | 
			
		||||
use actix_multipart::form::tempfile::TempFileConfig;
 | 
			
		||||
use actix_remote_ip::RemoteIPConfig;
 | 
			
		||||
use actix_web::middleware::Logger;
 | 
			
		||||
use actix_web::{web, App, HttpServer};
 | 
			
		||||
@@ -35,6 +36,8 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
            .app_data(web::Data::new(RemoteIPConfig {
 | 
			
		||||
                proxy: AppConfig::get().proxy_ip.clone(),
 | 
			
		||||
            }))
 | 
			
		||||
            // Uploaded files
 | 
			
		||||
            .app_data(TempFileConfig::default().directory(&AppConfig::get().temp_dir))
 | 
			
		||||
            // Config controller
 | 
			
		||||
            .route("/", web::get().to(server_controller::home))
 | 
			
		||||
            .route(
 | 
			
		||||
@@ -150,6 +153,10 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
                "/family/{id}/member/{member_id}",
 | 
			
		||||
                web::delete().to(members_controller::delete),
 | 
			
		||||
            )
 | 
			
		||||
            .route(
 | 
			
		||||
                "/family/{id}/member/{member_id}/photo",
 | 
			
		||||
                web::put().to(members_controller::set_photo),
 | 
			
		||||
            )
 | 
			
		||||
    })
 | 
			
		||||
    .bind(AppConfig::get().listen_address.as_str())?
 | 
			
		||||
    .run()
 | 
			
		||||
 
 | 
			
		||||
@@ -117,6 +117,10 @@ pub struct FamilyMembership {
 | 
			
		||||
    pub count_admins: i64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Photo ID holder
 | 
			
		||||
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
 | 
			
		||||
pub struct PhotoID(pub i32);
 | 
			
		||||
 | 
			
		||||
/// Member ID holder
 | 
			
		||||
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
 | 
			
		||||
pub struct MemberID(pub i32);
 | 
			
		||||
@@ -153,7 +157,7 @@ pub struct Member {
 | 
			
		||||
    pub first_name: Option<String>,
 | 
			
		||||
    pub last_name: Option<String>,
 | 
			
		||||
    pub birth_last_name: Option<String>,
 | 
			
		||||
    pub photo_id: Option<String>,
 | 
			
		||||
    photo_id: Option<i32>,
 | 
			
		||||
    pub email: Option<String>,
 | 
			
		||||
    pub phone: Option<String>,
 | 
			
		||||
    pub address: Option<String>,
 | 
			
		||||
@@ -183,6 +187,10 @@ impl Member {
 | 
			
		||||
        FamilyID(self.family_id)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn photo_id(&self) -> Option<PhotoID> {
 | 
			
		||||
        self.photo_id.map(PhotoID)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn sex(&self) -> Option<Sex> {
 | 
			
		||||
        self.sex.as_deref().map(Sex::parse_str).unwrap_or_default()
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ diesel::table! {
 | 
			
		||||
    couples (wife, husband) {
 | 
			
		||||
        wife -> Int4,
 | 
			
		||||
        husband -> Int4,
 | 
			
		||||
        photo_id -> Nullable<Varchar>,
 | 
			
		||||
        photo_id -> Nullable<Int4>,
 | 
			
		||||
        wedding_year -> Nullable<Int2>,
 | 
			
		||||
        wedding_month -> Nullable<Int2>,
 | 
			
		||||
        wedding_day -> Nullable<Int2>,
 | 
			
		||||
@@ -30,7 +30,7 @@ diesel::table! {
 | 
			
		||||
        first_name -> Nullable<Varchar>,
 | 
			
		||||
        last_name -> Nullable<Varchar>,
 | 
			
		||||
        birth_last_name -> Nullable<Varchar>,
 | 
			
		||||
        photo_id -> Nullable<Varchar>,
 | 
			
		||||
        photo_id -> Nullable<Int4>,
 | 
			
		||||
        email -> Nullable<Varchar>,
 | 
			
		||||
        phone -> Nullable<Varchar>,
 | 
			
		||||
        address -> Nullable<Varchar>,
 | 
			
		||||
@@ -61,6 +61,17 @@ diesel::table! {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
diesel::table! {
 | 
			
		||||
    photos (id) {
 | 
			
		||||
        id -> Int4,
 | 
			
		||||
        time_create -> Varchar,
 | 
			
		||||
        mime_type -> Varchar,
 | 
			
		||||
        sha512 -> Varchar,
 | 
			
		||||
        file_size -> Int4,
 | 
			
		||||
        thumb_sha512 -> Varchar,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
diesel::table! {
 | 
			
		||||
    users (id) {
 | 
			
		||||
        id -> Int4,
 | 
			
		||||
@@ -78,8 +89,17 @@ diesel::table! {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
diesel::joinable!(couples -> photos (photo_id));
 | 
			
		||||
diesel::joinable!(members -> families (family_id));
 | 
			
		||||
diesel::joinable!(members -> photos (photo_id));
 | 
			
		||||
diesel::joinable!(memberships -> families (family_id));
 | 
			
		||||
diesel::joinable!(memberships -> users (user_id));
 | 
			
		||||
 | 
			
		||||
diesel::allow_tables_to_appear_in_same_query!(couples, families, members, memberships, users,);
 | 
			
		||||
diesel::allow_tables_to_appear_in_same_query!(
 | 
			
		||||
    couples,
 | 
			
		||||
    families,
 | 
			
		||||
    members,
 | 
			
		||||
    memberships,
 | 
			
		||||
    photos,
 | 
			
		||||
    users,
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ pub async fn update(member: &mut Member) -> anyhow::Result<()> {
 | 
			
		||||
                members::dsl::first_name.eq(member.first_name.clone()),
 | 
			
		||||
                members::dsl::last_name.eq(member.last_name.clone()),
 | 
			
		||||
                members::dsl::birth_last_name.eq(member.birth_last_name.clone()),
 | 
			
		||||
                members::dsl::photo_id.eq(member.photo_id.clone()),
 | 
			
		||||
                members::dsl::photo_id.eq(member.photo_id().map(|p| p.0)),
 | 
			
		||||
                members::dsl::email.eq(member.email.clone()),
 | 
			
		||||
                members::dsl::phone.eq(member.phone.clone()),
 | 
			
		||||
                members::dsl::address.eq(member.address.clone()),
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user