federails 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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