reinhardt_admin/server/
import.rs1#[cfg(server)]
6use super::admin_auth::AdminAuthenticatedUser;
7use crate::adapters::{AdminDatabase, AdminRecord, AdminSite, ImportFormat, ImportResponse};
8#[cfg(server)]
9use crate::core::{AdminDatabaseKey, AdminSiteKey};
10#[cfg(server)]
11use reinhardt_di::Depends;
12#[cfg(server)]
13use reinhardt_pages::server_fn::ServerFnRequest;
14use reinhardt_pages::server_fn::{ServerFnError, server_fn};
15#[cfg(server)]
16use std::collections::HashMap;
17
18#[cfg(server)]
19use super::error::{AdminAuth, MapServerFnError, ModelPermission};
20#[cfg(server)]
21use super::limits::{MAX_IMPORT_FILE_SIZE, MAX_IMPORT_RECORDS};
22
23#[server_fn]
53pub async fn import_data(
54 model_name: String,
55 format: crate::adapters::ImportFormat,
56 data: Vec<u8>,
57 #[inject] site: Depends<AdminSiteKey, AdminSite>,
58 #[inject] db: Depends<AdminDatabaseKey, AdminDatabase>,
59 #[inject] http_request: ServerFnRequest,
60 #[inject] AdminAuthenticatedUser(user): AdminAuthenticatedUser,
61) -> Result<crate::adapters::ImportResponse, ServerFnError> {
62 let auth = AdminAuth::from_request(&http_request);
64 let model_admin = site.get_model_admin(&model_name).map_server_fn_error()?;
65 auth.require_model_permission(model_admin.as_ref(), user.as_ref(), ModelPermission::Add)
66 .await?;
67
68 if data.len() > MAX_IMPORT_FILE_SIZE {
70 return Err(ServerFnError::application(format!(
71 "Import file size ({} bytes) exceeds maximum allowed size ({} bytes)",
72 data.len(),
73 MAX_IMPORT_FILE_SIZE
74 )));
75 }
76
77 let table_name = model_admin.table_name();
78 let pk_field = model_admin.pk_field();
79
80 let records: Vec<HashMap<String, serde_json::Value>> = match format {
83 ImportFormat::JSON => serde_json::from_slice(&data)
84 .map_err(|_| ServerFnError::deserialization("Invalid JSON format in import data"))?,
85 ImportFormat::CSV => {
86 let mut rdr = csv::Reader::from_reader(&data[..]);
87 rdr.deserialize()
88 .collect::<Result<Vec<_>, _>>()
89 .map_err(|_| ServerFnError::deserialization("Invalid CSV format in import data"))?
90 }
91 ImportFormat::TSV => {
92 let mut rdr = csv::ReaderBuilder::new()
93 .delimiter(b'\t')
94 .from_reader(&data[..]);
95 rdr.deserialize()
96 .collect::<Result<Vec<_>, _>>()
97 .map_err(|_| ServerFnError::deserialization("Invalid TSV format in import data"))?
98 }
99 };
100
101 if records.len() > MAX_IMPORT_RECORDS {
103 return Err(ServerFnError::application(format!(
104 "Import record count ({}) exceeds maximum allowed count ({})",
105 records.len(),
106 MAX_IMPORT_RECORDS
107 )));
108 }
109
110 let mut imported = 0;
112 let mut failed = 0;
113 let mut errors = Vec::new();
114
115 for (index, record) in records.into_iter().enumerate() {
116 match db
117 .create::<AdminRecord>(table_name, Some(pk_field), record)
118 .await
119 {
120 Ok(_) => imported += 1,
121 Err(_) => {
122 failed += 1;
125 errors.push(format!("Record {}: import failed", index + 1));
126 }
127 }
128 }
129
130 Ok(ImportResponse {
131 success: failed == 0,
132 imported,
133 updated: 0, skipped: 0,
135 failed,
136 message: if failed == 0 {
137 format!("Successfully imported {} {} records", imported, model_name)
138 } else {
139 format!(
140 "Imported {} {} records, {} failed",
141 imported, model_name, failed
142 )
143 },
144 errors: if errors.is_empty() {
145 None
146 } else {
147 Some(errors)
148 },
149 })
150}