about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/assets/stylesheets/forms.scss7
-rw-r--r--app/controllers/settings/preferences_controller.rb3
-rw-r--r--app/models/account.rb2
-rw-r--r--app/models/status.rb5
-rw-r--r--app/views/settings/preferences/show.html.haml10
-rw-r--r--config/locales/simple_form.en.yml2
-rw-r--r--db/migrate/20170423005413_add_allowed_languages_to_user.rb6
-rw-r--r--db/schema.rb2
-rw-r--r--spec/controllers/settings/preferences_controller_spec.rb8
-rw-r--r--spec/models/status_spec.rb25
10 files changed, 66 insertions, 4 deletions
diff --git a/app/assets/stylesheets/forms.scss b/app/assets/stylesheets/forms.scss
index 890a00510..18258099b 100644
--- a/app/assets/stylesheets/forms.scss
+++ b/app/assets/stylesheets/forms.scss
@@ -326,3 +326,10 @@ code {
     flex: 0 0 auto;
   }
 }
+
+.user_allowed_languages {
+  li {
+    float: left;
+    width: 50%;
+  }
+}
diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb
index 6762faee4..04a85849d 100644
--- a/app/controllers/settings/preferences_controller.rb
+++ b/app/controllers/settings/preferences_controller.rb
@@ -25,7 +25,8 @@ class Settings::PreferencesController < ApplicationController
 
   def user_params
     params.require(:user).permit(
-      :locale
+      :locale,
+      allowed_languages: []
     )
   end
 
diff --git a/app/models/account.rb b/app/models/account.rb
index 03584b4e6..c5fc6d7ab 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -82,6 +82,8 @@ class Account < ApplicationRecord
            prefix: true,
            allow_nil: true
 
+  delegate :allowed_languages, to: :user, prefix: false, allow_nil: true
+
   def follow!(other_account)
     active_relationships.where(target_account: other_account).first_or_create!(target_account: other_account)
   end
diff --git a/app/models/status.rb b/app/models/status.rb
index f005813e5..3243d1ecb 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -119,6 +119,10 @@ class Status < ApplicationRecord
   end
 
   class << self
+    def in_allowed_languages(account)
+      where(language: account.allowed_languages)
+    end
+
     def as_home_timeline(account)
       where(account: [account] + account.following)
     end
@@ -198,6 +202,7 @@ class Status < ApplicationRecord
 
     def filter_timeline_for_account(query, account)
       query = query.not_excluded_by_account(account)
+      query = query.in_allowed_languages(account) if account.allowed_languages.present?
       query.merge(account_silencing_filter(account))
     end
 
diff --git a/app/views/settings/preferences/show.html.haml b/app/views/settings/preferences/show.html.haml
index 8a4113ab4..10618ebf6 100644
--- a/app/views/settings/preferences/show.html.haml
+++ b/app/views/settings/preferences/show.html.haml
@@ -7,6 +7,16 @@
   .fields-group
     = f.input :locale, collection: I18n.available_locales, wrapper: :with_label, include_blank: false, label_method: lambda { |locale| human_locale(locale) }
 
+    = f.input :allowed_languages,
+      collection: I18n.available_locales,
+      wrapper: :with_label,
+      include_blank: false,
+      label_method: lambda { |locale| human_locale(locale) },
+      required: false,
+      as: :check_boxes,
+      collection_wrapper_tag: 'ul',
+      item_wrapper_tag: 'li'
+
     = f.input :setting_default_privacy, collection: Status.visibilities.keys - ['direct'], wrapper: :with_label, include_blank: false, label_method: lambda { |visibility| safe_join([I18n.t("statuses.visibilities.#{visibility}"), content_tag(:span, I18n.t("statuses.visibilities.#{visibility}_long"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
 
   .fields-group
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index 4aa3818fd..941d83a47 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -12,6 +12,8 @@ en:
         data: CSV file exported from another Mastodon instance
       sessions:
         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:
       defaults:
         avatar: Avatar
diff --git a/db/migrate/20170423005413_add_allowed_languages_to_user.rb b/db/migrate/20170423005413_add_allowed_languages_to_user.rb
new file mode 100644
index 000000000..044a13334
--- /dev/null
+++ b/db/migrate/20170423005413_add_allowed_languages_to_user.rb
@@ -0,0 +1,6 @@
+class AddAllowedLanguagesToUser < ActiveRecord::Migration[5.0]
+  def change
+    add_column :users, :allowed_languages, :string, array: true, default: [], null: false
+    add_index :users, :allowed_languages, using: :gin
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 66326f2e2..f6a13671c 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -326,7 +326,9 @@ ActiveRecord::Schema.define(version: 20170425202925) do
     t.boolean  "otp_required_for_login"
     t.datetime "last_emailed_at"
     t.string   "otp_backup_codes",                                       array: true
+    t.string   "allowed_languages",         default: [],    null: false, array: true
     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 ["email"], name: "index_users_on_email", unique: true, using: :btree
     t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
diff --git a/spec/controllers/settings/preferences_controller_spec.rb b/spec/controllers/settings/preferences_controller_spec.rb
index 92b626d2d..432e35cd4 100644
--- a/spec/controllers/settings/preferences_controller_spec.rb
+++ b/spec/controllers/settings/preferences_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 describe Settings::PreferencesController do
   render_views
 
-  let(:user) { Fabricate(:user) }
+  let(:user) { Fabricate(:user, allowed_languages: []) }
 
   before do
     sign_in user, scope: :user
@@ -18,10 +18,12 @@ describe Settings::PreferencesController do
 
   describe 'PUT #update' do
     it 'updates the user record' do
-      put :update, params: { user: { locale: 'en' } }
+      put :update, params: { user: { locale: 'en', allowed_languages: ['es', 'fr'] } }
 
       expect(response).to redirect_to(settings_preferences_path)
-      expect(user.reload.locale).to eq 'en'
+      user.reload
+      expect(user.locale).to eq 'en'
+      expect(user.allowed_languages).to eq ['es', 'fr']
     end
 
     it 'updates user settings' do
diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb
index c553b052e..0c0b16829 100644
--- a/spec/models/status_spec.rb
+++ b/spec/models/status_spec.rb
@@ -251,6 +251,31 @@ RSpec.describe Status, type: :model do
         expect(results).not_to include(muted_status)
       end
 
+      context 'with language preferences' do
+        it 'excludes statuses in languages not allowed by the account user' do
+          user = Fabricate(:user, allowed_languages: [:en, :es])
+          @account.update(user: user)
+          en_status = Fabricate(:status, language: 'en')
+          es_status = Fabricate(:status, language: 'es')
+          fr_status = Fabricate(:status, language: 'fr')
+
+          results = Status.as_public_timeline(@account)
+          expect(results).to include(en_status)
+          expect(results).to include(es_status)
+          expect(results).not_to include(fr_status)
+        end
+
+        it 'includes all languages when account does not have a user' do
+          expect(@account.user).to be_nil
+          en_status = Fabricate(:status, language: 'en')
+          es_status = Fabricate(:status, language: 'es')
+
+          results = Status.as_public_timeline(@account)
+          expect(results).to include(en_status)
+          expect(results).to include(es_status)
+        end
+      end
+
       context 'where that account is silenced' do
         it 'includes statuses from other accounts that are silenced' do
           @account.update(silenced: true)