Filter languages with opt out (#3175)
* Remove allowed_languages and add filtered_languages * Use filtered_languages instead of allowed_languagesgh/stable
parent
2e112e2406
commit
8f4b7c1820
|
@ -26,7 +26,7 @@ class Settings::PreferencesController < ApplicationController
|
||||||
def user_params
|
def user_params
|
||||||
params.require(:user).permit(
|
params.require(:user).permit(
|
||||||
:locale,
|
:locale,
|
||||||
allowed_languages: []
|
filtered_languages: []
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -352,7 +352,7 @@ code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.user_allowed_languages {
|
.user_filtered_languages {
|
||||||
li {
|
li {
|
||||||
float: left;
|
float: left;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
|
|
|
@ -99,7 +99,7 @@ class Account < ApplicationRecord
|
||||||
prefix: true,
|
prefix: true,
|
||||||
allow_nil: true
|
allow_nil: true
|
||||||
|
|
||||||
delegate :allowed_languages, to: :user, prefix: false, allow_nil: true
|
delegate :filtered_languages, to: :user, prefix: false, allow_nil: true
|
||||||
|
|
||||||
def local?
|
def local?
|
||||||
domain.nil?
|
domain.nil?
|
||||||
|
|
|
@ -142,8 +142,8 @@ class Status < ApplicationRecord
|
||||||
before_validation :set_conversation
|
before_validation :set_conversation
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def in_allowed_languages(account)
|
def not_in_filtered_languages(account)
|
||||||
where(language: account.allowed_languages)
|
where.not(language: account.filtered_languages)
|
||||||
end
|
end
|
||||||
|
|
||||||
def as_home_timeline(account)
|
def as_home_timeline(account)
|
||||||
|
@ -234,7 +234,7 @@ class Status < ApplicationRecord
|
||||||
def filter_timeline_for_account(query, account, local_only)
|
def filter_timeline_for_account(query, account, local_only)
|
||||||
query = query.not_excluded_by_account(account)
|
query = query.not_excluded_by_account(account)
|
||||||
query = query.not_domain_blocked_by_account(account) unless local_only
|
query = query.not_domain_blocked_by_account(account) unless local_only
|
||||||
query = query.in_allowed_languages(account) if account.allowed_languages.present?
|
query = query.not_in_filtered_languages(account) if account.filtered_languages.present?
|
||||||
query.merge(account_silencing_filter(account))
|
query.merge(account_silencing_filter(account))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
# otp_required_for_login :boolean
|
# otp_required_for_login :boolean
|
||||||
# last_emailed_at :datetime
|
# last_emailed_at :datetime
|
||||||
# otp_backup_codes :string is an Array
|
# otp_backup_codes :string is an Array
|
||||||
# allowed_languages :string default([]), not null, is an Array
|
# filtered_languages :string default([]), not null, is an Array
|
||||||
#
|
#
|
||||||
|
|
||||||
class User < ApplicationRecord
|
class User < ApplicationRecord
|
||||||
|
@ -83,6 +83,6 @@ class User < ApplicationRecord
|
||||||
private
|
private
|
||||||
|
|
||||||
def sanitize_languages
|
def sanitize_languages
|
||||||
allowed_languages.reject!(&:blank?)
|
filtered_languages.reject!(&:blank?)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
label_method: lambda { |locale| human_locale(locale) },
|
label_method: lambda { |locale| human_locale(locale) },
|
||||||
selected: I18n.locale
|
selected: I18n.locale
|
||||||
|
|
||||||
= f.input :allowed_languages,
|
= f.input :filtered_languages,
|
||||||
collection: I18n.available_locales,
|
collection: I18n.available_locales,
|
||||||
wrapper: :with_label,
|
wrapper: :with_label,
|
||||||
include_blank: false,
|
include_blank: false,
|
||||||
|
|
|
@ -12,8 +12,6 @@ ar:
|
||||||
data: ملف CSV تم تصديره من خادوم مثيل آخر لماستدون
|
data: ملف CSV تم تصديره من خادوم مثيل آخر لماستدون
|
||||||
sessions:
|
sessions:
|
||||||
otp: أدخل الرمز الثنائي من هاتفك أو استخدم أحد رموز الاسترداد.
|
otp: أدخل الرمز الثنائي من هاتفك أو استخدم أحد رموز الاسترداد.
|
||||||
user:
|
|
||||||
allowed_languages: سوف يتم السماح بعرض اللغات المختارة على خيوطك المتسلسلة العامة أما التي لم يتم تحديدها فسوف تصفّى.
|
|
||||||
labels:
|
labels:
|
||||||
defaults:
|
defaults:
|
||||||
avatar: الصورة الرمزية
|
avatar: الصورة الرمزية
|
||||||
|
|
|
@ -17,7 +17,7 @@ en:
|
||||||
sessions:
|
sessions:
|
||||||
otp: Enter the Two-factor code from your phone or use one of your recovery codes.
|
otp: Enter the Two-factor code from your phone or use one of your recovery codes.
|
||||||
user:
|
user:
|
||||||
allowed_languages: These languages will be allowed in your public timelines. Languages that are not selected will be filtered out.
|
filtered_languages: Selected languages will be removed from your public timelines.
|
||||||
labels:
|
labels:
|
||||||
defaults:
|
defaults:
|
||||||
avatar: Avatar
|
avatar: Avatar
|
||||||
|
|
|
@ -12,8 +12,6 @@ fa:
|
||||||
data: پروندهٔ CSV که از سرور ماستدون دیگری برونسپاری شده
|
data: پروندهٔ CSV که از سرور ماستدون دیگری برونسپاری شده
|
||||||
sessions:
|
sessions:
|
||||||
otp: کد تأیید دومرحلهای را از تلفن خود وارد کنید یا یکی از کدهای بازیابی را به کار ببرید.
|
otp: کد تأیید دومرحلهای را از تلفن خود وارد کنید یا یکی از کدهای بازیابی را به کار ببرید.
|
||||||
user:
|
|
||||||
allowed_languages: این زبانها در فهرست عمومی نوشتهها مجاز خواهند بود. زبانهایی که انتخاب نشده باشند به این فهرست راه پیدا نمیکنند.
|
|
||||||
labels:
|
labels:
|
||||||
defaults:
|
defaults:
|
||||||
avatar: تصویر نمایه
|
avatar: تصویر نمایه
|
||||||
|
|
|
@ -16,8 +16,6 @@ he:
|
||||||
data: 'קובץ CSV שיוצא משרת מסטודון אחר'
|
data: 'קובץ CSV שיוצא משרת מסטודון אחר'
|
||||||
sessions:
|
sessions:
|
||||||
otp: 'נא להקליד קוד אימות דו-שלבי ממכשירך או קוד אחזור גישה.'
|
otp: 'נא להקליד קוד אימות דו-שלבי ממכשירך או קוד אחזור גישה.'
|
||||||
user:
|
|
||||||
allowed_languages: אלו השפות שיהיה מותרות בצירי הזמן הציבוריים שלך. שפות שלא ייבחרו יפולטרו מעיני הקוראים.
|
|
||||||
labels:
|
labels:
|
||||||
defaults:
|
defaults:
|
||||||
avatar: תמונת פרופיל
|
avatar: תמונת פרופיל
|
||||||
|
|
|
@ -12,11 +12,8 @@ ja:
|
||||||
data: 他の Mastodon インスタンスからエクスポートしたCSVファイルを選択して下さい
|
data: 他の Mastodon インスタンスからエクスポートしたCSVファイルを選択して下さい
|
||||||
sessions:
|
sessions:
|
||||||
otp: 携帯電話に表示された2段階認証コードを入力するか、生成したリカバリーコードを使用してください。
|
otp: 携帯電話に表示された2段階認証コードを入力するか、生成したリカバリーコードを使用してください。
|
||||||
user:
|
|
||||||
allowed_languages: 選択した言語があなたの公開タイムラインに表示されます。選択していない言語は取り除かれます。
|
|
||||||
labels:
|
labels:
|
||||||
defaults:
|
defaults:
|
||||||
allowed_languages: 許可する言語
|
|
||||||
avatar: アイコン
|
avatar: アイコン
|
||||||
confirm_new_password: 新しいパスワード(確認用)
|
confirm_new_password: 新しいパスワード(確認用)
|
||||||
confirm_password: パスワード(確認用)
|
confirm_password: パスワード(確認用)
|
||||||
|
|
|
@ -12,11 +12,8 @@ oc:
|
||||||
data: Fichièr CSV exportat d’una autra instància Mastodon
|
data: Fichièr CSV exportat d’una autra instància Mastodon
|
||||||
sessions:
|
sessions:
|
||||||
otp: Picatz lo còdi d’autentificacion en dos temps (Two factor code) de vòstre mobil o utilizatz un de vòstres còdis de recuperacion.
|
otp: Picatz lo còdi d’autentificacion en dos temps (Two factor code) de vòstre mobil o utilizatz un de vòstres còdis de recuperacion.
|
||||||
user:
|
|
||||||
allowed_languages: Aquestas lengas seràn las que seràn autorizadas dins vòstre flux public. Las lengas pas causidas seràn rescondudas.
|
|
||||||
labels:
|
labels:
|
||||||
defaults:
|
defaults:
|
||||||
allowed_languages: Lengas autorizadas
|
|
||||||
avatar: Avatar
|
avatar: Avatar
|
||||||
confirm_new_password: Confirmacion del nòu senhal
|
confirm_new_password: Confirmacion del nòu senhal
|
||||||
confirm_password: Confirmatz lo nòu senhal
|
confirm_password: Confirmatz lo nòu senhal
|
||||||
|
|
|
@ -12,8 +12,6 @@ pl:
|
||||||
data: Plik CSV wyeksportowany z innej instancji Mastodona
|
data: Plik CSV wyeksportowany z innej instancji Mastodona
|
||||||
sessions:
|
sessions:
|
||||||
otp: Wprowadź kod weryfikacji dwuetapowej z telefonu lub wykorzystaj jeden z kodów zapasowych.
|
otp: Wprowadź kod weryfikacji dwuetapowej z telefonu lub wykorzystaj jeden z kodów zapasowych.
|
||||||
user:
|
|
||||||
allowed_languages: Te języki będą wyświetlać się na Twojej osi czasu. Wpisy w niezaznaczonych językach nie będą widoczne.
|
|
||||||
labels:
|
labels:
|
||||||
defaults:
|
defaults:
|
||||||
avatar: Awatar
|
avatar: Awatar
|
||||||
|
|
|
@ -12,8 +12,6 @@ pt-BR:
|
||||||
data: Arquivo CSV exportado de outra instancia Mastodon
|
data: Arquivo CSV exportado de outra instancia Mastodon
|
||||||
sessions:
|
sessions:
|
||||||
otp: Entre com o código de 2 passos do seu telefone ou use os códiogos de recuperação.
|
otp: Entre com o código de 2 passos do seu telefone ou use os códiogos de recuperação.
|
||||||
user:
|
|
||||||
allowed_languages: Essas línguas vão ser permitidas na sua timeline pública. Línguas que não forem selecionadas serão filtradas.
|
|
||||||
labels:
|
labels:
|
||||||
defaults:
|
defaults:
|
||||||
avatar: Avatar
|
avatar: Avatar
|
||||||
|
|
|
@ -16,8 +16,6 @@ th:
|
||||||
data: CSV file exported from another Mastodon instance
|
data: CSV file exported from another Mastodon instance
|
||||||
sessions:
|
sessions:
|
||||||
otp: Enter the Two-factor code from your phone or use one of your recovery codes.
|
otp: Enter the Two-factor code from your phone or use one of your recovery codes.
|
||||||
user:
|
|
||||||
allowed_languages: These languages will be allowed in your public timelines. Languages that are not selected will be filtered out.
|
|
||||||
labels:
|
labels:
|
||||||
defaults:
|
defaults:
|
||||||
avatar: Avatar
|
avatar: Avatar
|
||||||
|
|
|
@ -12,8 +12,6 @@ zh-CN:
|
||||||
data: 自其他服务站导出的 CSV 文件
|
data: 自其他服务站导出的 CSV 文件
|
||||||
sessions:
|
sessions:
|
||||||
otp: 输入你手机生成的两步验证码,或者恢复代码。
|
otp: 输入你手机生成的两步验证码,或者恢复代码。
|
||||||
user:
|
|
||||||
allowed_languages: 允许下列语言的内容出现在你的公共时间线上。
|
|
||||||
labels:
|
labels:
|
||||||
defaults:
|
defaults:
|
||||||
avatar: 头像
|
avatar: 头像
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
class ChangeLanguageFilterToOptOut < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
remove_index :users, :allowed_languages
|
||||||
|
remove_column :users, :allowed_languages
|
||||||
|
|
||||||
|
add_column :users, :filtered_languages, :string, array: true, default: [], null: false
|
||||||
|
add_index :users, :filtered_languages, using: :gin
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20170517205741) do
|
ActiveRecord::Schema.define(version: 20170520145338) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -350,11 +350,11 @@ ActiveRecord::Schema.define(version: 20170517205741) do
|
||||||
t.boolean "otp_required_for_login"
|
t.boolean "otp_required_for_login"
|
||||||
t.datetime "last_emailed_at"
|
t.datetime "last_emailed_at"
|
||||||
t.string "otp_backup_codes", array: true
|
t.string "otp_backup_codes", array: true
|
||||||
t.string "allowed_languages", default: [], null: false, array: true
|
t.string "filtered_languages", default: [], null: false, array: true
|
||||||
t.index ["account_id"], name: "index_users_on_account_id", using: :btree
|
t.index ["account_id"], name: "index_users_on_account_id", using: :btree
|
||||||
t.index ["allowed_languages"], name: "index_users_on_allowed_languages", using: :gin
|
|
||||||
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
|
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
|
||||||
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
|
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
|
||||||
|
t.index ["filtered_languages"], name: "index_users_on_filtered_languages", using: :gin
|
||||||
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
|
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
||||||
describe Settings::PreferencesController do
|
describe Settings::PreferencesController do
|
||||||
render_views
|
render_views
|
||||||
|
|
||||||
let(:user) { Fabricate(:user, allowed_languages: []) }
|
let(:user) { Fabricate(:user, filtered_languages: []) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
sign_in user, scope: :user
|
sign_in user, scope: :user
|
||||||
|
@ -18,12 +18,12 @@ describe Settings::PreferencesController do
|
||||||
|
|
||||||
describe 'PUT #update' do
|
describe 'PUT #update' do
|
||||||
it 'updates the user record' do
|
it 'updates the user record' do
|
||||||
put :update, params: { user: { locale: 'en', allowed_languages: ['es', 'fr', ''] } }
|
put :update, params: { user: { locale: 'en', filtered_languages: ['es', 'fr', ''] } }
|
||||||
|
|
||||||
expect(response).to redirect_to(settings_preferences_path)
|
expect(response).to redirect_to(settings_preferences_path)
|
||||||
user.reload
|
user.reload
|
||||||
expect(user.locale).to eq 'en'
|
expect(user.locale).to eq 'en'
|
||||||
expect(user.allowed_languages).to eq ['es', 'fr']
|
expect(user.filtered_languages).to eq ['es', 'fr']
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'updates user settings' do
|
it 'updates user settings' do
|
||||||
|
|
|
@ -512,7 +512,7 @@ RSpec.describe Status, type: :model do
|
||||||
|
|
||||||
context 'with language preferences' do
|
context 'with language preferences' do
|
||||||
it 'excludes statuses in languages not allowed by the account user' do
|
it 'excludes statuses in languages not allowed by the account user' do
|
||||||
user = Fabricate(:user, allowed_languages: [:en, :es])
|
user = Fabricate(:user, filtered_languages: [:fr])
|
||||||
@account.update(user: user)
|
@account.update(user: user)
|
||||||
en_status = Fabricate(:status, language: 'en')
|
en_status = Fabricate(:status, language: 'en')
|
||||||
es_status = Fabricate(:status, language: 'es')
|
es_status = Fabricate(:status, language: 'es')
|
||||||
|
@ -525,7 +525,7 @@ RSpec.describe Status, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'includes all languages when user does not have a setting' do
|
it 'includes all languages when user does not have a setting' do
|
||||||
user = Fabricate(:user, allowed_languages: [])
|
user = Fabricate(:user, filtered_languages: [])
|
||||||
@account.update(user: user)
|
@account.update(user: user)
|
||||||
|
|
||||||
en_status = Fabricate(:status, language: 'en')
|
en_status = Fabricate(:status, language: 'en')
|
||||||
|
|
|
@ -24,9 +24,9 @@ RSpec.describe User, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'cleans out empty string from languages' do
|
it 'cleans out empty string from languages' do
|
||||||
user = Fabricate.build(:user, allowed_languages: [''])
|
user = Fabricate.build(:user, filtered_languages: [''])
|
||||||
user.valid?
|
user.valid?
|
||||||
expect(user.allowed_languages).to eq []
|
expect(user.filtered_languages).to eq []
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Reference in New Issue