Skip to content

Commit 18629b4

Browse files
ClearlyClairehiyuki2578
authored andcommitted
Add public blocks to /about/blocks (mastodon#11298)
* Add automatic blocklist display in /about/blocks Inspired by https://github.com/Gargron/mastodon.social-misc * Add admin option to set who can see instance blocks * Normalize locales files * Rename “Sandbox” to “Silence” for consistency * Disable /about/blocks when in whitelist mode * Optionally display rationale for domain blocks * Only display domain blocks that have user-facing limitations, and order them * Redesign table of blocked domains to better handle long domain names and rationales * Change domain blocks ordering now that rationales aren't displayed right away * Only show explanation for block severities actually in use * Reword instance block explanations and add disclaimer for public fetch mode
1 parent fc5684b commit 18629b4

10 files changed

Lines changed: 197 additions & 5 deletions

File tree

app/controllers/about_controller.rb

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
class AboutController < ApplicationController
44
layout 'public'
55

6-
before_action :require_open_federation!, only: [:show, :more]
6+
before_action :require_open_federation!, only: [:show, :more, :blocks]
7+
before_action :check_blocklist_enabled, only: [:blocks]
8+
before_action :authenticate_user!, only: [:blocks], if: :blocklist_account_required?
79
before_action :set_body_classes, only: :show
810
before_action :set_instance_presenter
9-
before_action :set_expires_in
11+
before_action :set_expires_in, only: [:show, :more, :terms]
1012

1113
skip_before_action :require_functional!, only: [:more, :terms]
1214

@@ -18,12 +20,40 @@ def more
1820

1921
def terms; end
2022

23+
def blocks
24+
@show_rationale = Setting.show_domain_blocks_rationale == 'all'
25+
@show_rationale |= Setting.show_domain_blocks_rationale == 'users' && !current_user.nil? && current_user.functional?
26+
@blocks = DomainBlock.with_user_facing_limitations.order('(CASE severity WHEN 0 THEN 1 WHEN 1 THEN 2 WHEN 2 THEN 0 END), reject_media, domain').to_a
27+
end
28+
2129
private
2230

2331
def require_open_federation!
2432
not_found if whitelist_mode?
2533
end
2634

35+
def check_blocklist_enabled
36+
not_found if Setting.show_domain_blocks == 'disabled'
37+
end
38+
39+
def blocklist_account_required?
40+
Setting.show_domain_blocks == 'users'
41+
end
42+
43+
def block_severity_text(block)
44+
if block.severity == 'suspend'
45+
I18n.t('domain_blocks.suspension')
46+
else
47+
limitations = []
48+
limitations << I18n.t('domain_blocks.media_block') if block.reject_media?
49+
limitations << I18n.t('domain_blocks.silence') if block.severity == 'silence'
50+
limitations.join(', ')
51+
end
52+
end
53+
54+
helper_method :block_severity_text
55+
helper_method :public_fetch_mode?
56+
2757
def new_user
2858
User.new.tap do |user|
2959
user.build_account

app/javascript/packs/public.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,15 @@ function main() {
141141
return false;
142142
});
143143

144+
delegate(document, '.blocks-table button.icon-button', 'click', function(e) {
145+
e.preventDefault();
146+
147+
const classList = this.firstElementChild.classList;
148+
classList.toggle('fa-chevron-down');
149+
classList.toggle('fa-chevron-up');
150+
this.parentElement.parentElement.nextElementSibling.classList.toggle('hidden');
151+
});
152+
144153
delegate(document, '.modal-button', 'click', e => {
145154
e.preventDefault();
146155

app/javascript/styles/mastodon/tables.scss

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,3 +241,70 @@ a.table-action-link {
241241
}
242242
}
243243
}
244+
245+
.blocks-table {
246+
width: 100%;
247+
max-width: 100%;
248+
border-spacing: 0;
249+
border-collapse: collapse;
250+
table-layout: fixed;
251+
border: 1px solid darken($ui-base-color, 8%);
252+
253+
thead {
254+
border: 1px solid darken($ui-base-color, 8%);
255+
background: darken($ui-base-color, 4%);
256+
font-weight: 500;
257+
258+
th.severity-column {
259+
width: 120px;
260+
}
261+
262+
th.button-column {
263+
width: 23px;
264+
}
265+
}
266+
267+
tbody > tr {
268+
border: 1px solid darken($ui-base-color, 8%);
269+
border-bottom: 0;
270+
background: darken($ui-base-color, 4%);
271+
272+
&:hover {
273+
background: darken($ui-base-color, 2%);
274+
}
275+
276+
&.even {
277+
background: $ui-base-color;
278+
279+
&:hover {
280+
background: lighten($ui-base-color, 2%);
281+
}
282+
}
283+
284+
&.rationale {
285+
background: lighten($ui-base-color, 4%);
286+
border-top: 0;
287+
288+
&:hover {
289+
background: lighten($ui-base-color, 6%);
290+
}
291+
292+
&.hidden {
293+
display: none;
294+
}
295+
}
296+
297+
td:first-child {
298+
overflow: hidden;
299+
text-overflow: ellipsis;
300+
}
301+
}
302+
303+
th,
304+
td {
305+
padding: 8px;
306+
line-height: 18px;
307+
vertical-align: top;
308+
text-align: left;
309+
}
310+
}

