federails 0.0.1 → 0.2.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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +182 -7
  3. data/Rakefile +5 -5
  4. data/app/controllers/federails/application_controller.rb +23 -0
  5. data/app/controllers/federails/client/activities_controller.rb +21 -0
  6. data/app/controllers/federails/client/actors_controller.rb +37 -0
  7. data/app/controllers/federails/client/followings_controller.rb +101 -0
  8. data/app/controllers/federails/server/activities_controller.rb +65 -0
  9. data/app/controllers/federails/server/actors_controller.rb +34 -0
  10. data/app/controllers/federails/server/followings_controller.rb +19 -0
  11. data/app/controllers/federails/server/nodeinfo_controller.rb +22 -0
  12. data/app/controllers/federails/server/server_controller.rb +17 -0
  13. data/app/controllers/federails/server/web_finger_controller.rb +38 -0
  14. data/app/helpers/federails/application_helper.rb +8 -0
  15. data/app/jobs/federails/notify_inbox_job.rb +12 -0
  16. data/app/mailers/federails/application_mailer.rb +2 -2
  17. data/app/models/concerns/federails/entity.rb +57 -0
  18. data/app/models/concerns/federails/has_uuid.rb +35 -0
  19. data/app/models/federails/activity.rb +35 -0
  20. data/app/models/federails/actor.rb +189 -0
  21. data/app/models/federails/following.rb +52 -0
  22. data/app/policies/federails/client/activity_policy.rb +6 -0
  23. data/app/policies/federails/client/actor_policy.rb +15 -0
  24. data/app/policies/federails/client/following_policy.rb +35 -0
  25. data/app/policies/federails/federails_policy.rb +59 -0
  26. data/app/policies/federails/server/activity_policy.rb +6 -0
  27. data/app/policies/federails/server/actor_policy.rb +23 -0
  28. data/app/policies/federails/server/following_policy.rb +6 -0
  29. data/app/views/federails/client/activities/_activity.html.erb +5 -0
  30. data/app/views/federails/client/activities/_activity.json.jbuilder +1 -0
  31. data/app/views/federails/client/activities/_index.json.jbuilder +1 -0
  32. data/app/views/federails/client/activities/feed.html.erb +4 -0
  33. data/app/views/federails/client/activities/feed.json.jbuilder +1 -0
  34. data/app/views/federails/client/activities/index.html.erb +5 -0
  35. data/app/views/federails/client/activities/index.json.jbuilder +1 -0
  36. data/app/views/federails/client/actors/_actor.json.jbuilder +14 -0
  37. data/app/views/federails/client/actors/_lookup_form.html.erb +5 -0
  38. data/app/views/federails/client/actors/index.html.erb +24 -0
  39. data/app/views/federails/client/actors/index.json.jbuilder +1 -0
  40. data/app/views/federails/client/actors/show.html.erb +100 -0
  41. data/app/views/federails/client/actors/show.json.jbuilder +1 -0
  42. data/app/views/federails/client/followings/_follow.html.erb +4 -0
  43. data/app/views/federails/client/followings/_follower.html.erb +7 -0
  44. data/app/views/federails/client/followings/_following.json.jbuilder +1 -0
  45. data/app/views/federails/client/followings/_form.html.erb +21 -0
  46. data/app/views/federails/client/followings/index.html.erb +29 -0
  47. data/app/views/federails/client/followings/index.json.jbuilder +1 -0
  48. data/app/views/federails/client/followings/show.html.erb +21 -0
  49. data/app/views/federails/client/followings/show.json.jbuilder +1 -0
  50. data/app/views/federails/server/activities/_activity.activitypub.jbuilder +14 -0
  51. data/app/views/federails/server/activities/outbox.activitypub.jbuilder +18 -0
  52. data/app/views/federails/server/activities/show.activitypub.jbuilder +1 -0
  53. data/app/views/federails/server/actors/_actor.activitypub.jbuilder +21 -0
  54. data/app/views/federails/server/actors/followers.activitypub.jbuilder +18 -0
  55. data/app/views/federails/server/actors/following.activitypub.jbuilder +18 -0
  56. data/app/views/federails/server/actors/show.activitypub.jbuilder +1 -0
  57. data/app/views/federails/server/followings/_following.activitypub.jbuilder +7 -0
  58. data/app/views/federails/server/followings/show.activitypub.jbuilder +1 -0
  59. data/app/views/federails/server/nodeinfo/index.nodeinfo.jbuilder +6 -0
  60. data/app/views/federails/server/nodeinfo/show.nodeinfo.jbuilder +19 -0
  61. data/app/views/federails/server/web_finger/find.jrd.jbuilder +24 -0
  62. data/app/views/federails/server/web_finger/host_meta.xrd.erb +5 -0
  63. data/config/initializers/mime_types.rb +21 -0
  64. data/config/routes.rb +43 -0
  65. data/db/migrate/20200712133150_create_federails_actors.rb +24 -0
  66. data/db/migrate/20200712143127_create_federails_followings.rb +14 -0
  67. data/db/migrate/20200712174938_create_federails_activities.rb +11 -0
  68. data/db/migrate/20240731145400_change_actor_entity_rel_to_polymorphic.rb +11 -0
  69. data/db/migrate/20241002094500_add_uuids.rb +13 -0
  70. data/db/migrate/20241002094501_add_keypair_to_actors.rb +8 -0
  71. data/lib/federails/configuration.rb +92 -0
  72. data/lib/federails/engine.rb +6 -0
  73. data/lib/federails/utils/host.rb +54 -0
  74. data/lib/federails/version.rb +1 -1
  75. data/lib/federails.rb +34 -3
  76. data/lib/fediverse/inbox.rb +71 -0
  77. data/lib/fediverse/notifier.rb +60 -0
  78. data/lib/fediverse/request.rb +38 -0
  79. data/lib/fediverse/signature.rb +49 -0
  80. data/lib/fediverse/webfinger.rb +117 -0
  81. data/lib/generators/federails/install/USAGE +9 -0
  82. data/lib/generators/federails/install/install_generator.rb +10 -0
  83. data/lib/generators/federails/install/templates/federails.rb +1 -0
  84. data/lib/generators/federails/install/templates/federails.yml +23 -0
  85. data/lib/tasks/factory_bot.rake +15 -0
  86. metadata +170 -10
  87. data/app/views/layouts/federails/application.html.erb +0 -15
