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..7a665b72f 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 diff --git a/app/controllers/follows_controller.rb b/app/controllers/follows_controller.rb index 16254a880..4ec6cf2f2 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,12 @@ def get_target id = params[followable_param] @target = policy_scope(followable).find_param(id) 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) + 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/models/creator.rb b/app/models/creator.rb index 323e3c622..83e71d8d3 100644 --- a/app/models/creator.rb +++ b/app/models/creator.rb @@ -32,6 +32,18 @@ def summary_html "
#{"
#{caption}
" if caption}#{Kramdown::Document.new(notes).to_html.rstrip if notes}
" 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 + def to_activitypub_object { "@context": { diff --git a/app/views/creators/_creator.html.erb b/app/views/creators/_creator.html.erb index 2163052c0..585670d5f 100644 --- a/app/views/creators/_creator.html.erb +++ b/app/views/creators/_creator.html.erb @@ -1,7 +1,10 @@

-
<%= creator.name %>
+
+ <%= icon "globe2", t(".distant") if creator.remote? %> + <%= creator.name %> +
<% if creator.caption %> <%= sanitize creator.caption %> <% end %> @@ -10,8 +13,13 @@
  • <%= 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 "#{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? %> + <% end %>
    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 b4768ea6e..ac385433d 100644 --- a/config/locales/creators/en.yml +++ b/config/locales/creators/en.yml @@ -4,11 +4,16 @@ 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_label: Show local models by %{name} + visit_button: + label: Visit + text: Visit original profile destroy: success: Creator deleted! form: @@ -22,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.