chore: reorganize project into monorepo
This commit is contained in:
179
backend/src/controllers/site_settings.rs
Normal file
179
backend/src/controllers/site_settings.rs
Normal file
@@ -0,0 +1,179 @@
|
||||
#![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))
|
||||
}
|
||||
Reference in New Issue
Block a user