diff --git a/app/components/admin/settings/features_tab_component.rb b/app/components/admin/settings/features_tab_component.rb index 67d54d337..9b06e32a3 100644 --- a/app/components/admin/settings/features_tab_component.rb +++ b/app/components/admin/settings/features_tab_component.rb @@ -26,6 +26,7 @@ class Admin::Settings::FeaturesTabComponent < ApplicationComponent feature.sdg feature.machine_learning feature.remove_investments_supports + feature.gdpr.require_consent_for_notifications feature.dashboard.notification_emails ] end diff --git a/app/models/setting.rb b/app/models/setting.rb index d9b6f2fb1..7b997e563 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -91,6 +91,7 @@ class Setting < ApplicationRecord "feature.machine_learning": false, "feature.remove_investments_supports": true, "feature.cookies_consent": false, + "feature.gdpr.require_consent_for_notifications": false, "homepage.widgets.feeds.debates": true, "homepage.widgets.feeds.processes": true, "homepage.widgets.feeds.proposals": true, diff --git a/app/models/user.rb b/app/models/user.rb index 30cee72c1..7af90cdbe 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,6 +1,10 @@ class User < ApplicationRecord include Verification attribute :registering_from_web, default: false + %i[newsletter email_digest email_on_direct_message public_activity recommended_debates + recommended_proposals].each do |field| + attribute field, :boolean, default: -> { !Setting["feature.gdpr.require_consent_for_notifications"] } + end devise :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :password_expirable, :secure_validatable, diff --git a/config/locales/en/settings.yml b/config/locales/en/settings.yml index 50ace1eb0..fc4e95012 100644 --- a/config/locales/en/settings.yml +++ b/config/locales/en/settings.yml @@ -140,6 +140,9 @@ en: sdg_description: Enable Sustainable Development Goals sections in the administration menu and in the Global Settings. cookies_consent: Cookies consent banner cookies_consent_description: Enable the cookies consent banner to inform users about the cookies the application uses. + gdpr: + require_consent_for_notifications: Explicit consent for notifications + require_consent_for_notifications_description: Require explicit user consent in order to send them newsletters and similar information as required by the General Data Protection Regulation (GDPR). remote_census: general: endpoint: "Endpoint" diff --git a/config/locales/es/settings.yml b/config/locales/es/settings.yml index 02bb55f5c..77c1acf87 100644 --- a/config/locales/es/settings.yml +++ b/config/locales/es/settings.yml @@ -140,6 +140,9 @@ es: sdg_description: Habilitar secciones relacionadas con Objetivos de Desarrollo Sostenible en el menú de administración y en la sección de Configuración Global. cookies_consent: Banner de consentimiento de cookies cookies_consent_description: Activa el banner de consentimiento de cookies para informar a los usuarios sobre las cookies que utiliza la aplicación. + gdpr: + require_consent_for_notifications: Consentimiento explícito para notificaciones + require_consent_for_notifications_description: Requerir que los usuarios tengan que dar consentimiento explícito para enviarles boletines e información similar tal y como describe Reglamento General de Protección de Datos (RGPD). remote_census: general: endpoint: "Endpoint" diff --git a/db/migrate/20251009084919_remove_default_value_in_user_notifications.rb b/db/migrate/20251009084919_remove_default_value_in_user_notifications.rb new file mode 100644 index 000000000..0c0d61d74 --- /dev/null +++ b/db/migrate/20251009084919_remove_default_value_in_user_notifications.rb @@ -0,0 +1,9 @@ +class RemoveDefaultValueInUserNotifications < ActiveRecord::Migration[7.1] + def change + change_table :users do |t| + t.change_default :newsletter, from: true, to: nil + t.change_default :email_digest, from: true, to: nil + t.change_default :email_on_direct_message, from: true, to: nil + end + end +end diff --git a/db/migrate/20251009085327_remove_default_value_in_user_recommendations.rb b/db/migrate/20251009085327_remove_default_value_in_user_recommendations.rb new file mode 100644 index 000000000..557c01a6b --- /dev/null +++ b/db/migrate/20251009085327_remove_default_value_in_user_recommendations.rb @@ -0,0 +1,8 @@ +class RemoveDefaultValueInUserRecommendations < ActiveRecord::Migration[7.1] + def change + change_table :users do |t| + t.change_default :recommended_debates, from: true, to: nil + t.change_default :recommended_proposals, from: true, to: nil + end + end +end diff --git a/db/migrate/20251009085528_remove_default_value_in_user_public_activity.rb b/db/migrate/20251009085528_remove_default_value_in_user_public_activity.rb new file mode 100644 index 000000000..315be7a56 --- /dev/null +++ b/db/migrate/20251009085528_remove_default_value_in_user_public_activity.rb @@ -0,0 +1,7 @@ +class RemoveDefaultValueInUserPublicActivity < ActiveRecord::Migration[7.1] + def change + change_table :users do |t| + t.change_default :public_activity, from: true, to: nil + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 10cc0d023..f003810bc 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[7.1].define(version: 2025_09_09_145207) do +ActiveRecord::Schema[7.1].define(version: 2025_10_09_085528) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" enable_extension "plpgsql" @@ -1608,8 +1608,8 @@ ActiveRecord::Schema[7.1].define(version: 2025_09_09_145207) do t.datetime "level_two_verified_at", precision: nil t.string "erase_reason" t.datetime "erased_at", precision: nil - t.boolean "public_activity", default: true - t.boolean "newsletter", default: true + t.boolean "public_activity" + t.boolean "newsletter" t.integer "notifications_count", default: 0 t.boolean "registering_with_oauth", default: false t.string "locale" @@ -1617,16 +1617,16 @@ ActiveRecord::Schema[7.1].define(version: 2025_09_09_145207) do t.integer "geozone_id" t.string "gender", limit: 10 t.datetime "date_of_birth", precision: nil - t.boolean "email_digest", default: true - t.boolean "email_on_direct_message", default: true + t.boolean "email_digest" + t.boolean "email_on_direct_message" t.boolean "official_position_badge", default: false t.datetime "password_changed_at", precision: nil, default: "2015-01-01 01:01:01", null: false t.boolean "created_from_signature", default: false t.integer "failed_email_digests_count", default: 0 t.text "former_users_data_log", default: "" t.boolean "public_interests", default: false - t.boolean "recommended_debates", default: true - t.boolean "recommended_proposals", default: true + t.boolean "recommended_debates" + t.boolean "recommended_proposals" t.string "subscriptions_token" t.integer "failed_attempts", default: 0, null: false t.datetime "locked_at", precision: nil diff --git a/spec/factories/users.rb b/spec/factories/users.rb index d9b8789c5..cad4c8880 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -7,7 +7,6 @@ FactoryBot.define do terms_of_service { "1" } confirmed_at { Time.current } date_of_birth { 20.years.ago } - public_activity { true } trait :incomplete_verification do after :create do |user| diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index c8d6777c3..a986f556e 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -92,37 +92,103 @@ describe User do end describe "preferences" do - describe "email_on_comment" do + describe "#email_on_comment" do it "is false by default" do expect(subject.email_on_comment).to be false end end - describe "email_on_comment_reply" do + describe "#email_on_comment_reply" do it "is false by default" do expect(subject.email_on_comment_reply).to be false end end - describe "subscription_to_website_newsletter" do - it "is true by default" do - expect(subject.newsletter).to be true + describe "#newsletter" do + it "is true by default when the consent for notifications setting is disabled" do + Setting["feature.gdpr.require_consent_for_notifications"] = false + + expect(build(:user).newsletter).to be true + end + + it "is false by default when the consent for notifications setting is enabled" do + Setting["feature.gdpr.require_consent_for_notifications"] = true + + expect(build(:user).newsletter).to be false end end - describe "email_digest" do - it "is true by default" do - expect(subject.email_digest).to be true + describe "#email_digest" do + it "is true by default when the consent for notifications setting is disabled" do + Setting["feature.gdpr.require_consent_for_notifications"] = false + + expect(build(:user).email_digest).to be true + end + + it "is false by default when the consent for notifications setting is enabled" do + Setting["feature.gdpr.require_consent_for_notifications"] = true + + expect(build(:user).email_digest).to be false end end - describe "email_on_direct_message" do - it "is true by default" do - expect(subject.email_on_direct_message).to be true + describe "#email_on_direct_message" do + it "is true by default when the consent for notifications setting is disabled" do + Setting["feature.gdpr.require_consent_for_notifications"] = false + + expect(build(:user).email_on_direct_message).to be true + end + + it "is false by default when the consent for notifications setting is enabled" do + Setting["feature.gdpr.require_consent_for_notifications"] = true + + expect(build(:user).email_on_direct_message).to be false end end - describe "official_position_badge" do + describe "#public_activity" do + it "is true by default when the consent for notifications setting is disabled" do + Setting["feature.gdpr.require_consent_for_notifications"] = false + + expect(build(:user).public_activity).to be true + end + + it "is false by default when the consent for notifications setting is enabled" do + Setting["feature.gdpr.require_consent_for_notifications"] = true + + expect(build(:user).public_activity).to be false + end + end + + describe "#recommended_debates" do + it "is true by default when the consent for notifications setting is disabled" do + Setting["feature.gdpr.require_consent_for_notifications"] = false + + expect(build(:user).recommended_debates).to be true + end + + it "is false by default when the consent for notifications setting is enabled" do + Setting["feature.gdpr.require_consent_for_notifications"] = true + + expect(build(:user).recommended_debates).to be false + end + end + + describe "#recommended_proposals" do + it "is true by default when the consent for notifications setting is disabled" do + Setting["feature.gdpr.require_consent_for_notifications"] = false + + expect(build(:user).recommended_proposals).to be true + end + + it "is false by default when the consent for notifications setting is enabled" do + Setting["feature.gdpr.require_consent_for_notifications"] = true + + expect(build(:user).recommended_proposals).to be false + end + end + + describe "#official_position_badge" do it "is false by default" do expect(subject.official_position_badge).to be false end @@ -402,6 +468,26 @@ describe User do end end + describe ".newsletter" do + it "returns users subscribed to the newsletter" do + create(:user, newsletter: true, username: "Subscriber1") + create(:user, newsletter: true, username: "Subscriber2") + create(:user, newsletter: false, username: "NonSubscriber") + + expect(User.newsletter.pluck(:username)).to eq ["Subscriber1", "Subscriber2"] + end + end + + describe ".email_digest" do + it "returns users subscribed to email digests" do + create(:user, email_digest: true, username: "Digester1") + create(:user, email_digest: true, username: "Digester2") + create(:user, email_digest: false, username: "NonDigester") + + expect(User.email_digest.pluck(:username)).to eq ["Digester1", "Digester2"] + end + end + describe ".by_username_email_or_document_number" do let!(:larry) do create(:user, email: "larry@consul.dev", username: "Larry Bird", document_number: "12345678Z")