about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/lib/activitypub/activity/create.rb12
-rw-r--r--app/lib/activitypub/adapter.rb1
-rw-r--r--app/serializers/activitypub/note_serializer.rb12
3 files changed, 21 insertions, 4 deletions
diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb
index 08dd98e94..f09caaae4 100644
--- a/app/lib/activitypub/activity/create.rb
+++ b/app/lib/activitypub/activity/create.rb
@@ -137,7 +137,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
       # If there is at least one silent mention, then the status can be considered
       # as a limited-audience status, and not strictly a direct message, but only
       # if we considered a direct message in the first place
-      next unless @params[:visibility] == :direct
+      next unless @params[:visibility] == :direct && direct_message.nil?
 
       @params[:visibility] = :limited
     end
@@ -148,7 +148,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
 
     @mentions << Mention.new(account_id: @options[:delivered_to_account_id], silent: true)
 
-    return unless @params[:visibility] == :direct
+    return unless @params[:visibility] == :direct && direct_message.nil?
 
     @params[:visibility] = :limited
   end
@@ -159,7 +159,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
     delivered_to_account = Account.find(@options[:delivered_to_account_id])
 
     @status.mentions.create(account: delivered_to_account, silent: true)
-    @status.update(visibility: :limited) if @status.direct_visibility?
+    @status.update(visibility: :limited) if @status.direct_visibility? && direct_message.nil?
 
     return unless delivered_to_account.following?(@account)
 
@@ -358,6 +358,8 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
       :unlisted
     elsif equals_or_includes?(audience_to, @account.followers_url)
       :private
+    elsif direct_message == false
+      :limited
     else
       :direct
     end
@@ -368,6 +370,10 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
     equals_or_includes?(audience_to, uri) || equals_or_includes?(audience_cc, uri)
   end
 
+  def direct_message
+    @object['directMessage']
+  end
+
   def replied_to_status
     return @replied_to_status if defined?(@replied_to_status)
 
diff --git a/app/lib/activitypub/adapter.rb b/app/lib/activitypub/adapter.rb
index 634ed29fa..712c48823 100644
--- a/app/lib/activitypub/adapter.rb
+++ b/app/lib/activitypub/adapter.rb
@@ -7,6 +7,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
   }.freeze
 
   CONTEXT_EXTENSION_MAP = {
+    direct_message: { 'litepub': 'http://litepub.social/ns#', 'directMessage': 'litepub:directMessage' },
     manually_approves_followers: { 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers' },
     sensitive: { 'sensitive' => 'as:sensitive' },
     hashtag: { 'Hashtag' => 'as:Hashtag' },
diff --git a/app/serializers/activitypub/note_serializer.rb b/app/serializers/activitypub/note_serializer.rb
index a06cd17d4..a0965790e 100644
--- a/app/serializers/activitypub/note_serializer.rb
+++ b/app/serializers/activitypub/note_serializer.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class ActivityPub::NoteSerializer < ActivityPub::Serializer
-  context_extensions :atom_uri, :conversation, :sensitive, :voters_count
+  context_extensions :atom_uri, :conversation, :sensitive, :voters_count, :direct_message
 
   attributes :id, :type, :summary,
              :in_reply_to, :published, :url,
@@ -12,6 +12,8 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
   attribute :content
   attribute :content_map, if: :language?
 
+  attribute :direct_message, if: :non_public?
+
   has_many :media_attachments, key: :attachment
   has_many :virtual_tags, key: :tag
 
@@ -42,6 +44,14 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
     object.sensitive || (!instance_options[:allow_local_only] && Setting.outgoing_spoilers.present?)
   end
 
+  def direct_message
+    object.direct_visibility?
+  end
+
+  def non_public?
+    !object.distributable?
+  end
+
   def content
     Formatter.instance.format(object)
   end