Skip to content

Commit 16b2caa

Browse files
committed
Add relationship manager UI
1 parent 782b622 commit 16b2caa

57 files changed

Lines changed: 264 additions & 660 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# frozen_string_literal: true
2+
3+
class RelationshipsController < ApplicationController
4+
layout 'admin'
5+
6+
before_action :authenticate_user!
7+
before_action :set_accounts, only: :show
8+
before_action :set_body_classes
9+
10+
helper_method :following_relationship?, :followed_by_relationship?, :mutual_relationship?
11+
12+
def show
13+
@form = Form::AccountBatch.new
14+
end
15+
16+
def update
17+
@form = Form::AccountBatch.new(form_account_batch_params.merge(current_account: current_account, action: action_from_button))
18+
@form.save
19+
rescue ActionController::ParameterMissing
20+
# Do nothing
21+
ensure
22+
redirect_to relationships_path(current_params)
23+
end
24+
25+
private
26+
27+
def set_accounts
28+
@accounts = relationships_scope.page(params[:page]).per(40)
29+
end
30+
31+
def relationships_scope
32+
scope = begin
33+
if following_relationship?
34+
current_account.following.includes(:account_stat)
35+
else
36+
current_account.followers.includes(:account_stat)
37+
end
38+
end
39+
40+
scope.merge!(Follow.recent)
41+
scope.merge!(mutual_relationship_scope) if mutual_relationship?
42+
scope.merge!(abandoned_account_scope) if params[:status] == 'abandoned'
43+
scope.merge!(active_account_scope) if params[:status] == 'active'
44+
scope.merge!(by_domain_scope) if params[:by_domain].present?
45+
46+
scope
47+
end
48+
49+
def mutual_relationship_scope
50+
Account.where(id: current_account.following)
51+
end
52+
53+
def abandoned_account_scope
54+
Account.where.not(moved_to_account_id: nil)
55+
end
56+
57+
def active_account_scope
58+
Account.where(moved_to_account_id: nil)
59+
end
60+
61+
def by_domain_scope
62+
Account.where(domain: params[:by_domain])
63+
end
64+
65+
def form_account_batch_params
66+
params.require(:form_account_batch).permit(:action, account_ids: [])
67+
end
68+
69+
def following_relationship?
70+
params[:relationship].blank? || params[:relationship] == 'following'
71+
end
72+
73+
def mutual_relationship?
74+
params[:relationship] == 'mutual'
75+
end
76+
77+
def followed_by_relationship?
78+
params[:relationship] == 'followed_by'
79+
end
80+
81+
def current_params
82+
params.slice(:page, :status, :relationship, :by_domain).permit(:page, :status, :relationship, :by_domain)
83+
end
84+
85+
def action_from_button
86+
if params[:unfollow]
87+
'unfollow'
88+
elsif params[:remove_from_followers]
89+
'remove_from_followers'
90+
elsif params[:block_domains]
91+
'block_domains'
92+
end
93+
end
94+
95+
def set_body_classes
96+
@body_classes = 'admin'
97+
end
98+
end

app/controllers/settings/follower_domains_controller.rb

Lines changed: 0 additions & 28 deletions
This file was deleted.

app/helpers/admin/filter_helper.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ module Admin::FilterHelper
77
CUSTOM_EMOJI_FILTERS = %i(local remote by_domain shortcode).freeze
88
TAGS_FILTERS = %i(hidden).freeze
99
INSTANCES_FILTERS = %i(limited by_domain).freeze
10+
FOLLOWERS_FILTERS = %i(relationship status by_domain).freeze
1011

11-
FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS + INVITE_FILTER + CUSTOM_EMOJI_FILTERS + TAGS_FILTERS + INSTANCES_FILTERS
12+
FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS + INVITE_FILTER + CUSTOM_EMOJI_FILTERS + TAGS_FILTERS + INSTANCES_FILTERS + FOLLOWERS_FILTERS
1213

1314
def filter_link_to(text, link_to_params, link_class_params = link_to_params)
1415
new_url = filtered_url_for(link_to_params)

