decidim-core 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/decidim.js.es6 +2 -0
  3. data/app/assets/javascripts/decidim/account_form.js.es6 +27 -0
  4. data/app/assets/javascripts/decidim/editor.js.es6 +9 -2
  5. data/app/assets/javascripts/decidim/form_filter.component.js.es6 +1 -1
  6. data/app/assets/javascripts/decidim/form_filter.component.test.js +2 -2
  7. data/app/assets/javascripts/decidim/history.js.es6 +7 -4
  8. data/app/commands/decidim/create_registration.rb +2 -1
  9. data/app/commands/decidim/destroy_account.rb +47 -0
  10. data/app/constraints/decidim/current_feature.rb +4 -5
  11. data/app/controllers/concerns/decidim/needs_participatory_process.rb +6 -1
  12. data/app/controllers/decidim/account_controller.rb +25 -2
  13. data/app/controllers/decidim/authorizations_controller.rb +2 -2
  14. data/app/controllers/decidim/pages_controller.rb +4 -2
  15. data/app/forms/decidim/delete_account_form.rb +8 -0
  16. data/app/forms/decidim/registration_form.rb +13 -0
  17. data/app/helpers/decidim/action_authorization_helper.rb +10 -4
  18. data/app/helpers/decidim/decidim_form_helper.rb +96 -0
  19. data/app/helpers/decidim/omniauth_helper.rb +1 -1
  20. data/app/helpers/decidim/resource_helper.rb +3 -36
  21. data/app/mailers/decidim/reported_mailer.rb +5 -3
  22. data/app/models/decidim/attachment.rb +1 -1
  23. data/app/models/decidim/authorization.rb +1 -1
  24. data/app/models/decidim/categorization.rb +8 -0
  25. data/app/models/decidim/category.rb +7 -2
  26. data/app/models/decidim/feature.rb +3 -5
  27. data/app/models/decidim/identity.rb +0 -1
  28. data/app/models/decidim/moderation.rb +0 -2
  29. data/app/models/decidim/participatory_process.rb +4 -2
  30. data/app/models/decidim/report.rb +1 -1
  31. data/app/models/decidim/resource_link.rb +1 -2
  32. data/app/models/decidim/static_page.rb +1 -2
  33. data/app/models/decidim/user.rb +16 -3
  34. data/app/models/decidim/user_group.rb +5 -3
  35. data/app/presenters/decidim/resource_locator_presenter.rb +48 -0
  36. data/app/services/decidim/authorization_handler.rb +4 -7
  37. data/app/services/decidim/resource_search.rb +3 -1
  38. data/app/uploaders/decidim/avatar_uploader.rb +2 -2
  39. data/app/uploaders/decidim/image_uploader.rb +1 -1
  40. data/app/uploaders/decidim/official_image_footer_uploader.rb +1 -5
  41. data/app/uploaders/decidim/official_image_header_uploader.rb +1 -5
  42. data/app/uploaders/decidim/organization_logo_uploader.rb +1 -1
  43. data/app/views/decidim/account/delete.html.erb +30 -0
  44. data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +2 -2
  45. data/app/views/decidim/reported_mailer/hide.html.erb +5 -1
  46. data/app/views/decidim/reported_mailer/report.html.erb +5 -1
  47. data/app/views/layouts/decidim/user_profile.html.erb +2 -1
  48. data/config/initializers/devise.rb +9 -9
  49. data/config/locales/ca.yml +20 -3
  50. data/config/locales/en.yml +20 -3
  51. data/config/locales/es.yml +20 -3
  52. data/config/locales/eu.yml +0 -3
  53. data/config/locales/fi.yml +0 -2
  54. data/config/locales/fr.yml +0 -3
  55. data/config/locales/it.yml +350 -0
  56. data/config/locales/nl.yml +0 -2
  57. data/config/routes.rb +5 -1
  58. data/db/migrate/20160817115213_devise_create_decidim_users.rb +1 -0
  59. data/db/migrate/20160919104837_create_decidim_organizations.rb +2 -0
  60. data/db/migrate/20160920140207_devise_invitable_add_to_decidim_users.rb +2 -0
  61. data/db/migrate/20160920141039_user_belongs_to_organization.rb +2 -0
  62. data/db/migrate/20160920141151_user_has_roles.rb +2 -0
  63. data/db/migrate/20161005130108_add_participatory_processes.rb +4 -2
  64. data/db/migrate/20161005153007_add_description_to_organizations.rb +2 -0
  65. data/db/migrate/20161006085629_add_confirmable_to_devise.rb +2 -0
  66. data/db/migrate/20161010085443_add_name_to_users.rb +2 -0
  67. data/db/migrate/20161010102356_translate_processes.rb +2 -0
  68. data/db/migrate/20161010131544_add_locale_to_users.rb +2 -0
  69. data/db/migrate/20161011125616_add_hero_image_to_processes.rb +2 -0
  70. data/db/migrate/20161011141033_add_banner_image_to_processes.rb +2 -0
  71. data/db/migrate/20161013134732_add_promoted_flag_to_processes.rb +2 -0
  72. data/db/migrate/20161017085822_add_participatory_process_steps.rb +4 -2
  73. data/db/migrate/20161018091013_create_decidim_authorizations.rb +2 -0
  74. data/db/migrate/20161019072016_add_active_flag_to_step.rb +7 -1
  75. data/db/migrate/20161020080756_add_position_to_steps.rb +2 -0
  76. data/db/migrate/20161025125300_add_published_at_to_processes.rb +2 -0
  77. data/db/migrate/20161107152228_remove_not_null_on_step_position.rb +2 -0
  78. data/db/migrate/20161108093802_create_decidim_static_pages.rb +2 -0
  79. data/db/migrate/20161110092735_add_index_for_process_slug_organization.rb +5 -3
  80. data/db/migrate/20161110105712_create_decidim_features.rb +2 -0
  81. data/db/migrate/20161116115156_create_attachments.rb +4 -2
  82. data/db/migrate/20161123085134_add_categories.rb +2 -0
  83. data/db/migrate/20161130105257_create_decidim_scopes.rb +2 -0
  84. data/db/migrate/20161209134715_make_organization_description_optional.rb +2 -0
  85. data/db/migrate/20161213094244_add_avatar_to_users.rb +2 -0
  86. data/db/migrate/20161214152811_add_logo_to_organizations.rb +2 -0
  87. data/db/migrate/20170110133113_add_configuration_to_features.rb +2 -0
  88. data/db/migrate/20170110153807_add_handler_to_organization.rb +2 -0
  89. data/db/migrate/20170113150627_create_resource_links.rb +2 -0
  90. data/db/migrate/20170116110851_create_identities.rb +2 -0
  91. data/db/migrate/20170116135237_loosen_step_requirements.rb +2 -0
  92. data/db/migrate/20170117142904_add_uniqueness_field_to_authorizations.rb +2 -0
  93. data/db/migrate/20170119145359_create_user_groups.rb +2 -0
  94. data/db/migrate/20170119150255_create_user_group_memberships.rb +2 -0
  95. data/db/migrate/20170119150649_add_show_statistics_to_organization.rb +3 -1
  96. data/db/migrate/20170120120733_add_user_groups_verified.rb +2 -0
  97. data/db/migrate/20170123134023_make_attachments_polymorphic.rb +2 -0
  98. data/db/migrate/20170123140857_add_avatar_to_user_groups.rb +2 -0
  99. data/db/migrate/20170125135937_rename_attachable_to_attached_to.rb +3 -1
  100. data/db/migrate/20170125152026_add_weight_to_features.rb +2 -0
  101. data/db/migrate/20170126151123_add_extra_info_to_processes.rb +6 -4
  102. data/db/migrate/20170128140553_add_timestamps_to_identities.rb +2 -0
  103. data/db/migrate/20170130132833_add_favicon_to_decidim_organizations.rb +2 -0
  104. data/db/migrate/20170131134349_add_action_permissions_to_decidim_features.rb +2 -0
  105. data/db/migrate/20170202084913_add_comments_and_replies_notifications_to_users.rb +2 -0
  106. data/db/migrate/20170203150545_add_newsletter_notifications_to_users.rb +2 -0
  107. data/db/migrate/20170206083118_rename_extra_info_on_processes.rb +2 -0
  108. data/db/migrate/20170206142116_add_published_at_to_decidim_features.rb +2 -0
  109. data/db/migrate/20170207091021_add_social_media_handlers_to_organization.rb +2 -0
  110. data/db/migrate/20170207093048_add_organization_logo_and_url.rb +3 -1
  111. data/db/migrate/20170213081133_create_decidim_newsletters.rb +2 -0
  112. data/db/migrate/20170215115407_add_organization_custom_reference.rb +2 -0
  113. data/db/migrate/20170220110740_remove_steps_short_description.rb +2 -0
  114. data/db/migrate/20170221094835_add_scopes_to_processes.rb +2 -0
  115. data/db/migrate/20170228142440_add_participatory_process_groups.rb +2 -0
  116. data/db/migrate/20170306144354_add_secondary_hosts_to_organizations.rb +2 -0
  117. data/db/migrate/20170307084957_create_reports.rb +2 -0
  118. data/db/migrate/20170308091316_create_moderations.rb +2 -0
  119. data/db/migrate/20170313095436_add_available_authorizations_to_organization.rb +2 -0
  120. data/db/migrate/20170404132616_change_steps_end_and_start_date_to_date.rb +2 -0
  121. data/db/migrate/20170405091801_change_decidim_user_email_index_uniqueness.rb +2 -0
  122. data/db/migrate/20170405094028_add_organization_to_identities.rb +2 -0
  123. data/db/migrate/20170405094258_change_decidim_identities_provider_uid_index_uniqueness.rb +3 -1
  124. data/db/migrate/20170529150743_add_rejected_at_to_user_groups.rb +2 -0
  125. data/db/migrate/20170605140421_add_deleted_fields_to_users.rb +8 -0
  126. data/db/migrate/20170606102659_set_email_unique_in_organization_conditional.rb +8 -0
  127. data/db/migrate/20170608142521_add_organization_to_user_groups.rb +14 -0
  128. data/db/migrate/20170612070905_add_uniqueness_to_name_and_document_number_to_user_groups.rb +8 -0
  129. data/db/migrate/20170612100253_create_decidim_categorizations.rb +12 -0
  130. data/db/seeds.rb +10 -8
  131. data/lib/decidim/authorable.rb +2 -2
  132. data/lib/decidim/core.rb +1 -1
  133. data/lib/decidim/core/api/author_interface.rb +6 -0
  134. data/lib/decidim/core/api/user_group_type.rb +14 -0
  135. data/lib/decidim/core/api/user_type.rb +10 -0
  136. data/lib/decidim/core/engine.rb +1 -1
  137. data/lib/decidim/core/test/factories.rb +12 -0
  138. data/lib/decidim/core/test/shared_examples/manage_moderations_examples.rb +3 -3
  139. data/lib/decidim/core/version.rb +2 -2
  140. data/lib/decidim/feature_manifest.rb +2 -3
  141. data/lib/decidim/form_builder.rb +3 -2
  142. data/lib/decidim/has_category.rb +3 -1
  143. data/lib/decidim/has_scope.rb +5 -2
  144. data/lib/decidim/query_extensions.rb +2 -2
  145. data/lib/decidim/reportable.rb +3 -3
  146. data/lib/decidim/stats_registry.rb +2 -2
  147. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.fr.js +14 -0
  148. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.it.js +14 -0
  149. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.nl.js +14 -0
  150. metadata +45 -17
  151. data/app/models/decidim/component.rb +0 -52
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0b0dd8d6b3f087054a2af0d5d971d81c6a52adae
4
- data.tar.gz: 5395196374ab3e8f0f7a65abba480e914505938d
3
+ metadata.gz: d96ba296398fd826bdcf4c32066893664f91f190
4
+ data.tar.gz: e378de5bd40d0cbd7f95e811e921cbbce3fd3f15
5
5
  SHA512:
