federails 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/concerns/federails/server/render_collections.rb +19 -0
- data/app/controllers/federails/client/followings_controller.rb +3 -3
- data/app/controllers/federails/server/activities_controller.rb +14 -6
- data/app/controllers/federails/server/actors_controller.rb +16 -7
- data/app/helpers/federails/server_helper.rb +6 -0
- data/app/jobs/federails/application_job.rb +2 -0
- data/app/jobs/federails/fetch_nodeinfo_job.rb +10 -0
- data/app/jobs/federails/notify_inbox_job.rb +0 -2
- data/app/models/concerns/federails/actor_entity.rb +2 -2
- data/app/models/federails/activity.rb +15 -22
- data/app/models/federails/actor.rb +8 -2
- data/app/models/federails/following.rb +3 -3
- data/app/models/federails/host.rb +48 -0
- data/app/views/federails/server/activities/_activity.activitypub.jbuilder +7 -3
- data/app/views/federails/server/actors/_actor.activitypub.jbuilder +7 -6
- data/app/views/federails/server/actors/_tombstone.activitypub.jbuilder +1 -4
- data/app/views/federails/server/followings/_following.activitypub.jbuilder +1 -1
- data/app/views/federails/server/nodeinfo/show.nodeinfo.jbuilder +2 -3
- data/app/views/federails/server/published/_publishable.activitypub.jbuilder +2 -2
- data/app/views/federails/server/published/_tombstone.activitypub.jbuilder +1 -4
- data/app/views/federails/server/shared/ordered_collection.activitypub.jbuilder +6 -0
- data/app/views/federails/server/shared/ordered_collection_page.activitypub.jbuilder +12 -0
- data/app/views/users/show.html.erb +4 -0
- data/db/migrate/20250426061729_create_federails_hosts.rb +22 -0
- data/db/migrate/20251121160720_add_to_and_cc_to_federails_activities.rb +6 -0
- data/lib/federails/configuration.rb +18 -0
- data/lib/federails/data_transformer/note.rb +6 -1
- data/lib/federails/maintenance/hosts_updater.rb +19 -0
- data/lib/federails/utils/context.rb +12 -0
- data/lib/federails/utils/response_codes.rb +11 -0
- data/lib/federails/version.rb +1 -1
- data/lib/federails.rb +11 -3
- data/lib/fediverse/collection.rb +31 -0
- data/lib/fediverse/notifier.rb +39 -12
- data/lib/fediverse/signature.rb +1 -1
- data/lib/fediverse.rb +2 -0
- data/lib/generators/federails/copy_factories/copy_factories_generator.rb +25 -3
- data/lib/generators/federails/install/templates/federails.yml +2 -0
- data/lib/tasks/federails_tasks.rake +5 -0
- metadata +18 -6
- data/app/views/federails/server/activities/outbox.activitypub.jbuilder +0 -18
- data/app/views/federails/server/actors/followers.activitypub.jbuilder +0 -18
- data/app/views/federails/server/actors/following.activitypub.jbuilder +0 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 36117bc1ea548be65aebe4ee505850ecac3233851f07aaae18136188ec1c1077
|
|
4
|
+
data.tar.gz: '0958b68fce09e2775504b28f5227e098470c0cb3c89eb4ca3dec7f5ece871d78'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2f6e4dc1e3554b81a02710b9d893c88ffa77ff7c33e623574378cd7b87a13165297dcd4b22a4ce38e90073a545708d7d82e17e9867b1f345a1ebcad2c1cdf237
|
|
7
|
+
data.tar.gz: a8fb6f9811a9369ee7cf706c64517f47c8a66b335de715b8325e508ca6790dc4e1f7db6ae67b62651920cf3fd467d1c2e23263fb5b4f38f2d40a2c1d5a9cdfc2
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Federails
|
|
2
|
+
module Server
|
|
3
|
+
module RenderCollections
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
def render_collection(actor:, collection:, url_helper:, &items_block)
|
|
7
|
+
if params[:page].present?
|
|
8
|
+
render_collection_page(actor: actor, collection: collection, url_helper: url_helper, items_block: items_block)
|
|
9
|
+
else
|
|
10
|
+
render 'federails/server/shared/ordered_collection', locals: { collection: collection, url_helper: url_helper, actor: actor }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def render_collection_page(collection:, actor:, url_helper:, items_block:)
|
|
15
|
+
render 'federails/server/shared/ordered_collection_page', locals: { collection: collection, url_helper: url_helper, actor: actor, items_block: items_block }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -23,7 +23,7 @@ module Federails
|
|
|
23
23
|
format.json { render :show, status: :ok, location: @following }
|
|
24
24
|
else
|
|
25
25
|
format.html { redirect_to url, alert: I18n.t('controller.followings.accept.error') }
|
|
26
|
-
format.json { render json: @following.errors, status:
|
|
26
|
+
format.json { render json: @following.errors, status: Federails::Utils::ResponseCodes::UNPROCESSABLE_CONTENT }
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
end
|
|
@@ -49,7 +49,7 @@ module Federails
|
|
|
49
49
|
# Renders a 422 instead of a 404
|
|
50
50
|
respond_to do |format|
|
|
51
51
|
format.html { redirect_to federails.client_actors_url, alert: I18n.t('controller.followings.follow.error') }
|
|
52
|
-
format.json { render json: { target_actor: ['does not exist'] }, status:
|
|
52
|
+
format.json { render json: { target_actor: ['does not exist'] }, status: Federails::Utils::ResponseCodes::UNPROCESSABLE_CONTENT }
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
return
|
|
@@ -94,7 +94,7 @@ module Federails
|
|
|
94
94
|
format.json { render :show, status: :created, location: @following }
|
|
95
95
|
else
|
|
96
96
|
format.html { redirect_to url, alert: I18n.t('controller.followings.save_and_render.error') }
|
|
97
|
-
format.json { render json: @following.errors, status:
|
|
97
|
+
format.json { render json: @following.errors, status: Federails::Utils::ResponseCodes::UNPROCESSABLE_CONTENT }
|
|
98
98
|
end
|
|
99
99
|
end
|
|
100
100
|
end
|
|
@@ -3,6 +3,8 @@ require 'fediverse/inbox'
|
|
|
3
3
|
module Federails
|
|
4
4
|
module Server
|
|
5
5
|
class ActivitiesController < Federails::ServerController
|
|
6
|
+
include Federails::Server::RenderCollections
|
|
7
|
+
|
|
6
8
|
before_action :set_activity, only: [:show]
|
|
7
9
|
|
|
8
10
|
# GET /federation/activities
|
|
@@ -10,10 +12,16 @@ module Federails
|
|
|
10
12
|
def outbox
|
|
11
13
|
authorize Federails::Activity, policy_class: Federails::Server::ActivityPolicy
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
actor = Actor.find_param(params[:actor_id])
|
|
16
|
+
activities = policy_scope(Federails::Activity, policy_scope_class: Federails::Server::ActivityPolicy::Scope).where(actor: actor).order(created_at: :desc)
|
|
17
|
+
|
|
18
|
+
render_collection(
|
|
19
|
+
collection: activities.page(params[:page]),
|
|
20
|
+
actor: actor,
|
|
21
|
+
url_helper: :server_actor_outbox_url
|
|
22
|
+
) do |builder, items|
|
|
23
|
+
builder.array! items, partial: 'federails/server/activities/activity', as: :activity, context: false
|
|
24
|
+
end
|
|
17
25
|
end
|
|
18
26
|
|
|
19
27
|
# GET /federation/actors/1/activities/1.json
|
|
@@ -24,12 +32,12 @@ module Federails
|
|
|
24
32
|
skip_authorization
|
|
25
33
|
|
|
26
34
|
payload = payload_from_params
|
|
27
|
-
return head
|
|
35
|
+
return head Federails::Utils::ResponseCodes::UNPROCESSABLE_CONTENT unless payload
|
|
28
36
|
|
|
29
37
|
if Fediverse::Inbox.dispatch_request(payload)
|
|
30
38
|
head :created
|
|
31
39
|
else
|
|
32
|
-
head
|
|
40
|
+
head Federails::Utils::ResponseCodes::UNPROCESSABLE_CONTENT
|
|
33
41
|
end
|
|
34
42
|
end
|
|
35
43
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module Federails
|
|
2
2
|
module Server
|
|
3
3
|
class ActorsController < Federails::ServerController
|
|
4
|
+
include Federails::Server::RenderCollections
|
|
5
|
+
|
|
4
6
|
before_action :set_actor, only: [:show, :followers, :following]
|
|
5
7
|
|
|
6
8
|
# GET /federation/actors/1
|
|
@@ -14,14 +16,26 @@ module Federails
|
|
|
14
16
|
# GET /federation/actors/:id/followers.json
|
|
15
17
|
def followers
|
|
16
18
|
@actors = @actor.followers.order(created_at: :desc)
|
|
17
|
-
|
|
19
|
+
render_collection(
|
|
20
|
+
collection: @actors.page(params[:page]),
|
|
21
|
+
actor: @actor,
|
|
22
|
+
url_helper: :followers_server_actor_url
|
|
23
|
+
) do |builder, items|
|
|
24
|
+
builder.array! items.map(&:federated_url)
|
|
25
|
+
end
|
|
18
26
|
end
|
|
19
27
|
|
|
20
28
|
# GET /federation/actors/:id/followers
|
|
21
29
|
# GET /federation/actors/:id/followers.json
|
|
22
30
|
def following
|
|
23
31
|
@actors = @actor.follows.order(created_at: :desc)
|
|
24
|
-
|
|
32
|
+
render_collection(
|
|
33
|
+
collection: @actors.page(params[:page]),
|
|
34
|
+
actor: @actor,
|
|
35
|
+
url_helper: :following_server_actor_url
|
|
36
|
+
) do |builder, items|
|
|
37
|
+
builder.array! items.map(&:federated_url)
|
|
38
|
+
end
|
|
25
39
|
end
|
|
26
40
|
|
|
27
41
|
private
|
|
@@ -31,11 +45,6 @@ module Federails
|
|
|
31
45
|
@actor = Actor.find_param(params[:id])
|
|
32
46
|
authorize @actor, policy_class: Federails::Server::ActorPolicy
|
|
33
47
|
end
|
|
34
|
-
|
|
35
|
-
def followings_queries
|
|
36
|
-
@total_actors = @actors.count
|
|
37
|
-
@actors = @actors.page(params[:page])
|
|
38
|
-
end
|
|
39
48
|
end
|
|
40
49
|
end
|
|
41
50
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'federails/utils/context'
|
|
2
|
+
|
|
1
3
|
module Federails
|
|
2
4
|
module ServerHelper
|
|
3
5
|
def remote_follow_url
|
|
@@ -8,5 +10,9 @@ module Federails
|
|
|
8
10
|
Rails.application.routes.url_helpers.send(method_name)
|
|
9
11
|
end
|
|
10
12
|
end
|
|
13
|
+
|
|
14
|
+
def set_json_ld_context(json, additional: nil)
|
|
15
|
+
json.set! '@context', Federails::Utils::Context.generate(additional: additional)
|
|
16
|
+
end
|
|
11
17
|
end
|
|
12
18
|
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
require 'fediverse/notifier'
|
|
2
|
+
|
|
3
|
+
module Federails
|
|
4
|
+
class FetchNodeinfoJob < ApplicationJob
|
|
5
|
+
# @param domain [String] Domain to create/update
|
|
6
|
+
def perform(domain)
|
|
7
|
+
Federails::Host.create_or_update domain, min_update_interval: Federails::Configuration.remote_entities_cache_duration
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -156,11 +156,11 @@ module Federails
|
|
|
156
156
|
end
|
|
157
157
|
|
|
158
158
|
def tombstone_federails_actor!
|
|
159
|
-
federails_actor.tombstone!
|
|
159
|
+
federails_actor.presence&.tombstone!
|
|
160
160
|
end
|
|
161
161
|
|
|
162
162
|
def untombstone_federails_actor!
|
|
163
|
-
federails_actor.untombstone!
|
|
163
|
+
federails_actor.presence&.untombstone!
|
|
164
164
|
end
|
|
165
165
|
end
|
|
166
166
|
end
|
|
@@ -24,31 +24,24 @@ module Federails
|
|
|
24
24
|
|
|
25
25
|
after_create_commit :post_to_inboxes
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return [] unless actor.local?
|
|
32
|
-
|
|
33
|
-
case action
|
|
34
|
-
when 'Follow'
|
|
35
|
-
[entity]
|
|
36
|
-
when 'Undo'
|
|
37
|
-
[entity.entity]
|
|
38
|
-
when 'Accept'
|
|
39
|
-
[entity.actor]
|
|
40
|
-
else
|
|
41
|
-
default_recipient_list
|
|
42
|
-
end
|
|
43
|
-
end
|
|
27
|
+
before_validation :set_default_addressing, on: :create
|
|
28
|
+
|
|
29
|
+
serialize :cc, coder: YAML
|
|
30
|
+
serialize :to, coder: YAML
|
|
44
31
|
|
|
45
32
|
private
|
|
46
33
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
34
|
+
# Sets up default public-and-followers addressing unless to and cc are already set
|
|
35
|
+
#
|
|
36
|
+
# This retains compatibility with previous behaviour
|
|
37
|
+
def set_default_addressing
|
|
38
|
+
return if to.present? || cc.present?
|
|
39
|
+
|
|
40
|
+
self.to = [Fediverse::Collection::PUBLIC]
|
|
41
|
+
self.cc = [
|
|
42
|
+
actor.followers_url,
|
|
43
|
+
(entity.try(:followers_url) if entity.try(:local?)),
|
|
44
|
+
].compact.uniq
|
|
52
45
|
end
|
|
53
46
|
|
|
54
47
|
def post_to_inboxes
|
|
@@ -37,12 +37,18 @@ module Federails
|
|
|
37
37
|
has_many :followers, source: :actor, through: :following_followers
|
|
38
38
|
# Actors followed by actor
|
|
39
39
|
has_many :follows, source: :target_actor, through: :following_follows
|
|
40
|
+
belongs_to :host, class_name: 'Federails::Host', foreign_key: :server, primary_key: :domain, inverse_of: :actors, optional: true
|
|
41
|
+
|
|
42
|
+
# Explicitly explain serialization for MariaDB
|
|
43
|
+
attribute :extensions, :json
|
|
40
44
|
|
|
41
45
|
scope :local, -> { where(local: true) }
|
|
42
46
|
scope :distant, -> { where(local: false) }
|
|
43
47
|
scope :tombstoned, -> { where.not(tombstoned_at: nil) }
|
|
44
48
|
scope :not_tombstoned, -> { where(tombstoned_at: nil) }
|
|
45
49
|
|
|
50
|
+
after_create -> { FetchNodeinfoJob.perform_later(server) }, unless: :local?
|
|
51
|
+
|
|
46
52
|
on_federails_delete_requested -> { tombstone! }
|
|
47
53
|
on_federails_undelete_requested -> { untombstone! }
|
|
48
54
|
|
|
@@ -116,7 +122,7 @@ module Federails
|
|
|
116
122
|
# @return [Federails::Following, false]
|
|
117
123
|
def follows?(actor)
|
|
118
124
|
list = following_follows.where target_actor: actor
|
|
119
|
-
return list.first if list.
|
|
125
|
+
return list.first if list.one?
|
|
120
126
|
|
|
121
127
|
false
|
|
122
128
|
end
|
|
@@ -126,7 +132,7 @@ module Federails
|
|
|
126
132
|
# @return [Federails::Following, false]
|
|
127
133
|
def followed_by?(actor)
|
|
128
134
|
list = following_followers.where actor: actor
|
|
129
|
-
return list.first if list.
|
|
135
|
+
return list.first if list.one?
|
|
130
136
|
|
|
131
137
|
false
|
|
132
138
|
end
|
|
@@ -28,7 +28,7 @@ module Federails
|
|
|
28
28
|
|
|
29
29
|
def accept!
|
|
30
30
|
update! status: :accepted
|
|
31
|
-
Activity.create! actor: target_actor, action: 'Accept', entity: self
|
|
31
|
+
Activity.create! actor: target_actor, action: 'Accept', entity: self, to: [actor.federated_url]
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def follow_activity
|
|
@@ -62,11 +62,11 @@ module Federails
|
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
def create_activity
|
|
65
|
-
Activity.create! actor: actor, action: 'Follow', entity: target_actor
|
|
65
|
+
Activity.create! actor: actor, action: 'Follow', entity: target_actor, to: [target_actor.federated_url]
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def destroy_activity
|
|
69
|
-
Activity.create! actor: actor, action: 'Undo', entity: follow_activity
|
|
69
|
+
Activity.create! actor: actor, action: 'Undo', entity: follow_activity, to: [target_actor.federated_url]
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'fediverse/node_info'
|
|
2
|
+
|
|
3
|
+
module Federails
|
|
4
|
+
class Host < ApplicationRecord
|
|
5
|
+
attribute :protocols, :json
|
|
6
|
+
attribute :services, :json
|
|
7
|
+
|
|
8
|
+
validates :domain, presence: true, allow_blank: false, uniqueness: true
|
|
9
|
+
|
|
10
|
+
# No "dependent" option here as this is not a hard reference, and we want to keep the actors if the host gets deleted
|
|
11
|
+
has_many :actors, class_name: 'Federails::Actor', primary_key: :domain, foreign_key: :server, inverse_of: :host # rubocop:disable Rails/HasManyOrHasOneDependent
|
|
12
|
+
|
|
13
|
+
scope :same_app, -> { where software_name: Configuration.app_name }
|
|
14
|
+
scope :same_app_and_version, -> { same_app.where app_version: Configuration.app_version }
|
|
15
|
+
|
|
16
|
+
def same_app?
|
|
17
|
+
software_name == Configuration.app_name
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def same_app_and_version?
|
|
21
|
+
software_name == Configuration.app_name && app_version == Configuration.app_version
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Update from remote data
|
|
25
|
+
def sync!
|
|
26
|
+
update! Fediverse::NodeInfo.fetch(domain)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class << self
|
|
30
|
+
# Creates or update a Host
|
|
31
|
+
#
|
|
32
|
+
# @param domain [String] Domain to check
|
|
33
|
+
# @param min_update_interval [Integer, ActiveSupport::Duration] Minimum amount of seconds since the last update to fetch fresh data
|
|
34
|
+
def create_or_update(domain, min_update_interval: 0)
|
|
35
|
+
entry = find_or_initialize_by domain: domain
|
|
36
|
+
return if min_update_interval && entry.persisted? && (entry.updated_at + min_update_interval) > Time.current
|
|
37
|
+
|
|
38
|
+
entry.sync!
|
|
39
|
+
|
|
40
|
+
entry
|
|
41
|
+
rescue Fediverse::NodeInfo::NoActivityPubError
|
|
42
|
+
Rails.logger.info { "#{domain} does not provide ActivityPub service" }
|
|
43
|
+
rescue Federails::Utils::JsonRequest::UnhandledResponseStatus, Faraday::SSLError => e
|
|
44
|
+
Rails.logger.info { "Error connecting to #{domain}: '#{e.message}'" }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
context = true unless context == false
|
|
2
2
|
addressing = true unless addressing == false
|
|
3
|
-
json
|
|
3
|
+
set_json_ld_context(json) if context
|
|
4
4
|
|
|
5
5
|
json.id Federails::Engine.routes.url_helpers.server_actor_activity_url activity.actor, activity
|
|
6
6
|
json.type activity.action
|
|
7
7
|
json.actor activity.actor.federated_url
|
|
8
8
|
if addressing
|
|
9
|
-
json.
|
|
10
|
-
|
|
9
|
+
json.merge!(
|
|
10
|
+
{
|
|
11
|
+
to: activity.to,
|
|
12
|
+
cc: activity.cc,
|
|
13
|
+
}.compact
|
|
14
|
+
)
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
if activity.entity.is_a? Federails::Activity
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
actor_data = actor.entity&.to_activitypub_object || {}
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
]
|
|
3
|
+
set_json_ld_context(
|
|
4
|
+
json,
|
|
5
|
+
additional: [
|
|
6
|
+
'https://w3id.org/security/v1',
|
|
7
|
+
actor_data.delete(:@context),
|
|
8
|
+
]
|
|
9
|
+
)
|
|
9
10
|
|
|
10
11
|
json.id actor.federated_url
|
|
11
12
|
json.name actor.name
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
json.version '2.0'
|
|
2
|
-
|
|
3
|
-
json.software name: Federails::Configuration.app_name,
|
|
2
|
+
json.software name: Federails::Configuration.app_name&.parameterize,
|
|
4
3
|
version: Federails::Configuration.app_version
|
|
5
4
|
json.protocols [
|
|
6
5
|
'activitypub',
|
|
@@ -17,4 +16,4 @@ if @has_user_counts
|
|
|
17
16
|
activeHalfyear: @active_halfyear,
|
|
18
17
|
}
|
|
19
18
|
end
|
|
20
|
-
json.metadata({})
|
|
19
|
+
json.metadata(Federails::Configuration.nodeinfo_metadata || {})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
context = true unless context == false
|
|
2
|
-
json
|
|
2
|
+
set_json_ld_context(json) if context
|
|
3
3
|
|
|
4
4
|
publishable.to_activitypub_object.each_pair do |key, value|
|
|
5
5
|
json.set! key, value
|
|
@@ -7,5 +7,5 @@ end
|
|
|
7
7
|
|
|
8
8
|
json.id publishable.federated_url
|
|
9
9
|
json.actor publishable.federails_actor.federated_url
|
|
10
|
-
json.to [
|
|
10
|
+
json.to [Fediverse::Collection::PUBLIC]
|
|
11
11
|
json.cc [publishable.federails_actor.followers_url]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
set_json_ld_context(json)
|
|
2
|
+
json.type 'OrderedCollectionPage'
|
|
3
|
+
json.id send(url_helper, actor, page: collection.current_page)
|
|
4
|
+
json.partOf send(url_helper, actor)
|
|
5
|
+
json.first send(url_helper, actor, page: 1)
|
|
6
|
+
json.last send(url_helper, actor, page: collection.total_pages)
|
|
7
|
+
json.next send(url_helper, actor, page: collection.next_page) if collection.next_page
|
|
8
|
+
json.prev send(url_helper, actor, page: collection.prev_page) if collection.prev_page
|
|
9
|
+
json.totalItems collection.total_count
|
|
10
|
+
json.orderedItems do
|
|
11
|
+
items_block.call(json, collection)
|
|
12
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class CreateFederailsHosts < ActiveRecord::Migration[7.2]
|
|
2
|
+
def change
|
|
3
|
+
create_table :federails_hosts do |t|
|
|
4
|
+
t.string :domain, null: false, default: nil
|
|
5
|
+
t.string :nodeinfo_url
|
|
6
|
+
t.string :software_name
|
|
7
|
+
t.string :software_version
|
|
8
|
+
|
|
9
|
+
# Uncomment the lines below if you use PostgreSQL
|
|
10
|
+
# t.jsonb :protocols, default: []
|
|
11
|
+
# t.jsonb :services, default: {}
|
|
12
|
+
#
|
|
13
|
+
# Other databases
|
|
14
|
+
t.text :protocols, default: '[]'
|
|
15
|
+
t.text :services, default: '{}'
|
|
16
|
+
|
|
17
|
+
t.timestamps
|
|
18
|
+
|
|
19
|
+
t.index :domain, unique: true
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -35,6 +35,14 @@ module Federails
|
|
|
35
35
|
@@open_registrations.is_a?(Proc) ? @@open_registrations.call : @@open_registrations
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
# Custom metadata for nodeinfo
|
|
39
|
+
# Can either be a static hash, or a Proc which will be called to get the state.
|
|
40
|
+
mattr_writer :nodeinfo_metadata
|
|
41
|
+
@@nodeinfo_metadata = {}
|
|
42
|
+
def self.nodeinfo_metadata
|
|
43
|
+
@@nodeinfo_metadata.is_a?(Proc) ? @@nodeinfo_metadata.call : @@nodeinfo_metadata
|
|
44
|
+
end
|
|
45
|
+
|
|
38
46
|
# Application layout
|
|
39
47
|
mattr_accessor :app_layout
|
|
40
48
|
@@app_layout = nil
|
|
@@ -81,6 +89,16 @@ module Federails
|
|
|
81
89
|
Federails::Engine.routes.default_url_options[:port] = value
|
|
82
90
|
end
|
|
83
91
|
|
|
92
|
+
# Default amount of seconds to consider that a remote entity could be updated
|
|
93
|
+
#
|
|
94
|
+
# This setting is used for hosts information only, for now.
|
|
95
|
+
mattr_accessor :remote_entities_cache_duration
|
|
96
|
+
@@remote_entities_cache_duration = 1.day
|
|
97
|
+
|
|
98
|
+
# Job queue name
|
|
99
|
+
mattr_accessor :job_queue
|
|
100
|
+
@@job_queue = :default
|
|
101
|
+
|
|
84
102
|
# List of actor types (classes using Federails::ActorEntity)
|
|
85
103
|
mattr_reader :actor_types
|
|
86
104
|
@@actor_types = {}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'federails/utils/context'
|
|
2
|
+
|
|
1
3
|
module Federails
|
|
2
4
|
module DataTransformer
|
|
3
5
|
module Note
|
|
@@ -17,7 +19,10 @@ module Federails
|
|
|
17
19
|
# - https://www.w3.org/TR/activitystreams-vocabulary/#dfn-object
|
|
18
20
|
# - https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note
|
|
19
21
|
def self.to_federation(entity, content:, name: nil, custom: {})
|
|
20
|
-
custom
|
|
22
|
+
# Merge default and custom contexts
|
|
23
|
+
context = Utils::Context.generate(additional: custom.delete('@context'))
|
|
24
|
+
# Merge in standard Note fields
|
|
25
|
+
custom.merge '@context' => context,
|
|
21
26
|
'id' => entity.federated_url,
|
|
22
27
|
'type' => 'Note',
|
|
23
28
|
'name' => name,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Federails
|
|
2
|
+
module Maintenance
|
|
3
|
+
class HostsUpdater
|
|
4
|
+
class << self
|
|
5
|
+
# Update information for all known hosts, and complete if some are missing
|
|
6
|
+
def run(cache_interval: nil)
|
|
7
|
+
cache_interval ||= Federails::Configuration.remote_entities_cache_duration
|
|
8
|
+
|
|
9
|
+
domains = Federails::Actor.distant.distinct(:server).pluck(:server) + Federails::Host.pluck(:domain)
|
|
10
|
+
domains.uniq!
|
|
11
|
+
|
|
12
|
+
domains.each do |domain|
|
|
13
|
+
Federails::Host.create_or_update domain, min_update_interval: cache_interval
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Federails
|
|
2
|
+
module Utils
|
|
3
|
+
module Context
|
|
4
|
+
class << self
|
|
5
|
+
def generate(additional: nil)
|
|
6
|
+
activity_streams = 'https://www.w3.org/ns/activitystreams'
|
|
7
|
+
additional.nil? ? activity_streams : [activity_streams, additional].flatten.compact
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/federails/version.rb
CHANGED
data/lib/federails.rb
CHANGED
|
@@ -7,6 +7,9 @@ require 'federails/engine'
|
|
|
7
7
|
require 'federails/configuration'
|
|
8
8
|
require 'federails/utils/object'
|
|
9
9
|
require 'federails/utils/json_request'
|
|
10
|
+
require 'federails/utils/response_codes'
|
|
11
|
+
|
|
12
|
+
require 'fediverse'
|
|
10
13
|
|
|
11
14
|
# rubocop:disable Style/ClassVars
|
|
12
15
|
|
|
@@ -35,11 +38,14 @@ module Federails
|
|
|
35
38
|
:site_port,
|
|
36
39
|
:enable_discovery,
|
|
37
40
|
:open_registrations,
|
|
41
|
+
:nodeinfo_metadata,
|
|
38
42
|
:app_layout,
|
|
39
43
|
:server_routes_path,
|
|
40
44
|
:client_routes_path,
|
|
41
45
|
:remote_follow_url_method,
|
|
42
46
|
:base_client_controller,
|
|
47
|
+
:remote_entities_cache_duration,
|
|
48
|
+
:job_queue,
|
|
43
49
|
].each { |key| Configuration.send :"#{key}=", config[key] if config.key?(key) }
|
|
44
50
|
end
|
|
45
51
|
|
|
@@ -82,9 +88,11 @@ module Federails
|
|
|
82
88
|
# @return [Hash, nil] Data entity configuration
|
|
83
89
|
def data_entity_handler_for(hash)
|
|
84
90
|
data_entity_handlers_for(hash['type']).find do |handler|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
if handler[:filter_method] || handler[:class].respond_to?(DEFAULT_DATA_FILTER_METHOD)
|
|
92
|
+
handler[:class].send(handler[:filter_method] || DEFAULT_DATA_FILTER_METHOD, hash)
|
|
93
|
+
else
|
|
94
|
+
true
|
|
95
|
+
end
|
|
88
96
|
end
|
|
89
97
|
end
|
|
90
98
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Fediverse
|
|
2
|
+
class Collection < Array
|
|
3
|
+
PUBLIC = 'https://www.w3.org/ns/activitystreams#Public'.freeze
|
|
4
|
+
|
|
5
|
+
attr_reader :total_items, :id, :type
|
|
6
|
+
|
|
7
|
+
def self.fetch(url)
|
|
8
|
+
new.fetch(url)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def fetch(url)
|
|
12
|
+
json = Fediverse::Request.dereference(url)
|
|
13
|
+
@total_items = json['totalItems']
|
|
14
|
+
@id = json['id']
|
|
15
|
+
@type = json['type']
|
|
16
|
+
raise Errors::NotACollection unless %w[OrderedCollection Collection].include?(@type)
|
|
17
|
+
|
|
18
|
+
next_url = json['first']
|
|
19
|
+
while next_url
|
|
20
|
+
page = Fediverse::Request.dereference(next_url)
|
|
21
|
+
concat(page['orderedItems'] || page['items'])
|
|
22
|
+
next_url = page['next']
|
|
23
|
+
end
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
module Errors
|
|
29
|
+
class NotACollection < StandardError; end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/fediverse/notifier.rb
CHANGED
|
@@ -7,18 +7,45 @@ module Fediverse
|
|
|
7
7
|
#
|
|
8
8
|
# @param activity [Federails::Activity]
|
|
9
9
|
def post_to_inboxes(activity)
|
|
10
|
-
actors
|
|
11
|
-
|
|
10
|
+
# Get the list of actors we need to send the activity to
|
|
11
|
+
inboxes = inboxes_for(activity)
|
|
12
|
+
Rails.logger.debug('Nobody to notice') && return if inboxes.none?
|
|
12
13
|
|
|
14
|
+
# Deliver to each inbox
|
|
13
15
|
message = payload(activity)
|
|
14
|
-
|
|
15
|
-
Rails.logger.debug { "Sending activity ##{activity.id} to #{
|
|
16
|
-
post_to_inbox(
|
|
16
|
+
inboxes.each do |url|
|
|
17
|
+
Rails.logger.debug { "Sending activity ##{activity.id} to inbox at #{url}" }
|
|
18
|
+
post_to_inbox(inbox_url: url, message: message, from: activity.actor)
|
|
17
19
|
end
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
private
|
|
21
23
|
|
|
24
|
+
# Determines the list of inboxes that the activity should be delivered to
|
|
25
|
+
#
|
|
26
|
+
# @return [Array<Federails::Actor>]
|
|
27
|
+
def inboxes_for(activity)
|
|
28
|
+
return [] unless activity.actor.local?
|
|
29
|
+
|
|
30
|
+
[activity.to, activity.cc].flatten.compact.reject { |x| x == Fediverse::Collection::PUBLIC }.map do |url|
|
|
31
|
+
actor = Federails::Actor.find_or_create_by_federation_url(url)
|
|
32
|
+
[actor.inbox_url]
|
|
33
|
+
rescue ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid
|
|
34
|
+
collection_to_actors(url).map(&:inbox_url)
|
|
35
|
+
end.flatten.compact
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def collection_to_actors(url)
|
|
39
|
+
collection = Collection.fetch(url)
|
|
40
|
+
collection.filter_map do |actor_url|
|
|
41
|
+
Federails::Actor.find_or_create_by_federation_url(actor_url)
|
|
42
|
+
rescue ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid
|
|
43
|
+
nil
|
|
44
|
+
end
|
|
45
|
+
rescue Errors::NotACollection
|
|
46
|
+
[]
|
|
47
|
+
end
|
|
48
|
+
|
|
22
49
|
def payload(activity)
|
|
23
50
|
Federails::ServerController.renderer.new.render(
|
|
24
51
|
template: 'federails/server/activities/show',
|
|
@@ -27,27 +54,27 @@ module Fediverse
|
|
|
27
54
|
)
|
|
28
55
|
end
|
|
29
56
|
|
|
30
|
-
def post_to_inbox(
|
|
57
|
+
def post_to_inbox(inbox_url:, message:, from: nil)
|
|
31
58
|
conn = Faraday.default_connection
|
|
32
59
|
conn.builder.build_response(
|
|
33
60
|
conn,
|
|
34
|
-
signed_request(
|
|
61
|
+
signed_request(url: inbox_url, message: message, from: from)
|
|
35
62
|
)
|
|
36
63
|
end
|
|
37
64
|
|
|
38
|
-
def signed_request(
|
|
39
|
-
req = request(
|
|
65
|
+
def signed_request(url:, message:, from:)
|
|
66
|
+
req = request(url: url, message: message)
|
|
40
67
|
req.headers['Signature'] = Fediverse::Signature.sign(sender: from, request: req) if from
|
|
41
68
|
req
|
|
42
69
|
end
|
|
43
70
|
|
|
44
|
-
def request(
|
|
71
|
+
def request(url:, message:) # rubocop:todo Metrics/AbcSize
|
|
45
72
|
Faraday.default_connection.build_request(:post) do |req|
|
|
46
|
-
req.url
|
|
73
|
+
req.url url
|
|
47
74
|
req.body = message
|
|
48
75
|
req.headers['Content-Type'] = Mime[:activitypub].to_s
|
|
49
76
|
req.headers['Accept'] = Mime[:activitypub].to_s
|
|
50
|
-
req.headers['Host'] = URI.parse(
|
|
77
|
+
req.headers['Host'] = URI.parse(url).host
|
|
51
78
|
req.headers['Date'] = Time.now.utc.httpdate
|
|
52
79
|
req.headers['Digest'] = digest(message)
|
|
53
80
|
end
|
data/lib/fediverse/signature.rb
CHANGED
|
@@ -20,7 +20,7 @@ module Fediverse
|
|
|
20
20
|
raise 'Unsigned headers' unless request.headers['Signature']
|
|
21
21
|
|
|
22
22
|
signature_header = request.headers['Signature'].split(',').to_h do |pair|
|
|
23
|
-
/\A(?<key
|
|
23
|
+
/\A(?<key>\w+)="(?<value>.*)"\z/ =~ pair
|
|
24
24
|
[key, value]
|
|
25
25
|
end
|
|
26
26
|
|
data/lib/fediverse.rb
CHANGED
|
@@ -1,20 +1,42 @@
|
|
|
1
1
|
module Federails
|
|
2
2
|
class CopyFactoriesGenerator < Rails::Generators::Base
|
|
3
3
|
SOURCE_DIRECTORY = File.expand_path('../../../../spec/factories/federails', __dir__)
|
|
4
|
+
FACTORY_DEFINITION_REGEX = /(FactoryBot.define do\n\s+factory) :(\w+),/
|
|
4
5
|
|
|
5
6
|
source_root SOURCE_DIRECTORY
|
|
6
7
|
|
|
8
|
+
def initialize
|
|
9
|
+
super
|
|
10
|
+
@files = []
|
|
11
|
+
@factories = []
|
|
12
|
+
end
|
|
13
|
+
|
|
7
14
|
def copy_factories
|
|
8
15
|
dest = Rails.root.join('spec', 'factories')
|
|
9
16
|
|
|
10
|
-
Dir.entries(SOURCE_DIRECTORY)
|
|
11
|
-
.each do |node|
|
|
17
|
+
Dir.entries(SOURCE_DIRECTORY).each do |node|
|
|
12
18
|
source_path = File.join(SOURCE_DIRECTORY, node)
|
|
13
19
|
next unless File.file?(source_path) && node.match?(/\.rb\Z/)
|
|
14
20
|
|
|
15
21
|
file_path = File.join(dest, "federails_#{node}")
|
|
16
22
|
copy_file node, file_path
|
|
17
|
-
|
|
23
|
+
@files << file_path
|
|
24
|
+
@factories << File.read(file_path).match(FACTORY_DEFINITION_REGEX)&.[](2)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
substitute_values!
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def substitute_values!
|
|
33
|
+
@factories.compact!
|
|
34
|
+
@files.each do |file|
|
|
35
|
+
gsub_file file, FACTORY_DEFINITION_REGEX, '\1 :federails_\2,'
|
|
36
|
+
|
|
37
|
+
@factories.each do |factory|
|
|
38
|
+
gsub_file file, ":#{factory}", ":federails_#{factory}"
|
|
39
|
+
end
|
|
18
40
|
end
|
|
19
41
|
end
|
|
20
42
|
end
|
|
@@ -10,6 +10,8 @@ defaults: &defaults
|
|
|
10
10
|
app_layout: 'layouts/application'
|
|
11
11
|
server_routes_path: federation
|
|
12
12
|
client_routes_path: app
|
|
13
|
+
job_queue: default
|
|
14
|
+
#remote_entities_cache_duration: 86400 # 1 day in seconds
|
|
13
15
|
#base_client_controller: ::ActionController::Base
|
|
14
16
|
|
|
15
17
|
development:
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: federails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Manuel Tancoigne
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-03-25 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: faraday
|
|
@@ -133,6 +134,7 @@ files:
|
|
|
133
134
|
- Rakefile
|
|
134
135
|
- app/assets/config/federails_manifest.js
|
|
135
136
|
- app/assets/stylesheets/federails/application.css
|
|
137
|
+
- app/controllers/concerns/federails/server/render_collections.rb
|
|
136
138
|
- app/controllers/federails/client/activities_controller.rb
|
|
137
139
|
- app/controllers/federails/client/actors_controller.rb
|
|
138
140
|
- app/controllers/federails/client/followings_controller.rb
|
|
@@ -146,6 +148,7 @@ files:
|
|
|
146
148
|
- app/controllers/federails/server_controller.rb
|
|
147
149
|
- app/helpers/federails/server_helper.rb
|
|
148
150
|
- app/jobs/federails/application_job.rb
|
|
151
|
+
- app/jobs/federails/fetch_nodeinfo_job.rb
|
|
149
152
|
- app/jobs/federails/notify_inbox_job.rb
|
|
150
153
|
- app/mailers/federails/application_mailer.rb
|
|
151
154
|
- app/models/concerns/federails/actor_entity.rb
|
|
@@ -156,6 +159,7 @@ files:
|
|
|
156
159
|
- app/models/federails/actor.rb
|
|
157
160
|
- app/models/federails/application_record.rb
|
|
158
161
|
- app/models/federails/following.rb
|
|
162
|
+
- app/models/federails/host.rb
|
|
159
163
|
- app/policies/federails/client/activity_policy.rb
|
|
160
164
|
- app/policies/federails/client/actor_policy.rb
|
|
161
165
|
- app/policies/federails/client/following_policy.rb
|
|
@@ -189,12 +193,9 @@ files:
|
|
|
189
193
|
- app/views/federails/client/followings/show.html.erb
|
|
190
194
|
- app/views/federails/client/followings/show.json.jbuilder
|
|
191
195
|
- app/views/federails/server/activities/_activity.activitypub.jbuilder
|
|
192
|
-
- app/views/federails/server/activities/outbox.activitypub.jbuilder
|
|
193
196
|
- app/views/federails/server/activities/show.activitypub.jbuilder
|
|
194
197
|
- app/views/federails/server/actors/_actor.activitypub.jbuilder
|
|
195
198
|
- app/views/federails/server/actors/_tombstone.activitypub.jbuilder
|
|
196
|
-
- app/views/federails/server/actors/followers.activitypub.jbuilder
|
|
197
|
-
- app/views/federails/server/actors/following.activitypub.jbuilder
|
|
198
199
|
- app/views/federails/server/actors/show.activitypub.jbuilder
|
|
199
200
|
- app/views/federails/server/followings/_following.activitypub.jbuilder
|
|
200
201
|
- app/views/federails/server/followings/show.activitypub.jbuilder
|
|
@@ -203,8 +204,11 @@ files:
|
|
|
203
204
|
- app/views/federails/server/published/_publishable.activitypub.jbuilder
|
|
204
205
|
- app/views/federails/server/published/_tombstone.activitypub.jbuilder
|
|
205
206
|
- app/views/federails/server/published/show.activitypub.jbuilder
|
|
207
|
+
- app/views/federails/server/shared/ordered_collection.activitypub.jbuilder
|
|
208
|
+
- app/views/federails/server/shared/ordered_collection_page.activitypub.jbuilder
|
|
206
209
|
- app/views/federails/server/web_finger/find.jrd.jbuilder
|
|
207
210
|
- app/views/federails/server/web_finger/host_meta.xrd.erb
|
|
211
|
+
- app/views/users/show.html.erb
|
|
208
212
|
- config/initializers/mime_types.rb
|
|
209
213
|
- config/routes.rb
|
|
210
214
|
- db/migrate/20200712133150_create_federails_actors.rb
|
|
@@ -216,17 +220,23 @@ files:
|
|
|
216
220
|
- db/migrate/20250301082500_add_local_to_actors.rb
|
|
217
221
|
- db/migrate/20250329123939_add_actor_type_to_actors.rb
|
|
218
222
|
- db/migrate/20250329123940_add_tombstoned_at_to_actors.rb
|
|
223
|
+
- db/migrate/20250426061729_create_federails_hosts.rb
|
|
224
|
+
- db/migrate/20251121160720_add_to_and_cc_to_federails_activities.rb
|
|
219
225
|
- lib/federails.rb
|
|
220
226
|
- lib/federails/configuration.rb
|
|
221
227
|
- lib/federails/data_transformer/note.rb
|
|
222
228
|
- lib/federails/engine.rb
|
|
223
229
|
- lib/federails/maintenance/actors_updater.rb
|
|
230
|
+
- lib/federails/maintenance/hosts_updater.rb
|
|
224
231
|
- lib/federails/utils/actor.rb
|
|
232
|
+
- lib/federails/utils/context.rb
|
|
225
233
|
- lib/federails/utils/host.rb
|
|
226
234
|
- lib/federails/utils/json_request.rb
|
|
227
235
|
- lib/federails/utils/object.rb
|
|
236
|
+
- lib/federails/utils/response_codes.rb
|
|
228
237
|
- lib/federails/version.rb
|
|
229
238
|
- lib/fediverse.rb
|
|
239
|
+
- lib/fediverse/collection.rb
|
|
230
240
|
- lib/fediverse/inbox.rb
|
|
231
241
|
- lib/fediverse/node_info.rb
|
|
232
242
|
- lib/fediverse/notifier.rb
|
|
@@ -253,6 +263,7 @@ metadata:
|
|
|
253
263
|
homepage_uri: https://experimentslabs.com
|
|
254
264
|
source_code_uri: https://gitlab.com/experimentslabs/federails/
|
|
255
265
|
changelog_uri: https://gitlab.com/experimentslabs/federails/-/blob/main/CHANGELOG.md
|
|
266
|
+
post_install_message:
|
|
256
267
|
rdoc_options: []
|
|
257
268
|
require_paths:
|
|
258
269
|
- lib
|
|
@@ -267,7 +278,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
267
278
|
- !ruby/object:Gem::Version
|
|
268
279
|
version: '0'
|
|
269
280
|
requirements: []
|
|
270
|
-
rubygems_version: 3.
|
|
281
|
+
rubygems_version: 3.3.7
|
|
282
|
+
signing_key:
|
|
271
283
|
specification_version: 4
|
|
272
284
|
summary: An ActivityPub engine for Ruby on Rails
|
|
273
285
|
test_files: []
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
json.set!('@context', 'https://www.w3.org/ns/activitystreams')
|
|
2
|
-
collection_id = @actor.outbox_url
|
|
3
|
-
json.id collection_id
|
|
4
|
-
json.type 'OrderedCollectionPage'
|
|
5
|
-
json.totalItems @total_activities
|
|
6
|
-
json.first collection_id
|
|
7
|
-
json.last @activities.total_pages == 1 ? Federails::Engine.routes.url_helpers.server_actor_outbox_url(@actor) : Federails::Engine.routes.url_helpers.server_actor_outbox_url(@actor, page: @activities.total_pages)
|
|
8
|
-
json.current do |j|
|
|
9
|
-
j.type 'OrderedCollectionPage'
|
|
10
|
-
j.id @activities.current_page == 1 ? Federails::Engine.routes.url_helpers.server_actor_outbox_url(@actor) : Federails::Engine.routes.url_helpers.server_actor_outbox_url(@actor, page: @activities.current_page)
|
|
11
|
-
j.partOf collection_id
|
|
12
|
-
j.next @activities.next_page
|
|
13
|
-
j.prev @activities.prev_page
|
|
14
|
-
j.totalItems @total_activities
|
|
15
|
-
j.orderedItems do
|
|
16
|
-
json.array! @activities, partial: 'federails/server/activities/activity', as: :activity, context: false
|
|
17
|
-
end
|
|
18
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
json.set!('@context', 'https://www.w3.org/ns/activitystreams')
|
|
2
|
-
collection_id = @actor.followers_url
|
|
3
|
-
json.id collection_id
|
|
4
|
-
json.type 'OrderedCollectionPage'
|
|
5
|
-
json.totalItems @total_actors
|
|
6
|
-
json.first Federails::Engine.routes.url_helpers.followers_server_actor_url(@actor)
|
|
7
|
-
json.last @actors.total_pages == 1 ? Federails::Engine.routes.url_helpers.followers_server_actor_url(@actor) : Federails::Engine.routes.url_helpers.followers_server_actor_url(@actor, page: @actors.total_pages)
|
|
8
|
-
json.current do |j|
|
|
9
|
-
j.type 'OrderedCollectionPage'
|
|
10
|
-
j.id @actors.current_page == 1 ? Federails::Engine.routes.url_helpers.followers_server_actor_url(@actor) : Federails::Engine.routes.url_helpers.followers_server_actor_url(@actor, page: @actors.current_page)
|
|
11
|
-
j.partOf collection_id
|
|
12
|
-
j.next @actors.next_page
|
|
13
|
-
j.prev @actors.prev_page
|
|
14
|
-
j.totalItems @total_actors
|
|
15
|
-
j.orderedItems do
|
|
16
|
-
json.array! @actors.map(&:federated_url)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
json.set!('@context', 'https://www.w3.org/ns/activitystreams')
|
|
2
|
-
collection_id = @actor.followings_url
|
|
3
|
-
json.id collection_id
|
|
4
|
-
json.type 'OrderedCollectionPage'
|
|
5
|
-
json.totalItems @total_actors
|
|
6
|
-
json.first Federails::Engine.routes.url_helpers.following_server_actor_url(@actor)
|
|
7
|
-
json.last @actors.total_pages == 1 ? Federails::Engine.routes.url_helpers.following_server_actor_url(@actor) : Federails::Engine.routes.url_helpers.following_server_actor_url(@actor, page: @actors.total_pages)
|
|
8
|
-
json.current do |j|
|
|
9
|
-
j.type 'OrderedCollectionPage'
|
|
10
|
-
j.id @actors.current_page == 1 ? Federails::Engine.routes.url_helpers.following_server_actor_url(@actor) : Federails::Engine.routes.url_helpers.following_server_actor_url(@actor, page: @actors.current_page)
|
|
11
|
-
j.partOf collection_id
|
|
12
|
-
j.next @actors.next_page
|
|
13
|
-
j.prev @actors.prev_page
|
|
14
|
-
j.totalItems @total_actors
|
|
15
|
-
j.orderedItems do
|
|
16
|
-
json.array! @actors.map(&:federated_url)
|
|
17
|
-
end
|
|
18
|
-
end
|