federails 0.0.1 → 0.1.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 +171 -7
- data/Rakefile +5 -5
- data/app/controllers/federails/application_controller.rb +19 -0
- data/app/controllers/federails/client/activities_controller.rb +21 -0
- data/app/controllers/federails/client/actors_controller.rb +37 -0
- data/app/controllers/federails/client/followings_controller.rb +93 -0
- data/app/controllers/federails/server/activities_controller.rb +65 -0
- data/app/controllers/federails/server/actors_controller.rb +34 -0
- data/app/controllers/federails/server/followings_controller.rb +18 -0
- data/app/controllers/federails/server/nodeinfo_controller.rb +22 -0
- data/app/controllers/federails/server/server_controller.rb +17 -0
- data/app/controllers/federails/server/web_finger_controller.rb +38 -0
- data/app/jobs/federails/notify_inbox_job.rb +12 -0
- data/app/mailers/federails/application_mailer.rb +2 -2
- data/app/models/concerns/federails/entity.rb +46 -0
- data/app/models/federails/activity.rb +40 -0
- data/app/models/federails/actor.rb +152 -0
- data/app/models/federails/following.rb +43 -0
- data/app/policies/federails/client/activity_policy.rb +6 -0
- data/app/policies/federails/client/actor_policy.rb +15 -0
- data/app/policies/federails/client/following_policy.rb +35 -0
- data/app/policies/federails/federails_policy.rb +59 -0
- data/app/policies/federails/server/activity_policy.rb +6 -0
- data/app/policies/federails/server/actor_policy.rb +23 -0
- data/app/policies/federails/server/following_policy.rb +6 -0
- data/app/views/federails/client/activities/_activity.html.erb +5 -0
- data/app/views/federails/client/activities/_activity.json.jbuilder +1 -0
- data/app/views/federails/client/activities/_index.json.jbuilder +1 -0
- data/app/views/federails/client/activities/feed.html.erb +4 -0
- data/app/views/federails/client/activities/feed.json.jbuilder +1 -0
- data/app/views/federails/client/activities/index.html.erb +5 -0
- data/app/views/federails/client/activities/index.json.jbuilder +1 -0
- data/app/views/federails/client/actors/_actor.json.jbuilder +14 -0
- data/app/views/federails/client/actors/_lookup_form.html.erb +5 -0
- data/app/views/federails/client/actors/index.html.erb +24 -0
- data/app/views/federails/client/actors/index.json.jbuilder +1 -0
- data/app/views/federails/client/actors/show.html.erb +100 -0
- data/app/views/federails/client/actors/show.json.jbuilder +1 -0
- data/app/views/federails/client/followings/_follow.html.erb +4 -0
- data/app/views/federails/client/followings/_follower.html.erb +7 -0
- data/app/views/federails/client/followings/_following.json.jbuilder +1 -0
- data/app/views/federails/client/followings/_form.html.erb +21 -0
- data/app/views/federails/client/followings/index.html.erb +29 -0
- data/app/views/federails/client/followings/index.json.jbuilder +1 -0
- data/app/views/federails/client/followings/show.html.erb +21 -0
- data/app/views/federails/client/followings/show.json.jbuilder +1 -0
- data/app/views/federails/server/activities/_activity.json.jbuilder +9 -0
- data/app/views/federails/server/activities/outbox.json.jbuilder +18 -0
- data/app/views/federails/server/activities/show.json.jbuilder +1 -0
- data/app/views/federails/server/actors/_actor.json.jbuilder +11 -0
- data/app/views/federails/server/actors/followers.json.jbuilder +18 -0
- data/app/views/federails/server/actors/following.json.jbuilder +18 -0
- data/app/views/federails/server/actors/show.json.jbuilder +1 -0
- data/app/views/federails/server/followings/_following.json.jbuilder +7 -0
- data/app/views/federails/server/followings/show.json.jbuilder +1 -0
- data/app/views/federails/server/nodeinfo/index.json.jbuilder +6 -0
- data/app/views/federails/server/nodeinfo/show.json.jbuilder +19 -0
- data/app/views/federails/server/web_finger/find.json.jbuilder +20 -0
- data/app/views/federails/server/web_finger/host_meta.xml.erb +5 -0
- data/config/routes.rb +43 -0
- data/db/migrate/20200712133150_create_federails_actors.rb +24 -0
- data/db/migrate/20200712143127_create_federails_followings.rb +14 -0
- data/db/migrate/20200712174938_create_federails_activities.rb +11 -0
- data/db/migrate/20240731145400_change_actor_entity_rel_to_polymorphic.rb +11 -0
- data/lib/federails/configuration.rb +88 -0
- data/lib/federails/engine.rb +6 -0
- data/lib/federails/utils/host.rb +54 -0
- data/lib/federails/version.rb +1 -1
- data/lib/federails.rb +33 -3
- data/lib/fediverse/inbox.rb +71 -0
- data/lib/fediverse/notifier.rb +21 -0
- data/lib/fediverse/request.rb +38 -0
- data/lib/fediverse/webfinger.rb +93 -0
- data/lib/generators/federails/install/USAGE +9 -0
- data/lib/generators/federails/install/install_generator.rb +10 -0
- data/lib/generators/federails/install/templates/federails.rb +1 -0
- data/lib/generators/federails/install/templates/federails.yml +23 -0
- data/lib/tasks/factory_bot.rake +15 -0
- metadata +165 -10
- data/app/views/layouts/federails/application.html.erb +0 -15
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Federails
|
|
2
|
+
class Activity < ApplicationRecord
|
|
3
|
+
belongs_to :entity, polymorphic: true
|
|
4
|
+
belongs_to :actor
|
|
5
|
+
|
|
6
|
+
scope :feed_for, lambda { |actor|
|
|
7
|
+
actor_ids = []
|
|
8
|
+
Following.accepted.where(actor: actor).find_each do |following|
|
|
9
|
+
actor_ids << following.target_actor_id
|
|
10
|
+
end
|
|
11
|
+
where(actor_id: actor_ids)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
after_create_commit :post_to_inboxes
|
|
15
|
+
|
|
16
|
+
def recipients # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
17
|
+
return [] unless actor.local?
|
|
18
|
+
|
|
19
|
+
actors = []
|
|
20
|
+
case action
|
|
21
|
+
when 'Create'
|
|
22
|
+
actors.push(entity.target_actor) if entity_type == 'Federails::Following'
|
|
23
|
+
# FIXME: Move this to dummy, somehow
|
|
24
|
+
actors.push(*actor.followers) if entity_type == 'Note'
|
|
25
|
+
when 'Accept'
|
|
26
|
+
actors.push(entity.actor) if entity_type == 'Federails::Following'
|
|
27
|
+
when 'Undo'
|
|
28
|
+
actors.push(entity.target_actor) if entity_type == 'Federails::Following'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
actors
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def post_to_inboxes
|
|
37
|
+
NotifyInboxJob.perform_later(self)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
require 'federails/utils/host'
|
|
2
|
+
require 'fediverse/webfinger'
|
|
3
|
+
|
|
4
|
+
module Federails
|
|
5
|
+
class Actor < ApplicationRecord # rubocop:disable Metrics/ClassLength
|
|
6
|
+
validates :federated_url, presence: { unless: :entity }, uniqueness: { unless: :entity }
|
|
7
|
+
validates :username, presence: { unless: :entity }
|
|
8
|
+
validates :server, presence: { unless: :entity }
|
|
9
|
+
validates :inbox_url, presence: { unless: :entity }
|
|
10
|
+
validates :outbox_url, presence: { unless: :entity }
|
|
11
|
+
validates :followers_url, presence: { unless: :entity }
|
|
12
|
+
validates :followings_url, presence: { unless: :entity }
|
|
13
|
+
validates :profile_url, presence: { unless: :entity }
|
|
14
|
+
validates :entity_id, uniqueness: { scope: :entity_type }, if: :local?
|
|
15
|
+
|
|
16
|
+
belongs_to :entity, polymorphic: true, optional: true
|
|
17
|
+
# FIXME: Handle this with something like undelete
|
|
18
|
+
has_many :activities, dependent: :destroy
|
|
19
|
+
has_many :activities_as_entity, class_name: 'Federails::Activity', as: :entity, dependent: :destroy
|
|
20
|
+
has_many :following_followers, class_name: 'Federails::Following', foreign_key: :target_actor_id, dependent: :destroy, inverse_of: :target_actor
|
|
21
|
+
has_many :following_follows, class_name: 'Federails::Following', dependent: :destroy, inverse_of: :actor
|
|
22
|
+
has_many :followers, source: :actor, through: :following_followers
|
|
23
|
+
has_many :follows, source: :target_actor, through: :following_follows
|
|
24
|
+
|
|
25
|
+
scope :local, -> { where.not(entity: nil) }
|
|
26
|
+
|
|
27
|
+
def local?
|
|
28
|
+
entity.present?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def federated_url
|
|
32
|
+
local? ? Federails::Engine.routes.url_helpers.server_actor_url(self) : attributes['federated_url'].presence
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def username
|
|
36
|
+
return attributes['username'] unless local?
|
|
37
|
+
|
|
38
|
+
entity.send(entity_configuration[:username_field]).to_s
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def name
|
|
42
|
+
value = (entity.send(entity_configuration[:name_field]).to_s if local?)
|
|
43
|
+
|
|
44
|
+
value || attributes['name'] || username
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def server
|
|
48
|
+
local? ? Utils::Host.localhost : attributes['server']
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def inbox_url
|
|
52
|
+
local? ? Federails::Engine.routes.url_helpers.server_actor_inbox_url(self) : attributes['inbox_url']
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def outbox_url
|
|
56
|
+
local? ? Federails::Engine.routes.url_helpers.server_actor_outbox_url(self) : attributes['outbox_url']
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def followers_url
|
|
60
|
+
local? ? Federails::Engine.routes.url_helpers.followers_server_actor_url(self) : attributes['followers_url']
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def followings_url
|
|
64
|
+
local? ? Federails::Engine.routes.url_helpers.following_server_actor_url(self) : attributes['followings_url']
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def profile_url
|
|
68
|
+
return attributes['profile_url'].presence unless local?
|
|
69
|
+
|
|
70
|
+
method = entity_configuration[:profile_url_method]
|
|
71
|
+
return Federails::Engine.routes.url_helpers.server_actor_url self unless method
|
|
72
|
+
|
|
73
|
+
Rails.application.routes.url_helpers.send method, [entity]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def at_address
|
|
77
|
+
"#{username}@#{server}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def short_at_address
|
|
81
|
+
local? ? "@#{username}" : at_address
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def follows?(actor)
|
|
85
|
+
list = following_follows.where target_actor: actor
|
|
86
|
+
return list.first if list.count == 1
|
|
87
|
+
|
|
88
|
+
false
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def entity_configuration
|
|
92
|
+
Federails::Configuration.entity_types[entity.class.name]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
class << self
|
|
96
|
+
def find_by_account(account) # rubocop:todo Metrics/AbcSize
|
|
97
|
+
parts = Fediverse::Webfinger.split_account account
|
|
98
|
+
|
|
99
|
+
if Fediverse::Webfinger.local_user? parts
|
|
100
|
+
actor = nil
|
|
101
|
+
Federails::Configuration.entity_types.each_value do |entity|
|
|
102
|
+
actor ||= entity[:class].find_by(entity[:username_field] => parts[:username])&.actor
|
|
103
|
+
end
|
|
104
|
+
raise ActiveRecord::RecordNotFound if actor.nil?
|
|
105
|
+
else
|
|
106
|
+
actor = find_by username: parts[:username], server: parts[:domain]
|
|
107
|
+
actor ||= Fediverse::Webfinger.fetch_actor(parts[:username], parts[:domain])
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
actor
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def find_by_federation_url(federated_url)
|
|
114
|
+
local_route = Utils::Host.local_route federated_url
|
|
115
|
+
return find local_route[:id] if local_route && local_route[:controller] == 'federails/server/actors' && local_route[:action] == 'show'
|
|
116
|
+
|
|
117
|
+
actor = find_by federated_url: federated_url
|
|
118
|
+
return actor if actor
|
|
119
|
+
|
|
120
|
+
Fediverse::Webfinger.fetch_actor_url(federated_url)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def find_or_create_by_account(account)
|
|
124
|
+
actor = find_by_account account
|
|
125
|
+
# Create/update distant actors
|
|
126
|
+
actor.save! unless actor.local?
|
|
127
|
+
|
|
128
|
+
actor
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def find_or_create_by_federation_url(url)
|
|
132
|
+
actor = find_by_federation_url url
|
|
133
|
+
# Create/update distant actors
|
|
134
|
+
actor.save! unless actor.local?
|
|
135
|
+
|
|
136
|
+
actor
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Find or create actor from a given actor hash or actor id (actor's URL)
|
|
140
|
+
def find_or_create_by_object(object)
|
|
141
|
+
case object
|
|
142
|
+
when String
|
|
143
|
+
find_or_create_by_federation_url object
|
|
144
|
+
when Hash
|
|
145
|
+
find_or_create_by_federation_url object['id']
|
|
146
|
+
else
|
|
147
|
+
raise "Unsupported object type for actor (#{object.class})"
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Federails
|
|
2
|
+
class Following < ApplicationRecord
|
|
3
|
+
enum status: { pending: 0, accepted: 1 }
|
|
4
|
+
|
|
5
|
+
validates :target_actor_id, uniqueness: { scope: [:actor_id, :target_actor_id] }
|
|
6
|
+
|
|
7
|
+
belongs_to :actor
|
|
8
|
+
belongs_to :target_actor, class_name: 'Federails::Actor'
|
|
9
|
+
# FIXME: Handle this with something like undelete
|
|
10
|
+
has_many :activities, as: :entity, dependent: :destroy
|
|
11
|
+
|
|
12
|
+
after_create :create_activity
|
|
13
|
+
after_destroy :destroy_activity
|
|
14
|
+
|
|
15
|
+
scope :with_actor, ->(actor) { where(actor_id: actor.id).or(where(target_actor_id: actor.id)) }
|
|
16
|
+
|
|
17
|
+
def federated_url
|
|
18
|
+
attributes['federated_url'].presence || Federails::Engine.routes.url_helpers.server_actor_following_url(actor_id: actor_id, id: id)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def accept!
|
|
22
|
+
update! status: :accepted
|
|
23
|
+
Activity.create! actor: target_actor, action: 'Accept', entity: self
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class << self
|
|
27
|
+
def new_from_account(account, actor:)
|
|
28
|
+
target_actor = Actor.find_or_create_by_account account
|
|
29
|
+
new actor: actor, target_actor: target_actor
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def create_activity
|
|
36
|
+
Activity.create! actor: actor, action: 'Create', entity: self
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def destroy_activity
|
|
40
|
+
Activity.create! actor: actor, action: 'Undo', entity: self
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Federails
|
|
2
|
+
module Client
|
|
3
|
+
class FollowingPolicy < Federails::FederailsPolicy
|
|
4
|
+
def show?
|
|
5
|
+
in_following?
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def destroy?
|
|
9
|
+
in_following?
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def accept?
|
|
13
|
+
in_following? && @record.target_actor_id == @user.actor.id
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def follow?
|
|
17
|
+
create?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Scope < Scope
|
|
21
|
+
def resolve
|
|
22
|
+
scope.with_actor(@user.actor)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def in_following?
|
|
29
|
+
return false if @user.blank?
|
|
30
|
+
|
|
31
|
+
@record.actor_id == @user.actor.id || @record.target_actor_id == @user.actor.id
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Federails
|
|
2
|
+
class FederailsPolicy
|
|
3
|
+
attr_reader :user, :record
|
|
4
|
+
|
|
5
|
+
def initialize(user, record)
|
|
6
|
+
@user = user
|
|
7
|
+
@record = record
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def index?
|
|
11
|
+
true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def show?
|
|
15
|
+
true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create?
|
|
19
|
+
@user.present?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def new?
|
|
23
|
+
create?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def update?
|
|
27
|
+
owner?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def edit?
|
|
31
|
+
update?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def destroy?
|
|
35
|
+
owner?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class Scope
|
|
39
|
+
attr_reader :user, :scope
|
|
40
|
+
|
|
41
|
+
def initialize(user, scope)
|
|
42
|
+
@user = user
|
|
43
|
+
@scope = scope
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def resolve
|
|
47
|
+
scope.all
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def owner?
|
|
54
|
+
return false unless @user
|
|
55
|
+
|
|
56
|
+
@record.actor_id == @user.actor.id
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Federails
|
|
2
|
+
module Server
|
|
3
|
+
class ActorPolicy < Federails::FederailsPolicy
|
|
4
|
+
def show?
|
|
5
|
+
@record.local?
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def following?
|
|
9
|
+
true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def followers?
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class Scope < Scope
|
|
17
|
+
def resolve
|
|
18
|
+
scope.local
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
json.extract! activity, :id, :entity_id, :entity_type, :action, :actor_id, :created_at
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
json.array! @activities, partial: 'federails/client/activities/activity', as: :activity
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
json.partial! 'federails/client/activities/index'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
json.partial! 'federails/client/activities/index'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<h1>Listing actors</h1>
|
|
2
|
+
|
|
3
|
+
<table>
|
|
4
|
+
<thead>
|
|
5
|
+
<tr>
|
|
6
|
+
<th>Name</th>
|
|
7
|
+
<th>Username</th>
|
|
8
|
+
<th>Federation address</th>
|
|
9
|
+
<th>Local?</th>
|
|
10
|
+
<th></th>
|
|
11
|
+
</tr>
|
|
12
|
+
</thead>
|
|
13
|
+
<tbody>
|
|
14
|
+
<% @actors.each do |actor| %>
|
|
15
|
+
<tr>
|
|
16
|
+
<td><%= actor.name %></td>
|
|
17
|
+
<td><%= actor.username %></td>
|
|
18
|
+
<td><%= actor.at_address %></td>
|
|
19
|
+
<td><%= actor.local? %></td>
|
|
20
|
+
<td><%= link_to 'Show', federails.client_actor_url(actor) %></td>
|
|
21
|
+
</tr>
|
|
22
|
+
<% end %>
|
|
23
|
+
</tbody>
|
|
24
|
+
</table>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
json.array! @actors, partial: 'federails/client/actors/actor', as: :actor
|
|
@@ -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), 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,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 %>
|