6
- metadata.gz: fae7b86d0ca687eb0f3519d3cd7886c626224e023d95a6db84a7cdeef3d979193475117596993846231df7a4510bcab8f22b5f912283e1ea075b1d68b4018e77
7
- data.tar.gz: 6e0d57a494c3a2d7bcbc1ecac618c47447defd88422c1761006b65e7f9e3a1ecb1889db554d150451728e8fd5c11591d1a18cadbbec176630ffb2c34ea392ee3
6
+ metadata.gz: c5ad0b5762d5c1c9d2ec61392c7a22587ecc4d769f35dbe938be51513f0446df6104c75fb36e34cf5260ba104a71ab5bb591527a3706e5f1e8e1a22155515ba2
7
+ data.tar.gz: 5d32c6d26f18146787b85c53c019bb549d0a3569b90dcae89588a4a7249f6f472e2addad8b08b911276472b487809462b45639277f58fe346aaa95aaa2417c73
@@ -1,3 +1,4 @@
1
+ // = require jquery
1
2
  // = require decidim/foundation
2
3
  // = require modernizr
3
4
  // = require svg4everybody.min
@@ -8,6 +9,7 @@
8
9
  // = require decidim/history
9
10
  // = require decidim/append_elements
10
11
  // = require decidim/user_registrations
