Allow attributedTo to be array of values

Initial support for PeerTube.
This commit is contained in:
silverpill 2021-12-24 15:13:25 +00:00
parent 91a91b9c16
commit dc281f821f
2 changed files with 39 additions and 9 deletions

View file

@ -64,7 +64,7 @@ pub struct Object {
pub published: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attributed_to: Option<String>,
pub attributed_to: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub in_reply_to: Option<String>,

View file

@ -8,7 +8,7 @@ use uuid::Uuid;
use crate::config::{Config, Instance};
use crate::database::{Pool, get_database_client};
use crate::errors::{DatabaseError, HttpError, ValidationError};
use crate::errors::{ConversionError, DatabaseError, HttpError, ValidationError};
use crate::models::attachments::queries::create_attachment;
use crate::models::posts::mentions::mention_to_address;
use crate::models::posts::queries::{
@ -88,15 +88,30 @@ fn parse_object_id(
Ok(internal_object_id)
}
fn parse_array(value: &Value) -> Result<Vec<String>, ValidationError> {
fn parse_array(value: &Value) -> Result<Vec<String>, ConversionError> {
let result = match value {
Value::String(string) => vec![string.to_string()],
Value::Array(array) => {
array.iter()
.filter_map(|val| val.as_str().map(|s| s.to_string()))
.collect()
let mut results = vec![];
for value in array {
match value {
Value::String(string) => results.push(string.to_string()),
Value::Object(object) => {
if let Some(string) = object["id"].as_str() {
results.push(string.to_string());
} else {
// id property is missing
return Err(ConversionError);
};
},
// Unexpected array item type
_ => return Err(ConversionError),
};
};
results
},
_ => return Err(ValidationError("invalid attribute value")),
// Unexpected value type
_ => return Err(ConversionError),
};
Ok(result)
}
@ -242,10 +257,15 @@ pub async fn process_note(
for object in objects {
let attributed_to = object.attributed_to
.ok_or(ValidationError("unattributed note"))?;
let author_id = parse_array(&attributed_to)
.map_err(|_| ValidationError("invalid attributedTo property"))?
.get(0)
.ok_or(ValidationError("invalid attributedTo property"))?
.to_string();
let author = get_or_fetch_profile_by_actor_id(
db_client,
&instance,
&attributed_to,
&author_id,
&config.media_dir(),
).await?;
let content = object.content
@ -327,7 +347,8 @@ pub async fn process_note(
};
let visibility = match object.to {
Some(value) => {
let recipients = parse_array(&value)?;
let recipients = parse_array(&value)
.map_err(|_| ValidationError("invalid 'to' property value"))?;
if recipients.len() == 1 &&
parse_actor_id(&instance.url(), &recipients[0]).is_ok()
{
@ -627,6 +648,15 @@ mod tests {
);
}
#[test]
fn test_parse_array_with_array_of_objects() {
let value = json!([{"id": "test1"}, {"id": "test2"}]);
assert_eq!(
parse_array(&value).unwrap(),
vec!["test1".to_string(), "test2".to_string()],
);
}
#[test]
fn test_get_object_id_from_string() {
let value = json!("test_id");