Can export family data
This commit is contained in:
parent
680c2d2624
commit
3b5efb46cd
@ -1,6 +1,5 @@
|
|||||||
import { Link } from "react-router-dom";
|
|
||||||
import { RouterLink } from "../widgets/RouterLink";
|
|
||||||
import { Button } from "@mui/material";
|
import { Button } from "@mui/material";
|
||||||
|
import { RouterLink } from "../widgets/RouterLink";
|
||||||
|
|
||||||
export function NotFoundRoute(): React.ReactElement {
|
export function NotFoundRoute(): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
|
131
geneit_backend/Cargo.lock
generated
131
geneit_backend/Cargo.lock
generated
@ -70,7 +70,7 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
"zstd",
|
"zstd 0.12.3+zstd.1.5.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -262,6 +262,17 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
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]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.7.6"
|
version = "0.7.6"
|
||||||
@ -469,6 +480,12 @@ version = "0.21.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
|
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64ct"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bcrypt"
|
name = "bcrypt"
|
||||||
version = "0.15.0"
|
version = "0.15.0"
|
||||||
@ -573,6 +590,27 @@ dependencies = [
|
|||||||
"bytes",
|
"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]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.79"
|
version = "1.0.79"
|
||||||
@ -674,6 +712,12 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "constant_time_eq"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@ -1257,6 +1301,7 @@ dependencies = [
|
|||||||
"light-openid",
|
"light-openid",
|
||||||
"log",
|
"log",
|
||||||
"mailchecker",
|
"mailchecker",
|
||||||
|
"mime_guess",
|
||||||
"rand",
|
"rand",
|
||||||
"redis",
|
"redis",
|
||||||
"rust-s3",
|
"rust-s3",
|
||||||
@ -1267,6 +1312,7 @@ dependencies = [
|
|||||||
"sha2",
|
"sha2",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
"zip",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1779,6 +1825,16 @@ version = "0.3.17"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
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]]
|
[[package]]
|
||||||
name = "minidom"
|
name = "minidom"
|
||||||
version = "0.15.2"
|
version = "0.15.2"
|
||||||
@ -1991,12 +2047,35 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae"
|
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]]
|
[[package]]
|
||||||
name = "paste"
|
name = "paste"
|
||||||
version = "1.0.13"
|
version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35"
|
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]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
@ -2902,6 +2981,15 @@ version = "1.16.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
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]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.13"
|
version = "0.3.13"
|
||||||
@ -3204,13 +3292,52 @@ version = "1.6.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
|
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]]
|
[[package]]
|
||||||
name = "zstd"
|
name = "zstd"
|
||||||
version = "0.12.3+zstd.1.5.2"
|
version = "0.12.3+zstd.1.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806"
|
checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
|
@ -33,3 +33,5 @@ sha2 = "0.10.7"
|
|||||||
image = "0.24.6"
|
image = "0.24.6"
|
||||||
uuid = { version = "1.4.1", features = ["v4"] }
|
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::body::BoxBody;
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
|
use zip::result::ZipError;
|
||||||
|
|
||||||
pub mod auth_controller;
|
pub mod auth_controller;
|
||||||
pub mod couples_controller;
|
pub mod couples_controller;
|
||||||
|
pub mod data_controller;
|
||||||
pub mod families_controller;
|
pub mod families_controller;
|
||||||
pub mod members_controller;
|
pub mod members_controller;
|
||||||
pub mod photos_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>;
|
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::app_config::AppConfig;
|
||||||
use geneit_backend::connections::s3_connection;
|
use geneit_backend::connections::s3_connection;
|
||||||
use geneit_backend::controllers::{
|
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,
|
photos_controller, server_controller, users_controller,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -191,6 +191,11 @@ async fn main() -> std::io::Result<()> {
|
|||||||
"/family/{id}/couple/{couple_id}/photo",
|
"/family/{id}/couple/{couple_id}/photo",
|
||||||
web::delete().to(couples_controller::remove_photo),
|
web::delete().to(couples_controller::remove_photo),
|
||||||
)
|
)
|
||||||
|
// Data controller
|
||||||
|
.route(
|
||||||
|
"/family/{id}/data/export",
|
||||||
|
web::get().to(data_controller::export_family),
|
||||||
|
)
|
||||||
// Photos controller
|
// Photos controller
|
||||||
.route(
|
.route(
|
||||||
"/photo/{id}",
|
"/photo/{id}",
|
||||||
|
@ -168,6 +168,13 @@ impl Photo {
|
|||||||
pub fn thumbnail_path(&self) -> String {
|
pub fn thumbnail_path(&self) -> String {
|
||||||
format!("thumbnail/{}", self.file_id)
|
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)]
|
#[derive(Insertable)]
|
||||||
|
Loading…
Reference in New Issue
Block a user