180 lines
6.7 KiB
Rust
180 lines
6.7 KiB
Rust
#![allow(clippy::missing_errors_doc)]
|
|
#![allow(clippy::unnecessary_struct_initialization)]
|
|
#![allow(clippy::unused_async)]
|
|
|
|
use loco_rs::prelude::*;
|
|
use sea_orm::{ActiveModelTrait, EntityTrait, IntoActiveModel, QueryOrder, Set};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::models::_entities::site_settings::{self, ActiveModel, Entity, Model};
|
|
|
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
|
pub struct SiteSettingsPayload {
|
|
#[serde(default, alias = "siteName")]
|
|
pub site_name: Option<String>,
|
|
#[serde(default, alias = "siteShortName")]
|
|
pub site_short_name: Option<String>,
|
|
#[serde(default, alias = "siteUrl")]
|
|
pub site_url: Option<String>,
|
|
#[serde(default, alias = "siteTitle")]
|
|
pub site_title: Option<String>,
|
|
#[serde(default, alias = "siteDescription")]
|
|
pub site_description: Option<String>,
|
|
#[serde(default, alias = "heroTitle")]
|
|
pub hero_title: Option<String>,
|
|
#[serde(default, alias = "heroSubtitle")]
|
|
pub hero_subtitle: Option<String>,
|
|
#[serde(default, alias = "ownerName")]
|
|
pub owner_name: Option<String>,
|
|
#[serde(default, alias = "ownerTitle")]
|
|
pub owner_title: Option<String>,
|
|
#[serde(default, alias = "ownerBio")]
|
|
pub owner_bio: Option<String>,
|
|
#[serde(default, alias = "ownerAvatarUrl")]
|
|
pub owner_avatar_url: Option<String>,
|
|
#[serde(default, alias = "socialGithub")]
|
|
pub social_github: Option<String>,
|
|
#[serde(default, alias = "socialTwitter")]
|
|
pub social_twitter: Option<String>,
|
|
#[serde(default, alias = "socialEmail")]
|
|
pub social_email: Option<String>,
|
|
#[serde(default)]
|
|
pub location: Option<String>,
|
|
#[serde(default, alias = "techStack")]
|
|
pub tech_stack: Option<Vec<String>>,
|
|
}
|
|
|
|
fn normalize_optional_string(value: Option<String>) -> Option<String> {
|
|
value.and_then(|item| {
|
|
let trimmed = item.trim().to_string();
|
|
if trimmed.is_empty() {
|
|
None
|
|
} else {
|
|
Some(trimmed)
|
|
}
|
|
})
|
|
}
|
|
|
|
impl SiteSettingsPayload {
|
|
fn apply(self, item: &mut ActiveModel) {
|
|
if let Some(site_name) = self.site_name {
|
|
item.site_name = Set(normalize_optional_string(Some(site_name)));
|
|
}
|
|
if let Some(site_short_name) = self.site_short_name {
|
|
item.site_short_name = Set(normalize_optional_string(Some(site_short_name)));
|
|
}
|
|
if let Some(site_url) = self.site_url {
|
|
item.site_url = Set(normalize_optional_string(Some(site_url)));
|
|
}
|
|
if let Some(site_title) = self.site_title {
|
|
item.site_title = Set(normalize_optional_string(Some(site_title)));
|
|
}
|
|
if let Some(site_description) = self.site_description {
|
|
item.site_description = Set(normalize_optional_string(Some(site_description)));
|
|
}
|
|
if let Some(hero_title) = self.hero_title {
|
|
item.hero_title = Set(normalize_optional_string(Some(hero_title)));
|
|
}
|
|
if let Some(hero_subtitle) = self.hero_subtitle {
|
|
item.hero_subtitle = Set(normalize_optional_string(Some(hero_subtitle)));
|
|
}
|
|
if let Some(owner_name) = self.owner_name {
|
|
item.owner_name = Set(normalize_optional_string(Some(owner_name)));
|
|
}
|
|
if let Some(owner_title) = self.owner_title {
|
|
item.owner_title = Set(normalize_optional_string(Some(owner_title)));
|
|
}
|
|
if let Some(owner_bio) = self.owner_bio {
|
|
item.owner_bio = Set(normalize_optional_string(Some(owner_bio)));
|
|
}
|
|
if let Some(owner_avatar_url) = self.owner_avatar_url {
|
|
item.owner_avatar_url = Set(normalize_optional_string(Some(owner_avatar_url)));
|
|
}
|
|
if let Some(social_github) = self.social_github {
|
|
item.social_github = Set(normalize_optional_string(Some(social_github)));
|
|
}
|
|
if let Some(social_twitter) = self.social_twitter {
|
|
item.social_twitter = Set(normalize_optional_string(Some(social_twitter)));
|
|
}
|
|
if let Some(social_email) = self.social_email {
|
|
item.social_email = Set(normalize_optional_string(Some(social_email)));
|
|
}
|
|
if let Some(location) = self.location {
|
|
item.location = Set(normalize_optional_string(Some(location)));
|
|
}
|
|
if let Some(tech_stack) = self.tech_stack {
|
|
item.tech_stack = Set(Some(serde_json::json!(tech_stack)));
|
|
}
|
|
}
|
|
}
|
|
|
|
fn default_payload() -> SiteSettingsPayload {
|
|
SiteSettingsPayload {
|
|
site_name: Some("InitCool".to_string()),
|
|
site_short_name: Some("Termi".to_string()),
|
|
site_url: Some("https://termi.dev".to_string()),
|
|
site_title: Some("InitCool - 终端风格的内容平台".to_string()),
|
|
site_description: Some("一个基于终端美学的个人内容站,记录代码、设计和生活。".to_string()),
|
|
hero_title: Some("欢迎来到我的极客终端博客".to_string()),
|
|
hero_subtitle: Some("这里记录技术、代码和生活点滴".to_string()),
|
|
owner_name: Some("InitCool".to_string()),
|
|
owner_title: Some("前端开发者 / 技术博主".to_string()),
|
|
owner_bio: Some(
|
|
"一名热爱技术的前端开发者,专注于构建高性能、优雅的用户界面。相信代码不仅是工具,更是一种艺术表达。"
|
|
.to_string(),
|
|
),
|
|
owner_avatar_url: None,
|
|
social_github: Some("https://github.com".to_string()),
|
|
social_twitter: Some("https://twitter.com".to_string()),
|
|
social_email: Some("mailto:hello@termi.dev".to_string()),
|
|
location: Some("Hong Kong".to_string()),
|
|
tech_stack: Some(vec![
|
|
"Astro".to_string(),
|
|
"Svelte".to_string(),
|
|
"Tailwind CSS".to_string(),
|
|
"TypeScript".to_string(),
|
|
]),
|
|
}
|
|
}
|
|
|
|
async fn load_current(ctx: &AppContext) -> Result<Model> {
|
|
if let Some(settings) = Entity::find()
|
|
.order_by_asc(site_settings::Column::Id)
|
|
.one(&ctx.db)
|
|
.await?
|
|
{
|
|
return Ok(settings);
|
|
}
|
|
|
|
let mut item = ActiveModel {
|
|
id: Set(1),
|
|
..Default::default()
|
|
};
|
|
default_payload().apply(&mut item);
|
|
Ok(item.insert(&ctx.db).await?)
|
|
}
|
|
|
|
#[debug_handler]
|
|
pub async fn show(State(ctx): State<AppContext>) -> Result<Response> {
|
|
format::json(load_current(&ctx).await?)
|
|
}
|
|
|
|
#[debug_handler]
|
|
pub async fn update(
|
|
State(ctx): State<AppContext>,
|
|
Json(params): Json<SiteSettingsPayload>,
|
|
) -> Result<Response> {
|
|
let current = load_current(&ctx).await?;
|
|
let mut item = current.into_active_model();
|
|
params.apply(&mut item);
|
|
format::json(item.update(&ctx.db).await?)
|
|
}
|
|
|
|
pub fn routes() -> Routes {
|
|
Routes::new()
|
|
.prefix("api/site_settings/")
|
|
.add("/", get(show))
|
|
.add("/", put(update))
|
|
.add("/", patch(update))
|
|
}
|