Allow remote posts without content

This commit is contained in:
silverpill 2022-09-29 15:26:12 +00:00
parent b53a1298a2
commit f9465693a3
4 changed files with 19 additions and 29 deletions

View file

@ -1,6 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::path::Path; use std::path::Path;
use chrono::Utc;
use serde_json::{Value as JsonValue}; use serde_json::{Value as JsonValue};
use tokio_postgres::GenericClient; use tokio_postgres::GenericClient;
use uuid::Uuid; use uuid::Uuid;
@ -64,10 +65,10 @@ fn parse_object_url(value: &JsonValue) -> Result<String, ConversionError> {
} }
pub fn get_note_content(object: &Object) -> Result<String, ValidationError> { pub fn get_note_content(object: &Object) -> Result<String, ValidationError> {
let mut content = object.content.as_ref() let mut content = object.content.as_deref()
// Lemmy pages and PeerTube videos have "name" property // Lemmy pages and PeerTube videos have "name" property
.or(object.name.as_ref()) .or(object.name.as_deref())
.ok_or(ValidationError("no content"))? .unwrap_or("")
.to_owned(); .to_owned();
if object.object_type != NOTE { if object.object_type != NOTE {
if let Some(ref value) = object.url { if let Some(ref value) = object.url {
@ -159,6 +160,7 @@ pub async fn handle_note(
err err
})?; })?;
let content = get_note_content(&object)?; let content = get_note_content(&object)?;
let created_at = object.published.unwrap_or(Utc::now());
let mut attachments: Vec<Uuid> = Vec::new(); let mut attachments: Vec<Uuid> = Vec::new();
if let Some(value) = object.attachment { if let Some(value) = object.attachment {
@ -203,6 +205,10 @@ pub async fn handle_note(
attachments.push(db_attachment.id); attachments.push(db_attachment.id);
}; };
}; };
if content.is_empty() && attachments.is_empty() {
return Err(ValidationError("post is empty").into());
};
let mut mentions: Vec<Uuid> = Vec::new(); let mut mentions: Vec<Uuid> = Vec::new();
let mut tags = vec![]; let mut tags = vec![];
let mut links = vec![]; let mut links = vec![];
@ -361,7 +367,7 @@ pub async fn handle_note(
tags: tags, tags: tags,
links: links, links: links,
object_id: Some(object.id), object_id: Some(object.id),
created_at: object.published, created_at,
}; };
let post = create_post(db_client, &author.id, post_data).await?; let post = create_post(db_client, &author.id, post_data).await?;
Ok(post) Ok(post)

View file

@ -171,7 +171,7 @@ impl TryFrom<StatusData> for PostCreateData {
tags: vec![], tags: vec![],
links: vec![], links: vec![],
object_id: None, object_id: None,
created_at: None, created_at: Utc::now(),
}; };
Ok(post_data) Ok(post_data)
} }

View file

@ -38,7 +38,6 @@ pub async fn create_post(
) -> Result<Post, DatabaseError> { ) -> Result<Post, DatabaseError> {
let transaction = db_client.transaction().await?; let transaction = db_client.transaction().await?;
let post_id = new_uuid(); let post_id = new_uuid();
let created_at = data.created_at.unwrap_or(Utc::now());
// Replying to reposts is not allowed // Replying to reposts is not allowed
// Reposting of other reposts or non-public posts is not allowed // Reposting of other reposts or non-public posts is not allowed
let insert_statement = format!( let insert_statement = format!(
@ -78,7 +77,7 @@ pub async fn create_post(
&data.repost_of_id, &data.repost_of_id,
&data.visibility, &data.visibility,
&data.object_id, &data.object_id,
&created_at, &data.created_at,
], ],
).await.map_err(catch_unique_violation("post"))?; ).await.map_err(catch_unique_violation("post"))?;
let post_row = maybe_post_row.ok_or(DatabaseError::NotFound("post"))?; let post_row = maybe_post_row.ok_or(DatabaseError::NotFound("post"))?;

View file

@ -244,12 +244,13 @@ pub struct PostCreateData {
pub tags: Vec<String>, pub tags: Vec<String>,
pub links: Vec<Uuid>, pub links: Vec<Uuid>,
pub object_id: Option<String>, pub object_id: Option<String>,
pub created_at: Option<DateTime<Utc>>, pub created_at: DateTime<Utc>,
} }
impl PostCreateData { impl PostCreateData {
/// Validate and clean post data. /// Validate and clean post data (only for local posts).
pub fn clean(&mut self, character_limit: usize) -> Result<(), ValidationError> { pub fn clean(&mut self, character_limit: usize) -> Result<(), ValidationError> {
assert!(self.object_id.is_none());
if self.content.chars().count() > character_limit { if self.content.chars().count() > character_limit {
return Err(ValidationError("post is too long")); return Err(ValidationError("post is too long"));
}; };
@ -275,35 +276,19 @@ mod tests {
const POST_CHARACTER_LIMIT: usize = 1000; const POST_CHARACTER_LIMIT: usize = 1000;
#[test] #[test]
fn test_validate_post_data() { fn test_post_data_empty() {
let mut post_data_1 = PostCreateData { let mut post_data_1 = PostCreateData {
content: " ".to_string(), content: " ".to_string(),
in_reply_to_id: None, ..Default::default()
repost_of_id: None,
visibility: Visibility::Public,
attachments: vec![],
mentions: vec![],
tags: vec![],
links: vec![],
object_id: None,
created_at: None,
}; };
assert_eq!(post_data_1.clean(POST_CHARACTER_LIMIT).is_ok(), false); assert_eq!(post_data_1.clean(POST_CHARACTER_LIMIT).is_ok(), false);
} }
#[test] #[test]
fn test_trimming() { fn test_post_data_trimming() {
let mut post_data_2 = PostCreateData { let mut post_data_2 = PostCreateData {
content: "test ".to_string(), content: "test ".to_string(),
in_reply_to_id: None, ..Default::default()
repost_of_id: None,
visibility: Visibility::Public,
attachments: vec![],
mentions: vec![],
tags: vec![],
links: vec![],
object_id: None,
created_at: None,
}; };
assert_eq!(post_data_2.clean(POST_CHARACTER_LIMIT).is_ok(), true); assert_eq!(post_data_2.clean(POST_CHARACTER_LIMIT).is_ok(), true);
assert_eq!(post_data_2.content.as_str(), "test"); assert_eq!(post_data_2.content.as_str(), "test");