app/javascript/styles/mastodon/tables.scss

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,15 @@ a.table-action-link {
140140
input {
141141
margin-top: 8px;
142142
}
143+
144+
&--aligned {
145+
display: flex;
146+
align-items: center;
147+
148+
input {
149+
margin-top: 0;
150+
}
151+
}
143152
}
144153

145154
&__actions,
@@ -183,6 +192,10 @@ a.table-action-link {
183192
&__content {
184193
padding-top: 12px;
185194
padding-bottom: 16px;
195+
196+
&--unpadded {
197+
padding: 0;
198+
}
186199
}
187200
}
188201

@@ -197,4 +210,10 @@ a.table-action-link {
197210
font-weight: 700;
198211
}
199212
}
213+
214+
.nothing-here {
215+
border: 1px solid darken($ui-base-color, 8%);
216+
border-top: 0;
217+
box-shadow: none;
218+
}
200219
}

app/models/form/account_batch.rb

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# frozen_string_literal: true
2+
3+
class Form::AccountBatch
4+
include ActiveModel::Model
5+
6+
attr_accessor :account_ids, :action, :current_account
7+
8+
def save
9+
case action
10+
when 'unfollow'
11+
unfollow!
12+
when 'remove_from_followers'
13+
remove_from_followers!
14+
when 'block_domains'
15+
block_domains!
16+
end
17+
end
18+
19+
private
20+
21+
def unfollow!
22+
accounts.find_each do |target_account|
23+
UnfollowService.new.call(current_account, target_account)
24+
end
25+
end
26+
27+
def remove_from_followers!
28+
current_account.passive_relationships.where(account_id: account_ids).find_each do |follow|
29+
reject_follow!(follow)
30+
end
31+
end
32+
33+
def block_domains!
34+
AfterAccountDomainBlockWorker.push_bulk(account_domains) do |domain|
35+
[current_account.id, domain]
36+
end
37+
end
38+
39+
def account_domains
40+
accounts.pluck(Arel.sql('distinct domain')).compact
41+
end
42+
43+
def accounts
44+
Account.where(id: account_ids)
45+
end
46+
47+
def reject_follow!(follow)
48+
follow.destroy
49+
50+
return unless follow.account.activitypub?
51+
52+
json = ActiveModelSerializers::SerializableResource.new(
53+
follow,
54+
serializer: ActivityPub::RejectFollowSerializer,
55+
adapter: ActivityPub::Adapter
56+
).to_json
57+
58+
ActivityPub::DeliveryWorker.perform_async(json, current_account.id, follow.account.inbox_url)
59+
end
60+
end
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.batch-table__row
2+
%label.batch-table__row__select.batch-table__row__select--aligned.batch-checkbox
3+
= f.check_box :account_ids, { multiple: true, include_hidden: false }, account.id
4+
.batch-table__row__content.batch-table__row__content--unpadded
5+
%table.accounts-table
6+
%tbody
7+
%tr
8+
%td= account_link_to account
9+
%td.accounts-table__count.optional
10+
= number_to_human account.statuses_count, strip_insignificant_zeros: true
11+
%small= t('accounts.posts', count: account.statuses_count).downcase
12+
%td.accounts-table__count.optional
13+
= number_to_human account.followers_count, strip_insignificant_zeros: true
14+
%small= t('accounts.followers', count: account.followers_count).downcase
15+
%td.accounts-table__count
16+
- if account.last_status_at.present?
17+
%time.time-ago{ datetime: account.last_status_at.iso8601, title: l(account.last_status_at) }= l account.last_status_at
18+
- else
19+
\-
20+
%small= t('accounts.last_active')
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
- content_for :page_title do
2+
= t('settings.relationships')
3+
4+
- content_for :header_tags do
5+
= javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous'
6+
7+
.filters
8+
.filter-subset
9+
%strong= t 'relationships.relationship'
10+
%ul
11+
%li= filter_link_to t('accounts.following', count: current_account.following_count), relationship: nil
12+
%li= filter_link_to t('accounts.followers', count: current_account.followers_count), relationship: 'followed_by'
13+
%li= filter_link_to t('relationships.mutual'), relationship: 'mutual'
14+
15+
.filter-subset
16+
%strong= t 'relationships.status'
17+
%ul
18+
%li= filter_link_to t('generic.all'), status: nil
19+
%li= filter_link_to t('relationships.active'), status: 'active'
20+
%li= filter_link_to t('relationships.abandoned'), status: 'abandoned'
21+
22+
= form_for(@form, url: relationships_path, method: :patch) do |f|
23+
= hidden_field_tag :page, params[:page] || 1
24+
= hidden_field_tag :relationship, params[:relationship]
25+
= hidden_field_tag :status, params[:status]
26+
27+
.batch-table
28+
.batch-table__toolbar
29+
%label.batch-table__toolbar__select.batch-checkbox-all
30+
= check_box_tag :batch_checkbox_all, nil, false
31+
.batch-table__toolbar__actions
32+
= f.button safe_join([fa_icon('user-times'), t('relationships.remove_selected_follows')]), name: :unfollow, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } unless followed_by_relationship?
33+
34+
= f.button safe_join([fa_icon('trash'), t('relationships.remove_selected_followers')]), name: :remove_from_followers, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } unless following_relationship?
35+
36+
= f.button safe_join([fa_icon('trash'), t('relationships.remove_selected_domains')]), name: :block_domains, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } if followed_by_relationship?
37+
.batch-table__body
38+
- if @accounts.empty?
39+
= nothing_here 'nothing-here--under-tabs'
40+
- else
41+
= render partial: 'account', collection: @accounts, locals: { f: f }
42+
43+
= paginate @accounts

