chore: remove unnecessary attachement urls

This commit is contained in:
qaz741wsd856 2025-12-09 03:38:29 +00:00
parent a9ed226313
commit eee4cc90ef
4 changed files with 31 additions and 75 deletions

View file

@ -1,15 +1,17 @@
use std::{collections::HashMap, sync::Arc};
use axum::{body::Bytes, extract::{Multipart, Path, State}, Extension, Json};
use axum::{
body::Bytes,
extract::{Multipart, Path, State},
Extension, Json,
};
use chrono::Utc;
use jsonwebtoken::{encode, EncodingKey, Header};
use log;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use uuid::Uuid;
use worker::{
query, wasm_bindgen::JsValue, Bucket, D1Database, Env, HttpMetadata,
};
use worker::{query, wasm_bindgen::JsValue, Bucket, D1Database, Env, HttpMetadata};
use crate::{
auth::Claims,
@ -161,7 +163,7 @@ pub async fn create_attachment_v2(
// Return upload URL pointing to local upload endpoint
let url = upload_url(&env, &base_url, &cipher_id, &attachment_id, &claims.sub)?;
let mut cipher_response: Cipher = cipher.into();
hydrate_cipher_attachments(&db, &env, &base_url, &mut cipher_response, &claims.sub).await?;
hydrate_cipher_attachments(&db, &env, &mut cipher_response).await?;
touch_cipher_updated_at(&db, &cipher_id).await?;
db::touch_user_updated_at(&db, &claims.sub).await?;
@ -256,7 +258,6 @@ pub async fn upload_attachment_v2_data(
pub async fn upload_attachment_legacy(
claims: Claims,
State(env): State<Arc<Env>>,
Extension(BaseUrl(base_url)): Extension<BaseUrl>,
Path(cipher_id): Path<String>,
mut multipart: Multipart,
) -> Result<Json<Cipher>, AppError> {
@ -313,7 +314,7 @@ pub async fn upload_attachment_legacy(
// 返回最新的 Cipher含附件
let mut cipher_response: Cipher = cipher.into();
hydrate_cipher_attachments(&db, &env, &base_url, &mut cipher_response, &claims.sub).await?;
hydrate_cipher_attachments(&db, &env, &mut cipher_response).await?;
Ok(Json(cipher_response))
}
@ -339,7 +340,7 @@ pub async fn get_attachment(
}
let url = download_url(&env, &base_url, &cipher_id, &attachment_id, &claims.sub)?;
Ok(Json(attachment.to_response(url)))
Ok(Json(attachment.to_response(Some(url))))
}
/// DELETE /api/ciphers/{cipher_id}/attachment/{attachment_id}
@ -347,7 +348,6 @@ pub async fn get_attachment(
pub async fn delete_attachment(
claims: Claims,
State(env): State<Arc<Env>>,
Extension(BaseUrl(base_url)): Extension<BaseUrl>,
Path((cipher_id, attachment_id)): Path<(String, String)>,
) -> Result<Json<AttachmentDeleteResponse>, AppError> {
let bucket = require_bucket(&env)?;
@ -377,7 +377,7 @@ pub async fn delete_attachment(
let mut cipher_response: Cipher = ensure_cipher_for_user(&db, &cipher_id, &claims.sub)
.await?
.into();
hydrate_cipher_attachments(&db, &env, &base_url, &mut cipher_response, &claims.sub).await?;
hydrate_cipher_attachments(&db, &env, &mut cipher_response).await?;
Ok(Json(AttachmentDeleteResponse {
cipher: cipher_response,
@ -390,33 +390,23 @@ pub async fn delete_attachment(
pub async fn delete_attachment_post(
claims: Claims,
State(env): State<Arc<Env>>,
Extension(BaseUrl(base_url)): Extension<BaseUrl>,
Path((cipher_id, attachment_id)): Path<(String, String)>,
) -> Result<Json<AttachmentDeleteResponse>, AppError> {
delete_attachment(
claims,
State(env),
Extension(BaseUrl(base_url)),
Path((cipher_id, attachment_id)),
)
.await
delete_attachment(claims, State(env), Path((cipher_id, attachment_id))).await
}
/// Attach attachment information to Cipher (used by other handlers)
pub async fn hydrate_cipher_attachments(
db: &D1Database,
env: &Env,
base_url: &str,
cipher: &mut Cipher,
user_id: &str,
) -> Result<(), AppError> {
if !attachments_enabled(env) {
cipher.attachments = None;
return Ok(());
}
let mut map = load_attachment_map(db, env, base_url, &[cipher.id.clone()], user_id).await?;
let mut map = load_attachment_map(db, &[cipher.id.clone()]).await?;
if let Some(list) = map.remove(&cipher.id) {
if !list.is_empty() {
cipher.attachments = Some(list);
@ -429,9 +419,7 @@ pub async fn hydrate_cipher_attachments(
pub async fn hydrate_ciphers_attachments(
db: &D1Database,
env: &Env,
base_url: &str,
ciphers: &mut [Cipher],
user_id: &str,
) -> Result<(), AppError> {
if !attachments_enabled(env) {
for cipher in ciphers.iter_mut() {
@ -441,7 +429,7 @@ pub async fn hydrate_ciphers_attachments(
}
let ids: Vec<String> = ciphers.iter().map(|c| c.id.clone()).collect();
let mut map = load_attachment_map(db, env, base_url, &ids, user_id).await?;
let mut map = load_attachment_map(db, &ids).await?;
for cipher in ciphers.iter_mut() {
if let Some(list) = map.remove(&cipher.id) {
@ -612,10 +600,7 @@ async fn fetch_attachment(db: &D1Database, attachment_id: &str) -> Result<Attach
async fn load_attachment_map(
db: &D1Database,
env: &Env,
base_url: &str,
cipher_ids: &[String],
user_id: &str,
cipher_ids: &[String]
) -> Result<HashMap<String, Vec<AttachmentResponse>>, AppError> {
if cipher_ids.is_empty() {
return Ok(HashMap::new());
@ -635,16 +620,10 @@ async fn load_attachment_map(
let mut map: HashMap<String, Vec<AttachmentResponse>> = HashMap::new();
for attachment in attachments {
let url = download_url(
env,
base_url,
&attachment.cipher_id,
&attachment.id,
user_id,
)?;
map.entry(attachment.cipher_id.clone())
.or_default()
.push(attachment.to_response(url));
// URLs are minted on-demand via the download endpoint; skip pre-signing here.
.push(attachment.to_response(None));
}
Ok(map)

View file

@ -38,7 +38,6 @@ async fn fetch_cipher_for_user(
pub async fn create_cipher(
claims: Claims,
State(env): State<Arc<Env>>,
Extension(BaseUrl(base_url)): Extension<BaseUrl>,
Json(payload): Json<CreateCipherRequest>,
) -> Result<Json<Cipher>, AppError> {
let db = db::get_db(&env)?;
@ -97,7 +96,7 @@ pub async fn create_cipher(
.run()
.await?;
attachments::hydrate_cipher_attachments(&db, env.as_ref(), &base_url, &mut cipher, &claims.sub)
attachments::hydrate_cipher_attachments(&db, env.as_ref(), &mut cipher)
.await?;
db::touch_user_updated_at(&db, &claims.sub).await?;
@ -108,7 +107,7 @@ pub async fn create_cipher(
pub async fn update_cipher(
claims: Claims,
State(env): State<Arc<Env>>,
Extension(BaseUrl(base_url)): Extension<BaseUrl>,
Extension(BaseUrl(_base_url)): Extension<BaseUrl>,
Path(id): Path<String>,
Json(payload): Json<CipherRequestData>,
) -> Result<Json<Cipher>, AppError> {
@ -210,7 +209,7 @@ pub async fn update_cipher(
.run()
.await?;
attachments::hydrate_cipher_attachments(&db, env.as_ref(), &base_url, &mut cipher, &claims.sub)
attachments::hydrate_cipher_attachments(&db, env.as_ref(), &mut cipher)
.await?;
db::touch_user_updated_at(&db, &claims.sub).await?;
@ -222,7 +221,6 @@ pub async fn update_cipher(
pub async fn list_ciphers(
claims: Claims,
State(env): State<Arc<Env>>,
Extension(BaseUrl(base_url)): Extension<BaseUrl>,
) -> Result<Json<CipherListResponse>, AppError> {
let db = db::get_db(&env)?;
@ -239,14 +237,7 @@ pub async fn list_ciphers(
let mut ciphers: Vec<Cipher> = ciphers_db.into_iter().map(|c| c.into()).collect();
attachments::hydrate_ciphers_attachments(
&db,
env.as_ref(),
&base_url,
&mut ciphers,
&claims.sub,
)
.await?;
attachments::hydrate_ciphers_attachments(&db, env.as_ref(), &mut ciphers).await?;
Ok(Json(CipherListResponse {
data: ciphers,
@ -260,14 +251,13 @@ pub async fn list_ciphers(
pub async fn get_cipher(
claims: Claims,
State(env): State<Arc<Env>>,
Extension(BaseUrl(base_url)): Extension<BaseUrl>,
Path(id): Path<String>,
) -> Result<Json<Cipher>, AppError> {
let db = db::get_db(&env)?;
let cipher = fetch_cipher_for_user(&db, &id, &claims.sub).await?;
let mut cipher: Cipher = cipher.into();
attachments::hydrate_cipher_attachments(&db, env.as_ref(), &base_url, &mut cipher, &claims.sub)
attachments::hydrate_cipher_attachments(&db, env.as_ref(), &mut cipher)
.await?;
Ok(Json(cipher))
@ -278,10 +268,9 @@ pub async fn get_cipher(
pub async fn get_cipher_details(
claims: Claims,
state: State<Arc<Env>>,
extension: Extension<BaseUrl>,
id: Path<String>,
) -> Result<Json<Cipher>, AppError> {
get_cipher(claims, state, extension, id).await
get_cipher(claims, state, id).await
}
/// PUT/POST /api/ciphers/{id}/partial
@ -289,7 +278,6 @@ pub async fn get_cipher_details(
pub async fn update_cipher_partial(
claims: Claims,
State(env): State<Arc<Env>>,
Extension(BaseUrl(base_url)): Extension<BaseUrl>,
Path(id): Path<String>,
Json(payload): Json<PartialCipherData>,
) -> Result<Json<Cipher>, AppError> {
@ -334,7 +322,7 @@ pub async fn update_cipher_partial(
let cipher = fetch_cipher_for_user(&db, &id, user_id).await?;
let mut cipher: Cipher = cipher.into();
attachments::hydrate_cipher_attachments(&db, env.as_ref(), &base_url, &mut cipher, &claims.sub)
attachments::hydrate_cipher_attachments(&db, env.as_ref(), &mut cipher)
.await?;
Ok(Json(cipher))
@ -482,7 +470,6 @@ pub async fn hard_delete_ciphers_bulk(
pub async fn restore_cipher(
claims: Claims,
State(env): State<Arc<Env>>,
Extension(BaseUrl(base_url)): Extension<BaseUrl>,
Path(id): Path<String>,
) -> Result<Json<Cipher>, AppError> {
let db = db::get_db(&env)?;
@ -513,7 +500,7 @@ pub async fn restore_cipher(
.ok_or(AppError::NotFound("Cipher not found".to_string()))?;
let mut cipher: Cipher = cipher_db.into();
attachments::hydrate_cipher_attachments(&db, env.as_ref(), &base_url, &mut cipher, &claims.sub)
attachments::hydrate_cipher_attachments(&db, env.as_ref(), &mut cipher)
.await?;
db::touch_user_updated_at(&db, &claims.sub).await?;
@ -535,7 +522,6 @@ pub struct BulkRestoreResponse {
pub async fn restore_ciphers_bulk(
claims: Claims,
State(env): State<Arc<Env>>,
Extension(BaseUrl(base_url)): Extension<BaseUrl>,
Json(payload): Json<CipherIdsData>,
) -> Result<Json<BulkRestoreResponse>, AppError> {
let db = db::get_db(&env)?;
@ -582,14 +568,7 @@ pub async fn restore_ciphers_bulk(
.map(|cipher| cipher.into())
.collect();
attachments::hydrate_ciphers_attachments(
&db,
env.as_ref(),
&base_url,
&mut restored_ciphers,
&claims.sub,
)
.await?;
attachments::hydrate_ciphers_attachments(&db, env.as_ref(), &mut restored_ciphers).await?;
db::touch_user_updated_at(&db, &claims.sub).await?;
@ -607,7 +586,6 @@ pub async fn restore_ciphers_bulk(
pub async fn create_cipher_simple(
claims: Claims,
State(env): State<Arc<Env>>,
Extension(BaseUrl(base_url)): Extension<BaseUrl>,
Json(payload): Json<CipherRequestData>,
) -> Result<Json<Cipher>, AppError> {
let db = db::get_db(&env)?;
@ -660,7 +638,7 @@ pub async fn create_cipher_simple(
.run()
.await?;
attachments::hydrate_cipher_attachments(&db, env.as_ref(), &base_url, &mut cipher, &claims.sub)
attachments::hydrate_cipher_attachments(&db, env.as_ref(), &mut cipher)
.await?;
db::touch_user_updated_at(&db, &claims.sub).await?;

View file

@ -1,4 +1,4 @@
use axum::{extract::State, Extension, Json};
use axum::{extract::State, Json};
use serde_json::Value;
use std::sync::Arc;
use worker::Env;
@ -14,14 +14,12 @@ use crate::{
sync::{Profile, SyncResponse},
user::User,
},
BaseUrl,
};
#[worker::send]
pub async fn get_sync_data(
claims: Claims,
State(env): State<Arc<Env>>,
Extension(BaseUrl(base_url)): Extension<BaseUrl>,
) -> Result<Json<SyncResponse>, AppError> {
let user_id = claims.sub;
let db = db::get_db(&env)?;
@ -67,7 +65,7 @@ pub async fn get_sync_data(
.collect::<Vec<Cipher>>();
let mut ciphers = ciphers;
attachments::hydrate_ciphers_attachments(&db, env.as_ref(), &base_url, &mut ciphers, &user_id)
attachments::hydrate_ciphers_attachments(&db, env.as_ref(), &mut ciphers)
.await?;
let profile = Profile::from_user(user)?;

View file

@ -18,7 +18,8 @@ pub struct AttachmentDB {
#[serde(rename_all = "camelCase")]
pub struct AttachmentResponse {
pub id: String,
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
pub file_name: String,
pub size: String,
pub size_name: String,
@ -32,7 +33,7 @@ impl AttachmentDB {
format!("{}/{}", self.cipher_id, self.id)
}
pub fn to_response(&self, url: String) -> AttachmentResponse {
pub fn to_response(&self, url: Option<String>) -> AttachmentResponse {
AttachmentResponse {
id: self.id.clone(),
url,