fedipub 0.0.1 → 0.9.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/README.md +70 -2
- data/Rakefile +5 -9
- data/app/assets/config/fedipub_manifest.js +1 -0
- data/app/assets/stylesheets/fedipub/application.css +15 -0
- data/app/controllers/concerns/fedipub/server/render_collections.rb +19 -0
- data/app/controllers/fedipub/client/activities_controller.rb +27 -0
- data/app/controllers/fedipub/client/actors_controller.rb +54 -0
- data/app/controllers/fedipub/client/followings_controller.rb +103 -0
- data/app/controllers/fedipub/client_controller.rb +9 -0
- data/app/controllers/fedipub/server/activities_controller.rb +78 -0
- data/app/controllers/fedipub/server/actors_controller.rb +50 -0
- data/app/controllers/fedipub/server/followings_controller.rb +19 -0
- data/app/controllers/fedipub/server/nodeinfo_controller.rb +28 -0
- data/app/controllers/fedipub/server/published_controller.rb +30 -0
- data/app/controllers/fedipub/server/web_finger_controller.rb +45 -0
- data/app/controllers/fedipub/server_controller.rb +37 -0
- data/app/helpers/fedipub/server_helper.rb +18 -0
- data/app/jobs/fedipub/application_job.rb +10 -0
- data/app/jobs/fedipub/fetch_nodeinfo_job.rb +10 -0
- data/app/jobs/fedipub/notify_inbox_job.rb +10 -0
- data/app/mailers/fedipub/application_mailer.rb +6 -0
- data/app/models/concerns/fedipub/actor_entity.rb +166 -0
- data/app/models/concerns/fedipub/announceable.rb +18 -0
- data/app/models/concerns/fedipub/data_entity.rb +279 -0
- data/app/models/concerns/fedipub/handles_delete_requests.rb +36 -0
- data/app/models/concerns/fedipub/has_uuid.rb +61 -0
- data/app/models/concerns/fedipub/likeable.rb +29 -0
- data/app/models/fedipub/activity.rb +62 -0
- data/app/models/fedipub/actor.rb +303 -0
- data/app/models/fedipub/application_record.rb +5 -0
- data/app/models/fedipub/following.rb +72 -0
- data/app/models/fedipub/host.rb +48 -0
- data/app/policies/fedipub/client/activity_policy.rb +9 -0
- data/app/policies/fedipub/client/actor_policy.rb +15 -0
- data/app/policies/fedipub/client/following_policy.rb +35 -0
- data/app/policies/fedipub/fedipub_policy.rb +63 -0
- data/app/policies/fedipub/server/activity_policy.rb +9 -0
- data/app/policies/fedipub/server/actor_policy.rb +23 -0
- data/app/policies/fedipub/server/following_policy.rb +6 -0
- data/app/policies/fedipub/server/publishable_policy.rb +15 -0
- data/app/views/fedipub/client/activities/_activity.html.erb +5 -0
- data/app/views/fedipub/client/activities/_activity.json.jbuilder +1 -0
- data/app/views/fedipub/client/activities/_index.json.jbuilder +1 -0
- data/app/views/fedipub/client/activities/feed.html.erb +11 -0
- data/app/views/fedipub/client/activities/feed.json.jbuilder +1 -0
- data/app/views/fedipub/client/activities/index.html.erb +5 -0
- data/app/views/fedipub/client/activities/index.json.jbuilder +1 -0
- data/app/views/fedipub/client/actors/_actor.json.jbuilder +17 -0
- data/app/views/fedipub/client/actors/_lookup_form.html.erb +5 -0
- data/app/views/fedipub/client/actors/gone.html.erb +1 -0
- data/app/views/fedipub/client/actors/index.html.erb +44 -0
- data/app/views/fedipub/client/actors/index.json.jbuilder +1 -0
- data/app/views/fedipub/client/actors/show.html.erb +112 -0
- data/app/views/fedipub/client/actors/show.json.jbuilder +1 -0
- data/app/views/fedipub/client/common/_client_links.html.erb +26 -0
- data/app/views/fedipub/client/followings/_follow.html.erb +4 -0
- data/app/views/fedipub/client/followings/_follow_actions.html.erb +36 -0
- data/app/views/fedipub/client/followings/_follower.html.erb +7 -0
- data/app/views/fedipub/client/followings/_following.json.jbuilder +1 -0
- data/app/views/fedipub/client/followings/_form.html.erb +22 -0
- data/app/views/fedipub/client/followings/index.html.erb +29 -0
- data/app/views/fedipub/client/followings/index.json.jbuilder +1 -0
- data/app/views/fedipub/client/followings/show.html.erb +21 -0
- data/app/views/fedipub/client/followings/show.json.jbuilder +1 -0
- data/app/views/fedipub/server/activities/_activity.activitypub.jbuilder +25 -0
- data/app/views/fedipub/server/activities/show.activitypub.jbuilder +1 -0
- data/app/views/fedipub/server/actors/_actor.activitypub.jbuilder +27 -0
- data/app/views/fedipub/server/actors/_tombstone.activitypub.jbuilder +6 -0
- data/app/views/fedipub/server/actors/show.activitypub.jbuilder +5 -0
- data/app/views/fedipub/server/followings/_following.activitypub.jbuilder +7 -0
- data/app/views/fedipub/server/followings/show.activitypub.jbuilder +1 -0
- data/app/views/fedipub/server/nodeinfo/index.nodeinfo.jbuilder +6 -0
- data/app/views/fedipub/server/nodeinfo/show.nodeinfo.jbuilder +19 -0
- data/app/views/fedipub/server/published/_publishable.activitypub.jbuilder +11 -0
- data/app/views/fedipub/server/published/_tombstone.activitypub.jbuilder +6 -0
- data/app/views/fedipub/server/published/show.activitypub.jbuilder +5 -0
- data/app/views/fedipub/server/shared/ordered_collection.activitypub.jbuilder +6 -0
- data/app/views/fedipub/server/shared/ordered_collection_page.activitypub.jbuilder +12 -0
- data/app/views/fedipub/server/web_finger/find.jrd.jbuilder +24 -0
- data/app/views/fedipub/server/web_finger/host_meta.xrd.erb +5 -0
- data/app/views/users/show.html.erb +4 -0
- data/config/initializers/mime_types.rb +21 -0
- data/config/initializers/security_vocab.rb +53 -0
- data/config/routes.rb +53 -0
- data/db/migrate/20200712133150_create_federails_actors.rb +22 -0
- data/db/migrate/20200712143127_create_federails_followings.rb +14 -0
- data/db/migrate/20200712174938_create_federails_activities.rb +11 -0
- data/db/migrate/20241002094500_add_uuids.rb +13 -0
- data/db/migrate/20241002094501_add_keypair_to_actors.rb +8 -0
- data/db/migrate/20250122160618_add_extensions_to_federails_actors.rb +5 -0
- data/db/migrate/20250301082500_add_local_to_actors.rb +11 -0
- data/db/migrate/20250329123939_add_actor_type_to_actors.rb +5 -0
- data/db/migrate/20250329123940_add_tombstoned_at_to_actors.rb +5 -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/db/migrate/20260421170640_add_result_and_instrument_to_federails_activities.rb +6 -0
- data/db/migrate/20260723113716_rename_federails_to_fedipub.rb +15 -0
- data/lib/fedipub/configuration.rb +119 -0
- data/lib/fedipub/data_transformer/note.rb +36 -0
- data/lib/fedipub/engine.rb +11 -0
- data/lib/fedipub/maintenance/actors_updater.rb +66 -0
- data/lib/fedipub/maintenance/hosts_updater.rb +19 -0
- data/lib/fedipub/utils/actor.rb +85 -0
- data/lib/fedipub/utils/context.rb +12 -0
- data/lib/fedipub/utils/host.rb +54 -0
- data/lib/fedipub/utils/json_request.rb +41 -0
- data/lib/fedipub/utils/object.rb +131 -0
- data/lib/fedipub/utils/response_codes.rb +11 -0
- data/lib/fedipub/version.rb +1 -3
- data/lib/fedipub.rb +127 -4
- data/lib/fediverse/collection.rb +31 -0
- data/lib/fediverse/inbox.rb +110 -0
- data/lib/fediverse/node_info.rb +38 -0
- data/lib/fediverse/notifier.rb +90 -0
- data/lib/fediverse/request.rb +29 -0
- data/lib/fediverse/signature.rb +49 -0
- data/lib/fediverse/webfinger.rb +140 -0
- data/lib/fediverse.rb +5 -0
- data/lib/generators/fedipub/copy_client_policies/USAGE +8 -0
- data/lib/generators/fedipub/copy_client_policies/copy_client_policies_generator.rb +9 -0
- data/lib/generators/fedipub/copy_client_views/USAGE +8 -0
- data/lib/generators/fedipub/copy_client_views/copy_client_views_generator.rb +9 -0
- data/lib/generators/fedipub/copy_factories/USAGE +8 -0
- data/lib/generators/fedipub/copy_factories/copy_factories_generator.rb +43 -0
- data/lib/generators/fedipub/install/USAGE +9 -0
- data/lib/generators/fedipub/install/install_generator.rb +10 -0
- data/lib/generators/fedipub/install/templates/fedipub.rb +1 -0
- data/lib/generators/fedipub/install/templates/fedipub.yml +27 -0
- data/lib/tasks/factory_bot.rake +15 -0
- data/lib/tasks/fedipub_tasks.rake +13 -0
- metadata +259 -10
data/config/routes.rb
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Fedipub::Engine.routes.draw do
|
|
2
|
+
if Fedipub.configuration.enable_discovery
|
|
3
|
+
scope path: '/' do
|
|
4
|
+
get '/.well-known/webfinger', to: 'server/web_finger#find', as: :webfinger
|
|
5
|
+
get '/.well-known/host-meta', to: 'server/web_finger#host_meta', as: :host_meta
|
|
6
|
+
get '/.well-known/nodeinfo', to: 'server/nodeinfo#index', as: :node_info
|
|
7
|
+
get '/nodeinfo/2.0', to: 'server/nodeinfo#show', as: :show_node_info
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
if Fedipub.configuration.client_routes_path
|
|
12
|
+
scope Fedipub.configuration.client_routes_path, module: :client, as: :client do
|
|
13
|
+
resources :activities, only: [:index] do
|
|
14
|
+
collection do
|
|
15
|
+
get :feed, to: 'activities#feed'
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
resources :actors, only: [:index, :show] do
|
|
19
|
+
collection do
|
|
20
|
+
get :lookup, to: 'actors#lookup'
|
|
21
|
+
end
|
|
22
|
+
resources :activities, only: [:index]
|
|
23
|
+
end
|
|
24
|
+
get :feed, to: 'activities#feed'
|
|
25
|
+
resources :followings, only: [:new, :create, :destroy] do
|
|
26
|
+
collection do
|
|
27
|
+
post :follow, to: 'followings#follow'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
member do
|
|
31
|
+
put :accept, to: 'followings#accept'
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
scope Fedipub.configuration.server_routes_path, module: :server, as: :server, defaults: { format: :activitypub } do
|
|
38
|
+
resources :actors, only: [:show] do
|
|
39
|
+
member do
|
|
40
|
+
get :followers
|
|
41
|
+
get :following
|
|
42
|
+
end
|
|
43
|
+
get :outbox, to: 'activities#outbox'
|
|
44
|
+
post :inbox, to: 'activities#create'
|
|
45
|
+
resources :activities, only: [:show]
|
|
46
|
+
resources :followings, only: [:show]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
scope :published do
|
|
50
|
+
get ':publishable_type/:id', to: 'published#show', as: :published
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class CreateFederailsActors < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :federails_actors do |t|
|
|
4
|
+
t.string :name
|
|
5
|
+
t.string :federated_url
|
|
6
|
+
t.string :username
|
|
7
|
+
t.string :server
|
|
8
|
+
t.string :inbox_url
|
|
9
|
+
t.string :outbox_url
|
|
10
|
+
t.string :followers_url
|
|
11
|
+
t.string :followings_url
|
|
12
|
+
t.string :profile_url
|
|
13
|
+
|
|
14
|
+
t.integer :entity_id, null: true
|
|
15
|
+
t.string :entity_type, null: true
|
|
16
|
+
|
|
17
|
+
t.timestamps
|
|
18
|
+
t.index :federated_url, unique: true
|
|
19
|
+
t.index [:entity_type, :entity_id], name: 'index_federails_actors_on_entity', unique: true
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class CreateFederailsFollowings < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :federails_followings do |t|
|
|
4
|
+
t.references :actor, null: false, foreign_key: { to_table: :federails_actors }
|
|
5
|
+
t.references :target_actor, null: false, foreign_key: { to_table: :federails_actors }
|
|
6
|
+
t.integer :status, default: 0
|
|
7
|
+
t.string :federated_url
|
|
8
|
+
|
|
9
|
+
t.timestamps
|
|
10
|
+
|
|
11
|
+
t.index [:actor_id, :target_actor_id], unique: true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class CreateFederailsActivities < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :federails_activities do |t|
|
|
4
|
+
t.references :entity, polymorphic: true, null: false
|
|
5
|
+
t.string :action, null: false, default: nil
|
|
6
|
+
t.references :actor, null: false, foreign_key: { to_table: :federails_actors }
|
|
7
|
+
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class AddUuids < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
[
|
|
4
|
+
:federails_actors,
|
|
5
|
+
:federails_activities,
|
|
6
|
+
:federails_followings,
|
|
7
|
+
].each do |table|
|
|
8
|
+
change_table table do |t|
|
|
9
|
+
t.string :uuid, default: nil, index: { unique: true }
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class AddLocalToActors < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
add_column :federails_actors, :local, :boolean, null: false, default: false
|
|
4
|
+
|
|
5
|
+
reversible do |dir|
|
|
6
|
+
dir.up do
|
|
7
|
+
exec_update 'UPDATE federails_actors SET local=true WHERE entity_type IS NOT NULL'
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
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
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class RenameFederailsToFedipub < ActiveRecord::Migration[7.2]
|
|
2
|
+
def change
|
|
3
|
+
# Activities
|
|
4
|
+
rename_index 'federails_activities', 'index_federails_activities_on_entity', 'index_fedipub_activities_on_entity'
|
|
5
|
+
rename_table 'federails_activities', 'fedipub_activities'
|
|
6
|
+
# Actors
|
|
7
|
+
rename_index 'federails_actors', 'index_federails_actors_on_entity', 'index_fedipub_actors_on_entity'
|
|
8
|
+
rename_table 'federails_actors', 'fedipub_actors'
|
|
9
|
+
# Followings
|
|
10
|
+
rename_index 'federails_followings', 'index_federails_followings_on_actor_id_and_target_actor_id', 'index_fedipub_followings_on_actor_id_and_target_actor_id'
|
|
11
|
+
rename_table 'federails_followings', 'fedipub_followings'
|
|
12
|
+
# Hosts
|
|
13
|
+
rename_table 'federails_hosts', 'fedipub_hosts'
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
# rubocop:disable Style/ClassVars
|
|
3
|
+
|
|
4
|
+
# Stores the Fedipub configuration in a _singleton_.
|
|
5
|
+
module Configuration
|
|
6
|
+
# Application name, used in well-known and nodeinfo endpoints
|
|
7
|
+
mattr_accessor :app_name
|
|
8
|
+
@@app_name = nil
|
|
9
|
+
|
|
10
|
+
# Application version, used in well-known and nodeinfo endpoints
|
|
11
|
+
mattr_accessor :app_version
|
|
12
|
+
@@app_version = nil
|
|
13
|
+
|
|
14
|
+
# Force https urls in various rendered content (currently in webfinger views)
|
|
15
|
+
mattr_accessor :force_ssl
|
|
16
|
+
@@force_ssl = nil
|
|
17
|
+
|
|
18
|
+
# Site hostname
|
|
19
|
+
mattr_reader :site_host
|
|
20
|
+
@@site_host = nil
|
|
21
|
+
|
|
22
|
+
# Site port
|
|
23
|
+
mattr_reader :site_port
|
|
24
|
+
@@site_port = nil
|
|
25
|
+
|
|
26
|
+
# Whether to enable ".well-known" and "nodeinfo" endpoints
|
|
27
|
+
mattr_accessor :enable_discovery
|
|
28
|
+
@@enable_discovery = true
|
|
29
|
+
|
|
30
|
+
# Does the site allow open registrations? (only used for nodeinfo reporting)
|
|
31
|
+
# Can either be a static boolean, or a Proc which will be called to get the state.
|
|
32
|
+
mattr_writer :open_registrations
|
|
33
|
+
@@open_registrations = false
|
|
34
|
+
def self.open_registrations
|
|
35
|
+
@@open_registrations.is_a?(Proc) ? @@open_registrations.call : @@open_registrations
|
|
36
|
+
end
|
|
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
|
+
|
|
46
|
+
# Application layout
|
|
47
|
+
mattr_accessor :app_layout
|
|
48
|
+
@@app_layout = nil
|
|
49
|
+
|
|
50
|
+
# Route path for the federation URLs (to "Fedipub::Server::*" controllers)
|
|
51
|
+
mattr_accessor :server_routes_path
|
|
52
|
+
@@server_routes_path = :federation
|
|
53
|
+
|
|
54
|
+
# Route path for the webapp URLs (to "Fedipub::Client::*" controllers)
|
|
55
|
+
mattr_accessor :client_routes_path
|
|
56
|
+
@@client_routes_path = :app
|
|
57
|
+
|
|
58
|
+
# Default controller to use as base for client controllers
|
|
59
|
+
mattr_accessor :base_client_controller
|
|
60
|
+
@@base_client_controller = 'ActionController::Base'
|
|
61
|
+
|
|
62
|
+
# @!method self.remote_follow_url_method
|
|
63
|
+
#
|
|
64
|
+
# Route method for remote-following requests
|
|
65
|
+
|
|
66
|
+
# @!method self.remote_follow_url_method=(value)
|
|
67
|
+
#
|
|
68
|
+
# Sets the route method for remote-following requests
|
|
69
|
+
#
|
|
70
|
+
# The route should lead to a page displaying the remote actor and a button to follow it.
|
|
71
|
+
# Remote actor is specified in the `uri` query parameter.
|
|
72
|
+
#
|
|
73
|
+
# Its value defaults to a route of the Fedipub client, so your application will break
|
|
74
|
+
# if you don't use the client routes and don't override this value.
|
|
75
|
+
#
|
|
76
|
+
# @param value [String] Route method name as used in links
|
|
77
|
+
# @example
|
|
78
|
+
# remote_follow_url_method 'main_app.my_custom_route_helper'
|
|
79
|
+
mattr_accessor :remote_follow_url_method
|
|
80
|
+
@@remote_follow_url_method = 'fedipub.new_client_following_url'
|
|
81
|
+
|
|
82
|
+
def self.site_host=(value)
|
|
83
|
+
@@site_host = value
|
|
84
|
+
Fedipub::Engine.routes.default_url_options[:host] = value
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.site_port=(value)
|
|
88
|
+
@@site_port = value
|
|
89
|
+
Fedipub::Engine.routes.default_url_options[:port] = value
|
|
90
|
+
end
|
|
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
|
+
|
|
102
|
+
# List of actor types (classes using Fedipub::ActorEntity)
|
|
103
|
+
mattr_reader :actor_types
|
|
104
|
+
@@actor_types = {}
|
|
105
|
+
|
|
106
|
+
def self.register_actor_class(klass, config = {})
|
|
107
|
+
@@actor_types[klass.name] = config.merge(class: klass)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# List of data types (classes using Fedipub::DataEntity)
|
|
111
|
+
mattr_reader :data_types
|
|
112
|
+
@@data_types = {}
|
|
113
|
+
|
|
114
|
+
def self.register_data_type(klass, config = {})
|
|
115
|
+
@@data_types[klass.name] = config.merge(class: klass)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
# rubocop:enable Style/ClassVars
|
|
119
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'fedipub/utils/context'
|
|
2
|
+
|
|
3
|
+
module Fedipub
|
|
4
|
+
module DataTransformer
|
|
5
|
+
module Note
|
|
6
|
+
# Renders a Note. The entity is used to determine actor and generic fields data
|
|
7
|
+
#
|
|
8
|
+
# @param entity [#federail_actor, #federated_url, #created_at, #updated_at] A model instance
|
|
9
|
+
# @param content [String] Note content
|
|
10
|
+
# @param name [String, nil] Optional name/title
|
|
11
|
+
# @param custom [Hash] Optional additional keys (e.g.: attachment, icon, ...). Defaults will override these.
|
|
12
|
+
#
|
|
13
|
+
# @return [Hash]
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# Fedipub::DataTransformer::Note.to_federation(comment, content: comment.content, custom: { 'inReplyTo' => comment.parent.federated_url })
|
|
17
|
+
#
|
|
18
|
+
# See:
|
|
19
|
+
# - https://www.w3.org/TR/activitystreams-vocabulary/#dfn-object
|
|
20
|
+
# - https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note
|
|
21
|
+
def self.to_federation(entity, content:, name: nil, 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,
|
|
26
|
+
'id' => entity.federated_url,
|
|
27
|
+
'type' => 'Note',
|
|
28
|
+
'name' => name,
|
|
29
|
+
'content' => content,
|
|
30
|
+
'attributedTo' => entity.fedipub_actor.federated_url,
|
|
31
|
+
'published' => entity.created_at,
|
|
32
|
+
'updated' => entity.updated_at
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
module Maintenance
|
|
3
|
+
class ActorsUpdater
|
|
4
|
+
class << self
|
|
5
|
+
# Fetches all distant actors again and update their local copy
|
|
6
|
+
#
|
|
7
|
+
# A block can be passed with two arguments: the actor being updated and the update status
|
|
8
|
+
#
|
|
9
|
+
# @param actors [Integer, Fedipub::Actor, Array<Fedipub::Actor>, nil] Actor ID, Actor or list of actors to update.
|
|
10
|
+
# If nothing is passed, all distant actors are processed
|
|
11
|
+
# @example
|
|
12
|
+
# Update all distant actors
|
|
13
|
+
# Fedipub::Maintenance::ActorUpdater.run
|
|
14
|
+
# With an actor id:
|
|
15
|
+
# Fedipub::Maintenance::ActorUpdater.run 1
|
|
16
|
+
# With a federated URL:
|
|
17
|
+
# Fedipub::Maintenance::ActorUpdater.run 'https://example.com/actor'
|
|
18
|
+
# With a federated URL:
|
|
19
|
+
# Fedipub::Maintenance::ActorUpdater.run ['https://example.com/actors/1', 'https://example.com/actors/1']
|
|
20
|
+
# With actors:
|
|
21
|
+
# Fedipub::Maintenance::ActorUpdater.run Fedipub::Actor.last(10)
|
|
22
|
+
# Update all distant actors and puts status for each actor
|
|
23
|
+
# Fedipub::Maintenance::ActorUpdater.run {|actor, status| puts "#{actor.federated_url}: #{status}"}
|
|
24
|
+
def run(actors = nil, &block)
|
|
25
|
+
actors_list(actors).each do |actor|
|
|
26
|
+
status = update(actor)
|
|
27
|
+
|
|
28
|
+
yield(actor, status) if block
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
# Make a list of actors to update from the passed attribute
|
|
35
|
+
def actors_list(param) # rubocop:disable Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
|
|
36
|
+
if param.nil?
|
|
37
|
+
Fedipub::Actor.distant
|
|
38
|
+
elsif param.is_a? String
|
|
39
|
+
[Fedipub::Actor.distant.find_by!(federated_url: param)]
|
|
40
|
+
elsif param.is_a? Integer
|
|
41
|
+
[Fedipub::Actor.distant.find(param)]
|
|
42
|
+
elsif param.is_a?(Fedipub::Actor)
|
|
43
|
+
[param]
|
|
44
|
+
elsif param.respond_to?(:pluck) && param.first.is_a?(Fedipub::Actor)
|
|
45
|
+
param
|
|
46
|
+
elsif param.is_a?(Array) && param.first.is_a?(String)
|
|
47
|
+
Fedipub::Actor.distant.where(federated_url: param)
|
|
48
|
+
else
|
|
49
|
+
raise "Cannot extract actors from #{param.class}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @param actor [Fedipub::Actor]
|
|
54
|
+
def update(actor)
|
|
55
|
+
return :ignored_local if actor.local?
|
|
56
|
+
|
|
57
|
+
actor.sync! ? :updated : :failed
|
|
58
|
+
rescue ActiveRecord::RecordNotFound
|
|
59
|
+
:not_found
|
|
60
|
+
rescue StandardError
|
|
61
|
+
:failed
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Fedipub
|
|
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 ||= Fedipub::Configuration.remote_entities_cache_duration
|
|
8
|
+
|
|
9
|
+
domains = Fedipub::Actor.distant.distinct(:server).pluck(:server) + Fedipub::Host.pluck(:domain)
|
|
10
|
+
domains.uniq!
|
|
11
|
+
|
|
12
|
+
domains.each do |domain|
|
|
13
|
+
Fedipub::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,85 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
module Utils
|
|
3
|
+
class Actor
|
|
4
|
+
# List of the attributes computed for local actors
|
|
5
|
+
COMPUTED_ATTRIBUTES = [
|
|
6
|
+
:federated_url,
|
|
7
|
+
:username,
|
|
8
|
+
:name,
|
|
9
|
+
:server,
|
|
10
|
+
:inbox_url,
|
|
11
|
+
:outbox_url,
|
|
12
|
+
:followers_url,
|
|
13
|
+
:followings_url,
|
|
14
|
+
:profile_url,
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
# @param actor [Fedipub::Actor]
|
|
19
|
+
# @return [Fedipub::Actor]
|
|
20
|
+
def tombstone!(actor)
|
|
21
|
+
if actor.local?
|
|
22
|
+
tombstone_local_actor actor
|
|
23
|
+
else
|
|
24
|
+
tombstone_distant_actor actor
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
actor
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def untombstone!(actor)
|
|
31
|
+
if actor.local?
|
|
32
|
+
untombstone_local_actor actor
|
|
33
|
+
else
|
|
34
|
+
untombstone_distant_actor actor
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def tombstone_local_actor(actor)
|
|
41
|
+
Fedipub::Actor.transaction do
|
|
42
|
+
hash = {
|
|
43
|
+
tombstoned_at: Time.current,
|
|
44
|
+
entity: actor.entity || nil,
|
|
45
|
+
}
|
|
46
|
+
# Hardcode attributes depending on the actor's entity
|
|
47
|
+
COMPUTED_ATTRIBUTES.each { |attribute| hash[attribute] = actor.send(attribute) }
|
|
48
|
+
|
|
49
|
+
actor.update! hash
|
|
50
|
+
|
|
51
|
+
Activity.create! actor: actor, action: 'Delete', entity: actor
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def untombstone_local_actor(actor)
|
|
56
|
+
return unless actor.tombstoned?
|
|
57
|
+
raise 'Cannot restore a local actor without an entity' if actor.entity.blank?
|
|
58
|
+
|
|
59
|
+
Fedipub::Actor.transaction do
|
|
60
|
+
# Reset hardcoded attributes depending on the actor's entity
|
|
61
|
+
hash = { tombstoned_at: nil }
|
|
62
|
+
COMPUTED_ATTRIBUTES.each { |attribute| hash[attribute] = nil }
|
|
63
|
+
|
|
64
|
+
actor.update! hash
|
|
65
|
+
|
|
66
|
+
delete_activity = Activity.find_by actor: actor, action: 'Delete', entity: actor
|
|
67
|
+
return unless delete_activity
|
|
68
|
+
|
|
69
|
+
delete_activity.undo!
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def tombstone_distant_actor(actor)
|
|
74
|
+
actor.update! tombstoned_at: Time.current
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def untombstone_distant_actor(actor)
|
|
78
|
+
actor.tombstoned_at = nil
|
|
79
|
+
actor.sync!
|
|
80
|
+
actor.save
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Fedipub
|
|
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
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
module Utils
|
|
3
|
+
class Host
|
|
4
|
+
class << self
|
|
5
|
+
COMMON_PORTS = [80, 443].freeze
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# @return [String] Host and port of the current instance
|
|
9
|
+
def localhost
|
|
10
|
+
uri = URI.parse Fedipub.configuration.site_host
|
|
11
|
+
host_and_port (uri.host || 'localhost'), Fedipub.configuration.site_port
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# Checks if the given URL points somewhere on current instance
|
|
16
|
+
#
|
|
17
|
+
# @param url [String] URL to check
|
|
18
|
+
#
|
|
19
|
+
# @return [true, false]
|
|
20
|
+
def local_url?(url)
|
|
21
|
+
uri = URI.parse url
|
|
22
|
+
host = host_and_port uri.host, uri.port
|
|
23
|
+
localhost == host
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Gets the route on the current instance, or nil
|
|
28
|
+
#
|
|
29
|
+
# @param url [String] URL to check
|
|
30
|
+
#
|
|
31
|
+
# @return [ActionDispatch::Routing::RouteSet, nil] nil when URL do not match a route
|
|
32
|
+
def local_route(url)
|
|
33
|
+
return nil unless local_url? url
|
|
34
|
+
|
|
35
|
+
Rails.application.routes.recognize_path(url)
|
|
36
|
+
rescue ActionController::RoutingError
|
|
37
|
+
nil
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def host_and_port(host, port)
|
|
43
|
+
port_string = if port.present? && COMMON_PORTS.exclude?(port)
|
|
44
|
+
":#{port}"
|
|
45
|
+
else
|
|
46
|
+
''
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
"#{host}#{port_string}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
require 'faraday/follow_redirects'
|
|
3
|
+
|
|
4
|
+
module Fedipub
|
|
5
|
+
module Utils
|
|
6
|
+
# Simple wrapper to make requests expecting JSON
|
|
7
|
+
module JsonRequest
|
|
8
|
+
class UnhandledResponseStatus < StandardError; end
|
|
9
|
+
|
|
10
|
+
BASE_HEADERS = {
|
|
11
|
+
'Content-Type' => 'application/json',
|
|
12
|
+
'Accept' => 'application/json',
|
|
13
|
+
}.freeze
|
|
14
|
+
|
|
15
|
+
# Makes a GET request and returns a +Hash+ from the parsed body
|
|
16
|
+
#
|
|
17
|
+
# @param url [String] Target URL
|
|
18
|
+
# @param params [Hash] Querystring parameters
|
|
19
|
+
# @param headers [Hash] Additional headers
|
|
20
|
+
# @param follow_redirects [Boolean] Whether to follow redirections
|
|
21
|
+
# @param expected_status [Integer] Expected response status. Will raise a +UnhandledResponseStatus+ when status is different
|
|
22
|
+
#
|
|
23
|
+
# @return The parsed JSON object
|
|
24
|
+
#
|
|
25
|
+
# @raise [UnhandledResponseStatus] when response status is not the expected_status
|
|
26
|
+
def self.get_json(url, params: {}, headers: {}, follow_redirects: false, expected_status: 200)
|
|
27
|
+
headers = BASE_HEADERS.merge headers
|
|
28
|
+
|
|
29
|
+
connection = Faraday.new url: url, params: params, headers: headers do |faraday|
|
|
30
|
+
faraday.response :follow_redirects if follow_redirects
|
|
31
|
+
faraday.adapter Faraday.default_adapter
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
response = connection.get
|
|
35
|
+
raise UnhandledResponseStatus, "Unhandled status code #{response.status} for GET #{url}" if expected_status && response.status != expected_status
|
|
36
|
+
|
|
37
|
+
JSON.parse(response.body)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|