Can export family data
This commit is contained in:
		@@ -1,6 +1,5 @@
 | 
			
		||||
import { Link } from "react-router-dom";
 | 
			
		||||
import { RouterLink } from "../widgets/RouterLink";
 | 
			
		||||
import { Button } from "@mui/material";
 | 
			
		||||
import { RouterLink } from "../widgets/RouterLink";
 | 
			
		||||
 | 
			
		||||
export function NotFoundRoute(): React.ReactElement {
 | 
			
		||||
  return (
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										131
									
								
								geneit_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										131
									
								
								geneit_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -70,7 +70,7 @@ dependencies = [
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "tokio-util",
 | 
			
		||||
 "tracing",
 | 
			
		||||
 "zstd",
 | 
			
		||||
 "zstd 0.12.3+zstd.1.5.2",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -262,6 +262,17 @@ version = "1.0.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "aes"
 | 
			
		||||
version = "0.8.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "cipher",
 | 
			
		||||
 "cpufeatures",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "ahash"
 | 
			
		||||
version = "0.7.6"
 | 
			
		||||
@@ -469,6 +480,12 @@ version = "0.21.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "base64ct"
 | 
			
		||||
version = "1.6.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bcrypt"
 | 
			
		||||
version = "0.15.0"
 | 
			
		||||
@@ -573,6 +590,27 @@ dependencies = [
 | 
			
		||||
 "bytes",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bzip2"
 | 
			
		||||
version = "0.4.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bzip2-sys",
 | 
			
		||||
 "libc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bzip2-sys"
 | 
			
		||||
version = "0.1.11+1.0.8"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cc",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "pkg-config",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "cc"
 | 
			
		||||
version = "1.0.79"
 | 
			
		||||
@@ -674,6 +712,12 @@ dependencies = [
 | 
			
		||||
 "memchr",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "constant_time_eq"
 | 
			
		||||
version = "0.1.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "convert_case"
 | 
			
		||||
version = "0.4.0"
 | 
			
		||||
@@ -1257,6 +1301,7 @@ dependencies = [
 | 
			
		||||
 "light-openid",
 | 
			
		||||
 "log",
 | 
			
		||||
 "mailchecker",
 | 
			
		||||
 "mime_guess",
 | 
			
		||||
 "rand",
 | 
			
		||||
 "redis",
 | 
			
		||||
 "rust-s3",
 | 
			
		||||
@@ -1267,6 +1312,7 @@ dependencies = [
 | 
			
		||||
 "sha2",
 | 
			
		||||
 "thiserror",
 | 
			
		||||
 "uuid",
 | 
			
		||||
 "zip",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -1779,6 +1825,16 @@ version = "0.3.17"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "mime_guess"
 | 
			
		||||
version = "2.0.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "mime",
 | 
			
		||||
 "unicase",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "minidom"
 | 
			
		||||
version = "0.15.2"
 | 
			
		||||
@@ -1991,12 +2047,35 @@ version = "1.0.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "password-hash"
 | 
			
		||||
version = "0.4.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64ct",
 | 
			
		||||
 "rand_core",
 | 
			
		||||
 "subtle",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "paste"
 | 
			
		||||
version = "1.0.13"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "pbkdf2"
 | 
			
		||||
version = "0.11.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "digest",
 | 
			
		||||
 "hmac",
 | 
			
		||||
 "password-hash",
 | 
			
		||||
 "sha2",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "percent-encoding"
 | 
			
		||||
version = "2.3.0"
 | 
			
		||||
@@ -2902,6 +2981,15 @@ version = "1.16.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "unicase"
 | 
			
		||||
version = "2.6.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "version_check",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "unicode-bidi"
 | 
			
		||||
version = "0.3.13"
 | 
			
		||||
@@ -3204,13 +3292,52 @@ version = "1.6.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "zip"
 | 
			
		||||
version = "0.6.6"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "aes",
 | 
			
		||||
 "byteorder",
 | 
			
		||||
 "bzip2",
 | 
			
		||||
 "constant_time_eq",
 | 
			
		||||
 "crc32fast",
 | 
			
		||||
 "crossbeam-utils",
 | 
			
		||||
 "flate2",
 | 
			
		||||
 "hmac",
 | 
			
		||||
 "pbkdf2",
 | 
			
		||||
 "sha1",
 | 
			
		||||
 "time",
 | 
			
		||||
 "zstd 0.11.2+zstd.1.5.2",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "zstd"
 | 
			
		||||
version = "0.11.2+zstd.1.5.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "zstd-safe 5.0.2+zstd.1.5.2",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "zstd"
 | 
			
		||||
version = "0.12.3+zstd.1.5.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "zstd-safe",
 | 
			
		||||
 "zstd-safe 6.0.5+zstd.1.5.4",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "zstd-safe"
 | 
			
		||||
version = "5.0.2+zstd.1.5.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "libc",
 | 
			
		||||
 "zstd-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
 
 | 
			
		||||
@@ -32,4 +32,6 @@ rust-s3 = "0.33.0"
 | 
			
		||||
sha2 = "0.10.7"
 | 
			
		||||
image = "0.24.6"
 | 
			
		||||
uuid = { version = "1.4.1", features = ["v4"] }
 | 
			
		||||
httpdate = "1.0.2"
 | 
			
		||||
httpdate = "1.0.2"
 | 
			
		||||
zip = "0.6.6"
 | 
			
		||||
mime_guess = "2.0.4"
 | 
			
		||||
							
								
								
									
										58
									
								
								geneit_backend/src/controllers/data_controller.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								geneit_backend/src/controllers/data_controller.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
use crate::connections::s3_connection;
 | 
			
		||||
use crate::controllers::HttpResult;
 | 
			
		||||
use crate::extractors::family_extractor::FamilyInPath;
 | 
			
		||||
use crate::services::{couples_service, members_service, photos_service};
 | 
			
		||||
use actix_web::HttpResponse;
 | 
			
		||||
use std::io::{Cursor, Write};
 | 
			
		||||
use zip::write::FileOptions;
 | 
			
		||||
use zip::CompressionMethod;
 | 
			
		||||
 | 
			
		||||
const MEMBERS_FILE: &str = "members.json";
 | 
			
		||||
const COUPLES_FILE: &str = "couples.json";
 | 
			
		||||
 | 
			
		||||
/// Export whole family data
 | 
			
		||||
pub async fn export_family(f: FamilyInPath) -> HttpResult {
 | 
			
		||||
    let files_opt = FileOptions::default().compression_method(CompressionMethod::Bzip2);
 | 
			
		||||
 | 
			
		||||
    let members = members_service::get_all_of_family(f.family_id()).await?;
 | 
			
		||||
    let couples = couples_service::get_all_of_family(f.family_id()).await?;
 | 
			
		||||
 | 
			
		||||
    let buff = Vec::with_capacity(1000000);
 | 
			
		||||
    let mut zip_file = zip::ZipWriter::new(Cursor::new(buff));
 | 
			
		||||
 | 
			
		||||
    // Add main files
 | 
			
		||||
    zip_file.start_file(MEMBERS_FILE, files_opt)?;
 | 
			
		||||
    zip_file.write_all(serde_json::to_string(&members)?.as_bytes())?;
 | 
			
		||||
 | 
			
		||||
    zip_file.start_file(COUPLES_FILE, files_opt)?;
 | 
			
		||||
    zip_file.write_all(serde_json::to_string(&couples)?.as_bytes())?;
 | 
			
		||||
 | 
			
		||||
    // Add photos
 | 
			
		||||
    let mut photos = Vec::new();
 | 
			
		||||
    for member in &members {
 | 
			
		||||
        if let Some(id) = member.photo_id() {
 | 
			
		||||
            photos.push(id);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for couple in &couples {
 | 
			
		||||
        if let Some(id) = couple.photo_id() {
 | 
			
		||||
            photos.push(id);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for id in photos {
 | 
			
		||||
        let photo = photos_service::get_by_id(id).await?;
 | 
			
		||||
        let ext = photo.mime_extension().unwrap_or("bad");
 | 
			
		||||
        let file = s3_connection::get_file(&photo.photo_path()).await?;
 | 
			
		||||
 | 
			
		||||
        zip_file.start_file(format!("photos/{}.{ext}", id.0), files_opt)?;
 | 
			
		||||
        zip_file.write_all(&file)?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let buff = zip_file.finish()?.into_inner();
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Ok()
 | 
			
		||||
        .content_type("application/zip")
 | 
			
		||||
        .body(buff))
 | 
			
		||||
}
 | 
			
		||||
@@ -3,9 +3,11 @@
 | 
			
		||||
use actix_web::body::BoxBody;
 | 
			
		||||
use actix_web::HttpResponse;
 | 
			
		||||
use std::fmt::{Debug, Display, Formatter};
 | 
			
		||||
use zip::result::ZipError;
 | 
			
		||||
 | 
			
		||||
pub mod auth_controller;
 | 
			
		||||
pub mod couples_controller;
 | 
			
		||||
pub mod data_controller;
 | 
			
		||||
pub mod families_controller;
 | 
			
		||||
pub mod members_controller;
 | 
			
		||||
pub mod photos_controller;
 | 
			
		||||
@@ -37,4 +39,22 @@ impl From<anyhow::Error> for HttpErr {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ZipError> for HttpErr {
 | 
			
		||||
    fn from(value: ZipError) -> Self {
 | 
			
		||||
        HttpErr { err: value.into() }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<serde_json::Error> for HttpErr {
 | 
			
		||||
    fn from(value: serde_json::Error) -> Self {
 | 
			
		||||
        HttpErr { err: value.into() }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<std::io::Error> for HttpErr {
 | 
			
		||||
    fn from(value: std::io::Error) -> Self {
 | 
			
		||||
        HttpErr { err: value.into() }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub type HttpResult = Result<HttpResponse, HttpErr>;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ use actix_web::{web, App, HttpServer};
 | 
			
		||||
use geneit_backend::app_config::AppConfig;
 | 
			
		||||
use geneit_backend::connections::s3_connection;
 | 
			
		||||
use geneit_backend::controllers::{
 | 
			
		||||
    auth_controller, couples_controller, families_controller, members_controller,
 | 
			
		||||
    auth_controller, couples_controller, data_controller, families_controller, members_controller,
 | 
			
		||||
    photos_controller, server_controller, users_controller,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -191,6 +191,11 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
                "/family/{id}/couple/{couple_id}/photo",
 | 
			
		||||
                web::delete().to(couples_controller::remove_photo),
 | 
			
		||||
            )
 | 
			
		||||
            // Data controller
 | 
			
		||||
            .route(
 | 
			
		||||
                "/family/{id}/data/export",
 | 
			
		||||
                web::get().to(data_controller::export_family),
 | 
			
		||||
            )
 | 
			
		||||
            // Photos controller
 | 
			
		||||
            .route(
 | 
			
		||||
                "/photo/{id}",
 | 
			
		||||
 
 | 
			
		||||
@@ -168,6 +168,13 @@ impl Photo {
 | 
			
		||||
    pub fn thumbnail_path(&self) -> String {
 | 
			
		||||
        format!("thumbnail/{}", self.file_id)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn mime_extension(&self) -> Option<&str> {
 | 
			
		||||
        mime_guess::get_mime_extensions_str(&self.mime_type)
 | 
			
		||||
            .map(|e| e.first())
 | 
			
		||||
            .unwrap_or_default()
 | 
			
		||||
            .copied()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Insertable)]
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user