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