diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 9e65d7b..04f99e8 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -607,6 +607,10 @@ components: login_message: description: Login message for signer. type: string + post_character_limit: + description: Post character limit. + type: integer + example: 5000 blockchain_explorer_url: description: Blockchain explorer base URL. type: string diff --git a/src/config.rs b/src/config.rs index 7490a5f..fcc2892 100644 --- a/src/config.rs +++ b/src/config.rs @@ -65,6 +65,8 @@ fn default_environment() -> Environment { Environment::Development } fn default_log_level() -> LogLevel { LogLevel::Info } +fn default_post_character_limit() -> usize { 2000 } + #[derive(Clone, Deserialize)] pub struct BlockchainConfig { pub chain_id: String, @@ -116,6 +118,9 @@ pub struct Config { pub login_message: String, + #[serde(default = "default_post_character_limit")] + pub post_character_limit: usize, + // Blockchain integration pub blockchain: Option, diff --git a/src/mastodon_api/instance/types.rs b/src/mastodon_api/instance/types.rs index f679c61..f80a59b 100644 --- a/src/mastodon_api/instance/types.rs +++ b/src/mastodon_api/instance/types.rs @@ -13,6 +13,7 @@ pub struct InstanceInfo { registrations: bool, login_message: String, + post_character_limit: usize, blockchain_explorer_url: Option, blockchain_contract_address: Option, ipfs_gateway_url: Option, @@ -36,6 +37,7 @@ impl From<&Config> for InstanceInfo { version: get_full_api_version(&config.version), registrations: config.registrations_open, login_message: config.login_message.clone(), + post_character_limit: config.post_character_limit, blockchain_explorer_url: config.blockchain.as_ref() .and_then(|val| val.explorer_url.clone()), blockchain_contract_address: config.blockchain.as_ref() diff --git a/src/mastodon_api/statuses/views.rs b/src/mastodon_api/statuses/views.rs index 1e469a6..8446ebe 100644 --- a/src/mastodon_api/statuses/views.rs +++ b/src/mastodon_api/statuses/views.rs @@ -62,7 +62,7 @@ async fn create_status( let current_user = get_current_user(db_client, auth.token()).await?; let instance = config.instance(); let mut post_data = PostCreateData::try_from(data.into_inner())?; - post_data.clean()?; + post_data.clean(config.post_character_limit)?; // Mentions let mention_map = find_mentioned_profiles( db_client, diff --git a/src/models/posts/types.rs b/src/models/posts/types.rs index 51ee858..445cbf3 100644 --- a/src/models/posts/types.rs +++ b/src/models/posts/types.rs @@ -216,7 +216,10 @@ pub struct PostCreateData { impl PostCreateData { /// Validate and clean post data. - pub fn clean(&mut self) -> Result<(), ValidationError> { + pub fn clean(&mut self, character_limit: usize) -> Result<(), ValidationError> { + if self.content.chars().count() > character_limit { + return Err(ValidationError("post is too long")); + }; let content_safe = clean_html(&self.content); let content_trimmed = content_safe.trim(); if content_trimmed.is_empty() { @@ -231,6 +234,8 @@ impl PostCreateData { mod tests { use super::*; + const POST_CHARACTER_LIMIT: usize = 1000; + #[test] fn test_validate_post_data() { let mut post_data_1 = PostCreateData { @@ -244,7 +249,7 @@ mod tests { object_id: None, created_at: None, }; - assert_eq!(post_data_1.clean().is_ok(), false); + assert_eq!(post_data_1.clean(POST_CHARACTER_LIMIT).is_ok(), false); } #[test] @@ -260,7 +265,7 @@ mod tests { object_id: None, created_at: None, }; - assert_eq!(post_data_2.clean().is_ok(), true); + assert_eq!(post_data_2.clean(POST_CHARACTER_LIMIT).is_ok(), true); assert_eq!(post_data_2.content.as_str(), "test"); } }