12
+ // = require decidim/account_form
11
13
 
12
14
  /* globals svg4everybody */
13
15
 
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Since the delete account has a modal to confirm it we need to copy the content of the
3
+ * reason field to the hidden field in the form inside the modal.
4
+ */
5
+ $(() => {
6
+ const $deleteAccountForm = $('.delete-account');
7
+ const $deleteAccountModalForm = $('.delete-account-modal');
8
+
9
+ if ($deleteAccountForm.length > 0) {
10
+ const $openModalButton = $('.open-modal-button');
11
+ const $modal = $('#deleteConfirm');
12
+
13
+ $openModalButton.on('click', (event) => {
14
+ try {
15
+ const reasonValue = $deleteAccountForm.find('textarea#delete_account_delete_reason').val();
16
+ $deleteAccountModalForm.find('input#delete_account_delete_reason').val(reasonValue);
17
+ $modal.foundation('open');
18
+ } catch (error) {
19
+ console.error(error); // eslint-disable-line no-console
20
+ }
21
+
22
+ event.preventDefault();
23
+ event.stopPropagation();
24
+ return false;
25
+ });
26
+ }
27
+ });
@@ -5,7 +5,7 @@ $(() => {
5
5
  const $container = $('.editor-container');
6
6
  const quillFormats = ['bold', 'italic', 'link', 'underline', 'header', 'list', 'video'];
7
7
 
8
- $container.each((idx, container) => {
8
+ const createQuillEditor = (container) => {
9
9
  const toolbar = $(container).data('toolbar');
10
10
 
11
11
  let quillToolbar = [
@@ -39,6 +39,13 @@ $(() => {
39
39
  }
40
40
  });
41
41
 
42
- quill.root.innerHTML = $input.val();
42
+ quill.root.innerHTML = $input.val() || '';
43
+ };
44
+
45
+ $container.each((idx, container) => {
46
+ createQuillEditor(container);
43
47
  });
48
+
49
+ window.Decidim = window.Decidim || {};
50
+ window.Decidim.createQuillEditor = createQuillEditor;
44
51
  });
@@ -54,7 +54,7 @@
54
54
  }
55
55
 
56
56
  /**
57
- * Finds the values of the location prams that match the given regexp.
57
+ * Finds the values of the location params that match the given regexp.
58
58
  * @private
59
59
  * @param {Regexp} regex - a Regexp to match the params.
60
60
  * @returns {String[]} - An array of values of the params that match the regexp.
@@ -70,14 +70,14 @@ describe('FormFilterComponent', () => {
70
70
  it('clears the form data', () => {
71
71
  spyOn(subject, '_clearForm');
72
72
 
73
- window.onpopstate();
73
+ window.onpopstate({ isTrusted: true });
74
74
 
75
75
  expect(subject._clearForm).toHaveBeenCalled();
76
76
  });
77
77
 
78
78
  it('sets the correct form fields based on the current location', () => {
79
79
  spyOn(subject, '_getLocation').and.returnValue('/filters?filter[scope_id][]=1&scope_id[]=2&filter[category_id]=2');
80
- window.onpopstate();
80
+ window.onpopstate({ isTrusted: true });
81
81
 
82
82
  expect($(selector).find('select').val()).toEqual('2');
83
83
  expect($(selector).find('input[name="filter[scope_id][]"][value="1"]')[0].checked).toBeTruthy();
@@ -4,10 +4,13 @@
4
4
  ((exports) => {
5
5
  let callbacks = {};
6
6
 
7
- exports.onpopstate = () => {
8
- for (let callbackId in callbacks) {
9
- if (callbacks.hasOwnProperty(callbackId)) {
10
- callbacks[callbackId]();
7
+ exports.onpopstate = (event) => {
8
+ // Ensure the event is caused by user action
9
+ if (event.isTrusted) {
10
+ for (let callbackId in callbacks) {
11
+ if (callbacks.hasOwnProperty(callbackId)) {
12
+ callbacks[callbackId]();
13
+ }
11
14
  }
12
15
  }
13
16
  };
@@ -48,7 +48,8 @@ module Decidim
48
48
  UserGroupMembership.create!(user: @user,
49
49
  user_group: UserGroup.new(name: form.user_group_name,
50
50
  document_number: form.user_group_document_number,
51
- phone: form.user_group_phone))
51
+ phone: form.user_group_phone,
52
+ decidim_organization_id: form.current_organization.id))
52
53
  end
53
54
  end
54
55
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # This command destroys the user's account.
5
+ class DestroyAccount < Rectify::Command
6
+ # Destroy a user's account.
7
+ #
8
+ # user - The user to be updated.
9
+ # form - The form with the data.
10
+ def initialize(user, form)
11
+ @user = user
12
+ @form = form
13
+ end
14
+
15
+ def call
16
+ return broadcast(:invalid) unless @form.valid?
17
+
18
+ Decidim::User.transaction do
19
+ destroy_user_account!
20
+ destroy_user_identities
21
+ destroy_user_group_memberships
22
+ end
23
+
24
+ broadcast(:ok)
25
+ end
26
+
27
+ private
28
+
29
+ def destroy_user_account!
30
+ @user.name = ""
31
+ @user.email = ""
32
+ @user.delete_reason = @form.delete_reason
33
+ @user.deleted_at = Time.current
34
+ @user.skip_reconfirmation!
35
+ @user.remove_avatar!
36
+ @user.save!
37
+ end
38
+
39
+ def destroy_user_identities
40
+ @user.identities.destroy_all
41
+ end
42
+
43
+ def destroy_user_group_memberships
44
+ Decidim::UserGroupMembership.where(user: @user).destroy_all
45
+ end
46
+ end
47
+ end
@@ -28,7 +28,7 @@ module Decidim
28
28
 
29
29
  env["decidim.current_participatory_process"] ||= @participatory_process
30
30
 
31
- feature = detect_current_feature(request)
31
+ feature = detect_current_feature(params)
32
32
 
33
33
  return false unless feature
34
34
 
@@ -38,12 +38,11 @@ module Decidim
38
38
 
39
39
  private
40
40
 
41
- def detect_current_feature(request)
42
- params = request.params
41
+ def detect_current_feature(params)
43
42
  return nil unless params["feature_id"]
44
43
 
45
- @participatory_process.features.to_a.find do |feature|
46
- params["feature_id"].to_s == feature.id.to_s && feature.manifest_name == @manifest.name.to_s
44
+ @participatory_process.features.find do |feature|
45
+ params["feature_id"] == feature.id.to_s && feature.manifest_name == @manifest.name.to_s
47
46
  end
48
47
  end
49
48
  end
@@ -19,7 +19,7 @@ module Decidim
19
19
  #
20
20
  # Returns the current ParticipatoryProcess.
21
21
  def current_participatory_process
22
- @current_participatory_process ||= current_organization.participatory_processes.find_by(id: params[:participatory_process_id] || params[:id])
22
+ @current_participatory_process ||= detect_participatory_process
23
23
  end
24
24
 
25
25
  private
@@ -27,6 +27,11 @@ module Decidim
27
27
  def verify_participatory_process
28
28
  raise ActionController::RoutingError, "Participatory process not found." unless current_participatory_process
29
29
  end
30
+
31
+ def detect_participatory_process
32
+ request.env["current_participatory_process"] ||
33
+ current_organization.participatory_processes.find_by(id: params[:participatory_process_id] || params[:id])
34
+ end
30
35
  end
31
36
  end
32
37
  end
@@ -18,8 +18,8 @@ module Decidim
18
18
  @account = form(AccountForm).from_params(params)
19
19
 
20
20
  UpdateAccount.call(current_user, @account) do
21
- on(:ok) do |_account, unconfirmed_email|
22
- flash.now[:notice] = if unconfirmed_email
21
+ on(:ok) do |email_is_unconfirmed|
22
+ flash.now[:notice] = if email_is_unconfirmed
23
23
  t("account.update.success_with_email_confirmation", scope: "decidim")
24
24
  else
25
25
  t("account.update.success", scope: "decidim")
@@ -36,6 +36,29 @@ module Decidim
36
36
  render action: :show
37
37
  end
38
38
 
39
+ def delete
40
+ authorize! :delete, current_user
41
+ @form = form(DeleteAccountForm).from_model(current_user)
42
+ end
43
+
44
+ def destroy
45
+ authorize! :delete, current_user
46
+ @form = form(DeleteAccountForm).from_params(params)
47
+
48
+ DestroyAccount.call(current_user, @form) do
49
+ on(:ok) do
50
+ sign_out(current_user)
51
+ flash[:notice] = t("account.destroy.success", scope: "decidim")
52
+ end
53
+
54
+ on(:invalid) do
55
+ flash[:alert] = t("account.destroy.error", scope: "decidim")
56
+ end
57
+ end
58
+
59
+ redirect_to decidim.root_path
60
+ end
61
+
39
62
  private
40
63
 
41
64
  def authorizations
@@ -63,7 +63,7 @@ module Decidim
63
63
  end
64
64
 
65
65
  def handler_name
66
- params[:handler] || params[:authorization_handler][:handler_name]
66
+ params[:handler] || params.dig(:authorization_handler, :handler_name)
67
67
  end
68
68
 
69
69
  def valid_handler
@@ -72,7 +72,7 @@ module Decidim
72
72
  logger.warn "Invalid authorization handler given: #{handler_name} doesn't"\
73
73
  "exist or you haven't added it to `Decidim.authorization_handlers`"
74
74
 
75
- redirect_to(account_path) && (return false)
75
+ redirect_to(authorizations_path) && (return false)
76
76
  end
77
77
 
78
78
  def only_one_handler?
@@ -25,11 +25,13 @@ module Decidim
25
25
  end
26
26
 
27
27
  def promoted_participatory_processes
28
- @promoted_processes ||= OrganizationPrioritizedParticipatoryProcesses.new(current_organization) | PromotedParticipatoryProcesses.new
28
+ @promoted_participatory_processes ||=
29
+ OrganizationPrioritizedParticipatoryProcesses.new(current_organization) | PromotedParticipatoryProcesses.new
29
30
  end
30
31
 
31
32
  def highlighted_participatory_processes
32
- @promoted_processes ||= OrganizationParticipatoryProcesses.new(current_organization) | HighlightedParticipatoryProcesses.new
33
+ @highlighted_participatory_processes ||=
34
+ OrganizationParticipatoryProcesses.new(current_organization) | HighlightedParticipatoryProcesses.new
33
35
  end
34
36
 
35
37
  private
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # The form object that handles the data behind deleting users account.
5
+ class DeleteAccountForm < Form
6
+ attribute :delete_reason, String
7
+ end
8
+ end
@@ -28,6 +28,8 @@ module Decidim
28
28
  validates :user_group_phone, presence: true, if: :user_group?
29
29
 
30
30
  validate :email_unique_in_organization
31
+ validate :user_group_name_unique_in_organization
32
+ validate :user_group_document_number_unique_in_organization
31
33
 
32
34
  def user_group?
33
35
  sign_up_as == "user_group"
@@ -38,5 +40,16 @@ module Decidim
38
40
  def email_unique_in_organization
39
41
  errors.add :email, :taken if User.where(email: email, organization: current_organization).first.present?
40
42
  end
43
+
44
+ def user_group_name_unique_in_organization
45
+ errors.add :user_group_name, :taken if UserGroup.where(name: user_group_name, decidim_organization_id: current_organization.id).first.present?
46
+ end
47
+
48
+ def user_group_document_number_unique_in_organization
49
+ errors.add :user_group_document_number, :taken if UserGroup.where(
50
+ document_number: user_group_document_number,
51
+ decidim_organization_id: current_organization.id
52
+ ).first.present?
53
+ end
41
54
  end
42
55
  end
@@ -33,10 +33,10 @@ module Decidim
33
33
  html_options = arguments[2]
34
34
  end
35
35
 
36
- unless action_authorization(action).ok?
36
+ unless current_user_authorized?(action)
37
37
  html_options ||= {}
38
38
  html_options["onclick"] = "event.preventDefault();"
39
- html_options["data-toggle"] = "#{action.to_s.underscore}AuthorizationModal"
39
+ html_options["data-toggle"] = current_user ? "#{action.to_s.underscore}AuthorizationModal" : "loginModal"
40
40
  url = ""
41
41
  end
42
42
 
@@ -66,9 +66,9 @@ module Decidim
66
66
  html_options = arguments[2] || {}
67
67
  end
68
68
 
69
- unless action_authorization(action).ok?
69
+ unless current_user_authorized?(action)
70
70
  html_options["onclick"] = "event.preventDefault();"
71
- html_options["data-toggle"] = "#{action.to_s.underscore}AuthorizationModal"
71
+ html_options["data-toggle"] = current_user ? "#{action.to_s.underscore}AuthorizationModal" : "loginModal"
72
72
  url = ""
73
73
  end
74
74
 
@@ -78,5 +78,11 @@ module Decidim
78
78
  button_to(body, url, html_options)
79
79
  end
80
80
  end
81
+
82
+ private
83
+
84
+ def current_user_authorized?(action)
85
+ current_user && action_authorization(action).ok?
86
+ end
81
87
  end
82
88
  end
@@ -15,5 +15,101 @@ module Decidim
15
15
  options[:data].update(abide: true, "live-validate" => true, "validate-on-blur" => true)
16
16
  form_for(record, options, &block)
17
17
  end
18
+
19
+ # A custom helper to include an editor field without requiring a form object
20
+ #
21
+ # name - The input name
22
+ # value - The input value
23
+ # options - The set of options to send to the field
24
+ # :label - The Boolean value to create or not the input label (optional) (default: true)
25
+ # :toolbar - The String value to configure WYSIWYG toolbar. It should be 'basic' or
26
+ # or 'full' (optional) (default: 'basic')
27
+ # :lines - The Integer to indicate how many lines should editor have (optional)
28
+ #
29
+ # Returns a rich editor to be included in a html template.
30
+ def editor_field_tag(name, value, options = {})
31
+ options[:toolbar] ||= "basic"
32
+ options[:lines] ||= 10
33
+
34
+ content_tag(:div, class: "editor") do
35
+ template = ""
36
+ template += label_tag(name, options[:label]) if options[:label] != false
37
+ template += hidden_field_tag(name, value, options)
38
+ template += content_tag(:div, nil, class: "editor-container", data: {
39
+ toolbar: options[:toolbar]
40
+ }, style: "height: #{options[:lines]}rem")
41
+ template.html_safe
42
+ end
43
+ end
44
+
45
+ # A custom helper to include a translated field without requiring a form object.
46
+ #
47
+ # type - The type of the translated input field.
48
+ # object_name - The object name used to identify the Foundation tabs.
49
+ # name - The name of the input which will be suffixed with the corresponding locales.
50
+ # value - A hash containing the value for each locale.
51
+ # options - An optional hash of options.
52
+ # * enable_tabs: Adds the data-tabs attribute so Foundation picks up automatically.
53
+ # * tabs_id: The id to identify the Foundation tabs element.
54
+ # * label: The label used for the field.
55
+ #
56
+ # Returns a Foundation tabs element with the translated input field.
57
+ def translated_field_tag(type, object_name, name, value = {}, options = {})
58
+ locales = available_locales
59
+
60
+ tabs_id = options[:tabs_id] || "#{object_name}-#{name}-tabs"
61
+ enabled_tabs = options[:enable_tabs].nil? ? true : options[:enable_tabs]
62
+ tabs_panels_data = enabled_tabs ? { tabs: true } : {}
63
+
64
+ if locales.count == 1
65
+ return send(
66
+ type,
67
+ "#{name}_#{locales.first.to_s.gsub("-", "__")}",
68
+ options.merge(label: options[:label])
69
+ )
70
+ end
71
+
72
+ label_tabs = content_tag(:div, class: "label--tabs") do
73
+ field_label = label_tag(name, options[:label])
74
+
75
+ tabs_panels = "".html_safe
76
+ if options[:label] != false
77
+ tabs_panels = content_tag(:ul, class: "tabs tabs--lang", id: tabs_id, data: tabs_panels_data) do
78
+ locales.each_with_index.inject("".html_safe) do |string, (locale, index)|
79
+ string + content_tag(:li, class: tab_element_class_for("title", index)) do
80
+ title = I18n.with_locale(locale) { I18n.t("name", scope: "locale") }
81
+ tab_content_id = "#{tabs_id}-#{name}-panel-#{index}"
82
+ content_tag(:a, title, href: "##{tab_content_id}")
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ safe_join [field_label, tabs_panels]
89
+ end
90
+
91
+ tabs_content = content_tag(:div, class: "tabs-content", data: { tabs_content: tabs_id }) do
92
+ locales.each_with_index.inject("".html_safe) do |string, (locale, index)|
93
+ tab_content_id = "#{tabs_id}-#{name}-panel-#{index}"
94
+ string + content_tag(:div, class: tab_element_class_for("panel", index), id: tab_content_id) do
95
+ send(type, "#{object_name}[#{name_with_locale(name, locale)}]", value[locale.to_s], options.merge(id: "#{tabs_id}_#{name}_#{locale}", label: false))
96
+ end
97
+ end
98
+ end
99
+
100
+ safe_join [label_tabs, tabs_content]
101
+ end
102
+
103
+ # Helper method used by `translated_field_tag`
104
+ def tab_element_class_for(type, index)
105
+ element_class = "tabs-#{type}"
106
+ element_class += " is-active" if index.zero?
107
+ element_class
108
+ end
109
+
110
+ # Helper method used by `translated_field_tag`
111
+ def name_with_locale(name, locale)
112
+ "#{name}_#{locale.to_s.gsub("-", "__")}"
113
+ end
18
114
  end
19
115
  end