diff --git a/docs/contribute/activity_pub.md b/docs/contribute/activity_pub.md index 47986abe9..88f383e06 100644 --- a/docs/contribute/activity_pub.md +++ b/docs/contribute/activity_pub.md @@ -10,7 +10,7 @@ To match usernames to actors, Mobilizon uses [WebFinger](https://tools.ietf.org/ ## Instance subscriptions -Instances subscribe to each other through an internal actor named `relay@instance.tld` that publishes (through `Announce`) every created content to it's followers. Each content creation share is saved so that updates and deletes are correctly sent to every +Instances subscribe to each other through an internal actor named `relay@instance.tld` that publishes (through `Announce`) every created content to it's followers. Each content creation share is saved so that updates and deletes are correctly sent to every relay subscriber. ## Activities @@ -46,6 +46,9 @@ See [the corresponding issue](https://framagit.org/framasoft/mobilizon/issues/32 Accepted values: `allow_all`, `closed`, `moderated` (not used at the moment) +!!! info + We also support PeerTube's `commentEnabled` property as a fallback. It is set to `true` only when `repliesModeration` is equal to `allow_all`. + Example: ```json { @@ -53,6 +56,7 @@ Example: "...", { "mz": "https://joinmobilizon.org/ns#", + "pt": "https://joinpeertube.org/ns#", "repliesModerationOption": { "@id": "mz:repliesModerationOption", "@type": "mz:repliesModerationOptionType" @@ -60,11 +64,16 @@ Example: "repliesModerationOptionType": { "@id": "mz:repliesModerationOptionType", "@type": "rdfs:Class" + }, + "commentsEnabled": { + "@id": "pt:commentsEnabled", + "@type": "sc:Boolean" } } ], "...": "...", "repliesModerationOption": "allow_all", + "commentsEnabled": true, "type": "Event", "url": "http://mobilizon1.com/events/8cf76e9f-c426-4912-9cd6-c7030b969611" } @@ -102,3 +111,61 @@ Example: "url": "http://mobilizon1.com/events/8cf76e9f-c426-4912-9cd6-c7030b969611" } ``` + +#### location + +We use Schema.org's `location` property on `Event`. +[The ActivityStream vocabulary to represent places](https://www.w3.org/TR/activitystreams-vocabulary/#places) is quite limited so instead of using `Place` from ActivityStreams we use `Place` from Schema.org. + +A [Schema.org `Place` type](https://schema.org/Place) has [an `address` property](https://schema.org/address), which we assume to be [of `PostalAddress` type](https://schema.org/PostalAddress) and [a `geo` property](https://schema.org/geo), which is assumed to be of [`GeoCoordinates` type](https://schema.org/GeoCoordinates). + +```json +{ + "@context": [ + "...", + { + "GeoCoordinates": "sc:GeoCoordinates", + "Place": "sc:Place", + "PostalAddress": "sc:PostalAddress", + "address": { + "@id": "sc:address", + "@type": "sc:PostalAddress" + }, + "addressCountry": "sc:addressCountry", + "addressLocality": "sc:addressLocality", + "addressRegion": "sc:addressRegion", + "geo": { + "@id": "sc:geo", + "@type": "sc:GeoCoordinates" + }, + "location": { + "@id": "sc:location", + "@type": "sc:Place" + }, + "postalCode": "sc:postalCode", + "sc": "http://schema.org#", + "streetAddress": "sc:streetAddress", + } + ], + "id": "http://mobilizon2.com/events/945f350d-a3e6-4bcd-9bf2-0bd2e4d353c5", + "location": { + "address": { + "addressCountry": "France", + "addressLocality": "Lyon", + "addressRegion": "Auvergne-Rhône-Alpes", + "postalCode": "69007", + "streetAddress": "10 Rue Jangot", + "type": "PostalAddress" + }, + "geo": { + "latitude": 4.8425657, + "longitude": 45.7517141, + "type": "GeoCoordinates" + }, + "id": "http://mobilizon2.com/address/bdf7fb53-7177-46f3-8fb3-93c25a802522", + "name": "10 Rue Jangot", + "type": "Place" + }, + "type": "Event" +} +``` \ No newline at end of file diff --git a/lib/mobilizon/actors/actors.ex b/lib/mobilizon/actors/actors.ex index 05fc1c3de..a92710859 100644 --- a/lib/mobilizon/actors/actors.ex +++ b/lib/mobilizon/actors/actors.ex @@ -249,6 +249,7 @@ defmodule Mobilizon.Actors do case transaction do {:ok, %{actor: %Actor{} = actor}} -> + {:ok, true} = Cachex.del(:activity_pub, "actor_#{actor.preferred_username}") {:ok, actor} {:error, remove, error, _} when remove in [:remove_banner, :remove_avatar] -> diff --git a/lib/service/activity_pub/activity_pub.ex b/lib/service/activity_pub/activity_pub.ex index 4c612c803..298ba8690 100644 --- a/lib/service/activity_pub/activity_pub.ex +++ b/lib/service/activity_pub/activity_pub.ex @@ -328,6 +328,7 @@ defmodule Mobilizon.Service.ActivityPub do with audience <- Audience.calculate_to_and_cc_from_mentions(event), {:ok, %Event{} = event} <- Events.delete_event(event), + {:ok, true} <- Cachex.del(:activity_pub, "event_#{event.uuid}"), {:ok, %Tombstone{} = _tombstone} <- Tombstone.create_tombstone(%{uri: event.url, actor_id: actor.id}), Share.delete_all_by_uri(event.url), @@ -350,6 +351,7 @@ defmodule Mobilizon.Service.ActivityPub do with audience <- Audience.calculate_to_and_cc_from_mentions(comment), {:ok, %Comment{} = comment} <- Events.delete_comment(comment), + {:ok, true} <- Cachex.del(:activity_pub, "comment_#{comment.uuid}"), {:ok, %Tombstone{} = _tombstone} <- Tombstone.create_tombstone(%{uri: comment.url, actor_id: actor.id}), Share.delete_all_by_uri(comment.url), @@ -730,6 +732,7 @@ defmodule Mobilizon.Service.ActivityPub do ) do with args <- prepare_args_for_event(args), {:ok, %Event{} = new_event} <- Events.update_event(old_event, args), + {:ok, true} <- Cachex.del(:activity_pub, "event_#{new_event.uuid}"), event_as_data <- Convertible.model_to_as(new_event), audience <- Audience.calculate_to_and_cc_from_mentions(new_event), @@ -748,6 +751,7 @@ defmodule Mobilizon.Service.ActivityPub do defp update_actor(%Actor{} = old_actor, args, additional) do with {:ok, %Actor{} = new_actor} <- Actors.update_actor(old_actor, args), actor_as_data <- Convertible.model_to_as(new_actor), + {:ok, true} <- Cachex.del(:activity_pub, "actor_#{new_actor.preferred_username}"), audience <- Audience.calculate_to_and_cc_from_mentions(new_actor), additional <- Map.merge(additional, %{"actor" => old_actor.url}), diff --git a/lib/service/activity_pub/converter/event.ex b/lib/service/activity_pub/converter/event.ex index a273b87f1..d02065fe8 100644 --- a/lib/service/activity_pub/converter/event.ex +++ b/lib/service/activity_pub/converter/event.ex @@ -119,6 +119,7 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Event do "tag" => event.tags |> ConverterUtils.build_tags(), "maximumAttendeeCapacity" => event.options.maximum_attendee_capacity, "repliesModerationOption" => event.options.comment_moderation, + "commentsEnabled" => event.options.comment_moderation == :allow_all, # "draft" => event.draft, "ical:status" => event.status |> to_string |> String.upcase(), "id" => event.url, @@ -140,7 +141,12 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Event do defp get_options(object) do %{ maximum_attendee_capacity: object["maximumAttendeeCapacity"], - comment_moderation: object["repliesModerationOption"] + comment_moderation: + Map.get( + object, + "repliesModerationOption", + if(Map.get(object, "commentsEnabled", true), do: :allow_all, else: :closed) + ) } end diff --git a/lib/service/activity_pub/utils.ex b/lib/service/activity_pub/utils.ex index 94c06a16a..dc8e7eb95 100644 --- a/lib/service/activity_pub/utils.ex +++ b/lib/service/activity_pub/utils.ex @@ -32,10 +32,31 @@ defmodule Mobilizon.Service.ActivityPub.Utils do %{ "sc" => "http://schema.org#", "ical" => "http://www.w3.org/2002/12/cal/ical#", + "pt" => "https://joinpeertube.org/ns#", "Hashtag" => "as:Hashtag", "category" => "sc:category", "uuid" => "sc:identifier", "maximumAttendeeCapacity" => "sc:maximumAttendeeCapacity", + "location" => %{ + "@id" => "sc:location", + "@type" => "sc:Place" + }, + "Place" => "sc:Place", + "PostalAddress" => "sc:PostalAddress", + "GeoCoordinates" => "sc:GeoCoordinates", + "address" => %{ + "@id" => "sc:address", + "@type" => "sc:PostalAddress" + }, + "geo" => %{ + "@id" => "sc:geo", + "@type" => "sc:GeoCoordinates" + }, + "addressCountry" => "sc:addressCountry", + "addressRegion" => "sc:addressRegion", + "postalCode" => "sc:postalCode", + "addressLocality" => "sc:addressLocality", + "streetAddress" => "sc:streetAddress", "mz" => "https://joinmobilizon.org/ns#", "repliesModerationOptionType" => %{ "@id" => "mz:repliesModerationOptionType", @@ -45,6 +66,10 @@ defmodule Mobilizon.Service.ActivityPub.Utils do "@id" => "mz:repliesModerationOption", "@type" => "mz:repliesModerationOptionType" }, + "commentsEnabled" => %{ + "@type" => "sc:Boolean", + "@id" => "pt:commentsEnabled" + }, "joinModeType" => %{ "@id" => "mz:joinModeType", "@type" => "rdfs:Class"