refactor: extract slug utilities into api/slug.rs
This commit is contained in:
parent
4d7d7ec383
commit
4c88d5e2bb
81
src/api/slug.rs
Normal file
81
src/api/slug.rs
Normal file
@ -0,0 +1,81 @@
|
||||
#![allow(clippy::unused_unit, deprecated, unused_imports)]
|
||||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub fn slugify(title: &str) -> String {
|
||||
let slug: String = title
|
||||
.to_lowercase()
|
||||
.chars()
|
||||
.map(|c| {
|
||||
if c.is_ascii_alphanumeric() || c == '-' || c == '_' {
|
||||
c
|
||||
} else {
|
||||
'-'
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let parts: Vec<&str> = slug.split('-').filter(|s| !s.is_empty()).collect();
|
||||
let slug = parts.join("-");
|
||||
|
||||
if slug.is_empty() {
|
||||
return format!("{}", chrono::Utc::now().timestamp());
|
||||
}
|
||||
|
||||
slug.chars().take(100).collect()
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub fn is_valid_slug(slug: &str) -> bool {
|
||||
if slug.is_empty() || slug.len() > 200 {
|
||||
return false;
|
||||
}
|
||||
slug.chars()
|
||||
.all(|c| c.is_alphanumeric() || c == '-' || c == '_')
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub async fn ensure_unique_slug(
|
||||
client: &tokio_postgres::Client,
|
||||
base: &str,
|
||||
exclude_id: Option<i32>,
|
||||
) -> Result<String, ServerFnError> {
|
||||
use crate::api::utils::query_error;
|
||||
|
||||
let mut candidate = base.to_string();
|
||||
let mut suffix = 2;
|
||||
|
||||
loop {
|
||||
let exists = if let Some(exclude) = exclude_id {
|
||||
client
|
||||
.query_opt(
|
||||
"SELECT 1 FROM posts WHERE slug = $1 AND deleted_at IS NULL AND id != $2",
|
||||
&[&candidate, &exclude],
|
||||
)
|
||||
.await
|
||||
.map_err(query_error)?
|
||||
.is_some()
|
||||
} else {
|
||||
client
|
||||
.query_opt(
|
||||
"SELECT 1 FROM posts WHERE slug = $1 AND deleted_at IS NULL",
|
||||
&[&candidate],
|
||||
)
|
||||
.await
|
||||
.map_err(query_error)?
|
||||
.is_some()
|
||||
};
|
||||
|
||||
if !exists {
|
||||
return Ok(candidate);
|
||||
}
|
||||
|
||||
candidate = format!("{}-{}", base, suffix);
|
||||
suffix += 1;
|
||||
|
||||
if candidate.len() > 200 {
|
||||
return Err(ServerFnError::new("无法生成唯一 slug"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user