app/models/domain_block.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class DomainBlock < ApplicationRecord
2525
delegate :count, to: :accounts, prefix: true
2626

2727
scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) }
28+
scope :with_user_facing_limitations, -> { where(severity: [:silence, :suspend]).or(where(reject_media: true)) }
2829

2930
class << self
3031
def suspend?(domain)

app/models/form/admin_settings.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class Form::AdminSettings
3030
mascot
3131
spam_check_enabled
3232
trends
33+
show_domain_blocks
34+
show_domain_blocks_rationale
3335
).freeze
3436

3537
BOOLEAN_KEYS = %i(
@@ -60,6 +62,8 @@ class Form::AdminSettings
6062
validates :site_contact_email, :site_contact_username, presence: true
6163
validates :site_contact_username, existing_username: true
6264
validates :bootstrap_timeline_accounts, existing_username: { multiple: true }
65+
validates :show_domain_blocks, inclusion: { in: %w(disabled users all) }
66+
validates :show_domain_blocks_rationale, inclusion: { in: %w(disabled users all) }
6367

6468
def initialize(_attributes = {})
6569
super

app/views/about/blocks.html.haml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
- content_for :page_title do
2+
= t('domain_blocks.title', instance: site_hostname)
3+
4+
.grid
5+
.column-0
6+
.box-widget.rich-formatting
7+
%h2= t('domain_blocks.blocked_domains')
8+
%p= t('domain_blocks.description', instance: site_hostname)
9+
.table-wrapper
10+
%table.blocks-table
11+
%thead
12+
%tr
13+
%th= t('domain_blocks.domain')
14+
%th.severity-column= t('domain_blocks.severity')
15+
- if @show_rationale
16+
%th.button-column
17+
%tbody
18+
- if @blocks.empty?
19+
%tr
20+
%td{ colspan: @show_rationale ? 3 : 2 }= t('domain_blocks.no_domain_blocks')
21+
- else
22+
- @blocks.each_with_index do |block, i|
23+
%tr{ class: i % 2 == 0 ? 'even': nil }
24+
%td{ title: block.domain }= block.domain
25+
%td= block_severity_text(block)
26+
- if @show_rationale
27+
%td
28+
- if block.public_comment.present?
29+
%button.icon-button{ title: t('domain_blocks.show_rationale'), 'aria-label' => t('domain_blocks.show_rationale') }
30+
= fa_icon 'chevron-down fw', 'aria-hidden' => true
31+
- if @show_rationale
32+
- if block.public_comment.present?
33+
%tr.rationale.hidden
34+
%td{ colspan: 3 }= block.public_comment.presence
35+
%h2= t('domain_blocks.severity_legend.title')
36+
- if @blocks.any? { |block| block.reject_media? }
37+
%h3= t('domain_blocks.media_block')
38+
%p= t('domain_blocks.severity_legend.media_block')
39+
- if @blocks.any? { |block| block.severity == 'silence' }
40+
%h3= t('domain_blocks.silence')
41+
%p= t('domain_blocks.severity_legend.silence')
42+
- if @blocks.any? { |block| block.severity == 'suspend' }
43+
%h3= t('domain_blocks.suspension')
44+
%p= t('domain_blocks.severity_legend.suspension')
45+
- if public_fetch_mode?
46+
%p= t('domain_blocks.severity_legend.suspension_disclaimer')
47+
.column-1
48+
= render 'application/sidebar'

app/views/admin/settings/edit.html.haml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@
7979
.fields-group
8080
= f.input :min_invite_role, wrapper: :with_label, collection: %i(disabled user moderator admin), label: t('admin.settings.registrations.min_invite_role.title'), label_method: lambda { |role| role == :disabled ? t('admin.settings.registrations.min_invite_role.disabled') : t("admin.accounts.roles.#{role}") }, include_blank: false, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
8181

82+
.fields-row
83+
.fields-row__column.fields-row__column-6.fields-group
84+
= f.input :show_domain_blocks, wrapper: :with_label, collection: %i(disabled users all), label: t('admin.settings.domain_blocks.title'), label_method: lambda { |value| t("admin.settings.domain_blocks.#{value}") }, include_blank: false, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
85+
.fields-row__column.fields-row__column-6.fields-group
86+
= f.input :show_domain_blocks_rationale, wrapper: :with_label, collection: %i(disabled users all), label: t('admin.settings.domain_blocks_rationale.title'), label_method: lambda { |value| t("admin.settings.domain_blocks.#{value}") }, include_blank: false, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
87+
8288
.fields-group
8389
= f.input :closed_registrations_message, as: :text, wrapper: :with_block_label, label: t('admin.settings.registrations.closed_message.title'), hint: t('admin.settings.registrations.closed_message.desc_html'), input_html: { rows: 8 }
8490
= f.input :site_extended_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_description_extended.title'), hint: t('admin.settings.site_description_extended.desc_html'), input_html: { rows: 8 } unless whitelist_mode?

config/locales/en.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,13 @@ en:
424424
custom_css:
425425
desc_html: Modify the look with CSS loaded on every page
426426
title: Custom CSS
427+
domain_blocks:
428+
all: To everyone
429+
disabled: To no one
430+
title: Show domain blocks
431+
users: To logged-in local users
432+
domain_blocks_rationale:
433+
title: Show rationale
427434
hero:
428435
desc_html: Displayed on the frontpage. At least 600x100px recommended. When not set, falls back to server thumbnail
429436
title: Hero image
@@ -631,6 +638,23 @@ en:
631638
people:
632639
one: "%{count} person"
633640
other: "%{count} people"
641+
domain_blocks:
642+
blocked_domains: List of limited and blocked domains
643+
description: This is the list of servers that %{instance} limits or reject federation with.
644+
domain: Domain
645+
media_block: Media block
646+
no_domain_blocks: "(No domain blocks)"
647+
severity: Severity
648+
severity_legend:
649+
media_block: Media files coming from the server are neither fetched, stored, or displayed to the user.
650+
silence: Accounts from silenced servers can be found, followed and interacted with, but their toots will not appear in the public timelines, and notifications from them will not reach local users who are not following them.
651+
suspension: No content from suspended servers is stored or displayed, nor is any content sent to them. Interactions from suspended servers are ignored.
652+
suspension_disclaimer: Suspended servers may occasionally retrieve public content from this server.
653+
title: Severities
654+
show_rationale: Show rationale
655+
silence: Silence
656+
suspension: Suspension
657+
title: "%{instance} List of blocked instances"
634658
domain_validator:
635659
invalid_domain: is not a valid domain name
636660
errors:

config/routes.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -423,9 +423,10 @@
423423

424424
get '/web/(*any)', to: 'home#index', as: :web
425425

426-
get '/about', to: 'about#show'
427-
get '/about/more', to: 'about#more'
428-
get '/terms', to: 'about#terms'
426+
get '/about', to: 'about#show'
427+
get '/about/more', to: 'about#more'
428+
get '/about/blocks', to: 'about#blocks'
429+
get '/terms', to: 'about#terms'
429430

430431
root 'home#index'
431432

config/settings.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ defaults: &defaults
6464
peers_api_enabled: true
6565
show_known_fediverse_at_about_page: true
6666
spam_check_enabled: true
67+
show_domain_blocks: 'disabled'
68+
show_domain_blocks_rationale: 'disabled'
6769

6870
development:
6971
<<: *defaults

0 commit comments

Comments
 (0)