Merge branch 'main' into feature/privacy-require-user

This commit is contained in:
Andreas Nedbal 2022-11-13 17:27:53 +01:00 committed by GitHub
commit 3cefc829f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 107 additions and 40 deletions

View File

@ -0,0 +1,35 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/docker-existing-docker-compose
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
{
"name": "Retrospring",
// Update the 'dockerComposeFile' list if you have more compose files or use different names.
// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
"dockerComposeFile": [
"../docker-compose.yml"
],
// The 'service' property is the name of the service for the container that VS Code should
// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
"service": "web",
// The optional 'workspaceFolder' property is the path VS Code should open by default when
// connected. This is typically a file mount in .devcontainer/docker-compose.yml
"workspaceFolder": "/app",
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Uncomment the next line if you want start specific services in your Docker Compose config.
// "runServices": [],
// Uncomment the next line if you want to keep your containers running after VS Code shuts down.
// "shutdownAction": "none",
// Uncomment the next line to run commands after the container is created - for example installing curl.
// "postCreateCommand": "apt-get update && apt-get install -y curl",
// Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "app"
}

View File

@ -8,7 +8,7 @@ ARG GID=1000
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
RUN apt-get update -qq \
&& apt-get install -y --no-install-recommends build-essential \
@ -47,4 +47,4 @@ COPY . /app
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
CMD ["rails", "server", "-b", "0.0.0.0"]

View File

@ -48,10 +48,10 @@ jobs:
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Set up Node 12
- name: Set up Node 14
uses: actions/setup-node@v3
with:
node-version: '12'
node-version: '14'
- name: Copy default configuration
run: |
cp config/database.yml.postgres config/database.yml

View File

@ -80,13 +80,11 @@ gem "puma"
group :development, :test do
gem "better_errors"
gem "bullet"
gem "capybara"
gem "database_cleaner"
gem "factory_bot_rails", require: false
gem "faker"
gem "haml_lint", require: false
gem "letter_opener" # Use this just in local test environments
gem "poltergeist"
gem "rails-controller-testing"
gem "rake"
gem "rspec-its", "~> 1.3"

View File

@ -95,15 +95,6 @@ GEM
bullet (7.0.3)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
capybara (3.37.1)
addressable
matrix
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
carrierwave (2.1.0)
activemodel (>= 5.0.0)
activesupport (>= 5.0.0)
@ -112,7 +103,6 @@ GEM
mimemagic (>= 0.3.0)
mini_mime (>= 0.1.3)
chunky_png (1.4.0)
cliver (0.3.2)
coderay (1.1.3)
colorize (0.8.1)
concurrent-ruby (1.1.10)
@ -261,7 +251,6 @@ GEM
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (1.0.2)
matrix (0.4.2)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
method_source (1.0.0)
@ -315,10 +304,6 @@ GEM
pg (1.4.4)
pghero (3.0.1)
activerecord (>= 6)
poltergeist (1.18.1)
capybara (>= 2.1, < 4)
cliver (~> 0.3.1)
websocket-driver (>= 0.2.0)
public_suffix (4.0.7)
puma (6.0.0)
nio4r (~> 2.0)
@ -521,8 +506,6 @@ GEM
websocket-driver (0.7.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.6.5)
PLATFORMS
@ -536,7 +519,6 @@ DEPENDENCIES
bootsnap
bootstrap_form (~> 4.5)
bullet
capybara
carrierwave (~> 2.0)
carrierwave_backgrounder!
colorize
@ -571,7 +553,6 @@ DEPENDENCIES
omniauth-twitter
pg
pghero
poltergeist
puma
questiongenerator (~> 1.0)
rails (~> 6.1)

View File

@ -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,

View File

@ -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}?"}

View File

@ -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")
- elsif !user_signed_in? && user.privacy_require_user?
.text-center
%strong= t(".status.require_user_html", sign_in: link_to(t("voc.login"), new_user_session_path), sign_up: link_to(t("voc.register"), new_user_registration_path))

View File

@ -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_require_user
= f.check_box :privacy_allow_public_timeline

View File

@ -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 }

View File

@ -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_require_user: "Require users to be logged in to ask you questions"
privacy_allow_public_timeline: "Show your answers in the public timeline"

View File

@ -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"

View File

@ -122,6 +122,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."
require_user_html: |
This user requires others to be logged in to ask questions. <br/>
(%{sign_in} or %{sign_up})

View File

@ -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

View File

@ -31,8 +31,8 @@ ActiveRecord::Schema.define(version: 2022_11_13_110942) 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_11_13_110942) 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_11_13_110942) 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_11_13_110942) 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_11_13_110942) 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_11_13_110942) 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
@ -302,8 +294,8 @@ ActiveRecord::Schema.define(version: 2022_11_13_110942) do
t.integer "otp_module", default: 0, null: false
t.datetime "deleted_at"
t.boolean "privacy_require_user", default: false
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
@ -317,5 +309,7 @@ ActiveRecord::Schema.define(version: 2022_11_13_110942) 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

View File

@ -35,6 +35,9 @@ module Errors
class SelfAction < Forbidden
end
class InboxLocked < Forbidden
end
class FollowingSelf < SelfAction
end

View File

@ -15,6 +15,7 @@ module UseCase
def call
check_user
check_lock
check_anonymous_rules
check_blocks
@ -43,6 +44,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

View File

@ -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

View File

@ -10,8 +10,6 @@ require "rspec/rails"
# Add additional requires below this line. Rails is not loaded until this point!
require "rspec/its"
require "devise"
require "capybara/rails"
require "capybara/rspec"
require "rspec-sidekiq"
# Requires supporting ruby files with custom matchers and macros, etc, in

View File

@ -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