Correctly indicate markdown mediaType for apub objects (ref #1220)

This commit is contained in:
Felix Ableitner 2020-11-24 14:44:21 +01:00
parent 911b26f163
commit 33c6a600ad
7 changed files with 65 additions and 13 deletions

View file

@ -64,6 +64,7 @@ Receives activities from user: `Follow`, `Undo/Follow`, `Create`, `Update`, `Lik
"https://enterprise.lemmy.ml/u/riker" "https://enterprise.lemmy.ml/u/riker"
], ],
"content": "Welcome to the default community!", "content": "Welcome to the default community!",
"mediaType": "text/markdown",
"icon": { "icon": {
"type": "Image", "type": "Image",
"url": "https://enterprise.lemmy.ml/pictrs/image/Z8pFFb21cl.png" "url": "https://enterprise.lemmy.ml/pictrs/image/Z8pFFb21cl.png"
@ -123,7 +124,8 @@ Sends and receives activities from/to other users: `Create/Note`, `Update/Note`,
"type": "Person", "type": "Person",
"preferredUsername": "picard", "preferredUsername": "picard",
"name": "Jean-Luc Picard", "name": "Jean-Luc Picard",
"summary": "The user bio", "content": "The user bio",
"mediaType": "text/markdown",
"icon": { "icon": {
"type": "Image", "type": "Image",
"url": "https://enterprise.lemmy.ml/pictrs/image/DS3q0colRA.jpg" "url": "https://enterprise.lemmy.ml/pictrs/image/DS3q0colRA.jpg"
@ -150,7 +152,7 @@ Sends and receives activities from/to other users: `Create/Note`, `Update/Note`,
|---|---|---| |---|---|---|
| `preferredUsername` | yes | Name of the actor | | `preferredUsername` | yes | Name of the actor |
| `name` | no | The user's displayname | | `name` | no | The user's displayname |
| `summary` | no | User bio | | `content` | no | User bio |
| `icon` | no | The user's avatar, shown next to the username | | `icon` | no | The user's avatar, shown next to the username |
| `image` | no | The user's banner, shown on top of the profile | | `image` | no | The user's banner, shown on top of the profile |
| `inbox` | no | ActivityPub inbox URL | | `inbox` | no | ActivityPub inbox URL |
@ -174,6 +176,7 @@ A page with title, and optional URL and text content. The URL often leads to an
"to": "https://voyager.lemmy.ml/c/main", "to": "https://voyager.lemmy.ml/c/main",
"summary": "Test thumbnail 2", "summary": "Test thumbnail 2",
"content": "blub blub", "content": "blub blub",
"mediaType": "text/markdown",
"url": "https://voyager.lemmy.ml:/pictrs/image/fzGwCsq7BJ.jpg", "url": "https://voyager.lemmy.ml:/pictrs/image/fzGwCsq7BJ.jpg",
"image": { "image": {
"type": "Image", "type": "Image",
@ -213,6 +216,7 @@ A reply to a post, or reply to another comment. Contains only text (including re
"attributedTo": "https://enterprise.lemmy.ml/u/picard", "attributedTo": "https://enterprise.lemmy.ml/u/picard",
"to": "https://enterprise.lemmy.ml/c/main", "to": "https://enterprise.lemmy.ml/c/main",
"content": "mmmk", "content": "mmmk",
"mediaType": "text/markdown",
"inReplyTo": [ "inReplyTo": [
"https://enterprise.lemmy.ml/post/38", "https://enterprise.lemmy.ml/post/38",
"https://voyager.lemmy.ml/comment/73" "https://voyager.lemmy.ml/comment/73"
@ -243,6 +247,7 @@ A direct message from one user to another. Can not include additional users. Thr
"attributedTo": "https://enterprise.lemmy.ml/u/picard", "attributedTo": "https://enterprise.lemmy.ml/u/picard",
"to": "https://voyager.lemmy.ml/u/janeway", "to": "https://voyager.lemmy.ml/u/janeway",
"content": "test", "content": "test",
"mediaType": "text/markdown",
"published": "2020-10-08T19:10:46.542820+00:00", "published": "2020-10-08T19:10:46.542820+00:00",
"updated": "2020-10-08T20:13:52.547156+00:00" "updated": "2020-10-08T20:13:52.547156+00:00"
} }

View file

@ -4,7 +4,7 @@ use crate::{
get_or_fetch_and_insert_post, get_or_fetch_and_insert_post,
get_or_fetch_and_upsert_user, get_or_fetch_and_upsert_user,
}, },
objects::{check_object_domain, create_tombstone}, objects::{check_is_markdown, check_object_domain, create_tombstone, mime_markdown},
FromApub, FromApub,
ToApub, ToApub,
}; };
@ -64,6 +64,7 @@ impl ToApub for Comment {
.set_to(community.actor_id) .set_to(community.actor_id)
.set_many_in_reply_tos(in_reply_to_vec) .set_many_in_reply_tos(in_reply_to_vec)
.set_content(self.content.to_owned()) .set_content(self.content.to_owned())
.set_media_type(mime_markdown()?)
.set_attributed_to(creator.actor_id); .set_attributed_to(creator.actor_id);
if let Some(u) = self.updated { if let Some(u) = self.updated {
@ -124,6 +125,9 @@ impl FromApub for CommentForm {
} }
None => None, None => None,
}; };
check_is_markdown(note.media_type())?;
let content = note let content = note
.content() .content()
.context(location_info!())? .context(location_info!())?

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
extensions::group_extensions::GroupExtension, extensions::group_extensions::GroupExtension,
fetcher::get_or_fetch_and_upsert_user, fetcher::get_or_fetch_and_upsert_user,
objects::{check_object_domain, create_tombstone}, objects::{check_is_markdown, check_object_domain, create_tombstone, mime_markdown},
ActorType, ActorType,
FromApub, FromApub,
GroupExt, GroupExt,
@ -58,9 +58,7 @@ impl ToApub for Community {
group.set_updated(convert_datetime(u)); group.set_updated(convert_datetime(u));
} }
if let Some(d) = self.description.to_owned() { if let Some(d) = self.description.to_owned() {
// TODO: this should be html, also add source field with raw markdown group.set_content(d).set_media_type(mime_markdown()?);
// -> same for post.content and others
group.set_content(d);
} }
if let Some(icon_url) = &self.icon { if let Some(icon_url) = &self.icon {
@ -146,6 +144,10 @@ impl FromApub for CommunityForm {
.map(|s| s.as_single_xsd_string()) .map(|s| s.as_single_xsd_string())
.flatten() .flatten()
.map(|s| s.to_string()); .map(|s| s.to_string());
if description.is_some() {
check_is_markdown(group.media_type())?;
}
check_slurs(&name)?; check_slurs(&name)?;
check_slurs(&title)?; check_slurs(&title)?;
check_slurs_opt(&description)?; check_slurs_opt(&description)?;

View file

@ -2,6 +2,7 @@ use crate::check_is_apub_id_valid;
use activitystreams::{ use activitystreams::{
base::{AsBase, BaseExt}, base::{AsBase, BaseExt},
markers::Base, markers::Base,
mime::{FromStrError, Mime},
object::{Tombstone, TombstoneExt}, object::{Tombstone, TombstoneExt},
}; };
use anyhow::{anyhow, Context}; use anyhow::{anyhow, Context};
@ -58,3 +59,18 @@ where
}; };
Ok(actor_id.to_string()) Ok(actor_id.to_string())
} }
pub(in crate::objects) fn mime_markdown() -> Result<Mime, FromStrError> {
"text/markdown".parse()
}
pub(in crate::objects) fn check_is_markdown(mime: Option<&Mime>) -> Result<(), LemmyError> {
let mime = mime.context(location_info!())?;
if !mime.eq(&mime_markdown()?) {
Err(LemmyError::from(anyhow!(
"Lemmy only supports markdown content"
)))
} else {
Ok(())
}
}

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
extensions::page_extension::PageExtension, extensions::page_extension::PageExtension,
fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user}, fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user},
objects::{check_object_domain, create_tombstone}, objects::{check_is_markdown, check_object_domain, create_tombstone, mime_markdown},
FromApub, FromApub,
PageExt, PageExt,
ToApub, ToApub,
@ -57,7 +57,9 @@ impl ToApub for Post {
.set_attributed_to(creator.actor_id); .set_attributed_to(creator.actor_id);
if let Some(body) = &self.body { if let Some(body) = &self.body {
page.set_content(body.to_owned()); page
.set_content(body.to_owned())
.set_media_type(mime_markdown()?);
} }
// TODO: hacky code because we get self.url == Some("") // TODO: hacky code because we get self.url == Some("")
@ -162,6 +164,7 @@ impl FromApub for PostForm {
.as_single_xsd_string() .as_single_xsd_string()
.context(location_info!())? .context(location_info!())?
.to_string(); .to_string();
let body = page let body = page
.inner .inner
.content() .content()
@ -169,6 +172,10 @@ impl FromApub for PostForm {
.map(|c| c.as_single_xsd_string()) .map(|c| c.as_single_xsd_string())
.flatten() .flatten()
.map(|s| s.to_string()); .map(|s| s.to_string());
if body.is_some() {
check_is_markdown(page.media_type())?;
}
check_slurs(&name)?; check_slurs(&name)?;
let body_slurs_removed = body.map(|b| remove_slurs(&b)); let body_slurs_removed = body.map(|b| remove_slurs(&b));
Ok(PostForm { Ok(PostForm {

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
check_is_apub_id_valid, check_is_apub_id_valid,
fetcher::get_or_fetch_and_upsert_user, fetcher::get_or_fetch_and_upsert_user,
objects::{check_object_domain, create_tombstone}, objects::{check_is_markdown, check_object_domain, create_tombstone, mime_markdown},
FromApub, FromApub,
ToApub, ToApub,
}; };
@ -39,6 +39,7 @@ impl ToApub for PrivateMessage {
.set_id(Url::parse(&self.ap_id.to_owned())?) .set_id(Url::parse(&self.ap_id.to_owned())?)
.set_published(convert_datetime(self.published)) .set_published(convert_datetime(self.published))
.set_content(self.content.to_owned()) .set_content(self.content.to_owned())
.set_media_type(mime_markdown()?)
.set_to(recipient.actor_id) .set_to(recipient.actor_id)
.set_attributed_to(creator.actor_id); .set_attributed_to(creator.actor_id);
@ -83,6 +84,8 @@ impl FromApub for PrivateMessageForm {
let ap_id = note.id_unchecked().context(location_info!())?.to_string(); let ap_id = note.id_unchecked().context(location_info!())?.to_string();
check_is_apub_id_valid(&Url::parse(&ap_id)?)?; check_is_apub_id_valid(&Url::parse(&ap_id)?)?;
check_is_markdown(note.media_type())?;
Ok(PrivateMessageForm { Ok(PrivateMessageForm {
creator_id: creator.id, creator_id: creator.id,
recipient_id: recipient.id, recipient_id: recipient.id,

View file

@ -1,4 +1,10 @@
use crate::{objects::check_object_domain, ActorType, FromApub, PersonExt, ToApub}; use crate::{
objects::{check_is_markdown, check_object_domain, mime_markdown},
ActorType,
FromApub,
PersonExt,
ToApub,
};
use activitystreams::{ use activitystreams::{
actor::{ApActor, Endpoints, Person}, actor::{ApActor, Endpoints, Person},
object::{Image, Tombstone}, object::{Image, Tombstone},
@ -47,7 +53,12 @@ impl ToApub for User_ {
} }
if let Some(bio) = &self.bio { if let Some(bio) = &self.bio {
person.set_summary(bio.to_owned()); // Use `content` here because it supports markdown, while summary does not.
person
.set_content(bio.to_owned())
.set_media_type(mime_markdown()?)
// Also set summary for compatibility with older Lemmy versions. Remove this after a while.
.set_summary(bio.to_owned());
} }
if let Some(i) = self.preferred_username.to_owned() { if let Some(i) = self.preferred_username.to_owned() {
@ -121,10 +132,14 @@ impl FromApub for UserForm {
// here when we federate to other platforms. Same for preferred_username // here when we federate to other platforms. Same for preferred_username
let bio = person let bio = person
.inner .inner
.summary() .content()
.map(|s| s.as_single_xsd_string()) .map(|s| s.as_single_xsd_string())
.flatten() .flatten()
.map(|s| s.to_string()); .map(|s| s.to_string());
if bio.is_some() {
check_is_markdown(person.media_type())?;
}
check_slurs(&name)?; check_slurs(&name)?;
check_slurs_opt(&preferred_username)?; check_slurs_opt(&preferred_username)?;
check_slurs_opt(&bio)?; check_slurs_opt(&bio)?;