+// We're choosing to wrap span with div to keep the changes local only to this tool bar.
+const WrapFormattedMessage = ({ children, ...props }) =>
{children}
;
+WrapFormattedMessage.propTypes = {
+ children: PropTypes.any,
+};
+
+
export default @connect(mapStateToProps)
@injectIntl
class Explore extends React.PureComponent {
@@ -47,7 +57,7 @@ class Explore extends React.PureComponent {
this.column = c;
}
- render () {
+ render() {
const { intl, multiColumn, isSearching } = this.props;
const { signedIn } = this.context.identity;
@@ -70,10 +80,10 @@ class Explore extends React.PureComponent {
) : (
-
-
-
- {signedIn && }
+
+
+
+ {signedIn && }
diff --git a/app/javascript/mastodon/features/ui/components/header.js b/app/javascript/mastodon/features/ui/components/header.js
index 4e109080ee..bbb0ca1c62 100644
--- a/app/javascript/mastodon/features/ui/components/header.js
+++ b/app/javascript/mastodon/features/ui/components/header.js
@@ -35,7 +35,7 @@ class Header extends React.PureComponent {
if (signedIn) {
content = (
<>
- {location.pathname !== '/publish' && }
+ {location.pathname !== '/publish' && }
>
);
diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json
index f7ea661d7d..2b99ac502b 100644
--- a/app/javascript/mastodon/locales/defaultMessages.json
+++ b/app/javascript/mastodon/locales/defaultMessages.json
@@ -3989,7 +3989,7 @@
"descriptors": [
{
"defaultMessage": "Publish",
- "id": "compose_form.publish"
+ "id": "compose_form.publish_form"
},
{
"defaultMessage": "Sign in",
diff --git a/app/models/form/account_batch.rb b/app/models/form/account_batch.rb
index 5cfcf7205b..473622edf4 100644
--- a/app/models/form/account_batch.rb
+++ b/app/models/form/account_batch.rb
@@ -115,6 +115,10 @@ class Form::AccountBatch
authorize(account, :suspend?)
log_action(:suspend, account)
account.suspend!(origin: :local)
+ account.strikes.create!(
+ account: current_account,
+ action: :suspend
+ )
Admin::SuspensionWorker.perform_async(account.id)
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 0e8a87aea5..0eb975dec7 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -237,6 +237,11 @@ class User < ApplicationRecord
end
def functional?
+
+ functional_or_moved?
+ end
+
+ def functional_or_moved?
confirmed? && approved? && !disabled? && !account.suspended? && !account.memorial?
end
diff --git a/app/policies/email_domain_block_policy.rb b/app/policies/email_domain_block_policy.rb
index 1a0ddfa877..0d167ea3e7 100644
--- a/app/policies/email_domain_block_policy.rb
+++ b/app/policies/email_domain_block_policy.rb
@@ -5,6 +5,10 @@ class EmailDomainBlockPolicy < ApplicationPolicy
role.can?(:manage_blocks)
end
+ def show?
+ role.can?(:manage_blocks)
+ end
+
def create?
role.can?(:manage_blocks)
end
diff --git a/app/serializers/manifest_serializer.rb b/app/serializers/manifest_serializer.rb
index 5604325be4..48f3aa7a6a 100644
--- a/app/serializers/manifest_serializer.rb
+++ b/app/serializers/manifest_serializer.rb
@@ -35,6 +35,7 @@ class ManifestSerializer < ActiveModel::Serializer
src: full_pack_url("media/icons/android-chrome-#{size}x#{size}.png"),
sizes: "#{size}x#{size}",
type: 'image/png',
+ purpose: 'any maskable',
}
end
end
diff --git a/app/services/verify_link_service.rb b/app/services/verify_link_service.rb
index 0a39d7f26e..7496fe2d51 100644
--- a/app/services/verify_link_service.rb
+++ b/app/services/verify_link_service.rb
@@ -28,7 +28,7 @@ class VerifyLinkService < BaseService
links = Nokogiri::HTML(@body).xpath('//a[contains(concat(" ", normalize-space(@rel), " "), " me ")]|//link[contains(concat(" ", normalize-space(@rel), " "), " me ")]')
- if links.any? { |link| link['href'].downcase == @link_back.downcase }
+ if links.any? { |link| link['href']&.downcase == @link_back.downcase }
true
elsif links.empty?
false
@@ -38,6 +38,8 @@ class VerifyLinkService < BaseService
end
def link_redirects_back?(test_url)
+ return false if test_url.blank?
+
redirect_to_url = Request.new(:head, test_url, follow: false).perform do |res|
res.headers['Location']
end
diff --git a/app/views/application/_card.html.haml b/app/views/application/_card.html.haml
index 909d9ff818..3d0e6b1dad 100644
--- a/app/views/application/_card.html.haml
+++ b/app/views/application/_card.html.haml
@@ -13,4 +13,4 @@
%strong.emojify.p-name= display_name(account, custom_emojify: true)
%span
= acct(account)
- = fa_icon('lock', { :data => ({hidden: true} unless account.locked?)})
+ = fa_icon('lock', { data: ({hidden: true} unless account.locked?)})
diff --git a/app/views/auth/challenges/new.html.haml b/app/views/auth/challenges/new.html.haml
index ff4b7a506f..4f21e4af6e 100644
--- a/app/views/auth/challenges/new.html.haml
+++ b/app/views/auth/challenges/new.html.haml
@@ -5,7 +5,7 @@
= f.input :return_to, as: :hidden
.field-group
- = f.input :current_password, wrapper: :with_block_label, input_html: { :autocomplete => 'current-password', :autofocus => true }, label: t('challenge.prompt'), required: true
+ = f.input :current_password, wrapper: :with_block_label, input_html: { autocomplete: 'current-password', autofocus: true }, label: t('challenge.prompt'), required: true
.actions
= f.button :button, t('challenge.confirm'), type: :submit
diff --git a/app/views/auth/confirmations/new.html.haml b/app/views/auth/confirmations/new.html.haml
index 4a1bedaa42..a294d3cb5f 100644
--- a/app/views/auth/confirmations/new.html.haml
+++ b/app/views/auth/confirmations/new.html.haml
@@ -5,7 +5,7 @@
= render 'shared/error_messages', object: resource
.fields-group
- = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, hint: false
+ = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, hint: false
.actions
= f.button :button, t('auth.resend_confirmation'), type: :submit
diff --git a/app/views/auth/passwords/edit.html.haml b/app/views/auth/passwords/edit.html.haml
index c7dbebe756..b95a9b676b 100644
--- a/app/views/auth/passwords/edit.html.haml
+++ b/app/views/auth/passwords/edit.html.haml
@@ -8,9 +8,9 @@
= f.input :reset_password_token, as: :hidden
.fields-group
- = f.input :password, wrapper: :with_label, autofocus: true, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.new_password'), :autocomplete => 'new-password', :minlength => User.password_length.first, :maxlength => User.password_length.last }, required: true
+ = f.input :password, wrapper: :with_label, autofocus: true, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.new_password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, required: true
.fields-group
- = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_new_password'), :autocomplete => 'new-password' }, required: true
+ = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_new_password'), autocomplete: 'new-password' }, required: true
.actions
= f.button :button, t('auth.set_new_password'), type: :submit
diff --git a/app/views/auth/passwords/new.html.haml b/app/views/auth/passwords/new.html.haml
index bae5b24ba8..10ad108eaf 100644
--- a/app/views/auth/passwords/new.html.haml
+++ b/app/views/auth/passwords/new.html.haml
@@ -5,7 +5,7 @@
= render 'shared/error_messages', object: resource
.fields-group
- = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, hint: false
+ = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, hint: false
.actions
= f.button :button, t('auth.reset_password'), type: :submit
diff --git a/app/views/auth/registrations/_sessions.html.haml b/app/views/auth/registrations/_sessions.html.haml
index 5d993f574a..c094dfd255 100644
--- a/app/views/auth/registrations/_sessions.html.haml
+++ b/app/views/auth/registrations/_sessions.html.haml
@@ -18,7 +18,7 @@
%tr
%td
%span{ title: session.user_agent }<
- = fa_icon "#{session_device_icon(session)} fw", 'aria-label' => session_device_icon(session)
+ = fa_icon "#{session_device_icon(session)} fw", 'aria-label': session_device_icon(session)
= ' '
= t 'sessions.description', browser: t("sessions.browsers.#{session.browser}", default: "#{session.browser}"), platform: t("sessions.platforms.#{session.platform}", default: "#{session.platform}")
%td
diff --git a/app/views/auth/registrations/edit.html.haml b/app/views/auth/registrations/edit.html.haml
index c642c2293b..60fd1635ef 100644
--- a/app/views/auth/registrations/edit.html.haml
+++ b/app/views/auth/registrations/edit.html.haml
@@ -11,15 +11,15 @@
- if !use_seamless_external_login? || resource.encrypted_password.present?
.fields-row
.fields-row__column.fields-group.fields-row__column-6
- = f.input :email, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, required: true, disabled: current_account.suspended?
+ = f.input :email, wrapper: :with_label, input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, required: true, disabled: current_account.suspended?
.fields-row__column.fields-group.fields-row__column-6
- = f.input :current_password, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.current_password'), :autocomplete => 'current-password' }, required: true, disabled: current_account.suspended?, hint: false
+ = f.input :current_password, wrapper: :with_label, input_html: { 'aria-label': t('simple_form.labels.defaults.current_password'), autocomplete: 'current-password' }, required: true, disabled: current_account.suspended?, hint: false
.fields-row
.fields-row__column.fields-group.fields-row__column-6
- = f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.new_password'), :autocomplete => 'new-password', :minlength => User.password_length.first, :maxlength => User.password_length.last }, hint: t('simple_form.hints.defaults.password'), disabled: current_account.suspended?
+ = f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.new_password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, hint: t('simple_form.hints.defaults.password'), disabled: current_account.suspended?
.fields-row__column.fields-group.fields-row__column-6
- = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_new_password'), :autocomplete => 'new-password' }, disabled: current_account.suspended?
+ = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_new_password'), autocomplete: 'new-password' }, disabled: current_account.suspended?
.actions
= f.button :button, t('generic.save_changes'), type: :submit, class: 'button', disabled: current_account.suspended?
diff --git a/app/views/auth/registrations/new.html.haml b/app/views/auth/registrations/new.html.haml
index b1d52dd0c2..0d8fd800f9 100644
--- a/app/views/auth/registrations/new.html.haml
+++ b/app/views/auth/registrations/new.html.haml
@@ -17,13 +17,13 @@
.fields-group
= f.simple_fields_for :account do |ff|
- = ff.input :display_name, wrapper: :with_label, label: false, required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.display_name'), :autocomplete => 'off', placeholder: t('simple_form.labels.defaults.display_name') }
- = ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.username'), :autocomplete => 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}", hint: false
- = f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.email'), :autocomplete => 'username' }, hint: false
- = f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'new-password', :minlength => User.password_length.first, :maxlength => User.password_length.last }, hint: false
- = f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'new-password' }, hint: false
- = f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), :autocomplete => 'off' }, hint: false
- = f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: 'Website'), :autocomplete => 'off' }
+ = ff.input :display_name, wrapper: :with_label, label: false, required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.display_name'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.display_name') }
+ = ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.username'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}", hint: false
+ = f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'username' }, hint: false
+ = f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, hint: false
+ = f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_password'), autocomplete: 'new-password' }, hint: false
+ = f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), autocomplete: 'off' }, hint: false
+ = f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: 'Website'), autocomplete: 'off' }
- if approved_registrations? && !@invite.present?
.fields-group
diff --git a/app/views/auth/sessions/new.html.haml b/app/views/auth/sessions/new.html.haml
index 943618e390..304e3ab849 100644
--- a/app/views/auth/sessions/new.html.haml
+++ b/app/views/auth/sessions/new.html.haml
@@ -8,11 +8,11 @@
= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
.fields-group
- if use_seamless_external_login?
- = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.username_or_email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.username_or_email') }, hint: false
+ = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.username_or_email'), input_html: { 'aria-label': t('simple_form.labels.defaults.username_or_email') }, hint: false
- else
- = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, hint: false
+ = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, hint: false
.fields-group
- = f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'current-password' }, hint: false
+ = f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.password'), input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'current-password' }, hint: false
.actions
= f.button :button, t('auth.login'), type: :submit
diff --git a/app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml b/app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml
index 82f9575275..094b502b17 100644
--- a/app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml
+++ b/app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml
@@ -5,7 +5,7 @@
%p.hint.authentication-hint= t('simple_form.hints.sessions.otp')
.fields-group
- = f.input :otp_attempt, type: :number, wrapper: :with_label, label: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label' => t('simple_form.labels.defaults.otp_attempt'), :autocomplete => 'one-time-code' }, autofocus: true
+ = f.input :otp_attempt, type: :number, wrapper: :with_label, label: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label': t('simple_form.labels.defaults.otp_attempt'), autocomplete: 'one-time-code' }, autofocus: true
.actions
= f.button :button, t('auth.login'), type: :submit
diff --git a/app/views/auth/setup/show.html.haml b/app/views/auth/setup/show.html.haml
index c14fed56f8..1a6611ceb6 100644
--- a/app/views/auth/setup/show.html.haml
+++ b/app/views/auth/setup/show.html.haml
@@ -9,7 +9,7 @@
%p.hint= t('auth.setup.email_below_hint_html')
.fields-group
- = f.input :email, required: true, hint: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.email'), :autocomplete => 'off' }
+ = f.input :email, required: true, hint: false, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'off' }
.actions
= f.submit t('admin.accounts.change_email.label'), class: 'button'
diff --git a/app/views/settings/deletes/show.html.haml b/app/views/settings/deletes/show.html.haml
index c08ee85b0b..2e9785c898 100644
--- a/app/views/settings/deletes/show.html.haml
+++ b/app/views/settings/deletes/show.html.haml
@@ -21,9 +21,9 @@
%hr.spacer/
- if current_user.encrypted_password.present?
- = f.input :password, wrapper: :with_block_label, input_html: { :autocomplete => 'current-password' }, hint: t('deletes.confirm_password')
+ = f.input :password, wrapper: :with_block_label, input_html: { autocomplete: 'current-password' }, hint: t('deletes.confirm_password')
- else
- = f.input :username, wrapper: :with_block_label, input_html: { :autocomplete => 'off' }, hint: t('deletes.confirm_username')
+ = f.input :username, wrapper: :with_block_label, input_html: { autocomplete: 'off' }, hint: t('deletes.confirm_username')
.actions
= f.button :button, t('deletes.proceed'), type: :submit, class: 'negative'
diff --git a/app/views/settings/migration/redirects/new.html.haml b/app/views/settings/migration/redirects/new.html.haml
index d7868e900d..3700878799 100644
--- a/app/views/settings/migration/redirects/new.html.haml
+++ b/app/views/settings/migration/redirects/new.html.haml
@@ -19,9 +19,9 @@
.fields-row__column.fields-group.fields-row__column-6
- if current_user.encrypted_password.present?
- = f.input :current_password, wrapper: :with_block_label, input_html: { :autocomplete => 'current-password' }, required: true
+ = f.input :current_password, wrapper: :with_block_label, input_html: { autocomplete: 'current-password' }, required: true
- else
- = f.input :current_username, wrapper: :with_block_label, input_html: { :autocomplete => 'off' }, required: true
+ = f.input :current_username, wrapper: :with_block_label, input_html: { autocomplete: 'off' }, required: true
.actions
= f.button :button, t('migrations.set_redirect'), type: :submit, class: 'button button--destructive'
diff --git a/app/views/settings/migrations/show.html.haml b/app/views/settings/migrations/show.html.haml
index 1ecf7302a9..31f7d5e58d 100644
--- a/app/views/settings/migrations/show.html.haml
+++ b/app/views/settings/migrations/show.html.haml
@@ -48,9 +48,9 @@
.fields-row__column.fields-group.fields-row__column-6
- if current_user.encrypted_password.present?
- = f.input :current_password, wrapper: :with_block_label, input_html: { :autocomplete => 'current-password' }, required: true, disabled: on_cooldown?
+ = f.input :current_password, wrapper: :with_block_label, input_html: { autocomplete: 'current-password' }, required: true, disabled: on_cooldown?
- else
- = f.input :current_username, wrapper: :with_block_label, input_html: { :autocomplete => 'off' }, required: true, disabled: on_cooldown?
+ = f.input :current_username, wrapper: :with_block_label, input_html: { autocomplete: 'off' }, required: true, disabled: on_cooldown?
.actions
= f.button :button, t('migrations.proceed_with_move'), type: :submit, class: 'button button--destructive', disabled: on_cooldown?
diff --git a/app/views/settings/two_factor_authentication/confirmations/new.html.haml b/app/views/settings/two_factor_authentication/confirmations/new.html.haml
index 671237db57..43830ac27f 100644
--- a/app/views/settings/two_factor_authentication/confirmations/new.html.haml
+++ b/app/views/settings/two_factor_authentication/confirmations/new.html.haml
@@ -12,7 +12,7 @@
%samp.qr-alternative__code= @new_otp_secret.scan(/.{4}/).join(' ')
.fields-group
- = f.input :otp_attempt, wrapper: :with_label, hint: t('otp_authentication.code_hint'), label: t('simple_form.labels.defaults.otp_attempt'), input_html: { :autocomplete => 'off' }, required: true
+ = f.input :otp_attempt, wrapper: :with_label, hint: t('otp_authentication.code_hint'), label: t('simple_form.labels.defaults.otp_attempt'), input_html: { autocomplete: 'off' }, required: true
.actions
= f.button :button, t('otp_authentication.enable'), type: :submit
diff --git a/app/views/settings/two_factor_authentication/webauthn_credentials/new.html.haml b/app/views/settings/two_factor_authentication/webauthn_credentials/new.html.haml
index c5a323ee50..5ec0247577 100644
--- a/app/views/settings/two_factor_authentication/webauthn_credentials/new.html.haml
+++ b/app/views/settings/two_factor_authentication/webauthn_credentials/new.html.haml
@@ -8,7 +8,7 @@
%p.hint= t('webauthn_credentials.description_html')
.fields_group
- = f.input :nickname, wrapper: :with_block_label, hint: t('webauthn_credentials.nickname_hint'), input_html: { :autocomplete => 'off' }, required: true
+ = f.input :nickname, wrapper: :with_block_label, hint: t('webauthn_credentials.nickname_hint'), input_html: { autocomplete: 'off' }, required: true
.actions
= f.button :button, t('webauthn_credentials.add'), class: 'js-webauthn', type: :submit
diff --git a/app/views/statuses/_detailed_status.html.haml b/app/views/statuses/_detailed_status.html.haml
index 619406d897..bf498e33d5 100644
--- a/app/views/statuses/_detailed_status.html.haml
+++ b/app/views/statuses/_detailed_status.html.haml
@@ -15,12 +15,12 @@
= account_action_button(status.account)
- .status__content.emojify{ :data => ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
+ .status__content.emojify{ data: ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
- if status.spoiler_text?
%p<
%span.p-summary> #{prerender_custom_emojis(h(status.spoiler_text), status.emojis)}
%button.status__content__spoiler-link= t('statuses.show_more')
- .e-content{ :lang => status.language }
+ .e-content{ lang: status.language }
= prerender_custom_emojis(status_content_format(status), status.emojis)
- if status.preloadable_poll
diff --git a/app/views/statuses/_simple_status.html.haml b/app/views/statuses/_simple_status.html.haml
index 1e37b6cf3a..ecbabf34cf 100644
--- a/app/views/statuses/_simple_status.html.haml
+++ b/app/views/statuses/_simple_status.html.haml
@@ -27,12 +27,12 @@
%span.display-name__account
= acct(status.account)
= fa_icon('lock') if status.account.locked?
- .status__content.emojify{ :data => ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
+ .status__content.emojify{ data: ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
- if status.spoiler_text?
%p<
%span.p-summary> #{prerender_custom_emojis(h(status.spoiler_text), status.emojis)}
%button.status__content__spoiler-link= t('statuses.show_more')
- .e-content{ :lang => status.language }<
+ .e-content{ lang: status.language }<
= prerender_custom_emojis(status_content_format(status), status.emojis)
- if status.preloadable_poll
diff --git a/chart/Chart.yaml b/chart/Chart.yaml
index 7080095f2d..8d67e55ebe 100644
--- a/chart/Chart.yaml
+++ b/chart/Chart.yaml
@@ -15,12 +15,12 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
-version: 2.3.0
+version: 3.0.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
-appVersion: v3.5.3
+appVersion: v4.0.2
dependencies:
- name: elasticsearch
diff --git a/config/environments/production.rb b/config/environments/production.rb
index c50ece2f99..8e2f0cc7fc 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -116,18 +116,18 @@ Rails.application.configure do
end
config.action_mailer.smtp_settings = {
- :port => ENV['SMTP_PORT'],
- :address => ENV['SMTP_SERVER'],
- :user_name => ENV['SMTP_LOGIN'].presence,
- :password => ENV['SMTP_PASSWORD'].presence,
- :domain => ENV['SMTP_DOMAIN'] || ENV['LOCAL_DOMAIN'],
- :authentication => ENV['SMTP_AUTH_METHOD'] == 'none' ? nil : ENV['SMTP_AUTH_METHOD'] || :plain,
- :ca_file => ENV['SMTP_CA_FILE'].presence || '/etc/ssl/certs/ca-certificates.crt',
- :openssl_verify_mode => ENV['SMTP_OPENSSL_VERIFY_MODE'],
- :enable_starttls => enable_starttls,
- :enable_starttls_auto => enable_starttls_auto,
- :tls => ENV['SMTP_TLS'].presence && ENV['SMTP_TLS'] == 'true',
- :ssl => ENV['SMTP_SSL'].presence && ENV['SMTP_SSL'] == 'true',
+ port: ENV['SMTP_PORT'],
+ address: ENV['SMTP_SERVER'],
+ user_name: ENV['SMTP_LOGIN'].presence,
+ password: ENV['SMTP_PASSWORD'].presence,
+ domain: ENV['SMTP_DOMAIN'] || ENV['LOCAL_DOMAIN'],
+ authentication: ENV['SMTP_AUTH_METHOD'] == 'none' ? nil : ENV['SMTP_AUTH_METHOD'] || :plain,
+ ca_file: ENV['SMTP_CA_FILE'].presence || '/etc/ssl/certs/ca-certificates.crt',
+ openssl_verify_mode: ENV['SMTP_OPENSSL_VERIFY_MODE'],
+ enable_starttls: enable_starttls,
+ enable_starttls_auto: enable_starttls_auto,
+ tls: ENV['SMTP_TLS'].presence && ENV['SMTP_TLS'] == 'true',
+ ssl: ENV['SMTP_SSL'].presence && ENV['SMTP_SSL'] == 'true',
}
config.action_mailer.delivery_method = ENV.fetch('SMTP_DELIVERY_METHOD', 'smtp').to_sym
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb
index 84b649f5c1..43aac5769f 100644
--- a/config/initializers/doorkeeper.rb
+++ b/config/initializers/doorkeeper.rb
@@ -98,9 +98,19 @@ Doorkeeper.configure do
:'admin:read',
:'admin:read:accounts',
:'admin:read:reports',
+ :'admin:read:domain_allows',
+ :'admin:read:domain_blocks',
+ :'admin:read:ip_blocks',
+ :'admin:read:email_domain_blocks',
+ :'admin:read:canonical_email_blocks',
:'admin:write',
:'admin:write:accounts',
:'admin:write:reports',
+ :'admin:write:domain_allows',
+ :'admin:write:domain_blocks',
+ :'admin:write:ip_blocks',
+ :'admin:write:email_domain_blocks',
+ :'admin:write:canonical_email_blocks',
:crypto
# Change the way client credentials are retrieved from the request object.
diff --git a/config/locales-glitch/en.yml b/config/locales-glitch/en.yml
index c559ee0eca..23c566153e 100644
--- a/config/locales-glitch/en.yml
+++ b/config/locales-glitch/en.yml
@@ -4,26 +4,6 @@ en:
custom_emojis:
batch_copy_error: 'An error occurred when copying some of the selected emoji: %{message}'
batch_error: 'An error occurred: %{message}'
- domain_allows:
- export: Export
- import: Import
- domain_blocks:
- export: Export
- import: Import
- export_domain_allows:
- new:
- title: Import domain allows
- no_file: No file selected
- export_domain_blocks:
- import:
- description_html: You are about to import a list of domain blocks. Please review this list very carefully, especially if you have not authored this list yourself.
- existing_relationships_warning: Existing follow relationships
- private_comment_description_html: 'To help you track where imported blocks come from, imported blocks will be created with the following private comment: %{comment}
'
- private_comment_template: Imported from %{source} on %{date}
- title: Import domain blocks
- new:
- title: Import domain blocks
- no_file: No file selected
settings:
captcha_enabled:
desc_html: This relies on external scripts from hCaptcha, which may be a security and privacy concern. In addition, this can make the registration process significantly less accessible to some (especially disabled) people. For these reasons, please consider alternative measures such as approval-based or invite-based registration.
Users that have been invited through a limited-use invite will not need to solve a CAPTCHA
diff --git a/config/locales-glitch/ko.yml b/config/locales-glitch/ko.yml
index 0e6890db70..bc9c4e86b7 100644
--- a/config/locales-glitch/ko.yml
+++ b/config/locales-glitch/ko.yml
@@ -4,26 +4,6 @@ ko:
custom_emojis:
batch_copy_error: 'μ νλ μλͺ¨μ§λ₯Ό 볡μ¬νλ μ€ μ€λ₯κ° λ°μνμ΅λλ€: %{message}'
batch_error: 'μλ¬κ° λ°μνμ΅λλ€: %{message}'
- domain_allows:
- export: λ΄λ³΄λ΄κΈ°
- import: λΆλ¬μ€κΈ°
- domain_blocks:
- export: λ΄λ³΄λ΄κΈ°
- import: λΆλ¬μ€κΈ°
- export_domain_allows:
- new:
- title: λλ©μΈ νμ© λΆλ¬μ€κΈ°
- no_file: νμΌμ΄ μ νλμ§ μμμ΅λλ€
- export_domain_blocks:
- import:
- description_html: λλ©μΈ μ°¨λ¨ λͺ©λ‘μ λΆλ¬μ€λ €κ³ ν©λλ€. μ΄ λͺ©λ‘μ μ‘°μ¬μ€λ½κ² κ²ν νμΈμ, νΉν μμ μ΄ μ§μ μμ±ν λͺ©λ‘μ΄ μλλΌλ©΄ λ μ‘°μ¬νμΈμ.
- existing_relationships_warning: νλ‘μ° κ΄κ³κ° μ‘΄μ¬ν©λλ€
- private_comment_description_html: 'μ΄λμ λΆλ¬μ¨ κ²μΈμ§ μΆμ μ μννκ² νκΈ° μν΄μ, λΆλ¬μ¨ μ°¨λ¨λ€μ λ€μκ³Ό κ°μ λΉκ³΅κ° μ£Όμκ³Ό ν¨κ» μμ±λ κ²μ
λλ€: %{comment}
'
- private_comment_template: '%{date}μ %{source}μμ λΆλ¬μ΄'
- title: λλ©μΈ μ°¨λ¨ λΆλ¬μ€κΈ°
- new:
- title: λλ©μΈ μ°¨λ¨ λΆλ¬μ€κΈ°
- no_file: νμΌμ΄ μ νλμ§ μμμ΅λλ€
settings:
captcha_enabled:
desc_html: μ΄κ²μ hCaptchaμ μΈλΆ μ€ν¬λ¦½νΈμ μμ‘΄ν©λλ€, μ΄κ²μ κ°μΈμ 보 보νΈμ μνμ κ°ν μλ μμ΅λλ€. μΆκ°μ μΌλ‘, μ΄κ²μ λͺλͺ μ¬λλ€(νΉνλ μ₯μ μΈλ€)μκ² κ°μ
μ μ°¨μ μ κ·Όμ±μ μ¬κ°νκ² λ¨μ΄νΈλ¦΄ μ μμ΅λλ€. μ΄λ¬ν μ΄μ λ‘, λ체μ λ‘ μΉμΈ μ μ©μ΄λ μ΄λμ λ₯Ό ν΅ν κ°μ
μ κ³ λ €ν΄λ³΄μΈμ.
νμ λ μ¬μ©λ§ κ°λ₯ν μ΄λμ₯μ ν΅ν κ°μ
μλ€μ CAPTCHAλ₯Ό νμ§ μμλ λ©λλ€
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 2f766cef38..1cc53dca4b 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -373,6 +373,8 @@ en:
add_new: Allow federation with domain
created_msg: Domain has been successfully allowed for federation
destroyed_msg: Domain has been disallowed from federation
+ export: Export
+ import: Import
undo: Disallow federation with domain
domain_blocks:
add_new: Add new domain block
@@ -382,15 +384,19 @@ en:
edit: Edit domain block
existing_domain_block: You have already imposed stricter limits on %{name}.
existing_domain_block_html: You have already imposed stricter limits on %{name}, you need to unblock it first.
+ export: Export
+ import: Import
new:
create: Create block
hint: The domain block will not prevent creation of account entries in the database, but will retroactively and automatically apply specific moderation methods on those accounts.
severity:
- desc_html: "Silence will make the account's posts invisible to anyone who isn't following them. Suspend will remove all of the account's content, media, and profile data. Use None if you just want to reject media files."
+ desc_html: "Limit will make posts from accounts at this domain invisible to anyone who isn't following them. Suspend will remove all content, media, and profile data for this domain's accounts from your server. Use None if you just want to reject media files."
noop: None
- silence: Silence
+ silence: Limit
suspend: Suspend
title: New domain block
+ no_domain_block_selected: No domain blocks were changed as none were selected
+ not_permitted: You are not permitted to perform this action
obfuscate: Obfuscate domain name
obfuscate_hint: Partially obfuscate the domain name in the list if advertising the list of domain limitations is enabled
private_comment: Private comment
@@ -422,6 +428,20 @@ en:
resolved_dns_records_hint_html: The domain name resolves to the following MX domains, which are ultimately responsible for accepting e-mail. Blocking an MX domain will block sign-ups from any e-mail address which uses the same MX domain, even if the visible domain name is different. Be careful not to block major e-mail providers.
resolved_through_html: Resolved through %{domain}
title: Blocked e-mail domains
+ export_domain_allows:
+ new:
+ title: Import domain allows
+ no_file: No file selected
+ export_domain_blocks:
+ import:
+ description_html: You are about to import a list of domain blocks. Please review this list very carefully, especially if you have not authored this list yourself.
+ existing_relationships_warning: Existing follow relationships
+ private_comment_description_html: 'To help you track where imported blocks come from, imported blocks will be created with the following private comment: %{comment}
'
+ private_comment_template: Imported from %{source} on %{date}
+ title: Import domain blocks
+ new:
+ title: Import domain blocks
+ no_file: No file selected
follow_recommendations:
description_html: "Follow recommendations help new users quickly find interesting content. When a user has not interacted with others enough to form personalized follow recommendations, these accounts are recommended instead. They are re-calculated on a daily basis from a mix of accounts with the highest recent engagements and highest local follower counts for a given language."
language: For language
@@ -914,7 +934,7 @@ en:
warning: Be very careful with this data. Never share it with anyone!
your_token: Your access token
auth:
- apply_for_account: Get on waitlist
+ apply_for_account: Request an account
change_password: Password
delete_account: Delete account
delete_account_html: If you wish to delete your account, you can proceed here. You will be asked for confirmation.
diff --git a/config/navigation.rb b/config/navigation.rb
index 4d2da7aa47..aab72d27c4 100644
--- a/config/navigation.rb
+++ b/config/navigation.rb
@@ -23,7 +23,7 @@ SimpleNavigation::Configuration.run do |navigation|
n.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_path, if: -> { current_user.functional? }
n.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? }
- n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_path, if: -> { current_user.functional? }
+ n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_path, if: -> { current_user.functional_or_moved? }
n.item :security, safe_join([fa_icon('lock fw'), t('settings.account')]), edit_user_registration_path do |s|
s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_path, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities|^/disputes}
diff --git a/spec/controllers/admin/statuses_controller_spec.rb b/spec/controllers/admin/statuses_controller_spec.rb
index 227688e236..7f912c1c07 100644
--- a/spec/controllers/admin/statuses_controller_spec.rb
+++ b/spec/controllers/admin/statuses_controller_spec.rb
@@ -41,7 +41,7 @@ describe Admin::StatusesController do
describe 'POST #batch' do
before do
- post :batch, params: { :account_id => account.id, action => '', :admin_status_batch_action => { status_ids: status_ids } }
+ post :batch, params: { account_id: account.id, action => '', admin_status_batch_action: { status_ids: status_ids } }
end
let(:status_ids) { [media_attached_status.id] }
diff --git a/spec/services/favourite_service_spec.rb b/spec/services/favourite_service_spec.rb
index 94a8111dd5..9781f0d78b 100644
--- a/spec/services/favourite_service_spec.rb
+++ b/spec/services/favourite_service_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe FavouriteService, type: :service do
let(:status) { Fabricate(:status, account: bob) }
before do
- stub_request(:post, "http://example.com/inbox").to_return(:status => 200, :body => "", :headers => {})
+ stub_request(:post, "http://example.com/inbox").to_return(status: 200, body: "", headers: {})
subject.call(sender, status)
end
diff --git a/spec/services/follow_service_spec.rb b/spec/services/follow_service_spec.rb
index 88346ec54a..412c04d76b 100644
--- a/spec/services/follow_service_spec.rb
+++ b/spec/services/follow_service_spec.rb
@@ -140,7 +140,7 @@ RSpec.describe FollowService, type: :service do
let(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') }
before do
- stub_request(:post, "http://example.com/inbox").to_return(:status => 200, :body => "", :headers => {})
+ stub_request(:post, "http://example.com/inbox").to_return(status: 200, body: "", headers: {})
subject.call(sender, bob)
end
diff --git a/spec/services/verify_link_service_spec.rb b/spec/services/verify_link_service_spec.rb
index 3fc88e60e4..52ba454cce 100644
--- a/spec/services/verify_link_service_spec.rb
+++ b/spec/services/verify_link_service_spec.rb
@@ -76,7 +76,25 @@ RSpec.describe VerifyLinkService, type: :service do
context 'when a link does not contain a link back' do
let(:html) { '' }
- it 'marks the field as verified' do
+ it 'does not mark the field as verified' do
+ expect(field.verified?).to be false
+ end
+ end
+
+ context 'when link has no `href` attribute' do
+ let(:html) do
+ <<-HTML
+
+
+
+
+
+ Follow me on Mastodon
+
+ HTML
+ end
+
+ it 'does not mark the field as verified' do
expect(field.verified?).to be false
end
end
diff --git a/spec/views/statuses/show.html.haml_spec.rb b/spec/views/statuses/show.html.haml_spec.rb
index eeea2f6985..ca5bb2ae87 100644
--- a/spec/views/statuses/show.html.haml_spec.rb
+++ b/spec/views/statuses/show.html.haml_spec.rb
@@ -4,7 +4,7 @@ require 'rails_helper'
describe 'statuses/show.html.haml', without_verify_partial_doubles: true do
before do
- double(:api_oembed_url => '')
+ double(api_oembed_url: '')
allow(view).to receive(:show_landing_strip?).and_return(true)
allow(view).to receive(:site_title).and_return('example site')
allow(view).to receive(:site_hostname).and_return('example.com')