@@ -0,0 +1,100 @@
1
+ <h2><%= @actor.name %></h2>
2
+
3
+ <% if Federails::Client::FollowingPolicy.new(current_user, Federails::Following).create? %>
4
+ <p>
5
+ <%
6
+ follow = current_user.actor.follows? @actor
7
+ if @actor.entity == current_user
8
+ %>
9
+ <button role="button" disabled="disabled">That's you</button>
10
+ <% elsif follow %>
11
+ Already following (<%= follow.status %>)
12
+ <%= button_to 'Revoke', federails.client_following_path(follow), method: :delete %>
13
+ <% else %>
14
+ <%= button_to 'Follow!', federails.follow_client_followings_path, params: { account: @actor.at_address }, method: :post %>
15
+ <% end %>
16
+ </p>
17
+ <% end %>
18
+
19
+ <p>
20
+ <b>Federated url:</b>
21
+ <%= @actor.federated_url %>
22
+ </p>
23
+
24
+ <p>
25
+ <b>Username:</b>
26
+ <%= @actor.username %>
27
+ </p>
28
+
29
+ <p>
30
+ <b>Inbox URL:</b>
31
+ <%= @actor.inbox_url %>
32
+ </p>
33
+
34
+ <p>
35
+ <b>Outbox URL:</b>
36
+ <%= @actor.outbox_url %>
37
+ </p>
38
+
39
+ <p>
40
+ <b>Followers URL:</b>
41
+ <%= @actor.followers_url %>
42
+ </p>
43
+
44
+ <p>
45
+ <b>Followings URL:</b>
46
+ <%= @actor.followings_url %>
47
+ </p>
48
+
49
+ <p>
50
+ <b>Profile url:</b>
51
+ <% if @actor.profile_url %>
52
+ <%= link_to 'Profile', @actor.profile_url %>
53
+ <% end %>
54
+ </p>
55
+
56
+ <p>
57
+ <b>Federation address:</b>
58
+ <%= @actor.at_address %>
59
+ </p>
60
+
61
+ <p>
62
+ <b>Home page:</b>
63
+ <% if @actor.local? && Federails::Configuration.user_profile_url_method %>
64
+ <%= link_to @actor.send(Federails::Configuration.user_username_field), Rails.application.routes.url_helpers.send(Federails::Configuration.user_profile_url_method, @actor.user) %>
65
+ <% elsif @actor.profile_url %>
66
+ <%= link_to @actor.name, @actor.profile_url %>
67
+ <% else %>
68
+ (No homepage)
69
+ <% end %>
70
+ </p>
71
+
72
+ <hr>
73
+
74
+ <h2>Follows</h2>
75
+ <% if current_user && current_user == @actor.entity %>
76
+ <%= render 'federails/client/followings/form', following: Federails::Following.new %>
77
+ <% end %>
78
+
79
+ <% @actor.following_follows.each do |following| %>
80
+ <%= render 'federails/client/followings/follow', following: following %>
81
+ <% end %>
82
+
83
+ <h2>Followers</h2>
84
+ <% @actor.following_followers.each do |following| %>
85
+ <%= render 'federails/client/followings/follower', following: following %>
86
+ <% end %>
87
+
88
+ <%= link_to 'Back', federails.client_actors_url %>
89
+
90
+ <!-- FIXME: Fetch distant content somehow -->
91
+ <h2>10 last activities</h2>
92
+ <% if @actor.local? %>
93
+ <%= link_to 'All', federails.client_actor_activities_path(@actor) %>
94
+ <% elsif @actor.profile_url %>
95
+ <%= link_to 'Visit profile', @actor.profile_url %>
96
+ <% end %>
97
+
98
+ <% @actor.activities.last(10).each do |activity| %>
99
+ <%= render 'federails/client/activities/activity', activity: activity %>
100
+ <% end %>
@@ -0,0 +1 @@
1
+ json.partial! 'federails/client/actors/actor', actor: @actor
@@ -0,0 +1,4 @@
1
+ <div>
2
+ <b><%= link_to following.target_actor.name, federails.client_actor_url(following.target_actor) %></b>
3
+ (<%= following.target_actor.at_address %>) (<%= following.status %>)
4
+ </div>
@@ -0,0 +1,7 @@
1
+ <div>
2
+ <b><%= link_to following.actor.name, federails.client_actor_url(following.actor) %></b>
3
+ (<%= following.actor.at_address %>) (<%= following.status %>)
4
+ <% if following.pending? && following.target_actor == current_user.actor %>
5
+ <%= button_to 'Accept', federails.accept_client_following_path(following), method: :put %>
6
+ <% end %>
7
+ </div>
@@ -0,0 +1 @@
1
+ json.extract! following, :id, :actor_id, :target_actor_id, :status, :created_at, :updated_at
@@ -0,0 +1,21 @@
1
+ <%= form_for following, url: federails.client_following_url do |f| %>
2
+ <% if following.errors.any? %>
3
+ <div class="error_explanation">
4
+ <h2><%= pluralize(following.errors.count, 'error') %> prohibited this following from being saved:</h2>
5
+ <ul>
6
+ <% following.errors.full_messages.each do |message| %>
7
+ <li><%= message %></li>
8
+ <% end %>
9
+ </ul>
10
+ </div>
11
+ <% end %>
12
+
13
+ <div class="field">
14
+ <%= f.label :target_actor %>
15
+ <%= f.collection_select :target_actor_id, Federails::Actor.all, :id, :name %>
16
+ </div>
17
+
18
+ <div class="actions">
19
+ <%= f.submit 'Save' %>
20
+ </div>
21
+ <% end %>
@@ -0,0 +1,29 @@
1
+ <h1>Listing followings</h1>
2
+
3
+ <table>
4
+ <thead>
5
+ <tr>
6
+ <th>Actor</th>
7
+ <th>Target actor</th>
8
+ <th>Status</th>
9
+ <th></th>
10
+ <th></th>
11
+ <th></th>
12
+ </tr>
13
+ </thead>
14
+
15
+ <tbody>
16
+ <% @followings.each do |following| %>
17
+ <tr>
18
+ <td><%= following.actor %></td>
19
+ <td><%= following.target_actor %></td>
20
+ <td><%= following.status %></td>
21
+ <td><%= link_to 'Show', following %></td>
22
+ <td><%= link_to 'Edit', edit_following_path(following) %></td>
23
+ <td><%= link_to 'Destroy', following, method: :delete, data: { confirm: 'Are you sure?' } %></td>
24
+ </tr>
25
+ <% end %>
26
+ </tbody>
27
+ </table>
28
+
29
+ <%= link_to 'New Following', new_following_path %>
@@ -0,0 +1 @@
1
+ json.array! @followings, partial: 'federails/client/followings/following', as: :following
@@ -0,0 +1,21 @@
1
+ <p id="notice"><%= notice %></p>
2
+
3
+ <p>
4
+ <b>Actor:</b>
5
+ <%= @following.actor %>
6
+ </p>
7
+
8
+ <p>
9
+ <b>Target actor:</b>
10
+ <%= @following.target_actor %>
11
+ </p>
12
+
13
+ <p>
14
+ <b>Status:</b>
15
+ <%= @following.status %>
16
+ </p>
17
+
18
+
19
+ <%= link_to 'Edit', edit_following_path(@following) %>
20
+ \|
21
+ <%= link_to 'Back', followings_path %>
@@ -0,0 +1 @@
1
+ json.partial! 'federails/client/followings/following', following: @following
@@ -0,0 +1,14 @@
1
+ context = true unless context == false
2
+ json.set! '@context', 'https://www.w3.org/ns/activitystreams' if context
3
+
4
+ json.id Federails::Engine.routes.url_helpers.server_actor_activity_url activity.actor, activity
5
+ json.type activity.action
6
+ json.actor activity.actor.federated_url
7
+ json.to ['https://www.w3.org/ns/activitystreams#Public']
8
+ json.cc [activity.actor.followers_url]
9
+
10
+ if activity.entity.respond_to? :to_activitypub_object
11
+ json.object activity.entity.to_activitypub_object
12
+ elsif activity.entity.respond_to? :federated_url
13
+ json.object activity.entity.federated_url
14
+ end
@@ -0,0 +1,18 @@
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
@@ -0,0 +1 @@
1
+ json.partial! 'federails/server/activities/activity', activity: @activity
@@ -0,0 +1,21 @@
1
+ json.set! '@context', [
2
+ 'https://www.w3.org/ns/activitystreams',
3
+ 'https://w3id.org/security/v1',
4
+ ]
5
+
6
+ json.id actor.federated_url
7
+ json.name actor.name
8
+ json.type actor.entity_configuration[:actor_type]
9
+ json.preferredUsername actor.username
10
+ json.inbox actor.inbox_url
11
+ json.outbox actor.outbox_url
12
+ json.followers actor.followers_url
13
+ json.following actor.followings_url
14
+ json.url actor.profile_url
15
+ if actor.public_key
16
+ json.publicKey do
17
+ json.id actor.key_id
18
+ json.owner actor.federated_url
19
+ json.publicKeyPem actor.public_key
20
+ end
21
+ end
@@ -0,0 +1,18 @@
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
@@ -0,0 +1,18 @@
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
@@ -0,0 +1 @@
1
+ json.partial! 'federails/server/actors/actor', actor: @actor
@@ -0,0 +1,7 @@
1
+ context = true unless context == false
2
+ json.set! '@context', 'https://www.w3.org/ns/activitystreams' if context
3
+
4
+ json.id following.federated_url
5
+ json.type 'Follow'
6
+ json.actor following.actor.federated_url
7
+ json.object following.target_actor.federated_url
@@ -0,0 +1 @@
1
+ json.partial! 'federails/server/followings/following', following: @following
@@ -0,0 +1,6 @@
1
+ json.links [
2
+ {
3
+ rel: 'https://nodeinfo.diaspora.software/ns/schema/2.0',
4
+ href: show_node_info_url,
5
+ },
6
+ ]
@@ -0,0 +1,19 @@
1
+ json.version '2.0'
2
+ # FIXME: Use configuration values when created
3
+ json.software name: Federails::Configuration.app_name,
4
+ version: Federails::Configuration.app_version
5
+ json.protocols [
6
+ 'activitypub',
7
+ ]
8
+ # FIXME: When server is in good shape: update outbounds
9
+ # http://nodeinfo.diaspora.software/ns/schema/2.0 for possible values
10
+ json.services inbound: [],
11
+ outbound: []
12
+ # FIXME: Don't hardcode this
13
+ json.openRegistrations true
14
+ json.usage users: {
15
+ total: @total,
16
+ activeMonth: @active_month,
17
+ activeHalfyear: @active_halfyear,
18
+ }
19
+ json.metadata({})
@@ -0,0 +1,24 @@
1
+ json.subject params[:resource]
2
+
3
+ links = [
4
+ # Federation actor URL
5
+ {
6
+ rel: 'self',
7
+ type: Mime[:activitypub].to_s,
8
+ href: @user.actor.federated_url,
9
+ },
10
+ ]
11
+
12
+ # User profile URL if configured
13
+ # TODO: Add a profile controller/action in dummy to test this
14
+ if @user.actor.profile_url
15
+ links.push rel: 'https://webfinger.net/rel/profile-page',
16
+ type: 'text/html',
17
+ href: @user.actor.profile_url
18
+ end
19
+
20
+ # Remote following
21
+ links.push rel: 'http://ostatus.org/schema/1.0/subscribe',
22
+ template: "#{remote_follow_url}?uri={uri}"
23
+
24
+ json.links links
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <XRD
3
+ xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
4
+ <Link rel="lrdd" type="application/xrd+xml" template="<%= webfinger_url %>?resource={uri}" />
5
+ </XRD>
@@ -0,0 +1,21 @@
1
+ # Webfinger: https://datatracker.ietf.org/doc/html/rfc7033
2
+ Mime::Type.register 'application/jrd+json', :jrd
3
+ Mime::Type.register 'application/xrd+xml', :xrd
4
+
5
+ # ActivityPub: https://www.w3.org/TR/activitypub/#retrieving-objects
6
+ Mime::Type.register 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"', :activitypub, ['application/activity+json', 'application/json']
7
+
8
+ # Nodeinfo: https://github.com/jhass/nodeinfo/blob/main/PROTOCOL.md#retrieval
9
+ Mime::Type.register 'application/json; profile="http://nodeinfo.diaspora.software/ns/schema/2.0#"', :nodeinfo
10
+
11
+ # Get current request parsers. Apparently we need to do it this way and can't add in-place, see
12
+ # https://api.rubyonrails.org/classes/ActionDispatch/Http/Parameters/ClassMethods.html#method-i-parameter_parsers-3D
13
+ parsers = ActionDispatch::Request.parameter_parsers
14
+ # Copy the default JSON parsing for JSON types
15
+ [:jrd, :activitypub, :nodeinfo].each do |mime_type|
16
+ parsers[Mime[mime_type].symbol] = parsers[:json]
17
+ end
18
+ # XRD just needs a simple XML parser
19
+ parsers[Mime[:xrd].symbol] = ->(raw_post) { Hash.from_xml(raw_post) || {} }
20
+ # Store updated parsers
21
+ ActionDispatch::Request.parameter_parsers = parsers
data/config/routes.rb CHANGED
@@ -1,2 +1,45 @@
1
1
  Federails::Engine.routes.draw do
