Mobilizon federation (#2544)

* Mobilizon federation

* Also accept document attachments from mobilizon
This commit is contained in:
Nutomic 2022-11-12 13:51:08 +00:00 committed by GitHub
parent 83d2959b4b
commit e3bb43542c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 535 additions and 7 deletions

View file

@ -0,0 +1,186 @@
{
"timezone": "Europe/London",
"isOnline": false,
"contacts": [
"https://rendezvous.nomagic.uk/@emorrp1"
],
"cc": [
"https://rendezvous.nomagic.uk/@emorrp1/followers"
],
"id": "https://rendezvous.nomagic.uk/events/b81c0531-a57c-497d-93ba-af0f8b255498",
"inLanguage": "en",
"endTime": "2022-12-11T21:00:00+00:00",
"repliesModerationOption": "allow_all",
"content": "<p>£6 each.</p><p></p><p>The dance style is like a posh ceilidh, with some exciting new ways to turn your partner, set patterns and learn some reels by heart. Looking forward to sharing the Hamilton House and the Inverness with those of you who can make it along to this one.</p><p></p><p>For anyone unfamiliar with <a target=\"_blank\" rel=\"noopener noreferrer ugc\" href=\"https://www.exeterceilidhs.net/\">ceilidhs</a>, they&#39;re very social and energetic dances that are very accessible because everyone gets told exactly what to do by a caller and when to do it. Here&#39;s a <a target=\"_blank\" rel=\"noopener noreferrer ugc\" href=\"https://www.facebook.com/emorrp1/videos/735558448180\">sample video</a> from when I learned CaledonianDancing at uni. The cover photo is by Dave Conner CC-BY-2.0.</p>",
"category": "SPORTS",
"actor": "https://rendezvous.nomagic.uk/@emorrp1",
"type": "Event",
"url": "https://rendezvous.nomagic.uk/events/b81c0531-a57c-497d-93ba-af0f8b255498",
"remainingAttendeeCapacity": null,
"anonymousParticipationEnabled": true,
"ical:status": "CONFIRMED",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"joinMode": "free",
"location": {
"address": {
"addressCountry": "United Kingdom",
"addressLocality": "Teignbridge",
"addressRegion": "England",
"postalCode": "EX6 7TW",
"streetAddress": "Devon Expressway",
"type": "PostalAddress"
},
"id": "https://rendezvous.nomagic.uk/address/e4c95383-15ac-4cc7-adf6-723d74ee2ccc",
"latitude": 50.66881615,
"longitude": -3.537739788359949,
"name": "The Kenn Centre",
"type": "Place"
},
"startTime": "2022-12-11T19:00:00+00:00",
"published": "2022-09-27T14:33:14Z",
"draft": false,
"participantCount": 0,
"uuid": "b81c0531-a57c-497d-93ba-af0f8b255498",
"maximumAttendeeCapacity": 0,
"tag": [
{
"href": "https://rendezvous.nomagic.uk/tags/dance",
"name": "#Dance",
"type": "Hashtag"
},
{
"href": "https://rendezvous.nomagic.uk/tags/caledonian",
"name": "#Caledonian",
"type": "Hashtag"
},
{
"href": "https://rendezvous.nomagic.uk/tags/lesson",
"name": "#Lesson",
"type": "Hashtag"
}
],
"updated": "2022-09-27T14:39:18Z",
"attributedTo": "https://rendezvous.nomagic.uk/@devon_caledonian_society",
"commentsEnabled": true,
"attachment": [
{
"mediaType": "image/jpeg",
"name": "Banner",
"type": "Document",
"url": "https://rendezvous.nomagic.uk/media/cd75bf2f61b66004fe20af4797f5aa847ae1f9ea1c118f53093d6fc4e51a6045.jpg?name=devon_caledonian_society%27s%20banner.jpg"
}
],
"name": "Caledonian scottish dance class",
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"addressRegion": "sc:addressRegion",
"timezone": {
"@id": "mz:timezone",
"@type": "sc:Text"
},
"isOnline": {
"@id": "mz:isOnline",
"@type": "sc:Boolean"
},
"pt": "https://joinpeertube.org/ns#",
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"inLanguage": "sc:inLanguage",
"address": {
"@id": "sc:address",
"@type": "sc:PostalAddress"
},
"discoverable": "toot:discoverable",
"repliesModerationOption": {
"@id": "mz:repliesModerationOption",
"@type": "mz:repliesModerationOptionType"
},
"sc": "http://schema.org#",
"mz": "https://joinmobilizon.org/ns#",
"category": "sc:category",
"joinModeType": {
"@id": "mz:joinModeType",
"@type": "rdfs:Class"
},
"Hashtag": "as:Hashtag",
"propertyID": "sc:propertyID",
"PostalAddress": "sc:PostalAddress",
"discussions": {
"@id": "mz:discussions",
"@type": "@id"
},
"remainingAttendeeCapacity": "sc:remainingAttendeeCapacity",
"streetAddress": "sc:streetAddress",
"anonymousParticipationEnabled": {
"@id": "mz:anonymousParticipationEnabled",
"@type": "sc:Boolean"
},
"addressLocality": "sc:addressLocality",
"joinMode": {
"@id": "mz:joinMode",
"@type": "mz:joinModeType"
},
"location": {
"@id": "sc:location",
"@type": "sc:Place"
},
"toot": "http://joinmastodon.org/ns#",
"participantCount": {
"@id": "mz:participantCount",
"@type": "sc:Integer"
},
"uuid": "sc:identifier",
"maximumAttendeeCapacity": "sc:maximumAttendeeCapacity",
"participationMessage": {
"@id": "mz:participationMessage",
"@type": "sc:Text"
},
"openness": {
"@id": "mz:openness",
"@type": "@id"
},
"members": {
"@id": "mz:members",
"@type": "@id"
},
"events": {
"@id": "mz:events",
"@type": "@id"
},
"resources": {
"@id": "mz:resources",
"@type": "@id"
},
"addressCountry": "sc:addressCountry",
"posts": {
"@id": "mz:posts",
"@type": "@id"
},
"commentsEnabled": {
"@id": "pt:commentsEnabled",
"@type": "sc:Boolean"
},
"value": "sc:value",
"PropertyValue": "sc:PropertyValue",
"repliesModerationOptionType": {
"@id": "mz:repliesModerationOptionType",
"@type": "rdfs:Class"
},
"todos": {
"@id": "mz:todos",
"@type": "@id"
},
"ical": "http://www.w3.org/2002/12/cal/ical#",
"postalCode": "sc:postalCode",
"memberCount": {
"@id": "mz:memberCount",
"@type": "sc:Integer"
},
"@language": "und"
}
],
"mediaType": "text/html"
}

