From d9460970d1747ace1deb7d64ec57186f1f875468 Mon Sep 17 00:00:00 2001 From: James Smith Date: Wed, 22 Jan 2025 23:25:44 +0000 Subject: [PATCH 01/10] create a Creator object if the remote actor has the right concreteType --- app/controllers/follows_controller.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/controllers/follows_controller.rb b/app/controllers/follows_controller.rb index 16254a880..ae1af4439 100644 --- a/app/controllers/follows_controller.rb +++ b/app/controllers/follows_controller.rb @@ -46,6 +46,8 @@ def follow_remote_actor authorize Federails::Following, :create? @actor = Federails::Actor.find_param(params[:id]) current_user.follow(@actor) + # If the remote actor has a known Manyfold type, we can create a real object for it + find_or_create_entity(@actor) redirect_to root_url, notice: t(".followed", actor: @actor.at_address) end @@ -76,4 +78,11 @@ def get_target id = params[followable_param] @target = policy_scope(followable).find_param(id) end + + def find_or_create_entity(actor) + case actor.extensions&.dig("concreteType") + when "Creator" + Creator.create name: actor.name, links_attributes: [{url: actor.profile_url}], federails_actor: actor + end + end end From 2dac1c3c104e0cc327eb0c045172ed76112691a2 Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 23 Jan 2025 10:22:14 +0000 Subject: [PATCH 02/10] link to original profile from remote creator card --- app/controllers/follows_controller.rb | 7 ++++++- app/models/concerns/federails_common.rb | 4 ++++ app/views/creators/_creator.html.erb | 13 ++++++++++--- config/locales/creators/en.yml | 2 ++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/controllers/follows_controller.rb b/app/controllers/follows_controller.rb index ae1af4439..d20c41e61 100644 --- a/app/controllers/follows_controller.rb +++ b/app/controllers/follows_controller.rb @@ -82,7 +82,12 @@ def get_target def find_or_create_entity(actor) case actor.extensions&.dig("concreteType") when "Creator" - Creator.create name: actor.name, links_attributes: [{url: actor.profile_url}], federails_actor: actor + Creator.create( + name: actor.name, + slug: actor.username, + links_attributes: [], + federails_actor: actor + ) end end end diff --git a/app/models/concerns/federails_common.rb b/app/models/concerns/federails_common.rb index b990e968b..a2b0f45a3 100644 --- a/app/models/concerns/federails_common.rb +++ b/app/models/concerns/federails_common.rb @@ -10,4 +10,8 @@ def federails_actor end act end + + def remote? + !federails_actor&.local? + end end diff --git a/app/views/creators/_creator.html.erb b/app/views/creators/_creator.html.erb index 2163052c0..3cc082f2b 100644 --- a/app/views/creators/_creator.html.erb +++ b/app/views/creators/_creator.html.erb @@ -1,7 +1,10 @@
-
<%= creator.name %>
+
+ <%= icon 'globe', t(".distant") if creator.remote? %> + <%= creator.name %> +
<% if creator.caption %> <%= sanitize creator.caption %> <% end %> @@ -10,8 +13,12 @@
  • <%= link_to t("sites.%{site}" % {site: link.site}), link.url %>
  • <% end %> - <%= link_to "#{policy_scope(Model).where(creator: creator).count} #{Model.model_name.human count: policy_scope(Model).where(creator: creator).count}", creator, {class: "btn btn-primary", "aria-label": translate(".models_button.label", name: creator.name)} if policy(creator).show? %> - <%= link_to icon("pencil-fill", t(".edit_button.text")), edit_creator_path(creator), {class: "btn btn-outline-secondary", "aria-label": translate(".edit_button.label", name: creator.name)} if policy(creator).edit? %> + <% if creator.remote? %> + <%= link_to t(".remote_view", server: creator.federails_actor.server), creator.federails_actor.profile_url, {class: "btn btn-primary" , "aria-label": translate(".models_button.label", name: creator.name)} if policy(creator).show? %> + <% else %> + <%= link_to "#{policy_scope(Model).where(creator: creator).count} #{Model.model_name.human count: policy_scope(Model).where(creator: creator).count}", creator, {class: "btn btn-primary", "aria-label": translate(".models_button.label", name: creator.name)} if policy(creator).show? %> + <%= link_to icon("pencil-fill", t(".edit_button.text")), edit_creator_path(creator), {class: "btn btn-outline-secondary", "aria-label": translate(".edit_button.label", name: creator.name)} if policy(creator).edit? %> + <% end %>
    diff --git a/config/locales/creators/en.yml b/config/locales/creators/en.yml index b4768ea6e..1ce359904 100644 --- a/config/locales/creators/en.yml +++ b/config/locales/creators/en.yml @@ -4,11 +4,13 @@ en: create: success: New creator details saved. creator: + distant: Remote creator edit_button: label: Edit creator %{name} text: Edit models_button: label: Show models by %{name} + remote_view: View on %{server} destroy: success: Creator deleted! form: From cdc25d1beb686a093251ac9a58d11bcfa9195359 Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 23 Jan 2025 11:11:22 +0000 Subject: [PATCH 03/10] move creator creation from activitystreams into model --- app/controllers/follows_controller.rb | 7 +------ app/models/creator.rb | 9 +++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/controllers/follows_controller.rb b/app/controllers/follows_controller.rb index d20c41e61..ab28a0bb3 100644 --- a/app/controllers/follows_controller.rb +++ b/app/controllers/follows_controller.rb @@ -82,12 +82,7 @@ def get_target def find_or_create_entity(actor) case actor.extensions&.dig("concreteType") when "Creator" - Creator.create( - name: actor.name, - slug: actor.username, - links_attributes: [], - federails_actor: actor - ) + Creator.create_from_activitypub_object(actor) end end end diff --git a/app/models/creator.rb b/app/models/creator.rb index e50fd1579..fa69541fa 100644 --- a/app/models/creator.rb +++ b/app/models/creator.rb @@ -32,6 +32,15 @@ def summary_html "
    #{"
    #{caption}
    " if caption}#{Kramdown::Document.new(notes).to_html.rstrip if notes}
    " end + def self.create_from_activitypub_object(actor) + create( + name: actor.name, + slug: actor.username, + links_attributes: [], + federails_actor: actor + ) + end + def to_activitypub_object { "@context": { From 401c9f0d26a20275179852f957464e2e3456225e Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 23 Jan 2025 11:32:01 +0000 Subject: [PATCH 04/10] remove server name from visit button --- app/views/creators/_creator.html.erb | 2 +- config/locales/creators/en.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/creators/_creator.html.erb b/app/views/creators/_creator.html.erb index 3cc082f2b..a09b8714f 100644 --- a/app/views/creators/_creator.html.erb +++ b/app/views/creators/_creator.html.erb @@ -14,7 +14,7 @@ <% end %> <% if creator.remote? %> - <%= link_to t(".remote_view", server: creator.federails_actor.server), creator.federails_actor.profile_url, {class: "btn btn-primary" , "aria-label": translate(".models_button.label", name: creator.name)} if policy(creator).show? %> + <%= link_to t(".remote_view"), creator.federails_actor.profile_url, {class: "btn btn-primary" , "aria-label": translate(".models_button.label", name: creator.name)} if policy(creator).show? %> <% else %> <%= link_to "#{policy_scope(Model).where(creator: creator).count} #{Model.model_name.human count: policy_scope(Model).where(creator: creator).count}", creator, {class: "btn btn-primary", "aria-label": translate(".models_button.label", name: creator.name)} if policy(creator).show? %> <%= link_to icon("pencil-fill", t(".edit_button.text")), edit_creator_path(creator), {class: "btn btn-outline-secondary", "aria-label": translate(".edit_button.label", name: creator.name)} if policy(creator).edit? %> diff --git a/config/locales/creators/en.yml b/config/locales/creators/en.yml index 1ce359904..cc3f60676 100644 --- a/config/locales/creators/en.yml +++ b/config/locales/creators/en.yml @@ -10,7 +10,7 @@ en: text: Edit models_button: label: Show models by %{name} - remote_view: View on %{server} + remote_view: Visit destroy: success: Creator deleted! form: From 4bfadad719b20c09b9dbf99bf3743f332a1ba7b3 Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 23 Jan 2025 14:51:49 +0000 Subject: [PATCH 05/10] avoid double-creating actors --- Gemfile | 2 +- Gemfile.lock | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 467c4f147..6043d1e2f 100644 --- a/Gemfile +++ b/Gemfile @@ -148,7 +148,7 @@ gem "better_content_security_policy", "~> 0.1.4" gem "devise_zxcvbn", "~> 6.0" gem "ransack", "~> 4.2" -gem "federails", git: "https://gitlab.com/experimentslabs/federails", branch: "main" +gem "federails", git: "https://gitlab.com/experimentslabs/federails", branch: "avoid-double-create" gem "federails-moderation", "~> 0.2" gem "caber" diff --git a/Gemfile.lock b/Gemfile.lock index 334b1fbe8..31e78f4fa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,8 +9,8 @@ GIT GIT remote: https://gitlab.com/experimentslabs/federails - revision: 6698571f51f886a5fd5ba6fb57221c55d4d4d3b4 - branch: main + revision: 6ee94ba7ca869e543b55b0d568d412c5f90a788f + branch: avoid-double-create specs: federails (0.5.0) faraday @@ -435,7 +435,6 @@ GEM net-protocol (0.2.2) timeout net-smtp (0.5.0) - net-protocol nio4r (2.7.4) nokogiri (1.18.2) mini_portile2 (~> 2.8.2) From 631e7bd93707d9f551e1449202631af42e29a600 Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 23 Jan 2025 14:52:11 +0000 Subject: [PATCH 06/10] don't create entities twice --- app/controllers/follows_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/follows_controller.rb b/app/controllers/follows_controller.rb index ab28a0bb3..4ec6cf2f2 100644 --- a/app/controllers/follows_controller.rb +++ b/app/controllers/follows_controller.rb @@ -80,6 +80,7 @@ def get_target end def find_or_create_entity(actor) + return entity if actor.entity case actor.extensions&.dig("concreteType") when "Creator" Creator.create_from_activitypub_object(actor) From eb4f003be8bd52170b1e8396bc1d7e945a97dbbc Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 23 Jan 2025 14:52:32 +0000 Subject: [PATCH 07/10] add links from remote creator --- app/models/creator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/creator.rb b/app/models/creator.rb index fa69541fa..84423abe4 100644 --- a/app/models/creator.rb +++ b/app/models/creator.rb @@ -36,7 +36,7 @@ def self.create_from_activitypub_object(actor) create( name: actor.name, slug: actor.username, - links_attributes: [], + links_attributes: actor.extensions["attachment"]&.select { |it| it["type"] == "Link" }&.map { |it| {url: it["href"]} }, federails_actor: actor ) end From c30b1eb2ae4513c0b207795353bf3b069daa0b2d Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 23 Jan 2025 15:26:05 +0000 Subject: [PATCH 08/10] extract caption and notes for creator --- app/models/creator.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/models/creator.rb b/app/models/creator.rb index 84423abe4..5e10733a8 100644 --- a/app/models/creator.rb +++ b/app/models/creator.rb @@ -33,10 +33,13 @@ def summary_html end def self.create_from_activitypub_object(actor) + matches = actor.extensions["summary"].match(/
    (.+)<\/header>

    (.+)<\/p><\/section>/) create( name: actor.name, slug: actor.username, links_attributes: actor.extensions["attachment"]&.select { |it| it["type"] == "Link" }&.map { |it| {url: it["href"]} }, + caption: matches[1], + notes: matches[2], federails_actor: actor ) end From 36e5cbcb2d25a6e66dc0d6889020e2e1807e6bb1 Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 23 Jan 2025 16:09:45 +0000 Subject: [PATCH 09/10] customise UI for remote creators --- app/views/creators/_creator.html.erb | 5 +++-- app/views/creators/show.html.erb | 13 +++++++++++-- config/locales/creators/en.yml | 6 +++++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/views/creators/_creator.html.erb b/app/views/creators/_creator.html.erb index a09b8714f..585670d5f 100644 --- a/app/views/creators/_creator.html.erb +++ b/app/views/creators/_creator.html.erb @@ -2,7 +2,7 @@

    - <%= icon 'globe', t(".distant") if creator.remote? %> + <%= icon "globe2", t(".distant") if creator.remote? %> <%= creator.name %>
    <% if creator.caption %> @@ -14,7 +14,8 @@ <% end %> <% if creator.remote? %> - <%= link_to t(".remote_view"), creator.federails_actor.profile_url, {class: "btn btn-primary" , "aria-label": translate(".models_button.label", name: creator.name)} if policy(creator).show? %> + <%= link_to "#{policy_scope(Model).where(creator: creator).count} #{Model.model_name.human count: policy_scope(Model).where(creator: creator).count}", creator, {class: "btn btn-primary", "aria-label": translate(".models_button.remote_label", name: creator.name)} if policy(creator).show? %> + <%= link_to icon("globe2", t(".visit_button.text")), creator.federails_actor.profile_url, {class: "btn btn-outline-secondary", "aria-label": translate(".visit_button.label", name: creator.name, target: "new")} %> <% else %> <%= link_to "#{policy_scope(Model).where(creator: creator).count} #{Model.model_name.human count: policy_scope(Model).where(creator: creator).count}", creator, {class: "btn btn-primary", "aria-label": translate(".models_button.label", name: creator.name)} if policy(creator).show? %> <%= link_to icon("pencil-fill", t(".edit_button.text")), edit_creator_path(creator), {class: "btn btn-outline-secondary", "aria-label": translate(".edit_button.label", name: creator.name)} if policy(creator).edit? %> diff --git a/app/views/creators/show.html.erb b/app/views/creators/show.html.erb index 3aacabb5a..bbc628301 100644 --- a/app/views/creators/show.html.erb +++ b/app/views/creators/show.html.erb @@ -8,8 +8,17 @@
    <%= content_tag(:div, class: "text-center") do %> - <%= content_tag(:h2) { @creator.name } %> -

    @<%= @creator.federails_actor.at_address if SiteSettings.federation_enabled? %>

    +

    + <%= icon "globe2", t(".distant") if @creator.remote? %> + <%= @creator.name %> +

    +

    + <% if @creator.remote? %> + <%= link_to "@" + @creator.federails_actor.at_address, @creator.federails_actor.profile_url, target: "new" %> + <% else %> + @<%= @creator.federails_actor.at_address if SiteSettings.federation_enabled? %> + <% end %> +

    <%= render FollowButtonComponent.new(follower: current_user, target: @creator) %> <% end %>
    diff --git a/config/locales/creators/en.yml b/config/locales/creators/en.yml index cc3f60676..ac385433d 100644 --- a/config/locales/creators/en.yml +++ b/config/locales/creators/en.yml @@ -10,7 +10,10 @@ en: text: Edit models_button: label: Show models by %{name} - remote_view: Visit + remote_label: Show local models by %{name} + visit_button: + label: Visit + text: Visit original profile destroy: success: Creator deleted! form: @@ -24,6 +27,7 @@ en: index: skip_creators: Skip creator list show: + distant: Remote creator edit: Edit Creator Profile unassigned: caption: All the models without a known creator. From 7fcf5cb7a7b242160e911f47921b5bd5336ec3f5 Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 23 Jan 2025 17:16:13 +0000 Subject: [PATCH 10/10] fix net-protocol dependency --- Gemfile.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Gemfile.lock b/Gemfile.lock index 31e78f4fa..7a665b72f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -435,6 +435,7 @@ GEM net-protocol (0.2.2) timeout net-smtp (0.5.0) + net-protocol nio4r (2.7.4) nokogiri (1.18.2) mini_portile2 (~> 2.8.2)