diff --git a/app/controllers/settings/privacy_controller.rb b/app/controllers/settings/privacy_controller.rb index f85201f1..7921ef08 100644 --- a/app/controllers/settings/privacy_controller.rb +++ b/app/controllers/settings/privacy_controller.rb @@ -6,7 +6,8 @@ class Settings::PrivacyController < ApplicationController def edit; end def update - user_attributes = params.require(:user).permit(:privacy_allow_anonymous_questions, + user_attributes = params.require(:user).permit(:privacy_lock_inbox, + :privacy_allow_anonymous_questions, :privacy_allow_public_timeline, :privacy_allow_stranger_answers, :privacy_show_in_search) diff --git a/app/models/user.rb b/app/models/user.rb index a8f57dd5..2098f825 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -169,6 +169,10 @@ class User < ApplicationRecord !self.export_processing end + def inbox_locked? + privacy_lock_inbox + end + # %w[admin moderator].each do |m| # define_method(m) { raise "not allowed: #{m}" } # define_method(m+??) { raise "not allowed: #{m}?"} diff --git a/app/views/application/_questionbox.html.haml b/app/views/application/_questionbox.html.haml index fd9ceb36..1bb6d725 100644 --- a/app/views/application/_questionbox.html.haml +++ b/app/views/application/_questionbox.html.haml @@ -14,6 +14,9 @@ - elsif user_signed_in? && user.blocking?(current_user) .text-center %strong= t(".status.blocked") + - elsif user.inbox_locked? + .text-center + %strong= t(".status.locked") - else - if user_signed_in? || user.privacy_allow_anonymous_questions? #question-box{ data: { controller: "character-count", "character-count-max-value": 512 }} diff --git a/app/views/settings/privacy/edit.html.haml b/app/views/settings/privacy/edit.html.haml index e2287aad..55465898 100644 --- a/app/views/settings/privacy/edit.html.haml +++ b/app/views/settings/privacy/edit.html.haml @@ -1,6 +1,7 @@ .card .card-body = bootstrap_form_for(current_user, url: settings_privacy_path, method: :patch, data: { turbo: false }) do |f| + = f.check_box :privacy_lock_inbox = f.check_box :privacy_allow_anonymous_questions = f.check_box :privacy_allow_public_timeline = f.check_box :privacy_allow_stranger_answers diff --git a/app/workers/question_worker.rb b/app/workers/question_worker.rb index 8f7823a6..9a361553 100644 --- a/app/workers/question_worker.rb +++ b/app/workers/question_worker.rb @@ -12,6 +12,7 @@ class QuestionWorker question = Question.find(question_id) user.followers.each do |f| + next if f.inbox_locked? next if f.banned? next if MuteRule.where(user: f).any? { |rule| rule.applies_to? question } diff --git a/config/locales/activerecord.en.yml b/config/locales/activerecord.en.yml index cb5881a7..9863908f 100644 --- a/config/locales/activerecord.en.yml +++ b/config/locales/activerecord.en.yml @@ -67,6 +67,7 @@ en: remember_created_at: "Remember me set at" password: "Password" password_confirmation: "Confirm your password" + privacy_lock_inbox: "Lock inbox and don't allow new questions" privacy_allow_anonymous_questions: "Allow anonymous questions" privacy_allow_public_timeline: "Show your answers in the public timeline" privacy_allow_stranger_answers: "Allow other people to answer your questions" diff --git a/config/locales/errors.en.yml b/config/locales/errors.en.yml index c00de3cd..d5e1ff32 100644 --- a/config/locales/errors.en.yml +++ b/config/locales/errors.en.yml @@ -6,6 +6,7 @@ en: param_is_missing: "param is missing" forbidden: "This is illegal, you know" + inbox_locked: "This user currently does not accept questions" blocked: "You have been blocked from performing this request" other_blocked_self: "You have been blocked by this user" asking_other_blocked_self: "You have been blocked from asking this user questions" diff --git a/config/locales/views.en.yml b/config/locales/views.en.yml index 732e4891..0fc0891f 100644 --- a/config/locales/views.en.yml +++ b/config/locales/views.en.yml @@ -123,6 +123,7 @@ en: banned: "This user got hit with ye olde banhammer." blocking: "You are blocking this user." blocked: "This user has blocked you." + locked: "This user currently does not accept questions." devise: registrations: edit: diff --git a/db/migrate/20221106130744_add_inbox_locked_to_users.rb b/db/migrate/20221106130744_add_inbox_locked_to_users.rb new file mode 100644 index 00000000..295ebca7 --- /dev/null +++ b/db/migrate/20221106130744_add_inbox_locked_to_users.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class AddInboxLockedToUsers < ActiveRecord::Migration[6.1] + def up + add_column :users, :privacy_lock_inbox, :boolean, default: false + end + + def down + remove_column :users, :privacy_lock_inbox + end +end diff --git a/db/schema.rb b/db/schema.rb index 3f035379..1c9173f3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2022_08_20_163035) do +ActiveRecord::Schema.define(version: 2022_11_06_130744) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -31,8 +31,8 @@ ActiveRecord::Schema.define(version: 2022_08_20_163035) do t.string "identifier" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false - t.bigint "question_id" t.bigint "user_id" + t.bigint "question_id" t.index ["identifier"], name: "index_anonymous_blocks_on_identifier" t.index ["question_id"], name: "index_anonymous_blocks_on_question_id" t.index ["user_id"], name: "index_anonymous_blocks_on_user_id" @@ -46,8 +46,6 @@ ActiveRecord::Schema.define(version: 2022_08_20_163035) do t.datetime "created_at" t.datetime "updated_at" t.integer "smile_count", default: 0, null: false - t.datetime "deleted_at" - t.index ["deleted_at"], name: "index_answers_on_deleted_at" t.index ["question_id"], name: "index_answers_on_question_id" t.index ["user_id", "created_at"], name: "index_answers_on_user_id_and_created_at" end @@ -60,8 +58,6 @@ ActiveRecord::Schema.define(version: 2022_08_20_163035) do t.text "content" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false - t.datetime "deleted_at" - t.index ["deleted_at"], name: "index_appendables_on_deleted_at" t.index ["parent_id", "parent_type"], name: "index_appendables_on_parent_id_and_parent_type" t.index ["user_id", "created_at"], name: "index_appendables_on_user_id_and_created_at" end @@ -73,9 +69,7 @@ ActiveRecord::Schema.define(version: 2022_08_20_163035) do t.datetime "created_at" t.datetime "updated_at" t.integer "smile_count", default: 0, null: false - t.datetime "deleted_at" t.index ["answer_id"], name: "index_comments_on_answer_id" - t.index ["deleted_at"], name: "index_comments_on_deleted_at" t.index ["user_id", "created_at"], name: "index_comments_on_user_id_and_created_at" end @@ -108,10 +102,10 @@ ActiveRecord::Schema.define(version: 2022_08_20_163035) do end create_table "mute_rules", id: :bigint, default: -> { "gen_timestamp_id('mute_rules'::text)" }, force: :cascade do |t| + t.bigint "user_id" t.string "muted_phrase" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.bigint "user_id" t.index ["user_id"], name: "index_mute_rules_on_user_id" end @@ -150,8 +144,6 @@ ActiveRecord::Schema.define(version: 2022_08_20_163035) do t.datetime "updated_at" t.integer "answer_count", default: 0, null: false t.boolean "direct", default: false, null: false - t.datetime "deleted_at" - t.index ["deleted_at"], name: "index_questions_on_deleted_at" t.index ["user_id", "created_at"], name: "index_questions_on_user_id_and_created_at" end @@ -300,9 +292,8 @@ ActiveRecord::Schema.define(version: 2022_08_20_163035) do t.datetime "export_created_at" t.string "otp_secret_key" t.integer "otp_module", default: 0, null: false - t.datetime "deleted_at" + t.boolean "privacy_lock_inbox", default: false t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true - t.index ["deleted_at"], name: "index_users_on_deleted_at" t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true t.index ["screen_name"], name: "index_users_on_screen_name", unique: true @@ -316,5 +307,7 @@ ActiveRecord::Schema.define(version: 2022_08_20_163035) do t.index ["user_id"], name: "index_users_roles_on_user_id" end + add_foreign_key "anonymous_blocks", "questions" + add_foreign_key "anonymous_blocks", "users" add_foreign_key "profiles", "users" end diff --git a/lib/errors.rb b/lib/errors.rb index 5414f7f8..5d94f3cd 100644 --- a/lib/errors.rb +++ b/lib/errors.rb @@ -35,6 +35,9 @@ module Errors class SelfAction < Forbidden end + class InboxLocked < Forbidden + end + class FollowingSelf < SelfAction end diff --git a/lib/use_case/question/create.rb b/lib/use_case/question/create.rb index 7ec5b7fc..05c9ad1b 100644 --- a/lib/use_case/question/create.rb +++ b/lib/use_case/question/create.rb @@ -14,6 +14,7 @@ module UseCase option :direct, type: Types::Params::Bool, default: proc { true } def call + check_lock check_anonymous_rules check_blocks @@ -42,6 +43,10 @@ module UseCase private + def check_lock + raise Errors::InboxLocked if target_user.inbox_locked? + end + def check_anonymous_rules if !source_user_id && !anonymous # We can not create a non-anonymous question without a source user diff --git a/spec/controllers/ajax/question_controller_spec.rb b/spec/controllers/ajax/question_controller_spec.rb index cd3166a4..cbb1a0f1 100644 --- a/spec/controllers/ajax/question_controller_spec.rb +++ b/spec/controllers/ajax/question_controller_spec.rb @@ -328,6 +328,23 @@ describe Ajax::QuestionController, :ajax_controller, type: :controller do include_examples "does not create the question" end end + + context "when users inbox is locked" do + let(:user_allows_anonymous_questions) { true } + let(:expected_response) do + { + "success" => false, + "status" => "inbox_locked", + "message" => anything + } + end + + before do + target_user.update(privacy_lock_inbox: true) + end + + include_examples "does not create the question" + end end context "when rcpt is followers" do diff --git a/spec/workers/question_worker_spec.rb b/spec/workers/question_worker_spec.rb index cafbc455..ab1e2914 100644 --- a/spec/workers/question_worker_spec.rb +++ b/spec/workers/question_worker_spec.rb @@ -6,7 +6,7 @@ describe QuestionWorker do describe "#perform" do let(:user) { FactoryBot.create(:user) } let(:user_id) { user.id } - let(:question) { FactoryBot.create(:question, user: user) } + let(:question) { FactoryBot.create(:question, user:) } let(:question_id) { question.id } before do @@ -41,6 +41,18 @@ describe QuestionWorker do ) end + it "respects inbox locks" do + user.followers.first.update(privacy_lock_inbox: true) + + + expect { subject } + .to( + change { Inbox.where(user_id: user.followers.ids, question_id:, new: true).count } + .from(0) + .to(4) + ) + end + it "does not send questions to banned users" do user.followers.first.ban