d5939db
use bytes::Bytes;
use db::attachment::attachments as att_entity;
use db::attachment::attachments::OwnerType;
use db::conn::sea_orm::*;
use object_store::path::Path;
use time::OffsetDateTime;
use uuid::Uuid;
use crate::error::{IssueError, IssueResult};
use crate::features::IssueService;
use super::super::{AttachmentView, UploadAttachmentInput};
use super::helpers::require_authenticated;
pub async fn upload_attachment(
svc: &IssueService,
actor: Uuid,
channel_id: Uuid,
owner_type: OwnerType,
owner_id: Uuid,
input: UploadAttachmentInput,
) -> IssueResult<AttachmentView> {
require_authenticated(actor)?;
crate::features::issue::usecase::load_issue(svc, channel_id, owner_id).await?;
let size = input.data.len() as i64;
if size > svc.config.max_attachment_size_bytes {
return Err(IssueError::BadRequest(format!(
"attachment too large, max {} bytes",
svc.config.max_attachment_size_bytes
)));
}
if input.filename.trim().is_empty() {
return Err(IssueError::BadRequest("filename is required".into()));
}
let id = Uuid::new_v4();
let path = Path::from(format!(
"issues/{channel_id}/{owner_id}/{owner_type:?}/{id}-{}",
input.filename
));
svc.storage
.put(&path, Bytes::from(input.data))
.await
.map_err(|e| IssueError::Internal(format!("storage put failed: {e}")))?;
let db = svc.db.writer();
let now = OffsetDateTime::now_utc();
let active: att_entity::ActiveModel = att_entity::ActiveModel::builder()
.set_id(id)
.set_owner_type(owner_type)
.set_owner_id(owner_id)
.set_filename(input.filename)
.set_content_type(input.content_type)
.set_size(size)
.set_url(path.to_string())
.set_uploaded_by(Some(actor))
.set_created_at(now)
.into();
let saved = active.insert(&db).await?;
Ok(AttachmentView::from(saved))
}