Separate object URL handling from content validation
This commit is contained in:
parent
bc19a524c4
commit
01c894da9d
2 changed files with 37 additions and 30 deletions
|
@ -19,7 +19,7 @@ use crate::activitypub::{
|
||||||
};
|
};
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::database::{DatabaseClient, DatabaseError};
|
use crate::database::{DatabaseClient, DatabaseError};
|
||||||
use crate::errors::{ConversionError, ValidationError};
|
use crate::errors::ValidationError;
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
attachments::queries::create_attachment,
|
attachments::queries::create_attachment,
|
||||||
emojis::queries::{
|
emojis::queries::{
|
||||||
|
@ -68,23 +68,22 @@ fn get_object_attributed_to(object: &Object)
|
||||||
Ok(author_id)
|
Ok(author_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_object_url(value: &JsonValue) -> Result<String, ConversionError> {
|
pub fn get_object_url(object: &Object) -> Result<String, ValidationError> {
|
||||||
let object_url = match value {
|
let maybe_object_url = match &object.url {
|
||||||
JsonValue::String(string) => string.to_owned(),
|
Some(JsonValue::String(string)) => Some(string.to_owned()),
|
||||||
other_value => {
|
Some(other_value) => {
|
||||||
let links: Vec<Link> = parse_property_value(other_value)?;
|
let links: Vec<Link> = parse_property_value(other_value)
|
||||||
if let Some(link) = links.get(0) {
|
.map_err(|_| ValidationError("invalid object URL"))?;
|
||||||
link.href.clone()
|
links.get(0).map(|link| link.href.clone())
|
||||||
} else {
|
|
||||||
return Err(ConversionError);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
None => None,
|
||||||
};
|
};
|
||||||
|
let object_url = maybe_object_url.unwrap_or(object.id.clone());
|
||||||
Ok(object_url)
|
Ok(object_url)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_object_content(object: &Object) -> Result<String, ValidationError> {
|
pub fn get_object_content(object: &Object) -> Result<String, ValidationError> {
|
||||||
let mut content = if let Some(ref content) = object.content {
|
let content = if let Some(ref content) = object.content {
|
||||||
if object.media_type == Some("text/markdown".to_string()) {
|
if object.media_type == Some("text/markdown".to_string()) {
|
||||||
format!("<p>{}</p>", content)
|
format!("<p>{}</p>", content)
|
||||||
} else {
|
} else {
|
||||||
|
@ -95,19 +94,6 @@ pub fn get_object_content(object: &Object) -> Result<String, ValidationError> {
|
||||||
// Lemmy pages and PeerTube videos have "name" property
|
// Lemmy pages and PeerTube videos have "name" property
|
||||||
object.name.as_deref().unwrap_or("").to_string()
|
object.name.as_deref().unwrap_or("").to_string()
|
||||||
};
|
};
|
||||||
if object.object_type != NOTE {
|
|
||||||
// Append link to object
|
|
||||||
let object_url = if let Some(ref value) = object.url {
|
|
||||||
parse_object_url(value)
|
|
||||||
.map_err(|_| ValidationError("invalid object URL"))?
|
|
||||||
} else {
|
|
||||||
object.id.clone()
|
|
||||||
};
|
|
||||||
content += &format!(
|
|
||||||
r#"<p><a href="{0}">{0}</a></p>"#,
|
|
||||||
object_url,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
if content.len() > CONTENT_MAX_SIZE {
|
if content.len() > CONTENT_MAX_SIZE {
|
||||||
return Err(ValidationError("content is too long"));
|
return Err(ValidationError("content is too long"));
|
||||||
};
|
};
|
||||||
|
@ -115,6 +101,13 @@ pub fn get_object_content(object: &Object) -> Result<String, ValidationError> {
|
||||||
Ok(content_safe)
|
Ok(content_safe)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_content_link(url: String) -> String {
|
||||||
|
format!(
|
||||||
|
r#"<p><a href="{0}" rel="noopener">{0}</a></p>"#,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const ATTACHMENT_MAX_SIZE: usize = 20 * 1000 * 1000; // 20 MB
|
const ATTACHMENT_MAX_SIZE: usize = 20 * 1000 * 1000; // 20 MB
|
||||||
|
|
||||||
fn is_gnu_social_link(author_id: &str, attachment: &Attachment) -> bool {
|
fn is_gnu_social_link(author_id: &str, attachment: &Attachment) -> bool {
|
||||||
|
@ -498,9 +491,13 @@ pub async fn handle_note(
|
||||||
log::warn!("failed to import {} ({})", author_id, err);
|
log::warn!("failed to import {} ({})", author_id, err);
|
||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
let content = get_object_content(&object)?;
|
|
||||||
let created_at = object.published.unwrap_or(Utc::now());
|
|
||||||
|
|
||||||
|
let mut content = get_object_content(&object)?;
|
||||||
|
if object.object_type != NOTE {
|
||||||
|
// Append link to object
|
||||||
|
let object_url = get_object_url(&object)?;
|
||||||
|
content += &create_content_link(object_url);
|
||||||
|
};
|
||||||
let attachments = get_object_attachments(
|
let attachments = get_object_attachments(
|
||||||
config,
|
config,
|
||||||
db_client,
|
db_client,
|
||||||
|
@ -556,6 +553,7 @@ pub async fn handle_note(
|
||||||
author.username,
|
author.username,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
let created_at = object.published.unwrap_or(Utc::now());
|
||||||
let post_data = PostCreateData {
|
let post_data = PostCreateData {
|
||||||
content: content,
|
content: content,
|
||||||
in_reply_to_id,
|
in_reply_to_id,
|
||||||
|
@ -638,7 +636,9 @@ mod tests {
|
||||||
}])),
|
}])),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let content = get_object_content(&object).unwrap();
|
let mut content = get_object_content(&object).unwrap();
|
||||||
|
let object_url = get_object_url(&object).unwrap();
|
||||||
|
content += &create_content_link(object_url);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
content,
|
content,
|
||||||
r#"test-content<p><a href="https://example.org/xyz" rel="noopener">https://example.org/xyz</a></p>"#,
|
r#"test-content<p><a href="https://example.org/xyz" rel="noopener">https://example.org/xyz</a></p>"#,
|
||||||
|
|
|
@ -10,9 +10,11 @@ use crate::activitypub::{
|
||||||
types::Actor,
|
types::Actor,
|
||||||
},
|
},
|
||||||
handlers::create::{
|
handlers::create::{
|
||||||
|
create_content_link,
|
||||||
get_object_attachments,
|
get_object_attachments,
|
||||||
get_object_content,
|
get_object_content,
|
||||||
get_object_tags,
|
get_object_tags,
|
||||||
|
get_object_url,
|
||||||
},
|
},
|
||||||
types::Object,
|
types::Object,
|
||||||
vocabulary::{NOTE, PERSON},
|
vocabulary::{NOTE, PERSON},
|
||||||
|
@ -46,8 +48,12 @@ async fn handle_update_note(
|
||||||
Err(DatabaseError::NotFound(_)) => return Ok(None),
|
Err(DatabaseError::NotFound(_)) => return Ok(None),
|
||||||
Err(other_error) => return Err(other_error.into()),
|
Err(other_error) => return Err(other_error.into()),
|
||||||
};
|
};
|
||||||
let content = get_object_content(&object)?;
|
let mut content = get_object_content(&object)?;
|
||||||
let updated_at = object.updated.unwrap_or(Utc::now());
|
if object.object_type != NOTE {
|
||||||
|
// Append link to object
|
||||||
|
let object_url = get_object_url(&object)?;
|
||||||
|
content += &create_content_link(object_url);
|
||||||
|
};
|
||||||
let attachments = get_object_attachments(
|
let attachments = get_object_attachments(
|
||||||
config,
|
config,
|
||||||
db_client,
|
db_client,
|
||||||
|
@ -63,6 +69,7 @@ async fn handle_update_note(
|
||||||
&object,
|
&object,
|
||||||
&HashMap::new(),
|
&HashMap::new(),
|
||||||
).await?;
|
).await?;
|
||||||
|
let updated_at = object.updated.unwrap_or(Utc::now());
|
||||||
let post_data = PostUpdateData {
|
let post_data = PostUpdateData {
|
||||||
content,
|
content,
|
||||||
attachments,
|
attachments,
|
||||||
|
|
Loading…
Reference in a new issue