Correctly indicate markdown mediaType for apub objects (ref #1220)
This commit is contained in:
parent
911b26f163
commit
33c6a600ad
7 changed files with 65 additions and 13 deletions
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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!())?
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
Loading…
Reference in a new issue