app/views/settings/follower_domains/show.html.haml

Lines changed: 0 additions & 34 deletions
This file was deleted.

config/locales/ar.yml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -607,15 +607,6 @@ ar:
607607
title: عوامل التصفية
608608
new:
609609
title: إضافة عامل تصفية جديد
610-
followers:
611-
domain: النطاق
612-
followers_count: عدد المتابِعين
613-
lock_link: قم بتجميد حسابك
614-
purge: تنحية من بين متابعيك
615-
success: جارية عملية حظر المتابِعين بسلاسة من %{count} نطاقات أخرى ...
616-
true_privacy_html: تذكر دائمًا أنّ <strong>الخصوصية التامة لا يمكن بلوغها إلّا بالتعمية و التشفير من طرف إلى آخَر</strong>.
617-
unlocked_warning_html: يمكن لأي كان متابعة حسابك و الإطلاع مباشرة على تبويقاتك. إستخدِم %{lock_link} لمُعاينة أو رفض طلبات المتابِعين الجُدُد.
618-
unlocked_warning_title: إنّ حسابك غير مقفل
619610
footer:
620611
developers: المطورون
621612
more: المزيد …
@@ -818,7 +809,6 @@ ar:
818809
development: التطوير
819810
edit_profile: تعديل الملف الشخصي
820811
export: تصدير البيانات
821-
followers: المتابِعون المُرَخّصون
822812
import: إستيراد
823813
migrate: تهجير الحساب
824814
notifications: الإخطارات

config/locales/ast.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,6 @@ ast:
182182
title: Peñeres
183183
new:
184184
title: Amestar una peñera nueva
185-
followers:
186-
domain: Dominiu
187-
followers_count: Númberu de siguidores
188-
purge: Desaniciar de los siguidores
189185
generic:
190186
changes_saved_msg: "¡Los cambeos guardáronse con ésitu!"
191187
save_changes: Guardar cambeos
@@ -302,7 +298,6 @@ ast:
302298
back: Volver a Mastodon
303299
edit_profile: Edición del perfil
304300
export: Esportación de datos
305-
followers: Siguidores autorizaos
306301
import: Importación
307302
notifications: Avisos
308303
preferences: Preferencies

0 commit comments

Comments
 (0)