This commit is contained in:
2025-10-31 01:52:51 +01:00
parent 722c2f9a5c
commit 17db827e3a
11 changed files with 220 additions and 334 deletions
+21 -20
View File
@@ -15,6 +15,7 @@ use crate::{
schema::{correspondents, document_correspondents},
utils::{
db::{no_content, EnsureEntity, IntoJsonResponse},
named_entity::{ensure_name_available, normalize_name},
time::to_iso,
},
};
@@ -111,16 +112,15 @@ pub async fn create_correspondent(
}: TenantScopedConn,
Json(payload): Json<CreateCorrespondentRequest>,
) -> AppResult<Json<CorrespondentSummary>> {
let name = payload.name.trim();
if name.is_empty() {
return Err(AppError::bad_request("name must not be empty"));
}
let name = normalize_name(&payload.name, || {
AppError::bad_request("name must not be empty")
})?;
let metadata_value = normalize_metadata(payload.metadata);
let new_id = Uuid::new_v4();
let new_correspondent = NewCorrespondent {
id: new_id,
name: name.to_string(),
name: name.clone(),
metadata: metadata_value,
tenant_id,
};
@@ -170,21 +170,22 @@ pub async fn update_correspondent(
let mut new_name: Option<String> = None;
if let Some(ref candidate) = payload.name {
let trimmed = candidate.trim();
if trimmed.is_empty() {
return Err(AppError::bad_request("name must not be empty"));
}
if trimmed != existing.name {
let duplicate = correspondents::table
.filter(correspondents::name.eq(trimmed))
.filter(correspondents::id.ne(correspondent_id))
.filter(correspondents::tenant_id.eq(tenant_id))
.first::<Correspondent>(&mut conn)
.optional()?;
if duplicate.is_some() {
return Err(AppError::bad_request("correspondent name already exists"));
}
new_name = Some(trimmed.to_string());
let normalized = normalize_name(candidate, || {
AppError::bad_request("name must not be empty")
})?;
if normalized != existing.name {
ensure_name_available(
|| {
correspondents::table
.filter(correspondents::name.eq(&normalized))
.filter(correspondents::id.ne(correspondent_id))
.filter(correspondents::tenant_id.eq(tenant_id))
.first::<Correspondent>(&mut conn)
.optional()
},
|| AppError::bad_request("correspondent name already exists"),
)?;
new_name = Some(normalized);
}
}
+10 -9
View File
@@ -12,6 +12,7 @@ use crate::{
error::{AppError, AppResult},
models::{DocumentType, NewDocumentType},
schema::document_types,
utils::named_entity::normalize_name,
};
use super::documents::DocumentTypeResponse;
@@ -64,15 +65,14 @@ pub async fn create_document_type(
}: TenantScopedConn,
Json(payload): Json<CreateDocumentTypeRequest>,
) -> AppResult<(StatusCode, Json<DocumentTypeResponse>)> {
let name = payload.name.trim();
if name.is_empty() {
return Err(AppError::bad_request("name must not be empty"));
}
let name = normalize_name(&payload.name, || {
AppError::bad_request("name must not be empty")
})?;
let new_type = NewDocumentType {
id: Uuid::new_v4(),
tenant_id,
name: name.to_string(),
name: name.clone(),
};
match diesel::insert_into(document_types::table)
@@ -111,19 +111,20 @@ pub async fn update_document_type(
}: TenantScopedConn,
Json(payload): Json<UpdateDocumentTypeRequest>,
) -> AppResult<Json<DocumentTypeResponse>> {
let name = payload
let name_raw = payload
.name
.as_ref()
.map(|value| value.trim())
.filter(|value| !value.is_empty())
.ok_or_else(|| AppError::bad_request("name must be provided and not empty"))?;
let name = normalize_name(name_raw, || {
AppError::bad_request("name must be provided and not empty")
})?;
let target = document_types::table
.filter(document_types::tenant_id.eq(tenant_id))
.find(document_type_id);
let update_result = diesel::update(target.clone())
.set(document_types::name.eq(name))
.set(document_types::name.eq(&name))
.get_result::<DocumentType>(&mut conn);
match update_result {
+20 -19
View File
@@ -12,6 +12,7 @@ use crate::schema::{document_tags, tags};
use crate::utils::{
db::{no_content, EnsureEntity, IntoJsonResponse},
json::deserialize_patch_field,
named_entity::{ensure_name_available, normalize_name},
};
#[derive(Deserialize, ToSchema)]
@@ -125,13 +126,13 @@ pub async fn create_tag(
}: TenantScopedConn,
Json(payload): Json<CreateTagRequest>,
) -> AppResult<Json<TagCatalogEntry>> {
if payload.label.trim().is_empty() {
return Err(AppError::bad_request("label must not be empty"));
}
let label = normalize_name(&payload.label, || {
AppError::bad_request("label must not be empty")
})?;
let new_tag = NewTag {
id: Uuid::new_v4(),
label: payload.label.trim().to_string(),
label: label.clone(),
color: payload.color,
tenant_id,
};
@@ -211,21 +212,21 @@ pub async fn update_tag(
return Err(AppError::bad_request("label cannot be null"));
}
Some(Some(value)) => {
let trimmed = value.trim();
if trimmed.is_empty() {
return Err(AppError::bad_request("label must not be empty"));
}
if trimmed != existing.label {
let duplicate = tags::table
.filter(tags::label.eq(trimmed))
.filter(tags::id.ne(tag_id))
.filter(tags::tenant_id.eq(tenant_id))
.first::<Tag>(&mut conn)
.optional()?;
if duplicate.is_some() {
return Err(AppError::bad_request("tag label already exists"));
}
new_label = Some(trimmed.to_string());
let normalized =
normalize_name(&value, || AppError::bad_request("label must not be empty"))?;
if normalized != existing.label {
ensure_name_available(
|| {
tags::table
.filter(tags::label.eq(&normalized))
.filter(tags::id.ne(tag_id))
.filter(tags::tenant_id.eq(tenant_id))
.first::<Tag>(&mut conn)
.optional()
},
|| AppError::bad_request("tag label already exists"),
)?;
new_label = Some(normalized);
label_changed = true;
}
}