View file

@ -0,0 +1,168 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"addressRegion": "sc:addressRegion",
"timezone": {
"@id": "mz:timezone",
"@type": "sc:Text"
},
"isOnline": {
"@id": "mz:isOnline",
"@type": "sc:Boolean"
},
"pt": "https://joinpeertube.org/ns#",
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"inLanguage": "sc:inLanguage",
"address": {
"@id": "sc:address",
"@type": "sc:PostalAddress"
},
"discoverable": "toot:discoverable",
"repliesModerationOption": {
"@id": "mz:repliesModerationOption",
"@type": "mz:repliesModerationOptionType"
},
"sc": "http://schema.org#",
"mz": "https://joinmobilizon.org/ns#",
"category": "sc:category",
"joinModeType": {
"@id": "mz:joinModeType",
"@type": "rdfs:Class"
},
"Hashtag": "as:Hashtag",
"propertyID": "sc:propertyID",
"PostalAddress": "sc:PostalAddress",
"discussions": {
"@id": "mz:discussions",
"@type": "@id"
},
"remainingAttendeeCapacity": "sc:remainingAttendeeCapacity",
"streetAddress": "sc:streetAddress",
"anonymousParticipationEnabled": {
"@id": "mz:anonymousParticipationEnabled",
"@type": "sc:Boolean"
},
"addressLocality": "sc:addressLocality",
"joinMode": {
"@id": "mz:joinMode",
"@type": "mz:joinModeType"
},
"location": {
"@id": "sc:location",
"@type": "sc:Place"
},
"toot": "http://joinmastodon.org/ns#",
"participantCount": {
"@id": "mz:participantCount",
"@type": "sc:Integer"
},
"uuid": "sc:identifier",
"maximumAttendeeCapacity": "sc:maximumAttendeeCapacity",
"participationMessage": {
"@id": "mz:participationMessage",
"@type": "sc:Text"
},
"openness": {
"@id": "mz:openness",
"@type": "@id"
},
"members": {
"@id": "mz:members",
"@type": "@id"
},
"events": {
"@id": "mz:events",
"@type": "@id"
},
"resources": {
"@id": "mz:resources",
"@type": "@id"
},
"addressCountry": "sc:addressCountry",
"posts": {
"@id": "mz:posts",
"@type": "@id"
},
"commentsEnabled": {
"@id": "pt:commentsEnabled",
"@type": "sc:Boolean"
},
"value": "sc:value",
"PropertyValue": "sc:PropertyValue",
"repliesModerationOptionType": {
"@id": "mz:repliesModerationOptionType",
"@type": "rdfs:Class"
},
"todos": {
"@id": "mz:todos",
"@type": "@id"
},
"ical": "http://www.w3.org/2002/12/cal/ical#",
"postalCode": "sc:postalCode",
"memberCount": {
"@id": "mz:memberCount",
"@type": "sc:Integer"
},
"@language": "und"
}
],
"discoverable": true,
"discussions": "https://mobilizon.fr/@contribateliers/discussions",
"endpoints": {
"discussions": "https://mobilizon.fr/@contribateliers/discussions",
"events": "https://mobilizon.fr/@contribateliers/events",
"members": "https://mobilizon.fr/@contribateliers/members",
"posts": "https://mobilizon.fr/@contribateliers/posts",
"resources": "https://mobilizon.fr/@contribateliers/resources",
"sharedInbox": "https://mobilizon.fr/inbox",
"todos": "https://mobilizon.fr/@contribateliers/todos"
},
"events": "https://mobilizon.fr/@contribateliers/events",
"followers": "https://mobilizon.fr/@contribateliers/followers",
"following": "https://mobilizon.fr/@contribateliers/following",
"icon": {
"mediaType": null,
"type": "Image",
"url": "https://mobilizon.fr/media/a94f7f8da4b39f6b375f55bd8664abff4ae61d33496df7ee23ad6bf473c3632f.png?name=contribateliers%27s%20avatar.png"
},
"id": "https://mobilizon.fr/@contribateliers",
"image": {
"mediaType": null,
"type": "Image",
"url": "https://mobilizon.fr/media/7fe251dd5f8b5abcea10c31b655c09afee457efdd49f3087ba78b054b3f0dbeb.jpg?name=contribateliers%27s%20banner.jpg"
},
"inbox": "https://mobilizon.fr/@contribateliers/inbox",
"location": {
"address": {
"addressCountry": null,
"addressLocality": null,
"addressRegion": null,
"postalCode": null,
"streetAddress": null,
"type": "PostalAddress"
},
"id": "https://mobilizon.fr/address/935f207e-4c0f-4818-8762-51d6ab2ed27e",
"name": null,
"type": "Place"
},
"manuallyApprovesFollowers": false,
"memberCount": 13,
"members": "https://mobilizon.fr/@contribateliers/members",
"name": "Contribateliers",
"openness": "open",
"outbox": "https://mobilizon.fr/@contribateliers/outbox",
"posts": "https://mobilizon.fr/@contribateliers/posts",
"preferredUsername": "contribateliers",
"publicKey": {
"id": "https://mobilizon.fr/@contribateliers#main-key",
"owner": "https://mobilizon.fr/@contribateliers",
"publicKeyPem": "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEA1laog+0zKOkGdUHfWQ+lIJq5LOwWzGKLeqXzSdvaUzfk2X5Q5gTf\nbjh7pWJaWo2uxrIeNKRJSpmxeBn/lNR3+OrG05/MiYW6Y42q+ZL18coUDht46u23\nHH9+fFblmvY905cNslJ4/NouxpN0ai5JytZOzlNnJCan241rS4gkeLAy+LDW6UOd\nTvDPMJQlrAl8gr+OamRUxd4RL/8ws7/FbqNiAetXmN/5knjkQe5rFi0D/3fQtWEv\n/kSTG6CmnBhpeKE8eqp1sD0+CMROfOb7ceVIpJvUKAPHsENRE6DQFF9j3wl8AXjd\ndtGxTyOYYaMXCPyAUBjH/Rt6uV5Bc5x2CQIDAQAB\n-----END RSA PUBLIC KEY-----\n\n"
},
"resources": "https://mobilizon.fr/@contribateliers/resources",
"summary": "<p>Des ateliers pour contribuer au libre sans rien y connaître.</p>",
"todos": "https://mobilizon.fr/@contribateliers/todos",
"type": "Group",
"url": "https://mobilizon.fr/@contribateliers"
}

