diff --git a/Cargo.lock b/Cargo.lock index 8e31693..8d019c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -460,6 +460,15 @@ dependencies = [ "serde", ] +[[package]] +name = "emojis" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f619a926616ae7149a0d82610b051134a0d6c4ae2962d990c06c847a445c5d9" +dependencies = [ + "phf", +] + [[package]] name = "enum-iterator" version = "2.1.0" @@ -526,6 +535,7 @@ dependencies = [ "chrono", "clap", "color-print", + "emojis", "enum-iterator", "macros", "redis", @@ -1104,6 +1114,24 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1444,6 +1472,12 @@ dependencies = [ "rand_core", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" diff --git a/Cargo.toml b/Cargo.toml index d141765..95b00d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ macros = { path = "macros" } chrono = "0.4" clap = "4.5" color-print = "0.3" +emojis = "0.6" enum-iterator = "2.1" quote = "1.0" redis = "0.25" diff --git a/fishctl/Cargo.toml b/fishctl/Cargo.toml index 8f48a3d..e60d245 100644 --- a/fishctl/Cargo.toml +++ b/fishctl/Cargo.toml @@ -12,6 +12,7 @@ macros = { workspace = true } chrono = { workspace = true } clap = { workspace = true, features = ["derive"] } color-print = { workspace = true } +emojis = { workspace = true } enum-iterator = { workspace = true } redis = { workspace = true, features = ["tokio-comp"] } serde = { workspace = true, features = ["derive"] } diff --git a/fishctl/src/command/config/update/v1.rs b/fishctl/src/command/config/update/v1.rs index d0dcae0..1fa1f8d 100644 --- a/fishctl/src/command/config/update/v1.rs +++ b/fishctl/src/command/config/update/v1.rs @@ -363,13 +363,14 @@ fn create_new_server_config( let mut server_config = server::Config { config_revision: Revision::V1, - info: Some(server::Info { + custom: Some(server::Custom { name: meta.name.to_owned(), description: meta.description.to_owned(), maintainer_name: meta.maintainer_name.to_owned(), contact_info: meta.maintainer_email.to_owned(), open_registrations: !meta.disable_registration, repository_url, + default_reaction: meta.default_reaction.to_owned(), }), timeline: Some(server::Timeline { local: !meta.disable_local_timeline, diff --git a/fishctl/src/config/server.rs b/fishctl/src/config/server.rs index de1ac16..7cf4903 100644 --- a/fishctl/src/config/server.rs +++ b/fishctl/src/config/server.rs @@ -7,7 +7,7 @@ use crate::config::{ensure_latest_revision, Revision}; use serde::{Deserialize, Serialize}; -use validator::Validate; +use validator::{Validate, ValidationError}; #[derive(Deserialize, Serialize, Validate, Debug, Clone)] pub struct Config { @@ -16,7 +16,7 @@ pub struct Config { #[validate(nested)] pub network: Network, #[validate(nested)] - pub info: Option, + pub custom: Option, #[validate(nested)] pub timeline: Option, #[validate(nested)] @@ -63,7 +63,7 @@ pub struct Proxy { } #[derive(Deserialize, Serialize, Validate, Debug, Clone)] -pub struct Info { +pub struct Custom { /// Server name pub name: Option, /// Server description @@ -76,6 +76,9 @@ pub struct Info { pub open_registrations: bool, /// Repository URL pub repository_url: Option, + #[validate(custom(function = "validate_emoji"))] + /// Default reaction emoji + pub default_reaction: String, } #[derive(Deserialize, Serialize, Validate, Debug, Clone)] @@ -157,3 +160,26 @@ pub enum Captcha { #[serde(rename = "reCAPTCHA")] ReCaptcha, } + +fn validate_emoji(value: &str) -> Result<(), ValidationError> { + let error = Err(ValidationError::new("not a Unicode emoji or :emoji_code:")); + + // check if `value` is a Unicode emoji + if emojis::get(value).is_some() { + return Ok(()); + } + + // check if `value` is a custom emoji + // "+", "-", "_" are allowed in emoji shortcodes in Misskey variants + // ref: + if value.len() > 2 { + if value[1..value.len() - 1] + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '+' || c == '-' || c == '_') + { + return Ok(()); + } + } + + error +} diff --git a/macros/src/lib.rs b/macros/src/lib.rs index e69de29..8b13789 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -0,0 +1 @@ +