federails 0.4.0 → 0.6.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/LICENSE +21 -0
- data/README.md +19 -189
- data/app/controllers/federails/client/actors_controller.rb +18 -4
- data/app/controllers/federails/server/actors_controller.rb +4 -1
- data/app/controllers/federails/server/published_controller.rb +30 -0
- data/app/controllers/federails/server/web_finger_controller.rb +9 -6
- data/app/controllers/federails/server_controller.rb +7 -0
- data/app/models/concerns/federails/actor_entity.rb +120 -56
- data/app/models/concerns/federails/data_entity.rb +205 -0
- data/app/models/concerns/federails/handles_delete_requests.rb +31 -0
- data/app/models/concerns/federails/has_uuid.rb +27 -1
- data/app/models/federails/activity.rb +27 -4
- data/app/models/federails/actor.rb +93 -30
- data/app/models/federails/following.rb +29 -9
- data/app/policies/federails/server/publishable_policy.rb +15 -0
- data/app/views/federails/client/actors/_actor.json.jbuilder +4 -1
- data/app/views/federails/client/actors/gone.html.erb +1 -0
- data/app/views/federails/client/actors/index.html.erb +7 -1
- data/app/views/federails/server/activities/_activity.activitypub.jbuilder +8 -3
- data/app/views/federails/server/actors/_actor.activitypub.jbuilder +2 -2
- data/app/views/federails/server/actors/_tombstone.activitypub.jbuilder +9 -0
- data/app/views/federails/server/actors/show.activitypub.jbuilder +5 -1
- data/app/views/federails/server/published/_publishable.activitypub.jbuilder +11 -0
- data/app/views/federails/server/published/_tombstone.activitypub.jbuilder +9 -0
- data/app/views/federails/server/published/show.activitypub.jbuilder +5 -0
- data/config/routes.rb +4 -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/lib/federails/configuration.rb +24 -1
- data/lib/federails/data_transformer/note.rb +31 -0
- data/lib/federails/maintenance/actors_updater.rb +67 -0
- data/lib/federails/utils/actor.rb +53 -0
- data/lib/federails/utils/object.rb +131 -0
- data/lib/federails/version.rb +1 -1
- data/lib/federails.rb +54 -0
- data/lib/fediverse/inbox.rb +40 -8
- data/lib/fediverse/notifier.rb +3 -0
- data/lib/fediverse/request.rb +13 -0
- data/lib/fediverse/webfinger.rb +72 -26
- data/lib/fediverse.rb +3 -0
- data/lib/tasks/federails_tasks.rake +8 -4
- metadata +22 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0538a0c2d7f7e3845a5d8ae304ac2b319b3cf1e76b10520645773f8f763c3431'
|
4
|
+
data.tar.gz: e97c559ecc5aba1b1c05c9be5f39b982a22e92cb8f73ae8c8a08741a3efb3d01
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 560377c5b698b87274d1df302595c33467f010402096227583161087aaf124b0a9e2820f44234b2932c158e84b0ab8ccb79ea8501557840509a416c7b8205295
|
7
|
+
data.tar.gz: 6380fc79556446afbd4a81e3e5e2e6b49bdb5877576dd1038208c1c4471cd3986bb35bbfaae1a9f37e618ddf5ab14dcf6974f512f6a609c70c2de0b7c251803f
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2020 Experiments Labs / Experimentations
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -23,207 +23,37 @@ The general direction is to be able to:
|
|
23
23
|
- implement some or all the parts of the RFC labelled with **SHOULD** and **SHOULD NOT**
|
24
24
|
- maybe implement the parts of the RFC labelled with **MAY**
|
25
25
|
|
26
|
-
##
|
26
|
+
## Supported Ruby on Rails versions
|
27
27
|
|
28
|
-
|
28
|
+
This gem is tested against non end-of-life versions of Ruby and Rails:
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
```
|
30
|
+
- Ruby versions 3.1 to 3.4
|
31
|
+
- Rails 7.1 to 8.0.x.
|
33
32
|
|
34
|
-
|
33
|
+
Feel free to open an issue if we missed something
|
35
34
|
|
36
|
-
|
37
|
-
$ bundle
|
38
|
-
```
|
35
|
+
It _may_ work on other versions, but we won't provide support.
|
39
36
|
|
40
|
-
|
37
|
+
## Documentation
|
41
38
|
|
42
|
-
|
39
|
+
- [Usage](docs/usage.md)
|
40
|
+
- [Common questions](docs/faq.md)
|
41
|
+
- [Contributing](CONTRIBUTING.md)
|
43
42
|
|
44
|
-
|
45
|
-
bundle exec rails generate federails:install
|
46
|
-
```
|
47
|
-
|
48
|
-
It creates an initializer and a configuration file:
|
49
|
-
- `config/initializers/federails.rb`
|
50
|
-
- `config/federails.yml`
|
51
|
-
|
52
|
-
By default, Federails is configured using `config_from` method, that loads the appropriate YAML file, but you may want
|
53
|
-
to configure it differently:
|
54
|
-
|
55
|
-
```rb
|
56
|
-
# config/initializers/federails.rb
|
57
|
-
Federails.configure do |config|
|
58
|
-
config.host = 'localhost'
|
59
|
-
# ...
|
60
|
-
end
|
61
|
-
```
|
62
|
-
|
63
|
-
For now, refer to [the source code](lib/federails/configuration.rb) for the full list of options.
|
64
|
-
|
65
|
-
### Routes
|
66
|
-
|
67
|
-
Mount the engine on `/`: routes to `/.well-known/*` and `/nodeinfo/*` must be at the root of the site.
|
68
|
-
Federails routes are then available under the configured path (`routes_path`):
|
69
|
-
|
70
|
-
```rb
|
71
|
-
# config/routes.rb
|
72
|
-
mount Federails::Engine => '/'
|
73
|
-
```
|
74
|
-
|
75
|
-
With `routes_path = 'federation'`, routes will be:
|
76
|
-
|
77
|
-
```txt
|
78
|
-
/.well-known/webfinger(.:format)
|
79
|
-
/.well-known/host-meta(.:format)
|
80
|
-
/.well-known/nodeinfo(.:format)
|
81
|
-
/nodeinfo/2.0(.:format)
|
82
|
-
/federation/actors/:id/followers(.:format)
|
83
|
-
/federation/actors/:id/following(.:format)
|
84
|
-
/federation/actors/:actor_id/outbox(.:format)
|
85
|
-
/federation/actors/:actor_id/inbox(.:format)
|
86
|
-
/federation/actors/:actor_id/activities/:id(.:format)
|
87
|
-
/federation/actors/:actor_id/followings/:id(.:format)
|
88
|
-
/federation/actors/:actor_id/notes/:id(.:format)
|
89
|
-
/federation/actors/:id(.:format)
|
90
|
-
...
|
91
|
-
```
|
92
|
-
|
93
|
-
Some routes can be disabled in configuration if you don't want to expose particular features:
|
94
|
-
|
95
|
-
```rb
|
96
|
-
Federails.configure do |config|
|
97
|
-
# Disable routing for .well-known and nodeinfo
|
98
|
-
config.enable_discovery = false
|
99
|
-
|
100
|
-
# Disable web client UI routes
|
101
|
-
config.client_routes_path = nil
|
102
|
-
end
|
103
|
-
```
|
104
|
-
|
105
|
-
#### Remote following
|
106
|
-
|
107
|
-
By default, remote follow requests (where you press a follow button on another server and get redirected home to complete the follow)
|
108
|
-
will use the built-in client paths. If you're not using the client, or want to provide your own user interface, you can set the path like this, assuming that `new_follow_url` is a valid route in your app. A `uri` query parameter template will be automatically appended, you don't need to specify that.
|
109
|
-
|
110
|
-
```rb
|
111
|
-
Federails.configure do |config|
|
112
|
-
config.remote_follow_url_method = :new_follow_url
|
113
|
-
end
|
114
|
-
```
|
115
|
-
|
116
|
-
### Migrations
|
117
|
-
|
118
|
-
Copy the migrations:
|
119
|
-
|
120
|
-
```sh
|
121
|
-
bundle exec rails federails:install:migrations
|
122
|
-
```
|
123
|
-
|
124
|
-
### User model
|
125
|
-
|
126
|
-
In the ActivityPub world, we refer to _actors_ to represent the thing that publishes or subscribe to _other actors_.
|
127
|
-
|
128
|
-
Federails provides a concern to include in your "user" model or whatever will publish data:
|
129
|
-
|
130
|
-
```rb
|
131
|
-
# app/models/user.rb
|
132
|
-
|
133
|
-
class User < ApplicationRecord
|
134
|
-
# Include the concern here:
|
135
|
-
include Federails::ActorEntity
|
136
|
-
|
137
|
-
# Configure field names
|
138
|
-
acts_as_federails_actor username_field: :username, name_field: :name, profile_url_method: :user_url
|
139
|
-
end
|
140
|
-
```
|
141
|
-
|
142
|
-
This concern automatically create a `Federails::Actor` after a user creation, as well as the `actor` reference. When adding it to
|
143
|
-
an existing model with existing data, you will need to generate the corresponding actors yourself in a migration.
|
144
|
-
|
145
|
-
Usage example:
|
146
|
-
|
147
|
-
```rb
|
148
|
-
actor = User.find(1).federails_actor
|
149
|
-
|
150
|
-
actor.inbox
|
151
|
-
actor.outbox
|
152
|
-
actor.followers
|
153
|
-
actor.following
|
154
|
-
#...
|
155
|
-
```
|
156
|
-
|
157
|
-
### Using the Federails client
|
158
|
-
|
159
|
-
Federails comes with a client, enabled by default, that provides basic views to display and interact with Federails data,
|
160
|
-
accessible on `/app` by default (changeable with the configuration option `client_routes_path`)
|
161
|
-
|
162
|
-
If it's a good starting point, it might be disabled once you made your own integration by setting `client_routes_path`
|
163
|
-
to a `nil` value.
|
164
|
-
|
165
|
-
If you want to override the client's views, copy them in your application:
|
166
|
-
|
167
|
-
```sh
|
168
|
-
rails generate federails:copy_client_views
|
169
|
-
```
|
170
|
-
|
171
|
-
## Common questions
|
172
|
-
|
173
|
-
- **I override the base controller and the links breaks in my layout**
|
174
|
-
|
175
|
-
Use `main_app.<url_helper>` for links to your application; `federails.<federails_url_helper>` for links to the Federails client.
|
176
|
-
- **I specified a custom layout and the links breaks in it**
|
177
|
-
|
178
|
-
Use `main_app.<url_helper>` for links to your application; `federails.<federails_url_helper>` for links to the Federails client.
|
179
|
-
- **I specified a custom layout and my helpers are not available**
|
43
|
+
## License
|
180
44
|
|
181
|
-
|
45
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
182
46
|
|
183
47
|
## Contributing
|
184
48
|
|
185
|
-
|
49
|
+
See [CONTRIBUTING](CONTRIBUTING.md) to have an overview of the process and the tools we use.
|
186
50
|
|
187
|
-
|
188
|
-
- We adhere to [semantic versioning](). Please update the changelog in your commits
|
189
|
-
- We try to adhere to [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) principles
|
190
|
-
- We _may_ rename your commits before merging them
|
191
|
-
- We _may_ split your commits before merging them
|
51
|
+
### Contributors
|
192
52
|
|
193
|
-
|
53
|
+
- [echarp](https://gitlab.com/echarp)
|
54
|
+
- [James Smith](https://gitlab.com/floppy.uk)
|
55
|
+
- [Manuel Tancoigne](https://gitlab.com/mtancoigne)
|
194
56
|
|
195
|
-
|
196
|
-
2. Create small commits
|
197
|
-
3. Ideally create small pull requests. Don't hesitate to open them early so we all can follow how it's going
|
198
|
-
4. Get congratulated
|
57
|
+
### Indirect contributions
|
199
58
|
|
200
|
-
|
201
|
-
|
202
|
-
#### RSpec
|
203
|
-
|
204
|
-
RSpec is the test suite. Start it with
|
205
|
-
|
206
|
-
```sh
|
207
|
-
bundle exec rspec
|
208
|
-
```
|
209
|
-
|
210
|
-
#### Rubocop
|
211
|
-
|
212
|
-
Rubocop is a linter. Start it with
|
213
|
-
|
214
|
-
```sh
|
215
|
-
bundle exec rubocop
|
216
|
-
```
|
217
|
-
|
218
|
-
#### FactoryBot
|
219
|
-
|
220
|
-
FactoryBot is a factory generator used in tests and development.
|
221
|
-
A rake task checks the replayability of the factories and traits:
|
222
|
-
|
223
|
-
```sh
|
224
|
-
bundle exec app:factory_bot:lint
|
225
|
-
```
|
226
|
-
|
227
|
-
## License
|
228
|
-
|
229
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
59
|
+
- Gitlab runners are graciously provided by [Coopaname](https://coopaname.coop), a French cooperative.
|
@@ -14,14 +14,16 @@ module Federails
|
|
14
14
|
|
15
15
|
# GET /app/actors/1
|
16
16
|
# GET /app/actors/1.json
|
17
|
-
def show
|
17
|
+
def show
|
18
|
+
render_show
|
19
|
+
end
|
18
20
|
|
19
|
-
# GET /app/
|
20
|
-
# GET /app/
|
21
|
+
# GET /app/actors/lookup
|
22
|
+
# GET /app/actors/lookup.json
|
21
23
|
def lookup
|
22
24
|
@actor = Federails::Actor.find_by_account account_param
|
23
25
|
authorize @actor, policy_class: Federails::Client::ActorPolicy
|
24
|
-
|
26
|
+
render_show
|
25
27
|
end
|
26
28
|
|
27
29
|
private
|
@@ -35,6 +37,18 @@ module Federails
|
|
35
37
|
def account_param
|
36
38
|
params.require('account')
|
37
39
|
end
|
40
|
+
|
41
|
+
def render_show
|
42
|
+
respond_to do |format|
|
43
|
+
if @actor.tombstoned?
|
44
|
+
format.html { render :gone, status: :gone }
|
45
|
+
format.json { render json: { error: I18n.t('controller.actors.gone') }, status: :gone }
|
46
|
+
else
|
47
|
+
format.html { render :show }
|
48
|
+
format.json { render :show }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
38
52
|
end
|
39
53
|
end
|
40
54
|
end
|
@@ -5,7 +5,10 @@ module Federails
|
|
5
5
|
|
6
6
|
# GET /federation/actors/1
|
7
7
|
# GET /federation/actors/1.json
|
8
|
-
def show
|
8
|
+
def show
|
9
|
+
status = @actor.tombstoned? ? :gone : :ok
|
10
|
+
render :show, status: status
|
11
|
+
end
|
9
12
|
|
10
13
|
# GET /federation/actors/:id/followers
|
11
14
|
# GET /federation/actors/:id/followers.json
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Federails
|
2
|
+
module Server
|
3
|
+
# Controller to render ActivityPub representation of entities configured with Federails::DataEntity
|
4
|
+
class PublishedController < Federails::ServerController
|
5
|
+
def show
|
6
|
+
@publishable = type_scope.find_untombstoned_by!(url_param => params[:id])
|
7
|
+
authorize @publishable, policy_class: Federails::Server::PublishablePolicy
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def publishable_config
|
13
|
+
return @publishable_config if instance_variable_defined? :@publishable_config
|
14
|
+
|
15
|
+
_, @publishable_config = Federails.configuration.data_types.find { |_, v| v[:route_path_segment].to_s == params[:publishable_type] }
|
16
|
+
raise ActiveRecord::RecordNotFound, "Invalid #{params[:publishable_type]} type" unless @publishable_config
|
17
|
+
|
18
|
+
@publishable_config
|
19
|
+
end
|
20
|
+
|
21
|
+
def url_param
|
22
|
+
publishable_config[:url_param]
|
23
|
+
end
|
24
|
+
|
25
|
+
def type_scope
|
26
|
+
publishable_config[:class].all
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -9,11 +9,12 @@ module Federails
|
|
9
9
|
resource = params.require(:resource)
|
10
10
|
case resource
|
11
11
|
when %r{^https?://.+}
|
12
|
-
@user = Federails::Actor.find_by_federation_url(resource)
|
12
|
+
@user = Federails::Actor.find_by_federation_url!(resource).entity # rubocop:disable Rails/DynamicFindBy
|
13
13
|
when /^acct:.+/
|
14
|
-
Federails::
|
15
|
-
|
16
|
-
|
14
|
+
actor = Federails::Actor.find_local_by_username(username)
|
15
|
+
raise Federails::Actor::TombstonedError if actor&.tombstoned?
|
16
|
+
|
17
|
+
@user = actor&.entity
|
17
18
|
end
|
18
19
|
raise ActiveRecord::RecordNotFound if @user.nil?
|
19
20
|
|
@@ -31,11 +32,13 @@ module Federails
|
|
31
32
|
private
|
32
33
|
|
33
34
|
def username
|
34
|
-
|
35
|
+
return @username if instance_variable_defined? :@username
|
36
|
+
|
37
|
+
account = Fediverse::Webfinger.split_account params.require(:resource)
|
35
38
|
# Fail early if user don't _seems_ local
|
36
39
|
raise ActiveRecord::RecordNotFound unless account && Fediverse::Webfinger.local_user?(account)
|
37
40
|
|
38
|
-
account[:username]
|
41
|
+
@username = account[:username]
|
39
42
|
end
|
40
43
|
end
|
41
44
|
end
|
@@ -8,6 +8,9 @@ module Federails
|
|
8
8
|
helper Federails::ServerHelper
|
9
9
|
|
10
10
|
rescue_from ActiveRecord::RecordNotFound, with: :error_not_found
|
11
|
+
rescue_from Federails::Actor::TombstonedError,
|
12
|
+
Federails::DataEntity::TombstonedError,
|
13
|
+
with: :error_gone
|
11
14
|
|
12
15
|
private
|
13
16
|
|
@@ -26,5 +29,9 @@ module Federails
|
|
26
29
|
def error_not_found(exception = nil)
|
27
30
|
error_fallback(exception, 'Resource not found', :not_found)
|
28
31
|
end
|
32
|
+
|
33
|
+
def error_gone(exception = nil)
|
34
|
+
error_fallback(exception, 'Resource is gone', :gone)
|
35
|
+
end
|
29
36
|
end
|
30
37
|
end
|
@@ -1,51 +1,45 @@
|
|
1
1
|
module Federails
|
2
|
+
# Concern to include in models that acts as actors.
|
3
|
+
#
|
4
|
+
# Actors can be anything; they authors content _via_ their _outbox_ and receive content in their _inbox_.
|
5
|
+
# Actors can follow and be followed by each other
|
6
|
+
#
|
7
|
+
# By default, when an entry is created on models using this concern, a _local_ `Federails::Actor` will be created.
|
8
|
+
#
|
9
|
+
# See also:
|
10
|
+
# - https://www.w3.org/TR/activitypub/#actor-objects
|
11
|
+
#
|
12
|
+
# ## Usage
|
13
|
+
#
|
14
|
+
# Include the concern in an existing model:
|
15
|
+
#
|
16
|
+
# ```rb
|
17
|
+
# class User < ApplicationRecord
|
18
|
+
# include Federails::ActorEntity
|
19
|
+
# acts_as_federails_actor options
|
20
|
+
# end
|
21
|
+
# ```
|
2
22
|
module ActorEntity
|
3
23
|
extend ActiveSupport::Concern
|
4
24
|
|
5
|
-
included
|
6
|
-
|
7
|
-
define_callbacks :followed
|
8
|
-
|
9
|
-
# Define a method that will be called after the entity receives a follow request
|
10
|
-
# @param method [Symbol] The name of the method to call, or a block that will be called directly
|
11
|
-
# @example
|
12
|
-
# after_followed :accept_follow
|
13
|
-
def self.after_followed(method)
|
14
|
-
set_callback :followed, :after, method
|
15
|
-
end
|
16
|
-
|
17
|
-
# Define a method that will be called after an activity has been received
|
18
|
-
# @param activity_type [String] The activity action to handle, e.g. 'Create'. If you specify '*', the handler will be called for any activity type.
|
19
|
-
# @param object_type [String] The object type to handle, e.g. 'Note'. If you specify '*', the handler will be called for any object type.
|
20
|
-
# @param method [Symbol] The name of the class method to call. The method will receive the complete activity payload as a parameter.
|
21
|
-
# @example
|
22
|
-
# after_activity_received 'Create', 'Note', :create_note
|
23
|
-
def self.after_activity_received(activity_type, object_type, method)
|
24
|
-
Fediverse::Inbox.register_handler(activity_type, object_type, self, method)
|
25
|
-
end
|
26
|
-
|
27
|
-
has_one :federails_actor, class_name: 'Federails::Actor', as: :entity, dependent: :destroy
|
28
|
-
|
29
|
-
after_create :create_federails_actor, if: lambda {
|
30
|
-
raise("Entity not configured for #{self.class.name}. Did you use \"acts_as_federails_actor\"?") unless Federails.actor_entity? self
|
31
|
-
|
32
|
-
Federails.actor_entity(self)[:auto_create_actors]
|
33
|
-
}
|
34
|
-
|
25
|
+
# Class methods automatically included in the concern.
|
26
|
+
module ClassMethods
|
35
27
|
# Configures the mapping between entity and actor
|
28
|
+
#
|
36
29
|
# @param username_field [Symbol] The method or attribute name that returns the preferred username for ActivityPub
|
37
30
|
# @param name_field [Symbol] The method or attribute name that returns the preferred name for ActivityPub
|
38
31
|
# @param profile_url_method [Symbol] The route method name that will generate the profile URL for ActivityPub
|
39
32
|
# @param actor_type [String] The ActivityStreams Actor type for this entity; defaults to 'Person'
|
40
33
|
# @param user_count_method [Symbol] A class method to call to count active users. Leave unspecified to leave this
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
34
|
+
# entity out of user counts. Method signature should accept a single parameter which will specify a date range
|
35
|
+
# If parameter is nil, the total user count should be returned. If the parameter is specified, the number of users
|
36
|
+
# active during the time period should be returned.
|
44
37
|
# @param auto_create_actors [Boolean] Whether to automatically create an actor when the entity is created
|
38
|
+
#
|
45
39
|
# @example
|
46
40
|
# acts_as_federails_actor username_field: :username, name_field: :display_name, profile_url_method: :url_for, actor_type: 'Person'
|
47
41
|
# rubocop:disable Metrics/ParameterLists
|
48
|
-
def
|
42
|
+
def acts_as_federails_actor(
|
49
43
|
name_field:,
|
50
44
|
username_field:,
|
51
45
|
profile_url_method: nil,
|
@@ -65,34 +59,104 @@ module Federails
|
|
65
59
|
end
|
66
60
|
# rubocop:enable Metrics/ParameterLists
|
67
61
|
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
62
|
+
# Define a method that will be called after the entity receives a follow request.
|
63
|
+
# The follow request will be passed as an argument to the method.
|
64
|
+
#
|
65
|
+
# @param method_name [Symbol] The name of the method to call, or a block that will be called directly
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
# after_followed :accept_follow
|
69
|
+
def after_followed(method_name)
|
70
|
+
@after_followed = method_name
|
71
|
+
end
|
72
|
+
|
73
|
+
# Define a method that will be called after a follow request made by the entity is accepted
|
74
|
+
# The accepted follow request will be passed as an argument to the method.
|
75
|
+
#
|
76
|
+
# @param method_name [Symbol] The name of the method to call, or a block that will be called directly
|
77
|
+
#
|
72
78
|
# @example
|
73
|
-
#
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
|
87
|
-
|
88
|
-
{}
|
79
|
+
# after_follow_accepted :follow_accepted
|
80
|
+
def after_follow_accepted(method_name)
|
81
|
+
@after_follow_accepted = method_name
|
82
|
+
end
|
83
|
+
|
84
|
+
# Define a method that will be called after an activity has been received
|
85
|
+
#
|
86
|
+
# @param activity_type [String] The activity action to handle, e.g. 'Create'. If you specify '*', the handler will be called for any activity type.
|
87
|
+
# @param object_type [String] The object type to handle, e.g. 'Note'. If you specify '*', the handler will be called for any object type.
|
88
|
+
# @param method_name [Symbol] The name of the class method to call. The method will receive the complete activity payload as a parameter.
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# after_activity_received 'Create', 'Note', :create_note
|
92
|
+
def after_activity_received(activity_type, object_type, method_name)
|
93
|
+
Fediverse::Inbox.register_handler(activity_type, object_type, self, method_name)
|
89
94
|
end
|
90
95
|
|
91
96
|
private
|
92
97
|
|
93
|
-
def
|
94
|
-
|
98
|
+
def dispatch_callback(name, instance, *args)
|
99
|
+
case name
|
100
|
+
when :after_followed
|
101
|
+
instance.send(@after_followed, *args) if @after_followed
|
102
|
+
when :after_follow_accepted
|
103
|
+
instance.send(@after_follow_accepted, *args) if @after_follow_accepted
|
104
|
+
end
|
95
105
|
end
|
96
106
|
end
|
107
|
+
|
108
|
+
included do
|
109
|
+
# No "dependent: :xyz" as the "before_destroy" hook should have nullified the actor
|
110
|
+
has_one :federails_actor, class_name: 'Federails::Actor', as: :entity # rubocop:disable Rails/HasManyOrHasOneDependent
|
111
|
+
|
112
|
+
after_create :create_federails_actor, if: lambda {
|
113
|
+
raise("Entity not configured for #{self.class.name}. Did you use \"acts_as_federails_actor\"?") unless Federails.actor_entity? self
|
114
|
+
|
115
|
+
Federails.actor_entity(self)[:auto_create_actors]
|
116
|
+
}
|
117
|
+
before_destroy :tombstone_federails_actor!
|
118
|
+
end
|
119
|
+
|
120
|
+
# Add custom data to actor responses.
|
121
|
+
#
|
122
|
+
# Override in your own model to add extra data, which will be merged into the actor response
|
123
|
+
# generated by Federails. You can include extra `@context` for activitypub extensions and it will
|
124
|
+
# be merged with the main response context.
|
125
|
+
#
|
126
|
+
# @example
|
127
|
+
# def to_activitypub_object
|
128
|
+
# {
|
129
|
+
# "@context": {
|
130
|
+
# toot: "http://joinmastodon.org/ns#",
|
131
|
+
# attributionDomains: {
|
132
|
+
# "@id": "toot:attributionDomains",
|
133
|
+
# "@type": "@id"
|
134
|
+
# }
|
135
|
+
# },
|
136
|
+
# attributionDomains: [
|
137
|
+
# "example.com"
|
138
|
+
# ]
|
139
|
+
# }
|
140
|
+
# end
|
141
|
+
def to_activitypub_object
|
142
|
+
{}
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
# Result is used to determine if an actor related to this entity should be created as local actor or not
|
148
|
+
#
|
149
|
+
# Override it in your models if you need distant actors to be related to another entity.
|
150
|
+
def create_federails_actor_as_local?
|
151
|
+
true
|
152
|
+
end
|
153
|
+
|
154
|
+
def create_federails_actor
|
155
|
+
Federails::Actor.create_with(local: create_federails_actor_as_local?).find_or_create_by!(entity: self)
|
156
|
+
end
|
157
|
+
|
158
|
+
def tombstone_federails_actor!
|
159
|
+
federails_actor.tombstone!
|
160
|
+
end
|
97
161
|
end
|
98
162
|
end
|