View file

@ -0,0 +1,144 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"addressRegion": "sc:addressRegion",
"timezone": {
"@id": "mz:timezone",
"@type": "sc:Text"
},
"isOnline": {
"@id": "mz:isOnline",
"@type": "sc:Boolean"
},
"pt": "https://joinpeertube.org/ns#",
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"inLanguage": "sc:inLanguage",
"address": {
"@id": "sc:address",
"@type": "sc:PostalAddress"
},
"discoverable": "toot:discoverable",
"repliesModerationOption": {
"@id": "mz:repliesModerationOption",
"@type": "mz:repliesModerationOptionType"
},
"sc": "http://schema.org#",
"mz": "https://joinmobilizon.org/ns#",
"category": "sc:category",
"joinModeType": {
"@id": "mz:joinModeType",
"@type": "rdfs:Class"
},
"Hashtag": "as:Hashtag",
"propertyID": "sc:propertyID",
"PostalAddress": "sc:PostalAddress",
"discussions": {
"@id": "mz:discussions",
"@type": "@id"
},
"remainingAttendeeCapacity": "sc:remainingAttendeeCapacity",
"streetAddress": "sc:streetAddress",
"anonymousParticipationEnabled": {
"@id": "mz:anonymousParticipationEnabled",
"@type": "sc:Boolean"
},
"addressLocality": "sc:addressLocality",
"joinMode": {
"@id": "mz:joinMode",
"@type": "mz:joinModeType"
},
"location": {
"@id": "sc:location",
"@type": "sc:Place"
},
"toot": "http://joinmastodon.org/ns#",
"participantCount": {
"@id": "mz:participantCount",
"@type": "sc:Integer"
},
"uuid": "sc:identifier",
"maximumAttendeeCapacity": "sc:maximumAttendeeCapacity",
"participationMessage": {
"@id": "mz:participationMessage",
"@type": "sc:Text"
},
"openness": {
"@id": "mz:openness",
"@type": "@id"
},
"members": {
"@id": "mz:members",
"@type": "@id"
},
"events": {
"@id": "mz:events",
"@type": "@id"
},
"resources": {
"@id": "mz:resources",
"@type": "@id"
},
"addressCountry": "sc:addressCountry",
"posts": {
"@id": "mz:posts",
"@type": "@id"
},
"commentsEnabled": {
"@id": "pt:commentsEnabled",
"@type": "sc:Boolean"
},
"value": "sc:value",
"PropertyValue": "sc:PropertyValue",
"repliesModerationOptionType": {
"@id": "mz:repliesModerationOptionType",
"@type": "rdfs:Class"
},
"todos": {
"@id": "mz:todos",
"@type": "@id"
},
"ical": "http://www.w3.org/2002/12/cal/ical#",
"postalCode": "sc:postalCode",
"memberCount": {
"@id": "mz:memberCount",
"@type": "sc:Integer"
},
"@language": "und"
}
],
"discoverable": false,
"discussions": null,
"endpoints": {
"discussions": null,
"events": null,
"members": null,
"posts": null,
"resources": null,
"sharedInbox": "https://mobilizon.fr/inbox",
"todos": null
},
"events": null,
"followers": "https://mobilizon.fr/@sanof44/followers",
"following": "https://mobilizon.fr/@sanof44/following",
"id": "https://mobilizon.fr/@sanof44",
"inbox": "https://mobilizon.fr/@sanof44/inbox",
"manuallyApprovesFollowers": false,
"members": null,
"name": "Sanof44",
"openness": "moderated",
"outbox": "https://mobilizon.fr/@sanof44/outbox",
"posts": null,
"preferredUsername": "sanof44",
"publicKey": {
"id": "https://mobilizon.fr/@sanof44#main-key",
"owner": "https://mobilizon.fr/@sanof44",
"publicKeyPem": "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAneK5zzdQQ/6ElSpPv1mj34IMoIIHcTK+iEjZYd85yPfG4krK5bqI\nkUw0TUXFekpntLfDSsGohayrvD2WhN2b499y/A9wdl77RVLIAcBfE3UXr/TfDnjh\nsQEEzV4ghcYaKmXZa/ct2sSt6poT/WhahVweEugfyA75UHgW5VA7nS5URhd7uZUw\nS2CI8fXigDbJlB9AqcxvR7Uncgsn0JCCt5boP8X1jDrh5PEsqsqePm9ZpxvvX4WD\n1yib/ZPBsTo50hJgHoA9bLXO14KvAOeIrzgOlJkyjWTQ+rk+5ewXIZuM0ECPEzAC\nRcpopBjqk07lMxPu1OMG4D+oI0n0K+PgNwIDAQAB\n-----END RSA PUBLIC KEY-----\n\n"
},
"resources": null,
"summary": "",
"todos": null,
"type": "Person",
"url": "https://mobilizon.fr/@sanof44"
}