2
+ if Federails.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 Federails.configuration.client_routes_path
12
+ scope Federails.configuration.client_routes_path, module: :client, as: :client do
13
+ resources :activities, only: [:index, :feed]
14
+ resources :actors, only: [:index, :show] do
15
+ collection do
16
+ get :lookup, to: 'actors#lookup'
17
+ end
18
+ resources :activities, only: [:index]
19
+ end
20
+ get :feed, to: 'activities#feed'
21
+ resources :followings, only: [:new, :create, :destroy] do
22
+ collection do
23
+ post :follow, to: 'followings#follow'
24
+ end
25
+
26
+ member do
27
+ put :accept, to: 'followings#accept'
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ scope Federails.configuration.server_routes_path, module: :server, as: :server do
34
+ resources :actors, only: [:show] do
35
+ member do
36
+ get :followers
37
+ get :following
38
+ end
39
+ get :outbox, to: 'activities#outbox'
40
+ post :inbox, to: 'activities#create'
41
+ resources :activities, only: [:show]
42
+ resources :followings, only: [:show]
43
+ end
44
+ end
2
45
  end
@@ -0,0 +1,24 @@
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.references :user, null: true, foreign_key: { to_table: Federails.configuration.user_table }
15
+
16
+ t.timestamps
17
+ t.index :federated_url, unique: true
18
+ end
19
+ remove_foreign_key :federails_actors, :users if foreign_key_exists?(:federails_actors, :users)
20
+ remove_index :federails_actors, :user_id
21
+ add_index :federails_actors, :user_id, unique: true
22
+ add_foreign_key :federails_actors, :users
23
+ end
24
+ 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,11 @@
1
+ class ChangeActorEntityRelToPolymorphic < ActiveRecord::Migration[7.0]
2
+ def change
3
+ remove_foreign_key :federails_actors, column: :user_id, to_table: Federails::Configuration.user_table
4
+ remove_index :federails_actors, :user_id, unique: true
5
+ change_table :federails_actors do |t|
6
+ t.rename :user_id, :entity_id
7
+ t.string :entity_type, null: true, default: Federails::Configuration.user_class&.demodulize
8
+ t.index [:entity_type, :entity_id], name: 'index_federails_actors_on_entity', unique: true
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,8 @@
1
+ class AddKeypairToActors < ActiveRecord::Migration[7.0]
2
+ def change
3
+ change_table :federails_actors do |t|
4
+ t.text :public_key
5
+ t.text :private_key
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,92 @@
1
+ module Federails
2
+ # rubocop:disable Style/ClassVars
3
+ module Configuration
4
+ # Application name, used in well-known and nodeinfo endpoints
5
+ mattr_accessor :app_name
6
+ @@app_name = nil
7
+
8
+ # Application version, used in well-known and nodeinfo endpoints
9
+ mattr_accessor :app_version
10
+ @@app_version = nil
11
+
12
+ # Force https urls in various rendered content (currently in webfinger views)
13
+ mattr_accessor :force_ssl
14
+ @@force_ssl = nil
15
+
16
+ # Site hostname
17
+ mattr_reader :site_host
18
+ @@site_host = nil
19
+
20
+ # Site port
21
+ mattr_reader :site_port
22
+ @@site_port = nil
23
+
24
+ # Whether to enable ".well-known" and "nodeinfo" endpoints
25
+ mattr_accessor :enable_discovery
26
+ @@enable_discovery = true
27
+
28
+ # Site port
29
+ mattr_accessor :app_layout
30
+ @@app_layout = nil
31
+
32
+ # User class name
33
+ # @deprecated Kept for upgrade compatibility only
34
+ mattr_accessor :user_class
35
+ @@user_class = '::User'
36
+
37
+ # Route path for the federation URLs (to "Federails::Server::*" controllers)
38
+ mattr_accessor :server_routes_path
39
+ @@server_routes_path = :federation
40
+
41
+ # Route path for the webapp URLs (to "Federails::Client::*" controllers)
42
+ mattr_accessor :client_routes_path
43
+ @@client_routes_path = :app
44
+
45
+ # Route method for remote-following requests
46
+ mattr_accessor :remote_follow_url_method
47
+ @@remote_follow_url_method = 'federails.new_client_following_url'
48
+
49
+ # Method to use for links to user profiles
50
+ # @deprecated Set profile_url_method option on acts_as_federails_actor instead
51
+ mattr_accessor :user_profile_url_method
52
+ @@user_profile_url_method = nil
53
+
54
+ # Attribute in the user model to use as the user's name
55
+ # @deprecated Set name_field option on acts_as_federails_actor instead
56
+ #
57
+ # It only have sense if you have a separate username attribute
58
+ mattr_accessor :user_name_field
59
+ @@user_name_field = nil
60
+
61
+ # Attribute in the user model to use as the username for local actors
62
+ # @deprecated Set username_field option on acts_as_federails_actor instead
63
+ mattr_accessor :user_username_field
64
+ @@user_username_field = :id
65
+
66
+ ##
67
+ # @return [String] Table used for user model
68
+ # @deprecated Kept for upgrade compatibility only
69
+ def self.user_table
70
+ @@user_class&.constantize&.table_name
71
+ end
72
+
73
+ def self.site_host=(value)
74
+ @@site_host = value
75
+ Federails::Engine.routes.default_url_options[:host] = value
76
+ end
77
+
78
+ def self.site_port=(value)
79
+ @@site_port = value
80
+ Federails::Engine.routes.default_url_options[:port] = value
81
+ end
82
+
83
+ # List of entity types
84
+ mattr_reader :entity_types
85
+ @@entity_types = {}
86
+
87
+ def self.register_entity(klass, config = {})
88
+ @@entity_types[klass.name] = config.merge(class: klass)
89
+ end
90
+ end
91
+ # rubocop:enable Style/ClassVars
92
+ end
@@ -1,5 +1,11 @@
1
1
  module Federails
2
2
  class Engine < ::Rails::Engine
3
3
  isolate_namespace Federails
4
+
5
+ config.generators do |g|
6
+ g.test_framework :rspec
7
+ g.fixture_replacement :factory_bot
8
+ g.factory_bot dir: 'spec/factories'
9
+ end
4
10
  end
5
11
  end