Append object URL to post content if object type is not Note
This commit is contained in:
parent
85d35f9733
commit
ecc4afe568
3 changed files with 69 additions and 8 deletions
|
@ -8,4 +8,5 @@ rustflags = [
|
||||||
"-Aclippy::redundant_field_names",
|
"-Aclippy::redundant_field_names",
|
||||||
"-Aclippy::unused_unit",
|
"-Aclippy::unused_unit",
|
||||||
"-Aclippy::enum_variant_names",
|
"-Aclippy::enum_variant_names",
|
||||||
|
"-Aclippy::format_push_string",
|
||||||
]
|
]
|
||||||
|
|
|
@ -18,6 +18,12 @@ pub struct Attachment {
|
||||||
pub url: Option<String>,
|
pub url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Link {
|
||||||
|
pub href: String,
|
||||||
|
}
|
||||||
|
|
||||||
fn default_tag_type() -> String { HASHTAG.to_string() }
|
fn default_tag_type() -> String { HASHTAG.to_string() }
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
|
@ -80,6 +86,9 @@ pub struct Object {
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub updated: Option<DateTime<Utc>>,
|
pub updated: Option<DateTime<Utc>>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub url: Option<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
use serde_json::{Value as JsonValue};
|
||||||
use tokio_postgres::GenericClient;
|
use tokio_postgres::GenericClient;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::activitypub::{
|
use crate::activitypub::{
|
||||||
activity::{Attachment, Object},
|
activity::{Attachment, Link, Object},
|
||||||
constants::AP_PUBLIC,
|
constants::AP_PUBLIC,
|
||||||
fetcher::fetchers::fetch_file,
|
fetcher::fetchers::fetch_file,
|
||||||
fetcher::helpers::{
|
fetcher::helpers::{
|
||||||
|
@ -18,7 +19,7 @@ use crate::activitypub::{
|
||||||
vocabulary::{DOCUMENT, HASHTAG, IMAGE, MENTION, NOTE},
|
vocabulary::{DOCUMENT, HASHTAG, IMAGE, MENTION, NOTE},
|
||||||
};
|
};
|
||||||
use crate::config::Instance;
|
use crate::config::Instance;
|
||||||
use crate::errors::{DatabaseError, ValidationError};
|
use crate::errors::{ConversionError, DatabaseError, ValidationError};
|
||||||
use crate::models::attachments::queries::create_attachment;
|
use crate::models::attachments::queries::create_attachment;
|
||||||
use crate::models::posts::mentions::mention_to_address;
|
use crate::models::posts::mentions::mention_to_address;
|
||||||
use crate::models::posts::queries::{
|
use crate::models::posts::queries::{
|
||||||
|
@ -46,15 +47,42 @@ fn get_note_author_id(object: &Object) -> Result<String, ValidationError> {
|
||||||
|
|
||||||
const CONTENT_MAX_SIZE: usize = 100000;
|
const CONTENT_MAX_SIZE: usize = 100000;
|
||||||
|
|
||||||
|
fn parse_object_url(value: &JsonValue) -> Result<String, ConversionError> {
|
||||||
|
let object_url = match value {
|
||||||
|
JsonValue::String(string) => string.to_owned(),
|
||||||
|
other_value => {
|
||||||
|
let links: Vec<Link> = parse_property_value(other_value)?;
|
||||||
|
if let Some(link) = links.get(0) {
|
||||||
|
link.href.clone()
|
||||||
|
} else {
|
||||||
|
return Err(ConversionError);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Ok(object_url)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_note_content(object: &Object) -> Result<String, ValidationError> {
|
pub fn get_note_content(object: &Object) -> Result<String, ValidationError> {
|
||||||
let content = object.content.as_ref()
|
let mut content = object.content.as_ref()
|
||||||
// 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_ref())
|
||||||
.ok_or(ValidationError("no content"))?;
|
.ok_or(ValidationError("no content"))?
|
||||||
|
.to_owned();
|
||||||
|
if object.object_type != NOTE {
|
||||||
|
if let Some(ref value) = object.url {
|
||||||
|
// Append link to object
|
||||||
|
let object_url = parse_object_url(value)
|
||||||
|
.map_err(|_| ValidationError("invalid object URL"))?;
|
||||||
|
content += &format!(
|
||||||
|
r#"<p><a href="{0}" target="_blank" rel="noopener">{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"));
|
||||||
};
|
};
|
||||||
let content_safe = clean_html(content);
|
let content_safe = clean_html(&content);
|
||||||
Ok(content_safe)
|
Ok(content_safe)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,9 +330,12 @@ pub async fn handle_note(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::activitypub::activity::Object;
|
use serde_json::json;
|
||||||
use crate::activitypub::actors::types::Actor;
|
use crate::activitypub::{
|
||||||
use crate::activitypub::vocabulary::NOTE;
|
activity::Object,
|
||||||
|
actors::types::Actor,
|
||||||
|
vocabulary::NOTE,
|
||||||
|
};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -318,6 +349,26 @@ mod tests {
|
||||||
assert_eq!(content, "test");
|
assert_eq!(content, "test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_note_content_from_video() {
|
||||||
|
let object = Object {
|
||||||
|
name: Some("test-name".to_string()),
|
||||||
|
content: Some("test-content".to_string()),
|
||||||
|
object_type: "Video".to_string(),
|
||||||
|
url: Some(json!([{
|
||||||
|
"type": "Link",
|
||||||
|
"mediaType": "text/html",
|
||||||
|
"href": "https://example.org/xyz",
|
||||||
|
}])),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let content = get_note_content(&object).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
content,
|
||||||
|
r#"test-content<p><a href="https://example.org/xyz" target="_blank" rel="noopener">https://example.org/xyz</a></p>"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_note_visibility_public() {
|
fn test_get_note_visibility_public() {
|
||||||
let author = DbActorProfile::default();
|
let author = DbActorProfile::default();
|
||||||
|
|
Loading…
Reference in a new issue