');
+ // Omniauth registration form
+ $("#new_user label[for='user_birth_date'] select").wrapAll('
');
+
+ // Sélection des éléments du DOM
+ const passwordInput = document.getElementById('registration_user_password');
+ const confirmPasswordInput = document.getElementById('registration_user_password_confirmation');
+ const userNameInput = document.getElementById('registration_user_name');
+ const userNicknameInput = document.getElementById('registration_user_nickname');
+ const userNicknameField = document.querySelector('.user-nickname');
+ const fieldElements = document.querySelectorAll('.field');
+
+ // Masquer la classe "user-nickname"
+ if (userNicknameField !== null) {
+ userNicknameField.style.display = 'none';
+ }
+
+ // Masquer la classe "field" contenant la classe "registration_user_password_confirmation"
+ fieldElements.forEach(field => {
+ const confirmPasswordField = field.querySelector('#registration_user_password_confirmation');
+ if (confirmPasswordField !== null) {
+ field.style.display = 'none';
+ }
+ });
+
+ // // Écouteur d'événement sur le champ du mot de passe
+ if (passwordInput !== null) {
+ passwordInput.addEventListener('input', function() {
+ // If there is a form-error behind the password field, remove it
+ const passwordField = passwordInput.parentElement;
+ const passwordError = passwordField.querySelector('.form-error');
+ if (passwordError !== null) {
+ changeMessage(passwordError)
+ }
+
+ confirmPasswordInput.value = passwordInput.value;
+ });
+ }
+
+ function changeMessage(passwordError) {
+ const password = passwordInput.value;
+ const passwordLength = password.length;
+
+ if (passwordLength < 10) {
+ passwordError.textContent = 'Le mot de passe doit contenir au moins 10 caractères.';
+ }
+ }
+
+ // Génération automatique du surnom à partir du champ du nom
+ if (userNameInput !== null) {
+ userNameInput.addEventListener('input', function() {
+ const userName = userNameInput.value.toLowerCase().replace(/\s/g, '_').replace(/[^\w\s]/gi, ''); // Remplacement des espaces par des underscores, suppression des caractères spéciaux et mise en minuscules
+ const randomNum = Math.floor(100000 + Math.random() * 900000); // Génération d'un nombre aléatoire à 6 chiffres
+ const generatedNickname = userName + '_' + randomNum;
+
+ // Remplissage automatique du champ du surnom
+ userNicknameInput.value = generatedNickname.substr(0, 20); // Limite le surnom à 20 caractères
+
+ // Cacher les champs générés automatiquement
+ confirmPasswordInput.style.display = 'none'; // Cacher le champ de confirmation du mot de passe
+ userNicknameInput.style.display = 'none'; // Cacher le champ du surnom
+ });
+ }
+})
diff --git a/app/packs/stylesheets/signup_form.scss b/app/packs/stylesheets/signup_form.scss
new file mode 100644
index 00000000..388efd79
--- /dev/null
+++ b/app/packs/stylesheets/signup_form.scss
@@ -0,0 +1,13 @@
+#register-form, #new_user {
+ .select-date-container {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ margin: 0 20px;
+ }
+
+ .select-date-container .columns {
+ padding-right: 1.4rem;
+ }
+}
\ No newline at end of file
diff --git a/app/permissions/decidim/initiatives/permissions.rb b/app/permissions/decidim/initiatives/permissions.rb
index a94f3ba5..621248c2 100644
--- a/app/permissions/decidim/initiatives/permissions.rb
+++ b/app/permissions/decidim/initiatives/permissions.rb
@@ -151,6 +151,7 @@ def unvote_initiative?
can_unvote = initiative.accepts_online_unvotes? &&
initiative.organization&.id == user.organization&.id &&
initiative.votes.where(author: user).any? &&
+ user.tos_accepted? &&
authorized?(:vote, resource: initiative, permissions_holder: initiative.type)
toggle_allow(can_unvote)
@@ -181,6 +182,7 @@ def can_vote?
initiative.votes_enabled? &&
initiative.organization&.id == user.organization&.id &&
initiative.votes.where(author: user).empty? &&
+ user.tos_accepted? &&
authorized?(:vote, resource: initiative, permissions_holder: initiative.type)
end
diff --git a/app/views/decidim/confirmation_reminder_mailer/send_reminder.html.erb b/app/views/decidim/confirmation_reminder_mailer/send_reminder.html.erb
new file mode 100644
index 00000000..1e5c33fe
--- /dev/null
+++ b/app/views/decidim/confirmation_reminder_mailer/send_reminder.html.erb
@@ -0,0 +1,20 @@
+
+
+ <%== t "title", scope: "decidim.confirmation_reminder_mailer.send_reminder.body" %>
+
+
+
+ <%== t "body", scope: "decidim.confirmation_reminder_mailer.send_reminder.body" %>
+
+
+
+ <%= link_to t("confirmation_link", scope: "decidim.confirmation_reminder_mailer.send_reminder.body"), @confirmation_link %>
+
+
+
+ <%== t "warning", scope: "decidim.confirmation_reminder_mailer.send_reminder.body" %>
+
+
+<% content_for :note do %>
+ <%== t "subject", scope: "decidim.confirmation_reminder_mailer.send_reminder", organization_name: h(@organization.name), link: decidim.notifications_settings_url(host: @organization.host) %>
+<% end %>
diff --git a/app/views/decidim/devise/omniauth_registrations/new.html.erb b/app/views/decidim/devise/omniauth_registrations/new.html.erb
new file mode 100644
index 00000000..6180d1ea
--- /dev/null
+++ b/app/views/decidim/devise/omniauth_registrations/new.html.erb
@@ -0,0 +1,104 @@
+
+
+
+ <% if @form.errors[:minimum_age].present? %>
+
+
+
+ <%= @form.errors[:minimum_age].join %>
+
+
+
+
+
+
+
+ <%= link_to t("decidim.errors.not_found.back_home"), root_path, class: "button hollow expanded" %>
+
+
+ <% else %>
+
+
+
<%= t(".sign_up") %>
+
+ <%= t(".subtitle") %>
+
+
+
+
+
+
+
+ <%== t(".registration_info") %>
+
+
+
+
+ <%= decidim_form_for(@form, as: resource_name, url: omniauth_registrations_path(resource_name), html: { class: "register-form new_user" }) do |f| %>
+
+
<%= t(".personal_data_step") %>
+
+
+
+ <%= f.date_select :birth_date, { label: t(".birth_date"), start_year: Date.today.year - 100, end_year: Date.today.year }, { class: "columns medium-3" } %>
+
+
+ <%= t(".birth_date_help") %>
+
+
+
+
+ <%= f.text_field :address, autocomplete: "street-address", label: t(".address") %>
+
+
+
+
+
+ <%= f.text_field :postal_code, pattern: "^[0-9]+$", minlength: 5, maxlength: 5, autocomplete: "postal-code", label: t(".code") %>
+
+
+
+
+ <%= f.text_field :city, label: t(".city") %>
+
+
+
+
+
+ <%= f.check_box :certification, label: t(".certification") %>
+
+
+
+
+
+
<%= t(".tos_title") %>
+
+
+ <%= strip_tags(translated_attribute(Decidim::StaticPage.find_by(slug: "terms-and-conditions", organization: current_organization).content)) %>
+
+
+
+ <%= f.check_box :tos_agreement, label: t(".tos_agreement", link: link_to(t(".terms"), page_path("terms-and-conditions"))) %>
+
+
+
+
+ <%= f.hidden_field :email %>
+ <%= f.hidden_field :uid %>
+ <%= f.hidden_field :name %>
+ <%= f.hidden_field :provider %>
+ <%= f.hidden_field :oauth_signature %>
+
+ <%= f.submit t(".complete_profile"), class: "button expanded" %>
+
+ <% end %>
+
+
+
+
+ <% end %>
+
+
+
+<%= javascript_pack_tag "application" %>
+<%= stylesheet_pack_tag "application" %>
\ No newline at end of file
diff --git a/app/views/decidim/devise/registrations/new.html.erb b/app/views/decidim/devise/registrations/new.html.erb
new file mode 100644
index 00000000..fcf6164f
--- /dev/null
+++ b/app/views/decidim/devise/registrations/new.html.erb
@@ -0,0 +1,125 @@
+<% add_decidim_page_title(t(".sign_up")) %>
+
+<% content_for :devise_links do %>
+ <%= render "decidim/devise/shared/links" %>
+<% end %>
+
+
+
+
+
+
<%= t(".sign_up") %>
+
+ <%= t(".subtitle") %>
+
+
+ <%= t(".already_have_an_account?") %>
+ <%= link_to t(".sign_in"), new_user_session_path %>
+
+
+
+
+ <% cache current_organization do %>
+ <%= render "decidim/devise/shared/omniauth_buttons" %>
+ <% end %>
+
+
+
+ <%= decidim_form_for(@form, namespace: "registration", as: resource_name, url: registration_path(resource_name), html: { class: "register-form new_user", id: "register-form" }) do |f| %>
+ <%= invisible_captcha %>
+
+
+ <%= form_required_explanation %>
+
+
+
+ <%= f.text_field :name, help_text: t(".username_help"), autocomplete: "name" %>
+
+
+
+
+
+ <%= f.text_field :nickname, help_text: t(".nickname_help", organization: current_organization.name), prefix: { value: "@", small: 1, large: 1 }, autocomplete: "nickname" %>
+
+
+
+
+ <%= f.email_field :email, autocomplete: "email" %>
+
+
+
+ <%= f.password_field :password, password_field_options_for(:user) %>
+
+
+
+ <%= f.password_field :password_confirmation, password_field_options_for(:user).except(:help_text) %>
+
+
+
+
+
+
+
<%= t(".personal_data_step") %>
+
+
+ <%= f.date_select :birth_date, { label: t(".birth_date"), start_year: Date.today.year - 100, end_year: Date.today.year }, { class: "columns medium-3" } %>
+
+
+ <%= t(".birth_date_help") %>
+
+
+
+
+ <%= f.text_field :address, autocomplete: "street-address", label: t(".address") %>
+
+
+
+
+
+ <%= f.text_field :postal_code, pattern: "^[0-9]+$", minlength: 5, maxlength: 5, autocomplete: "postal-code", label: t(".code") %>
+
+
+
+
+ <%= f.text_field :city, label: t(".city") %>
+
+
+
+
+
+ <%= f.check_box :certification, label: t(".certification") %>
+
+
+
+
+
+
+
<%= t(".tos_title") %>
+
+
+ <%= strip_tags(translated_attribute(terms_and_conditions_page.content)) %>
+
+
+
+ <%= f.check_box :tos_agreement, label: t(".tos_agreement", link: link_to(t(".terms"), page_path("terms-and-conditions"))) %>
+
+
+
+
+
+
+
+ <%= f.submit t("devise.registrations.new.sign_up"), class: "button expanded" %>
+
+ <%= yield :devise_links %>
+
+
+ <% end %>
+
+
+
+
+
+<%= render "decidim/devise/shared/newsletter_modal" %>
+<%= javascript_pack_tag "application" %>
+<%= stylesheet_pack_tag "application" %>
diff --git a/app/views/decidim/unconfirmed_votes_clear_mailer/send_resume.html.erb b/app/views/decidim/unconfirmed_votes_clear_mailer/send_resume.html.erb
new file mode 100644
index 00000000..460d1980
--- /dev/null
+++ b/app/views/decidim/unconfirmed_votes_clear_mailer/send_resume.html.erb
@@ -0,0 +1,22 @@
+
+
+ <%== t "title", scope: "decidim.unconfirmed_votes_clear_mailer.send_resume.body" %>
+
+
+
+ <% @initiatives.each do |initiative| %>
+ -
+ <%== t("vote", scope: "decidim.unconfirmed_votes_clear_mailer.send_resume.body", initiative_title: translated_attribute(initiative.title)) %>
+
+ <% end %>
+
+
+
+
+ <%== t "confirm", scope: "decidim.unconfirmed_votes_clear_mailer.send_resume.body" %>
+
+
+
+<% content_for :note do %>
+ <%== t "subject", scope: "decidim.confirmation_reminder_mailer.send_reminder", organization_name: h(@organization.name), link: decidim.notifications_settings_url(host: @organization.host) %>
+<% end %>
diff --git a/config/application.rb b/config/application.rb
index 94c88fff..65f60ac4 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -47,12 +47,23 @@ class Application < Rails::Application
config.after_initialize do
require "extends/forms/decidim/initiatives/initiative_form_extends"
require "extends/controllers/decidim/devise/sessions_controller_extends"
+ require "extends/controllers/decidim/homepage_controller_extends"
require "extends/forms/decidim/admin/organization_appearance_form_extends"
+ require "extends/omniauth/strategies/france_connect_extends"
+ require "extends/forms/decidim/omniauth_registration_form_extend"
end
initializer "session cookie domain", after: "Expire sessions" do
Rails.application.config.session_store :active_record_store, key: "_decidim_session", expire_after: Decidim.config.expire_session_after
ActiveRecord::SessionStore::Session.serializer = :hybrid
end
+
+ initializer "decidim_app.overrides", after: "decidim.action_controller" do
+ config.to_prepare do
+ Decidim::Initiatives::InitiativeHelper.include(Decidim::Initiatives::InitiativeHelperVoteModalOverride)
+ Decidim::Devise::RegistrationsController.include(Decidim::RegistrationsControllerOverride)
+ Decidim::Devise::OmniauthRegistrationsController.include(Decidim::OmniauthRegistrationsControllerOverride)
+ end
+ end
end
end
diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml
index 83c0c7b5..1f828248 100644
--- a/config/i18n-tasks.yml
+++ b/config/i18n-tasks.yml
@@ -101,6 +101,10 @@ ignore_missing:
- decidim.initiatives.initiatives.show.illegal.{title,description}
- decidim.initiatives.create_initiative.select_initiative_type.*
- decidim.admin.organization_appearance.form.images.*
+ - decidim.devise.registrations.new.*
+ - devise.failure.invited
+ - devise.registrations.new.sign_up
+
# Consider these keys used:
ignore_unused:
@@ -133,3 +137,5 @@ ignore_unused:
- activemodel.attributes.confirmation.*
- activemodel.attributes.mobile_phone.*
- decidim.admin.participatory_space_private_users.create.*
+ - decidim.admin.participatory_space_private_users.create.*
+ - decidim.initiatives.initiative_votes.create.success
\ No newline at end of file
diff --git a/config/initializers/decidim.rb b/config/initializers/decidim.rb
index b85dca96..8437e449 100644
--- a/config/initializers/decidim.rb
+++ b/config/initializers/decidim.rb
@@ -19,6 +19,10 @@
# Timeout session
config.expire_session_after = ENV.fetch("DECIDIM_SESSION_TIMEOUT", 180).to_i.minutes
+ # Devise unconfirmed access
+ # see also config/initializers/devise.rb line 27
+ config.unconfirmed_access_for = ENV.fetch("DECIDIM_UNCONFIRMED_ACCESS", 0).to_i.days
+
config.maximum_attachment_height_or_width = 6000
# Whether SSL should be forced or not (only in production).
diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb
index ded55eaa..b6d49a6e 100644
--- a/config/initializers/extends.rb
+++ b/config/initializers/extends.rb
@@ -2,7 +2,6 @@
require "extends/controllers/decidim/meetings/meetings_controller_extends"
require "extends/commands/decidim/initiatives/create_initiative_extends"
-require "extends/commands/decidim/create_registration_extends"
require "extends/controllers/decidim/initiatives/create_initiative_controller_extends"
require "extends/controllers/decidim/initiatives/initiatives_controller_extends"
require "extends/helpers/decidim/initiatives/initiative_helper_extends"
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 54f8c703..72a5ce56 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -50,10 +50,50 @@ en:
name: Identity Verification Form
osp_authorization_workflow:
name: Authorization procedure
+ confirmation_reminder_mailer:
+ send_reminder:
+ body:
+ body: Please confirm your email address to persist your votes.
+ confirmation_link: Link to confirmation
+ title: You have created an account there is 2 days ago and you haven't confirmed your email yet.
+ warning: If you don't confirm your email address, your votes will be deleted.
+ subject: Please confirm your email address
devise:
+ omniauth_registrations:
+ new:
+ address: Address
+ birth_date: Date of birth
+ birth_date_help: You must be over 16 years old to access this service.
+ certification: CESE Certification
+ city: City
+ code: Postal code
+ complete_profile: Complete profile
+ personal_data_step: Complete your profile
+ registration_info: Please complete your profile
+ sign_up: Sign up
+ subtitle: Create your account
+ terms: the terms and conditions of use
+ tos_agreement: By signing up you agree to %{link}.
+ tos_title: Terms of Service
+ registrations:
+ form:
+ errors:
+ messages:
+ over_16: You must be over 16 years old to access this service.
+ new:
+ address: Address
+ birth_date: Date of birth
+ birth_date_help: You must be over 16 years old to access this service.
+ certification: Certification CESE
+ city: City
+ code: Postal code
+ personal_data_step: Personal data
sessions:
new:
sign_in_disabled: Sign in disabled
+ errors:
+ not_found:
+ back_home: Back to home
events:
budgets:
pending_order:
@@ -91,9 +131,12 @@ en:
decidim_user_group_id_help: It's not possible to change initiative authorship after creation
select_initiative_type:
verification_required: Verify your account to promote this initiative
+ initiative_votes:
+ create:
+ success: Congratulations! The initiative has been successfully signed
initiatives:
show:
- print: Voir le récépissé
+ print: Show receipt
modal:
not_authorized:
authorizations_page: View authorizations
@@ -188,6 +231,13 @@ en:
client_id: Client ID
client_secret: Client secret
site_url: Site URL
+ unconfirmed_votes_clear_mailer:
+ send_resume:
+ body:
+ confirm: You can still confirm your account and vote again on initiatives.
+ title: You did not confirm your account, existing votes have been deleted
+ vote: Your vote on %{initiative_title} has been deleted.
+ subject: You did not confirm your account, existing votes have been deleted
verifications:
authorizations:
create:
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 9a7b44db..373f5496 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -50,10 +50,50 @@ fr:
name: Formulaire de vérification d'identité
osp_authorization_workflow:
name: Procédure d'autorisation
+ confirmation_reminder_mailer:
+ send_reminder:
+ body:
+ body: Veuillez confirmer votre compte en cliquant sur le lien ci-dessous.
+ confirmation_link: Lien de confirmation
+ title: Vous avez créé un compte il y a 2 jours mais vous ne l'avez pas encore confirmé.
+ warning: L'ensemble de vos votes seront supprimés dans 6 jours si votre compte n'est pas confirmé dans ce délai.
+ subject: Veuillez confirmer votre compte
devise:
+ omniauth_registrations:
+ new:
+ address: Adresse
+ birth_date: Date de naissance
+ birth_date_help: Vous devez avoir plus de 16 ans pour avoir accès à ce service.
+ certification: Je certifie l'exactitude de ces informations.
+ city: Ville
+ code: Code postal
+ complete_profile: Complétez votre profil
+ personal_data_step: Complétez votre profil
+ registration_info: Renseignez vos informations personnelles
+ sign_up: Renseignez vos informations personnelles
+ subtitle: Vous êtes sur le point de créer un compte sur la plateforme de pétitions du CESE.
+ terms: les termes et conditions d'utilisation
+ tos_agreement: En vous créant un compte, vous acceptez %{link}.
+ tos_title: Conditions d'utilisation
+ registrations:
+ form:
+ errors:
+ messages:
+ over_16: Vous devez avoir plus de 16 ans pour accéder à ce service.
+ new:
+ address: Adresse
+ birth_date: Date de naissance
+ birth_date_help: Vous devez avoir plus de 16 ans pour avoir accès à ce service.
+ certification: Je certifie l'exactitude de ces informations.
+ city: Ville
+ code: Code postal
+ personal_data_step: Informations personnelles
sessions:
new:
sign_in_disabled: Vous pouvez accéder avec un compte externe
+ errors:
+ not_found:
+ back_home: Retour à l'accueil
events:
budgets:
pending_order:
@@ -80,6 +120,9 @@ fr:
email_subject: Un utilisateur a tenté de se faire vérifier avec les données d'un utilisateur représenté
notification_title: Le participant
%{resource_title} a tenté de se faire vérifier avec les données de l'utilisateur représenté
%{managed_user_name}.
initiatives:
+ initiative_votes:
+ create:
+ success: Toutes nos félicitations ! La pétition a été signée correctement
initiatives:
show:
print: Voir le récépissé
@@ -184,6 +227,13 @@ fr:
client_id: Client ID
client_secret: Client secret
site_url: Site URL
+ unconfirmed_votes_clear_mailer:
+ send_resume:
+ body:
+ confirm: Vous pouvez toujours confirmer votre compte et voter à nouveau sur les pétitions.
+ title: Vous n'avez pas confirmé votre compte, les votes que vous avez fait ont été supprimés
+ vote: Votre vote sur la pétition '%{initiative_title}' a été supprimé.
+ subject: Vous n'avez pas confirmé votre compte, vos votes ont été supprimés
verifications:
authorizations:
create:
diff --git a/config/puma.rb b/config/puma.rb
index a8adec5d..8e29df4d 100644
--- a/config/puma.rb
+++ b/config/puma.rb
@@ -6,8 +6,9 @@
# the maximum value specified for Puma. Default is set to 5 threads for minimum
# and maximum; this matches the default thread size of Active Record.
#
-threads_count = ENV.fetch("RAILS_MAX_THREADS", 5)
-threads threads_count, threads_count
+min_threads_count = ENV.fetch("PUMA_MIN_THREADS", 5).to_i
+max_threads_count = ENV.fetch("PUMA_MAX_THREADS", 5).to_i
+threads min_threads_count, max_threads_count
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
#
@@ -22,15 +23,15 @@
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
-#
-# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
+
+workers_count = ENV.fetch("PUMA_WORKERS", -1).to_i
+workers workers_count if workers_count.positive?
# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
-#
-# preload_app!
+preload_app! if ENV.fetch("PUMA_PRELOAD_APP", "false") == "true"
# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart
diff --git a/config/routes.rb b/config/routes.rb
index f7164ae2..a87f61ad 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -8,7 +8,7 @@
mount Sidekiq::Web => "/sidekiq"
end
- mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
+ mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development? || ENV.fetch("ENABLE_LETTER_OPENER", "0") == "1"
mount Decidim::Core::Engine => "/"
# mount Decidim::Map::Engine => '/map'
diff --git a/config/secrets.yml b/config/secrets.yml
index 63de95b4..c41ca0e8 100644
--- a/config/secrets.yml
+++ b/config/secrets.yml
@@ -13,6 +13,9 @@
default: &default
asset_host: <%= ENV["ASSET_HOST"] %>
decidim:
+ reminder:
+ unconfirmed_email:
+ days: <%= ENV["DECIDIM_REMINDER_UNCONFIRMED_EMAIL_DAYS"]&.to_i || 2 %>
verifications:
sms_gateway_service:
username: <%= ENV["SMS_GATEWAY_USERNAME"].presence %>
diff --git a/config/sidekiq.yml b/config/sidekiq.yml
index ddce4644..8811244a 100644
--- a/config/sidekiq.yml
+++ b/config/sidekiq.yml
@@ -24,6 +24,14 @@
cron: '0 0 1 * * *' # Run at 01:00
class: PreloadOpenDataJob
queue: scheduled
+ ConfirmationReminderJob:
+ cron: '0 0 9 * * *' # Run at 09:00
+ class: Decidim::ConfirmationReminderJob
+ queue: scheduled
+ UnconfirmedVotesCleanerJob:
+ cron: '0 0 9 * * *' # Run at 09:00
+ class: Decidim::UnconfirmedVotesCleanerJob
+ queue: scheduled
DetectSpamUsers:
cron: '0 <%= Random.rand(0..59) %> <%= Random.rand(6..8) %> * * *' # Run randomly between 06:00 and 08:59
class: Decidim::SpamDetection::MarkUsersJob
diff --git a/db/migrate/20231206212031_delete_extended_socio_demographic_authorization_handler_settings_on_initiatives.rb b/db/migrate/20231206212031_delete_extended_socio_demographic_authorization_handler_settings_on_initiatives.rb
new file mode 100644
index 00000000..5fd05b71
--- /dev/null
+++ b/db/migrate/20231206212031_delete_extended_socio_demographic_authorization_handler_settings_on_initiatives.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class DeleteExtendedSocioDemographicAuthorizationHandlerSettingsOnInitiatives < ActiveRecord::Migration[6.1]
+ def change
+ Decidim::InitiativesType.where(document_number_authorization_handler: "extended_socio_demographic_authorization_handler").each do |initiatives_type|
+ initiatives_type.update!(document_number_authorization_handler: nil)
+ end
+
+ Decidim::ResourcePermission.all.each do |resource_permission|
+ next if resource_permission.permissions.blank?
+
+ if resource_permission.resource.blank?
+ resource_permission.delete
+ next
+ end
+
+ resource_permission.permissions.each do |action, authorization|
+ if authorization.has_key?("authorization_handlers") && authorization["authorization_handlers"].has_key?("extended_socio_demographic_authorization_handler")
+ resource_permission.permissions.delete(action)
+ end
+ end
+
+ resource_permission.save! if resource_permission.changed?
+ end
+ end
+end
diff --git a/db/migrate/20231206230804_migrate_extended_socio_demographic_authorization_handler_data.rb b/db/migrate/20231206230804_migrate_extended_socio_demographic_authorization_handler_data.rb
new file mode 100644
index 00000000..11ba7b92
--- /dev/null
+++ b/db/migrate/20231206230804_migrate_extended_socio_demographic_authorization_handler_data.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class MigrateExtendedSocioDemographicAuthorizationHandlerData < ActiveRecord::Migration[6.1]
+ def change
+ Decidim::Authorization.where(name: "extended_socio_demographic_authorization_handler").each do |authorization|
+ next if authorization.user.deleted?
+
+ # We don't migrate the email because we don't want to confirm it if needed
+ authorization.user.name = "#{authorization.metadata["first_mane"]} #{authorization.metadata["first_mane"]}"
+ authorization.user.extended_data = {
+ city: authorization.metadata["city"],
+ address: authorization.metadata["address"],
+ birth_date: authorization.metadata["birth_date"],
+ postal_code: authorization.metadata["postal_code"],
+ certification: authorization.metadata["certification"]
+ }
+ authorization.user.save
+ authorization.delete
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 8275c50a..66c651fd 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: 2023_05_12_092845) do
+ActiveRecord::Schema.define(version: 2023_12_06_230804) do
# These are extensions that must be enabled in order to support this database
enable_extension "ltree"
@@ -577,6 +577,56 @@
t.index ["follows_count"], name: "index_decidim_debates_debates_on_follows_count"
end
+ create_table "decidim_dummy_resources_coauthorable_dummy_resources", force: :cascade do |t|
+ t.jsonb "translatable_text"
+ t.string "title"
+ t.string "body"
+ t.text "address"
+ t.float "latitude"
+ t.float "longitude"
+ t.datetime "published_at"
+ t.integer "coauthorships_count", default: 0, null: false
+ t.integer "endorsements_count", default: 0, null: false
+ t.integer "comments_count", default: 0, null: false
+ t.bigint "decidim_component_id"
+ t.bigint "decidim_category_id"
+ t.bigint "decidim_scope_id"
+ t.string "reference"
+ t.datetime "created_at", precision: 6, null: false
+ t.datetime "updated_at", precision: 6, null: false
+ end
+
+ create_table "decidim_dummy_resources_dummy_resources", force: :cascade do |t|
+ t.jsonb "translatable_text"
+ t.jsonb "title"
+ t.string "body"
+ t.text "address"
+ t.float "latitude"
+ t.float "longitude"
+ t.datetime "published_at"
+ t.integer "coauthorships_count", default: 0, null: false
+ t.integer "endorsements_count", default: 0, null: false
+ t.integer "comments_count", default: 0, null: false
+ t.integer "follows_count", default: 0, null: false
+ t.bigint "decidim_component_id"
+ t.integer "decidim_author_id"
+ t.string "decidim_author_type"
+ t.integer "decidim_user_group_id"
+ t.bigint "decidim_category_id"
+ t.bigint "decidim_scope_id"
+ t.string "reference"
+ t.datetime "created_at", precision: 6, null: false
+ t.datetime "updated_at", precision: 6, null: false
+ end
+
+ create_table "decidim_dummy_resources_nested_dummy_resources", force: :cascade do |t|
+ t.jsonb "translatable_text"
+ t.string "title"
+ t.bigint "dummy_resource_id"
+ t.datetime "created_at", precision: 6, null: false
+ t.datetime "updated_at", precision: 6, null: false
+ end
+
create_table "decidim_editor_images", force: :cascade do |t|
t.bigint "decidim_author_id", null: false
t.bigint "decidim_organization_id", null: false
@@ -591,7 +641,7 @@
t.bigint "resource_id"
t.string "decidim_author_type"
t.bigint "decidim_author_id"
- t.integer "decidim_user_group_id"
+ t.integer "decidim_user_group_id", default: 0
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["decidim_author_type", "decidim_author_id"], name: "idx_endorsements_authors"
@@ -1681,6 +1731,18 @@
t.index ["reset_password_token"], name: "index_decidim_system_admins_on_reset_password_token", unique: true
end
+ create_table "decidim_templates_templates", force: :cascade do |t|
+ t.integer "decidim_organization_id", null: false
+ t.string "templatable_type"
+ t.bigint "templatable_id"
+ t.jsonb "name", null: false
+ t.jsonb "description"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["decidim_organization_id"], name: "index_decidim_templates_organization"
+ t.index ["templatable_type", "templatable_id"], name: "index_decidim_templates_templatable"
+ end
+
create_table "decidim_term_customizer_constraints", force: :cascade do |t|
t.bigint "decidim_organization_id", null: false
t.string "subject_type"
diff --git a/docker-compose.dev.yml b/docker-compose.local.yml
similarity index 54%
rename from docker-compose.dev.yml
rename to docker-compose.local.yml
index 506541df..7f78d6a1 100644
--- a/docker-compose.dev.yml
+++ b/docker-compose.local.yml
@@ -19,34 +19,61 @@ services:
sidekiq:
build:
context: .
+ dockerfile: Dockerfile.local
command: [ "bundle", "exec", "sidekiq", "-C", "config/sidekiq.yml" ]
environment:
- - REDIS_URL=redis://redis:6379
- - MEMCACHE_SERVERS=memcached:11211
- DATABASE_HOST=database
- DATABASE_USERNAME=postgres
+ - DATABASE_NAME=decidim_cese
+ - DECIDIM_HOST=localhost
+ - REDIS_URL=redis://redis:6379
+ - MEMCACHE_SERVERS=memcached:11211
+ - RAILS_SERVE_STATIC_FILES=true
+ - RAILS_LOG_TO_STDOUT=true
+ - ASSET_HOST=localhost:3000
+ - FORCE_SSL=1
+ - ENABLE_LETTER_OPENER=1
+ - SEED=true
+ - DEFACE_ENABLED=true
+ - QUESTION_CAPTCHA_HOST=
+ - ENABLE_RACK_ATTACK=0
+ - PUMA_MIN_THREADS=5
+ - PUMA_MAX_THREADS=5
+ - PUMA_WORKERS=-1
+ - PUMA_PRELOAD_APP=false
depends_on:
- app
+ volumes:
+ - shared-volume:/app
links:
- database
- redis
app:
build:
context: .
- volumes:
- - .:/app
- - node_modules:/app/node_modules
+ dockerfile: Dockerfile.local
environment:
- DATABASE_HOST=database
+ - DATABASE_NAME=decidim_cese
- DATABASE_USERNAME=postgres
- - DECIDIM_HOST=0.0.0.0
+ - DECIDIM_HOST=localhost
- REDIS_URL=redis://redis:6379
- MEMCACHE_SERVERS=memcached:11211
- RAILS_SERVE_STATIC_FILES=true
- RAILS_LOG_TO_STDOUT=true
- - FORCE_SSL="0"
- - LETTER_OPENER_ENABLED="true"
+ - ASSET_HOST=localhost:3000
+ - FORCE_SSL=1
+ - ENABLE_LETTER_OPENER=1
- SEED=true
+ - DEFACE_ENABLED=true
+ - QUESTION_CAPTCHA_HOST=
+ - ENABLE_RACK_ATTACK=0
+ - PUMA_MIN_THREADS=5
+ - PUMA_MAX_THREADS=5
+ - PUMA_WORKERS=-1
+ - PUMA_PRELOAD_APP=false
+ volumes:
+ - shared-volume:/app
ports:
- 3000:3000
depends_on:
@@ -55,6 +82,6 @@ services:
- memcached
volumes:
- node_modules: { }
+ shared-volume: { }
pg-data: { }
redis-data: { }
\ No newline at end of file
diff --git a/lib/extends/commands/decidim/create_registration_extends.rb b/lib/extends/commands/decidim/create_registration_extends.rb
deleted file mode 100644
index 00d1b1bf..00000000
--- a/lib/extends/commands/decidim/create_registration_extends.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-module CreateRegistrationExtends
- private
-
- def create_user
- @user = Decidim::User.create!(
- email: form.email,
- name: form.name,
- nickname: form.nickname,
- password: form.password,
- password_confirmation: form.password_confirmation,
- organization: form.current_organization,
- tos_agreement: form.tos_agreement,
- newsletter_notifications_at: form.newsletter_at,
- accepted_tos_version: form.current_organization.tos_version,
- locale: form.current_locale,
- notifications_sending_frequency: :none
- )
- end
-end
-
-Decidim::CreateRegistration.class_eval do
- prepend(CreateRegistrationExtends)
-end
diff --git a/lib/extends/controllers/decidim/devise/sessions_controller_extends.rb b/lib/extends/controllers/decidim/devise/sessions_controller_extends.rb
index c7ec5047..ec6cc048 100644
--- a/lib/extends/controllers/decidim/devise/sessions_controller_extends.rb
+++ b/lib/extends/controllers/decidim/devise/sessions_controller_extends.rb
@@ -4,10 +4,13 @@ module SessionControllerExtends
extend ActiveSupport::Concern
included do
+ include Decidim::AfterSignInActionHelper
+
def destroy
+ after_sign_out_url = after_sign_out_path_for(current_user)
current_user.invalidate_all_sessions!
if active_france_connect_session?
- destroy_france_connect_session(session["omniauth.france_connect.end_session_uri"])
+ destroy_france_connect_session(session["omniauth.france_connect.end_session_uri"], after_sign_out_url)
elsif params[:translation_suffix].present?
super { set_flash_message! :notice, params[:translation_suffix], { scope: "decidim.devise.sessions" } }
else
@@ -16,6 +19,8 @@ def destroy
end
def after_sign_in_path_for(user)
+ after_sign_in_action_for(user, request.params[:after_action]) if request.params[:after_action].present?
+
if user.present? && user.blocked?
check_user_block_status(user)
elsif !skip_first_login_authorization? && (first_login_and_not_authorized?(user) && !user.admin? && !pending_redirect?(user))
@@ -33,13 +38,13 @@ def skip_first_login_authorization?
end
end
- def destroy_france_connect_session(fc_logout_path)
+ def destroy_france_connect_session(fc_logout_path, post_logout_redirect_uri)
signed_out = (::Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
if signed_out
set_flash_message! :notice, :signed_out
session.delete("omniauth.france_connect.end_session_uri")
end
-
+ session["omniauth.france_connect.post_logout_redirect_uri"] = post_logout_redirect_uri
redirect_to fc_logout_path
end
diff --git a/lib/extends/controllers/decidim/homepage_controller_extends.rb b/lib/extends/controllers/decidim/homepage_controller_extends.rb
new file mode 100644
index 00000000..89bbc300
--- /dev/null
+++ b/lib/extends/controllers/decidim/homepage_controller_extends.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module HomepageControllerExtends
+ extend ActiveSupport::Concern
+
+ included do
+ before_action :france_connect_after_sign_out, only: [:show]
+
+ def france_connect_after_sign_out
+ if session["omniauth.france_connect.post_logout_redirect_uri"].present?
+ post_logout_redirect_uri = session["omniauth.france_connect.post_logout_redirect_uri"]
+ session.delete("omniauth.france_connect.post_logout_redirect_uri")
+ redirect_to post_logout_redirect_uri
+ end
+ end
+ end
+end
+
+Decidim::HomepageController.class_eval do
+ include(HomepageControllerExtends)
+end
diff --git a/lib/extends/controllers/decidim/initiatives/initiatives_controller_extends.rb b/lib/extends/controllers/decidim/initiatives/initiatives_controller_extends.rb
index 572e6647..d3fa8223 100644
--- a/lib/extends/controllers/decidim/initiatives/initiatives_controller_extends.rb
+++ b/lib/extends/controllers/decidim/initiatives/initiatives_controller_extends.rb
@@ -4,11 +4,23 @@ module InitiativesControllerExtends
extend ActiveSupport::Concern
included do
+ include Decidim::AfterSignInActionHelper
+
helper Decidim::Initiatives::SignatureTypeOptionsHelper
helper Decidim::Initiatives::InitiativePrintHelper
helper_method :available_initiative_types
+ def show
+ enforce_permission_to :read, :initiative, initiative: current_initiative
+ if session["tos_after_action"].present? && URI.parse(request.referer).path == tos_path.split("?")&.first
+ tos_after_action = session["tos_after_action"]
+ session.delete("tos_after_action")
+ after_sign_in_action_for(current_user, tos_after_action)
+ current_initiative.reload
+ end
+ end
+
def print
enforce_permission_to :print, :initiative, initiative: current_initiative
end
diff --git a/lib/extends/forms/decidim/omniauth_registration_form_extend.rb b/lib/extends/forms/decidim/omniauth_registration_form_extend.rb
new file mode 100644
index 00000000..7d7084d1
--- /dev/null
+++ b/lib/extends/forms/decidim/omniauth_registration_form_extend.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require "active_support/concern"
+
+module OmniauthRegistrationFormExtend
+ extend ActiveSupport::Concern
+
+ included do
+ attribute :certification, ::ActiveModel::Type::Boolean
+ attribute :birth_date, Date
+ attribute :address, String
+ attribute :postal_code, String
+ attribute :city, String
+ attribute :tos_agreement, ::ActiveModel::Type::Boolean
+
+ validates :email, "valid_email_2/email": { mx: true }
+ validates :postal_code,
+ :birth_date,
+ :city,
+ :address,
+ :certification,
+ :tos_agreement,
+ presence: true, unless: ->(form) { form.tos_agreement.blank? }
+
+ validates :postal_code, numericality: { only_integer: true }, length: { is: 5 }, unless: ->(form) { form.tos_agreement.blank? }
+ validates :certification, acceptance: true, presence: true, unless: ->(form) { form.tos_agreement.blank? }
+ validates :tos_agreement, acceptance: true, presence: true
+ validate :over_16?
+
+ private
+
+ def over_16?
+ return if birth_date.blank?
+ return if 16.years.ago.to_date > birth_date
+
+ errors.add :base, I18n.t("decidim.devise.registrations.form.errors.messages.over_16")
+ errors.add :birth_date, I18n.t("decidim.devise.registrations.form.errors.messages.over_16")
+ end
+ end
+end
+
+Decidim::OmniauthRegistrationForm.class_eval do
+ clear_validators!
+ include OmniauthRegistrationFormExtend
+end
diff --git a/lib/extends/omniauth/strategies/france_connect_extends.rb b/lib/extends/omniauth/strategies/france_connect_extends.rb
new file mode 100644
index 00000000..dadc7b6a
--- /dev/null
+++ b/lib/extends/omniauth/strategies/france_connect_extends.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module FranceConnectExtends
+ extend ActiveSupport::Concern
+
+ included do
+ private
+
+ def redirect_uri
+ "#{omniauth_callback_url}?#{params.slice("redirect_uri", "after_action").to_query}"
+ end
+ end
+end
+
+OmniAuth::Strategies::FranceConnect.class_eval do
+ include(FranceConnectExtends)
+end
diff --git a/spec/commands/decidim/create_registration_spec.rb b/spec/commands/decidim/create_registration_spec.rb
index 92483b11..68638b45 100644
--- a/spec/commands/decidim/create_registration_spec.rb
+++ b/spec/commands/decidim/create_registration_spec.rb
@@ -14,7 +14,7 @@ module Comments
let(:password) { "Y1fERVzL2F" }
let(:password_confirmation) { password }
let(:tos_agreement) { "1" }
- let(:newsletter) { "1" }
+ let(:newsletter) { nil }
let(:current_locale) { "fr" }
let(:form_params) do
@@ -26,7 +26,12 @@ module Comments
"password" => password,
"password_confirmation" => password_confirmation,
"tos_agreement" => tos_agreement,
- "newsletter_at" => newsletter
+ "newsletter_at" => newsletter,
+ "birth_date" => "1980-01-01",
+ "address" => "Carrer de la Llibertat, 47",
+ "postal_code" => "08012",
+ "city" => "Barcelona",
+ "certification" => "1"
}
}
end
@@ -87,17 +92,30 @@ module Comments
email: form.email,
password: form.password,
password_confirmation: form.password_confirmation,
+ password_updated_at: an_instance_of(ActiveSupport::TimeWithZone),
tos_agreement: form.tos_agreement,
newsletter_notifications_at: form.newsletter_at,
organization: organization,
accepted_tos_version: organization.tos_version,
locale: form.current_locale,
- notifications_sending_frequency: :none
+ notifications_sending_frequency: :none,
+ extended_data: {
+ birth_date: Date.new(1980, 0o1, 0o1),
+ address: "Carrer de la Llibertat, 47",
+ postal_code: "08012",
+ city: "Barcelona",
+ certification: true
+ }
).and_call_original
expect { command.call }.to change(User, :count).by(1)
end
+ it "sets the password_updated_at to the current time" do
+ expect { command.call }.to broadcast(:ok)
+ expect(User.last.password_updated_at).to be_between(2.seconds.ago, Time.current)
+ end
+
describe "when user keeps the newsletter unchecked" do
let(:newsletter) { "0" }
diff --git a/spec/jobs/decidim/confirmation_reminder_job_spec.rb b/spec/jobs/decidim/confirmation_reminder_job_spec.rb
new file mode 100644
index 00000000..88eaa770
--- /dev/null
+++ b/spec/jobs/decidim/confirmation_reminder_job_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+describe Decidim::ConfirmationReminderJob do
+ subject { described_class }
+
+ let!(:unconfirmed_users) { create_list(:user, 2, created_at: 2.days.ago) }
+
+ before do
+ create(:user, created_at: 3.days.ago)
+ create(:user, :confirmed, created_at: 2.days.ago)
+ create(:user, created_at: 1.day.ago)
+ end
+
+ it "sends a reminder to unconfirmed users" do
+ expect { subject.new.perform }.to change { ActionMailer::Base.deliveries.count }.by(2)
+ end
+
+ context "when confirmation reminder is set to 3 days" do
+ before do
+ allow(Rails.application.secrets).to receive(:dig).and_call_original
+ allow(Rails.application.secrets).to receive(:dig).with(:decidim, :reminder, :unconfirmed_email, :days).and_return(3)
+ end
+
+ it "send a unique email to user created there is 3 days ago" do
+ expect { subject.new.perform }.to change { ActionMailer::Base.deliveries.count }.by(1)
+ end
+ end
+
+ describe "#unconfirmed_users" do
+ it "returns the unconfirmed users" do
+ expect(subject.new.send(:unconfirmed_users)).to match_array(unconfirmed_users)
+ end
+ end
+end
diff --git a/spec/jobs/decidim/unconfirmed_votes_cleaner_job_spec.rb b/spec/jobs/decidim/unconfirmed_votes_cleaner_job_spec.rb
new file mode 100644
index 00000000..df90ec30
--- /dev/null
+++ b/spec/jobs/decidim/unconfirmed_votes_cleaner_job_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+describe Decidim::UnconfirmedVotesCleanerJob do
+ subject { described_class }
+
+ let!(:unconfirmed_users) { create_list(:user, 2, created_at: 7.days.ago) }
+ let!(:confirmed_user) { create(:user, :confirmed, created_at: 7.days.ago) }
+ let!(:unconfirmed_votes) { create_list(:initiative_user_vote, 3, author: unconfirmed_users.first) }
+ let!(:confirmed_votes) { create_list(:initiative_user_vote, 3, author: confirmed_user) }
+
+ before do
+ allow(Decidim.unconfirmed_access_for).to receive(:ago).and_return(7.days.ago)
+ create(:user, created_at: 30.days.ago)
+ create(:user, :confirmed, created_at: 2.days.ago)
+ create(:user, created_at: 1.day.ago)
+ end
+
+ it "sends a reminder to unconfirmed users" do
+ expect { subject.new.perform }.to change { ActionMailer::Base.deliveries.count }.by(1)
+ end
+
+ describe "#unconfirmed_users" do
+ it "returns the unconfirmed user with initiatives votes" do
+ expect(subject.new.send(:unconfirmed_users).count).to eq(1)
+ expect(subject.new.send(:unconfirmed_users)).to include(unconfirmed_users.first)
+ expect(subject.new.send(:unconfirmed_users)).not_to include(unconfirmed_users.last)
+ end
+ end
+end
diff --git a/spec/mailers/confirmation_reminder_mailer_spec.rb b/spec/mailers/confirmation_reminder_mailer_spec.rb
new file mode 100644
index 00000000..08a5ad16
--- /dev/null
+++ b/spec/mailers/confirmation_reminder_mailer_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+module Decidim
+ describe ConfirmationReminderMailer, type: :mailer do
+ let(:user) { create(:user, name: "Sarah Connor", organization: organization) }
+ let(:organization) { create(:organization) }
+
+ describe "#send_reminder" do
+ let(:mail) { described_class.send_reminder(user) }
+
+ it "parses the subject" do
+ expect(mail.subject).to eq("Please confirm your email address")
+ end
+
+ it "parses the body" do
+ expect(email_body(mail)).to include("You have created an account there is 2 days ago and you haven't confirmed your email yet.")
+ expect(email_body(mail)).to include("Please confirm your email address to persist your votes.")
+ expect(email_body(mail)).to include("If you don't confirm your email address, your votes will be deleted.")
+ end
+
+ context "when the user has a different locale" do
+ before do
+ user.locale = "fr"
+ user.save!
+ end
+
+ it "parses the subject in the user's locale" do
+ expect(mail.subject).to eq("Veuillez confirmer votre compte")
+ end
+
+ it "parses the body in the user's locale" do
+ expect(email_body(mail)).to include("Vous avez créé un compte il y a 2 jours mais vous ne l'avez pas encore confirmé.")
+ expect(email_body(mail)).to include("Veuillez confirmer votre compte en cliquant sur le lien ci-dessous.")
+ expect(email_body(mail)).to include("L'ensemble de vos votes seront supprimés dans 6 jours si votre compte n'est pas confirmé dans ce délai.")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/mailers/unconfirmed_votes_clear_mailer_spec.rb b/spec/mailers/unconfirmed_votes_clear_mailer_spec.rb
new file mode 100644
index 00000000..410fa262
--- /dev/null
+++ b/spec/mailers/unconfirmed_votes_clear_mailer_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+module Decidim
+ describe UnconfirmedVotesClearMailer, type: :mailer do
+ let(:organization) { create(:organization) }
+ let(:user) { create(:user, name: "Sarah Connor", organization: organization) }
+ let(:unconfirmed_votes) { create_list(:initiative_user_vote, 3, author: user) }
+ let(:initiatives) { unconfirmed_votes.map(&:initiative) }
+
+ let(:confirmed_user) { create(:user, :confirmed, organization: organization) }
+ let(:confirmed_votes) { create_list(:initiative_user_vote, 3, author: confirmed_user) }
+
+ describe "#send_resume" do
+ let(:mail) { described_class.send_resume(user, initiatives) }
+
+ it "parses the subject" do
+ expect(mail.subject).to eq("You did not confirm your account, existing votes have been deleted")
+ end
+
+ it "parses the body" do
+ expect(email_body(mail)).to include("You did not confirm your account, existing votes have been deleted")
+ expect(email_body(mail)).to include("You can still confirm your account and vote again on initiatives.")
+ initiatives.each do |initiative|
+ expect(email_body(mail)).to include("Your vote on #{translated(initiative.title)} has been deleted.")
+ end
+ end
+
+ context "when the user has a different locale" do
+ before do
+ user.locale = "fr"
+ user.save!
+ end
+
+ it "parses the subject in the user's locale" do
+ expect(mail.subject).to eq("Vous n'avez pas confirmé votre compte, vos votes ont été supprimés")
+ end
+
+ it "parses the body in the user's locale" do
+ expect(email_body(mail)).to include("Vous n'avez pas confirmé votre compte, les votes que vous avez fait ont été supprimés")
+ expect(email_body(mail)).to include("Vous pouvez toujours confirmer votre compte et voter à nouveau sur les pétitions.")
+ initiatives.each do |initiative|
+ expect(email_body(mail)).to include("Votre vote sur la pétition '#{translated(initiative.title)}' a été supprimé.")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/system/authentication_spec.rb b/spec/system/authentication_spec.rb
index 3888b23b..35a19f4c 100644
--- a/spec/system/authentication_spec.rb
+++ b/spec/system/authentication_spec.rb
@@ -19,19 +19,26 @@
within ".new_user" do
fill_in :registration_user_email, with: "user@example.org"
fill_in :registration_user_name, with: "Responsible Citizen"
- fill_in :registration_user_nickname, with: "responsible"
fill_in :registration_user_password, with: "DfyvHn425mYAy2HL"
- fill_in :registration_user_password_confirmation, with: "DfyvHn425mYAy2HL"
+
+ select "1997", from: :registration_user_birth_date_1i
+ select "March", from: :registration_user_birth_date_2i
+ select "1", from: :registration_user_birth_date_3i
+ fill_in :registration_user_postal_code, with: "08080"
+ fill_in :registration_user_city, with: "Barcelona"
+ fill_in :registration_user_address, with: "Carrer de la Ciutat"
+ check :registration_user_certification
check :registration_user_tos_agreement
- check :registration_user_newsletter
+
find("*[type=submit]").click
+ page.save_screenshot("screenshot.png")
end
expect(page).to have_content("confirmation link")
end
end
- context "when using another langage" do
+ context "when using another language" do
before do
within_language_menu do
click_link "Français"
@@ -44,11 +51,17 @@
within ".new_user" do
fill_in :registration_user_email, with: "user@example.org"
fill_in :registration_user_name, with: "Responsible Citizen"
- fill_in :registration_user_nickname, with: "responsible"
fill_in :registration_user_password, with: "DfyvHn425mYAy2HL"
- fill_in :registration_user_password_confirmation, with: "DfyvHn425mYAy2HL"
+
+ select "1997", from: :registration_user_birth_date_1i
+ select "décembre", from: :registration_user_birth_date_2i
+ select "1", from: :registration_user_birth_date_3i
+ fill_in :registration_user_postal_code, with: "08080"
+ fill_in :registration_user_city, with: "Barcelona"
+ fill_in :registration_user_address, with: "Carrer de la Ciutat, 1"
+ check :registration_user_certification
check :registration_user_tos_agreement
- check :registration_user_newsletter
+
find("*[type=submit]").click
end
@@ -65,11 +78,17 @@
page.execute_script("$($('.new_user > div > input')[0]).val('Ima robot :D')")
fill_in :registration_user_email, with: "user@example.org"
fill_in :registration_user_name, with: "Responsible Citizen"
- fill_in :registration_user_nickname, with: "responsible"
fill_in :registration_user_password, with: "DfyvHn425mYAy2HL"
- fill_in :registration_user_password_confirmation, with: "DfyvHn425mYAy2HL"
+
+ select "1997", from: :registration_user_birth_date_1i
+ select "March", from: :registration_user_birth_date_2i
+ select "1", from: :registration_user_birth_date_3i
+ fill_in :registration_user_postal_code, with: "08080"
+ fill_in :registration_user_city, with: "Barcelona"
+ fill_in :registration_user_address, with: "Carrer de la Ciutat, 1"
+ check :registration_user_certification
check :registration_user_tos_agreement
- check :registration_user_newsletter
+
find("*[type=submit]").click
end
@@ -77,155 +96,6 @@
end
end
- context "when using facebook" do
- let(:omniauth_hash) do
- OmniAuth::AuthHash.new(
- provider: "facebook",
- uid: "123545",
- info: {
- email: "user@from-facebook.com",
- name: "Facebook User"
- }
- )
- end
-
- before do
- OmniAuth.config.test_mode = true
- OmniAuth.config.mock_auth[:facebook] = omniauth_hash
- OmniAuth.config.add_camelization "facebook", "FaceBook"
- OmniAuth.config.request_validation_phase = ->(env) {} if OmniAuth.config.respond_to?(:request_validation_phase)
- end
-
- after do
- OmniAuth.config.test_mode = false
- OmniAuth.config.mock_auth[:facebook] = nil
- OmniAuth.config.camelizations.delete("facebook")
- end
-
- context "when the user has confirmed the email in facebook" do
- it "creates a new User without sending confirmation instructions" do
- find(".sign-up-link").click
-
- click_link "Sign in with Facebook"
-
- expect(page).to have_content("Successfully")
- expect_user_logged
- end
- end
- end
-
- context "when using twitter" do
- let(:email) { nil }
- let(:omniauth_hash) do
- OmniAuth::AuthHash.new(
- provider: "twitter",
- uid: "123545",
- info: {
- name: "Twitter User",
- nickname: "twitter_user",
- email: email
- }
- )
- end
-
- before do
- OmniAuth.config.test_mode = true
- OmniAuth.config.mock_auth[:twitter] = omniauth_hash
-
- OmniAuth.config.add_camelization "twitter", "Twitter"
- OmniAuth.config.request_validation_phase = ->(env) {} if OmniAuth.config.respond_to?(:request_validation_phase)
- end
-
- after do
- OmniAuth.config.test_mode = false
- OmniAuth.config.mock_auth[:twitter] = nil
- OmniAuth.config.camelizations.delete("twitter")
- end
-
- context "when the response doesn't include the email" do
- it "redirects the user to a finish signup page" do
- find(".sign-up-link").click
-
- click_link "Sign in with Twitter"
-
- expect(page).to have_content("Successfully")
- expect(page).to have_content("Please complete your profile")
-
- within ".new_user" do
- fill_in :registration_user_email, with: "user@from-twitter.com"
- find("*[type=submit]").click
- end
- end
-
- context "and a user already exists with the given email" do
- it "doesn't allow it" do
- create(:user, :confirmed, email: "user@from-twitter.com", organization: organization)
- find(".sign-up-link").click
-
- click_link "Sign in with Twitter"
-
- expect(page).to have_content("Successfully")
- expect(page).to have_content("Please complete your profile")
-
- within ".new_user" do
- fill_in :registration_user_email, with: "user@from-twitter.com"
- find("*[type=submit]").click
- end
-
- expect(page).to have_content("Please complete your profile")
- expect(page).to have_content("Another account is using the same email address")
- end
- end
- end
-
- context "when the response includes the email" do
- let(:email) { "user@from-twitter.com" }
-
- it "creates a new User" do
- find(".sign-up-link").click
-
- click_link "Sign in with Twitter"
-
- expect_user_logged
- end
- end
- end
-
- context "when using google" do
- let(:omniauth_hash) do
- OmniAuth::AuthHash.new(
- provider: "google_oauth2",
- uid: "123545",
- info: {
- name: "Google User",
- email: "user@from-google.com"
- }
- )
- end
-
- before do
- OmniAuth.config.test_mode = true
- OmniAuth.config.mock_auth[:google_oauth2] = omniauth_hash
-
- OmniAuth.config.add_camelization "google_oauth2", "GoogleOauth"
- OmniAuth.config.request_validation_phase = ->(env) {} if OmniAuth.config.respond_to?(:request_validation_phase)
- end
-
- after do
- OmniAuth.config.test_mode = false
- OmniAuth.config.mock_auth[:google_oauth2] = nil
- OmniAuth.config.camelizations.delete("google_oauth2")
- end
-
- it "creates a new User" do
- find(".sign-up-link").click
-
- click_link "Sign in with Google"
-
- expect_user_logged
- end
- end
-
context "when sign up is disabled" do
let(:organization) { create(:organization, users_registration_mode: :existing) }
@@ -580,11 +450,15 @@
within ".new_user" do
fill_in :registration_user_email, with: user.email
fill_in :registration_user_name, with: "Responsible Citizen"
- fill_in :registration_user_nickname, with: "responsible"
fill_in :registration_user_password, with: "DfyvHn425mYAy2HL"
- fill_in :registration_user_password_confirmation, with: "DfyvHn425mYAy2HL"
+ select "1997", from: :registration_user_birth_date_1i
+ select "March", from: :registration_user_birth_date_2i
+ select "1", from: :registration_user_birth_date_3i
+ fill_in :registration_user_postal_code, with: "08080"
+ fill_in :registration_user_city, with: "Barcelona"
+ fill_in :registration_user_address, with: "Carrer de la Ciutat, 1"
+ check :registration_user_certification
check :registration_user_tos_agreement
- check :registration_user_newsletter
find("*[type=submit]").click
end
@@ -594,49 +468,6 @@
end
end
- context "when a user is already registered in another organization with the same fb account" do
- let(:user) { create(:user, :confirmed) }
- let(:identity) { create(:identity, user: user, provider: "facebook", uid: "12345") }
-
- let(:omniauth_hash) do
- OmniAuth::AuthHash.new(
- provider: identity.provider,
- uid: identity.uid,
- info: {
- email: user.email,
- name: "Facebook User",
- verified: true
- }
- )
- end
-
- before do
- OmniAuth.config.test_mode = true
- OmniAuth.config.mock_auth[:facebook] = omniauth_hash
- OmniAuth.config.add_camelization "facebook", "FaceBook"
- OmniAuth.config.request_validation_phase = ->(env) {} if OmniAuth.config.respond_to?(:request_validation_phase)
- end
-
- after do
- OmniAuth.config.test_mode = false
- OmniAuth.config.mock_auth[:facebook] = nil
- OmniAuth.config.camelizations.delete("facebook")
- end
-
- describe "Sign Up" do
- context "when the user has confirmed the email in facebook" do
- it "creates a new User without sending confirmation instructions" do
- find(".sign-up-link").click
-
- click_link "Sign in with Facebook"
-
- expect(page).to have_content("Successfully")
- expect_user_logged
- end
- end
- end
- end
-
context "when a user with the same email is already registered in another organization" do
let(:organization2) { create(:organization) }
diff --git a/spec/system/initiative_spec.rb b/spec/system/initiative_spec.rb
index a7ecbe7f..5b4cbdb8 100644
--- a/spec/system/initiative_spec.rb
+++ b/spec/system/initiative_spec.rb
@@ -46,13 +46,13 @@
shared_examples_for "initiative shows recepisse link" do
it "shows recepisse link" do
- expect(page).to have_link("Voir le récépissé")
+ expect(page).to have_link("Show receipt")
end
end
shared_examples_for "initiative does not show recepisse link" do
it "does not show recepisse link" do
- expect(page).not_to have_link("Voir le récépissé")
+ expect(page).not_to have_link("Show receipt")
end
end