View file

@ -167,12 +167,9 @@ impl ApubObject for ApubPost {
let community = page.extract_community(context, request_counter).await?; let community = page.extract_community(context, request_counter).await?;
let form = if !page.is_mod_action(context).await? { let form = if !page.is_mod_action(context).await? {
let url = if let Some(attachment) = page.attachment.first() { let first_attachment = page.attachment.into_iter().map(|a| a.url()).next();
Some(match attachment { let url = if first_attachment.is_some() {
// url as sent by Lemmy (new) first_attachment
Attachment::Link(link) => link.href.clone(),
Attachment::Image(image) => image.url.clone(),
})
} else if page.kind == PageType::Video { } else if page.kind == PageType::Video {
// we cant display videos directly, so insert a link to external video page // we cant display videos directly, so insert a link to external video page
Some(page.id.inner().clone()) Some(page.id.inner().clone())

View file

@ -167,4 +167,11 @@ mod tests {
test_json::<Page>("assets/peertube/objects/video.json").unwrap(); test_json::<Page>("assets/peertube/objects/video.json").unwrap();
test_json::<Note>("assets/peertube/objects/note.json").unwrap(); test_json::<Note>("assets/peertube/objects/note.json").unwrap();
} }
#[test]
fn test_parse_object_mobilizon() {
test_json::<Group>("assets/mobilizon/objects/group.json").unwrap();
test_json::<Page>("assets/mobilizon/objects/event.json").unwrap();
test_json::<Person>("assets/mobilizon/objects/person.json").unwrap();
}
} }

View file

@ -13,7 +13,10 @@ use activitypub_federation::{
}, },
traits::{ActivityHandler, ApubObject}, traits::{ActivityHandler, ApubObject},
}; };
use activitystreams_kinds::{link::LinkType, object::ImageType}; use activitystreams_kinds::{
link::LinkType,
object::{DocumentType, ImageType},
};
use chrono::{DateTime, FixedOffset}; use chrono::{DateTime, FixedOffset};
use itertools::Itertools; use itertools::Itertools;
use lemmy_db_schema::newtypes::DbUrl; use lemmy_db_schema::newtypes::DbUrl;
@ -29,6 +32,7 @@ pub enum PageType {
Article, Article,
Note, Note,
Video, Video,
Event,
} }
#[skip_serializing_none] #[skip_serializing_none]
@ -80,11 +84,33 @@ pub(crate) struct Image {
pub(crate) url: Url, pub(crate) url: Url,
} }
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Document {
#[serde(rename = "type")]
pub(crate) kind: DocumentType,
pub(crate) url: Url,
}
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)] #[serde(untagged)]
pub(crate) enum Attachment { pub(crate) enum Attachment {
Link(Link), Link(Link),
Image(Image), Image(Image),
Document(Document),
}
impl Attachment {
pub(crate) fn url(self) -> Url {
match self {
// url as sent by Lemmy (new)
Attachment::Link(l) => l.href,
// image sent by lotide
Attachment::Image(i) => i.url,
// sent by mobilizon
Attachment::Document(d) => d.url,
}
}
} }
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]