decidim-core 0.8.4 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (249) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +1 -1
  3. data/app/assets/images/decidim/decidim-logo.svg +23 -23
  4. data/app/assets/images/decidim/default-avatar.svg +7 -7
  5. data/app/assets/images/decidim/icons.svg +1 -0
  6. data/app/assets/javascripts/decidim.js.es6 +5 -2
  7. data/app/assets/javascripts/decidim/append_redirect_url_to_modals.js.es6 +84 -0
  8. data/app/assets/javascripts/decidim/data_picker.js.es6 +177 -0
  9. data/app/assets/javascripts/decidim/form_filter.component.js.es6 +25 -20
  10. data/app/assets/javascripts/decidim/form_filter.component.test.js +24 -13
  11. data/app/assets/javascripts/decidim/history.js.es6 +3 -3
  12. data/app/assets/stylesheets/decidim/_decidim.scss +1 -4
  13. data/app/assets/stylesheets/decidim/_variables.scss +4 -4
  14. data/app/assets/stylesheets/decidim/editor.scss +13 -0
  15. data/app/assets/stylesheets/decidim/email.css +9 -1
  16. data/app/assets/stylesheets/decidim/extras/_add_comments.scss +3 -3
  17. data/app/assets/stylesheets/decidim/extras/_announcement.scss +1 -1
  18. data/app/assets/stylesheets/decidim/extras/_collection-sort-controls.scss +2 -2
  19. data/app/assets/stylesheets/decidim/extras/_embed.scss +6 -5
  20. data/app/assets/stylesheets/decidim/extras/_impersonation-bar.scss +4 -0
  21. data/app/assets/stylesheets/decidim/extras/_label-required.scss +1 -1
  22. data/app/assets/stylesheets/decidim/extras/_leaflet.scss +6 -4
  23. data/app/assets/stylesheets/decidim/extras/_meeting-registrations.scss +4 -4
  24. data/app/assets/stylesheets/decidim/extras/_process_stats.scss +11 -4
  25. data/app/assets/stylesheets/decidim/extras/_proposal_form.scss +3 -3
  26. data/app/assets/stylesheets/decidim/extras/_quill.scss +1 -1
  27. data/app/assets/stylesheets/decidim/extras/_reference.scss +3 -3
  28. data/app/assets/stylesheets/decidim/extras/_register_form.scss +3 -3
  29. data/app/assets/stylesheets/decidim/extras/_results-per-page.scss +10 -10
  30. data/app/assets/stylesheets/decidim/extras/_social_icons_mini.scss +4 -3
  31. data/app/assets/stylesheets/decidim/layouts/_highlighted_banner.scss +38 -0
  32. data/app/assets/stylesheets/decidim/layouts/_home.scss +33 -3
  33. data/app/assets/stylesheets/decidim/layouts/_user.scss +33 -5
  34. data/app/assets/stylesheets/decidim/layouts/_view.scss +1 -2
  35. data/app/assets/stylesheets/decidim/map.css +5 -3
  36. data/app/assets/stylesheets/decidim/modules/_address.scss +1 -0
  37. data/app/assets/stylesheets/decidim/modules/_author-avatar.scss +24 -9
  38. data/app/assets/stylesheets/decidim/modules/_buttons.scss +24 -10
  39. data/app/assets/stylesheets/decidim/modules/_callout.scss +5 -1
  40. data/app/assets/stylesheets/decidim/modules/_card-grid.scss +1 -1
  41. data/app/assets/stylesheets/decidim/modules/_cards.scss +102 -31
  42. data/app/assets/stylesheets/decidim/modules/_comments.scss +21 -20
  43. data/app/assets/stylesheets/decidim/modules/_cookie-bar.scss +4 -0
  44. data/app/assets/stylesheets/decidim/modules/_data-picker.scss +159 -0
  45. data/app/assets/stylesheets/decidim/modules/_datepicker.scss +36 -36
  46. data/app/assets/stylesheets/decidim/modules/_definition-data.scss +12 -9
  47. data/app/assets/stylesheets/decidim/modules/_extra.scss +4 -1
  48. data/app/assets/stylesheets/decidim/modules/_filter-tags.scss +3 -0
  49. data/app/assets/stylesheets/decidim/modules/_filters.scss +9 -5
  50. data/app/assets/stylesheets/decidim/modules/_flag.scss +1 -0
  51. data/app/assets/stylesheets/decidim/modules/_footer.scss +10 -0
  52. data/app/assets/stylesheets/decidim/modules/_forms.scss +2 -1
  53. data/app/assets/stylesheets/decidim/modules/_help.scss +2 -0
  54. data/app/assets/stylesheets/decidim/modules/_icons.scss +1 -0
  55. data/app/assets/stylesheets/decidim/modules/_layout.scss +4 -0
  56. data/app/assets/stylesheets/decidim/modules/_list-docs.scss +3 -0
  57. data/app/assets/stylesheets/decidim/modules/_main-container.scss +13 -7
  58. data/app/assets/stylesheets/decidim/modules/_map.scss +13 -1
  59. data/app/assets/stylesheets/decidim/modules/_margins.scss +1 -0
  60. data/app/assets/stylesheets/decidim/modules/_messages.scss +2 -1
  61. data/app/assets/stylesheets/decidim/modules/_modules.scss +3 -0
  62. data/app/assets/stylesheets/decidim/modules/_navbar.scss +36 -16
  63. data/app/assets/stylesheets/decidim/modules/_omnipresent_banner.scss +26 -0
  64. data/app/assets/stylesheets/decidim/modules/_opinion-toggle.scss +5 -0
  65. data/app/assets/stylesheets/decidim/modules/_order-by.scss +10 -10
  66. data/app/assets/stylesheets/decidim/modules/_pagination.scss +3 -2
  67. data/app/assets/stylesheets/decidim/modules/_process-header.scss +11 -2
  68. data/app/assets/stylesheets/decidim/modules/_process-info.scss +9 -1
  69. data/app/assets/stylesheets/decidim/modules/_process-nav.scss +20 -3
  70. data/app/assets/stylesheets/decidim/modules/_process-phase.scss +12 -3
  71. data/app/assets/stylesheets/decidim/modules/_progress-bar.scss +69 -0
  72. data/app/assets/stylesheets/decidim/modules/_reference.scss +1 -2
  73. data/app/assets/stylesheets/decidim/modules/_reveal.scss +1 -1
  74. data/app/assets/stylesheets/decidim/modules/_share.scss +2 -0
  75. data/app/assets/stylesheets/decidim/modules/_signup.scss +5 -1
  76. data/app/assets/stylesheets/decidim/modules/_static-pages.scss +6 -0
  77. data/app/assets/stylesheets/decidim/modules/_status-labels.scss +2 -0
  78. data/app/assets/stylesheets/decidim/modules/_tags.scss +3 -1
  79. data/app/assets/stylesheets/decidim/modules/_timeline.scss +41 -30
  80. data/app/assets/stylesheets/decidim/modules/_title-action.scss +2 -1
  81. data/app/assets/stylesheets/decidim/modules/_typography.scss +13 -4
  82. data/app/assets/stylesheets/decidim/modules/_user-form.scss +1 -0
  83. data/app/assets/stylesheets/decidim/modules/_video.scss +2 -2
  84. data/app/assets/stylesheets/decidim/utils/_fontface.scss +22 -20
  85. data/app/assets/stylesheets/decidim/utils/_helpers.scss +6 -6
  86. data/app/assets/stylesheets/decidim/utils/_keyframes.scss +6 -6
  87. data/app/assets/stylesheets/decidim/utils/_mixins.scss +24 -7
  88. data/app/assets/stylesheets/decidim/utils/_settings.scss +50 -52
  89. data/app/assets/stylesheets/decidim/utils/_toggle-expand.scss +1 -0
  90. data/app/commands/decidim/create_omniauth_registration.rb +3 -0
  91. data/app/commands/decidim/create_registration.rb +3 -1
  92. data/app/commands/decidim/destroy_account.rb +1 -0
  93. data/app/commands/decidim/invite_user_again.rb +1 -1
  94. data/app/commands/decidim/messaging/reply_to_conversation.rb +1 -3
  95. data/app/commands/decidim/unsubscribe_settings.rb +29 -0
  96. data/app/commands/decidim/update_account.rb +16 -3
  97. data/app/controllers/concerns/decidim/action_authorization.rb +1 -1
  98. data/app/controllers/concerns/decidim/devise_controllers.rb +10 -0
  99. data/app/controllers/concerns/decidim/form_factory.rb +2 -1
  100. data/app/controllers/concerns/decidim/impersonate_users.rb +13 -8
  101. data/app/controllers/concerns/decidim/participatory_space_context.rb +1 -1
  102. data/app/controllers/decidim/application_controller.rb +16 -0
  103. data/app/controllers/decidim/cookie_policy_controller.rb +2 -0
  104. data/app/controllers/decidim/devise/invitations_controller.rb +9 -1
  105. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +10 -1
  106. data/app/controllers/decidim/devise/sessions_controller.rb +9 -1
  107. data/app/controllers/decidim/locales_controller.rb +2 -3
  108. data/app/controllers/decidim/messaging/conversations_controller.rb +2 -2
  109. data/app/controllers/decidim/newsletters_controller.rb +60 -0
  110. data/app/controllers/decidim/pages_controller.rb +1 -0
  111. data/app/controllers/decidim/profiles_controller.rb +23 -0
  112. data/app/controllers/decidim/scopes_controller.rb +19 -20
  113. data/app/events/decidim/profile_updated_event.rb +27 -0
  114. data/app/forms/decidim/account_form.rb +34 -0
  115. data/app/forms/decidim/form.rb +1 -0
  116. data/app/forms/decidim/messaging/conversation_form.rb +5 -2
  117. data/app/forms/decidim/omniauth_registration_form.rb +5 -0
  118. data/app/forms/decidim/registration_form.rb +8 -1
  119. data/app/helpers/decidim/action_authorization_helper.rb +2 -2
  120. data/app/helpers/decidim/application_helper.rb +8 -0
  121. data/app/helpers/decidim/feature_path_helper.rb +12 -2
  122. data/app/helpers/decidim/feature_reference_helper.rb +1 -1
  123. data/app/helpers/decidim/messaging/conversation_helper.rb +27 -9
  124. data/app/helpers/decidim/newsletters_helper.rb +49 -0
  125. data/app/helpers/decidim/scopes_helper.rb +43 -2
  126. data/app/helpers/decidim/translations_helper.rb +6 -2
  127. data/app/mailers/decidim/decidim_devise_mailer.rb +1 -3
  128. data/app/mailers/decidim/messaging/conversation_mailer.rb +1 -1
  129. data/app/mailers/decidim/newsletter_mailer.rb +7 -8
  130. data/app/models/decidim/abilities/everyone_ability.rb +1 -0
  131. data/app/models/decidim/authorization.rb +19 -5
  132. data/app/models/decidim/impersonation_log.rb +2 -1
  133. data/app/models/decidim/messaging/conversation.rb +2 -0
  134. data/app/models/decidim/messaging/message.rb +4 -0
  135. data/app/models/decidim/organization.rb +1 -0
  136. data/app/models/decidim/scope.rb +10 -2
  137. data/app/models/decidim/user.rb +10 -2
  138. data/app/presenters/decidim/home_stats_presenter.rb +10 -4
  139. data/app/presenters/decidim/user_group_presenter.rb +28 -0
  140. data/app/presenters/decidim/user_presenter.rb +42 -0
  141. data/app/services/decidim/action_authorizer.rb +32 -68
  142. data/app/services/decidim/notification_generator_for_recipient.rb +8 -3
  143. data/app/uploaders/decidim/avatar_uploader.rb +2 -2
  144. data/app/views/decidim/account/delete.html.erb +1 -1
  145. data/app/views/decidim/account/show.html.erb +4 -1
  146. data/app/views/decidim/devise/invitations/edit.html.erb +2 -0
  147. data/app/views/decidim/devise/omniauth_registrations/new.html.erb +7 -1
  148. data/app/views/decidim/devise/registrations/new.html.erb +7 -1
  149. data/app/views/decidim/messaging/conversations/_message.html.erb +6 -12
  150. data/app/views/decidim/messaging/conversations/_reply.html.erb +1 -1
  151. data/app/views/decidim/messaging/conversations/index.html.erb +1 -1
  152. data/app/views/decidim/messaging/conversations/update.js.erb +1 -0
  153. data/app/views/decidim/newsletter_mailer/newsletter.html.erb +11 -0
  154. data/app/views/decidim/newsletters/show.html.erb +11 -0
  155. data/app/views/decidim/newsletters/unsubscribe.html.erb +4 -0
  156. data/app/views/decidim/notifications/_notification.html.erb +1 -1
  157. data/app/views/decidim/profiles/show.html.erb +64 -0
  158. data/app/views/decidim/scopes/_scopes_picker_input.html.erb +6 -0
  159. data/app/views/decidim/scopes/picker.html.erb +36 -0
  160. data/app/views/decidim/shared/_action_authorization_modal.html.erb +25 -51
  161. data/app/views/decidim/shared/_author.html.erb +21 -0
  162. data/app/views/decidim/shared/_author_reference.html.erb +12 -0
  163. data/app/views/layouts/decidim/_application.html.erb +1 -0
  164. data/app/views/layouts/decidim/_impersonation_warning.html.erb +1 -1
  165. data/app/views/layouts/decidim/_mailer_logo.html.erb +6 -1
  166. data/app/views/layouts/decidim/_omnipresent_banner.html.erb +14 -0
  167. data/app/views/layouts/decidim/_user_menu.html.erb +3 -0
  168. data/app/views/layouts/decidim/mailer.html.erb +16 -4
  169. data/app/views/layouts/decidim/widget.html.erb +14 -9
  170. data/app/views/pages/home.html.erb +2 -0
  171. data/app/views/pages/home/_highlighted_content_banner.html.erb +26 -0
  172. data/config/initializers/devise.rb +1 -3
  173. data/config/locales/ca.yml +67 -9
  174. data/config/locales/en.yml +65 -4
  175. data/config/locales/es.yml +74 -14
  176. data/config/locales/eu.yml +66 -4
  177. data/config/locales/fi.yml +87 -25
  178. data/config/locales/fr.yml +71 -9
  179. data/config/locales/gl.yml +493 -0
  180. data/config/locales/it.yml +79 -17
  181. data/config/locales/nl.yml +71 -9
  182. data/config/locales/pl.yml +66 -4
  183. data/config/locales/pt-BR.yml +493 -0
  184. data/config/locales/pt.yml +99 -37
  185. data/config/locales/ru.yml +85 -13
  186. data/config/locales/sv.yml +493 -0
  187. data/config/locales/uk.yml +78 -16
  188. data/config/routes.rb +11 -1
  189. data/db/migrate/20171212103803_create_unique_nicknames.rb +29 -0
  190. data/db/migrate/20180115090038_extend_user_profile.rb +8 -0
  191. data/db/migrate/20180123125308_add_enable_omnipresent_banner_to_decidim_organizations.rb +7 -0
  192. data/db/migrate/20180123125409_add_omnipresent_banner_title_to_decidim_organizations.rb +7 -0
  193. data/db/migrate/20180123125432_add_omnipresent_banner_short_description_to_decidim_organizations.rb +7 -0
  194. data/db/migrate/20180123125452_add_omnipresent_banner_url_to_decidim_organizations.rb +7 -0
  195. data/db/migrate/20180125063433_add_highlighted_content_banner_to_decidim_organizations.rb +13 -0
  196. data/db/seeds.rb +8 -2
  197. data/lib/decidim/abilities/participatory_process_role_ability.rb +1 -3
  198. data/lib/decidim/content_parsers.rb +8 -0
  199. data/lib/decidim/content_parsers/base_parser.rb +58 -0
  200. data/lib/decidim/content_parsers/user_parser.rb +46 -0
  201. data/lib/decidim/content_processor.rb +84 -0
  202. data/lib/decidim/content_renderers.rb +8 -0
  203. data/lib/decidim/content_renderers/base_renderer.rb +37 -0
  204. data/lib/decidim/content_renderers/user_renderer.rb +32 -0
  205. data/lib/decidim/core.rb +66 -1
  206. data/lib/decidim/core/api/author_interface.rb +3 -3
  207. data/lib/decidim/core/api/user_group_type.rb +10 -8
  208. data/lib/decidim/core/api/user_type.rb +13 -7
  209. data/lib/decidim/core/engine.rb +7 -5
  210. data/lib/decidim/core/test.rb +1 -1
  211. data/lib/decidim/core/test/factories.rb +21 -45
  212. data/lib/decidim/core/test/shared_examples/announcements_examples.rb +3 -2
  213. data/lib/decidim/core/test/shared_examples/comments_examples.rb +5 -2
  214. data/lib/decidim/core/test/shared_examples/scope_helper_examples.rb +40 -3
  215. data/lib/decidim/core/test/shared_examples/simple_event.rb +73 -0
  216. data/lib/decidim/core/version.rb +1 -1
  217. data/lib/decidim/events.rb +2 -0
  218. data/lib/decidim/events/author_event.rb +41 -0
  219. data/lib/decidim/events/base_event.rb +28 -3
  220. data/lib/decidim/events/email_event.rb +1 -1
  221. data/lib/decidim/events/notification_event.rb +1 -1
  222. data/lib/decidim/events/simple_event.rb +79 -0
  223. data/lib/decidim/filter_form_builder.rb +2 -3
  224. data/lib/decidim/form_builder.rb +39 -27
  225. data/lib/decidim/friendly_dates.rb +26 -0
  226. data/lib/decidim/has_feature.rb +1 -0
  227. data/lib/decidim/has_reference.rb +1 -1
  228. data/lib/decidim/i18n_exceptions.rb +1 -3
  229. data/lib/decidim/menu.rb +1 -1
  230. data/lib/decidim/newsletter_encryptor.rb +22 -0
  231. data/lib/decidim/nicknamizable.rb +56 -0
  232. data/lib/decidim/participable.rb +8 -0
  233. data/lib/decidim/participatory_space_manifest.rb +10 -1
  234. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.gl.js +13 -0
  235. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.pt-br.js +14 -0
  236. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.pt.js +5 -1
  237. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.ru.js +4 -1
  238. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.sv.js +14 -0
  239. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.uk.js +4 -1
  240. data/vendor/assets/javascripts/form_datepicker.js.es6 +4 -2
  241. data/vendor/assets/javascripts/foundation-datepicker.js +42 -26
  242. metadata +124 -84
  243. data/app/assets/javascripts/decidim/select2.field.js.es6 +0 -47
  244. data/app/assets/javascripts/decidim/select2.js.es6 +0 -11
  245. data/app/assets/stylesheets/decidim/editor.sass +0 -4
  246. data/app/assets/stylesheets/decidim/plugins/_select2.scss +0 -63
  247. data/app/helpers/decidim/datetime_helper.rb +0 -23
  248. data/app/queries/decidim/freetext_scopes.rb +0 -39
  249. data/lib/decidim/core/test/shared_examples/manage_moderations_examples.rb +0 -64
@@ -36,10 +36,11 @@ shared_examples "manage announcements" do
36
36
 
37
37
  it "customize an announcement for the current step and it has more priority" do
38
38
  visit edit_feature_path(current_feature)
39
+ step_id = current_feature.participatory_space.steps.first.id
39
40
 
40
41
  fill_in_i18n_editor(
41
- :feature_step_settings_1_announcement,
42
- "#step-1-settings-announcement-tabs",
42
+ :"feature_step_settings_#{step_id}_announcement",
43
+ "#step-#{step_id}-settings-announcement-tabs",
43
44
  en: "An announcement for this step",
44
45
  es: "Un aviso para esta fase",
45
46
  ca: "Un avís per a aquesta fase"
@@ -23,12 +23,14 @@ shared_examples "comments" do
23
23
  end
24
24
  end
25
25
 
26
- it "allows user to sort the comments" do
26
+ it "allows user to sort the comments", :slow do
27
27
  comment = create(:comment, commentable: commentable, body: "Most Rated Comment")
28
28
  create(:comment_vote, comment: comment, author: user, weight: 1)
29
29
 
30
30
  visit resource_path
31
31
 
32
+ expect(page).to have_no_content("Comments are disabled at this time")
33
+
32
34
  expect(page).to have_css(".comment", minimum: 1)
33
35
  page.find(".order-by .dropdown.menu .is-dropdown-submenu-parent").hover
34
36
 
@@ -88,7 +90,7 @@ shared_examples "comments" do
88
90
  end
89
91
  end
90
92
 
91
- context "when a user replies to a comment" do
93
+ context "when a user replies to a comment", :slow do
92
94
  let!(:comment_author) { create(:user, :confirmed, organization: organization) }
93
95
  let!(:comment) { create(:comment, commentable: commentable, author: comment_author) }
94
96
 
@@ -99,6 +101,7 @@ shared_examples "comments" do
99
101
 
100
102
  within "#comments #comment_#{comment.id}" do
101
103
  click_button "Reply"
104
+ expect(page).to have_selector(".add-comment")
102
105
  fill_in "add-comment-Decidim::Comments::Comment-#{comment.id}", with: "This is a reply"
103
106
  click_button "Send"
104
107
  end
@@ -10,13 +10,19 @@ shared_examples "scope helpers" do
10
10
  let(:scope) { create(:scope, organization: organization) }
11
11
  let(:resource) { create(:dummy_resource, feature: feature, scope: scope) }
12
12
 
13
- subject { helper.has_visible_scopes?(resource) }
14
-
15
13
  before do
16
14
  allow(helper).to receive(:current_participatory_space).and_return(participatory_space)
17
15
  end
16
+ let(:helper) do
17
+ Class.new.tap do |v|
18
+ v.extend(Decidim::ScopesHelper)
19
+ v.extend(Decidim::TranslationsHelper)
20
+ end
21
+ end
18
22
 
19
23
  describe "has_visible_scopes?" do
24
+ subject { helper.has_visible_scopes?(resource) }
25
+
20
26
  context "when all conditions are met" do
21
27
  it { is_expected.to be_truthy }
22
28
  end
@@ -26,8 +32,13 @@ shared_examples "scope helpers" do
26
32
  it { is_expected.to be_falsey }
27
33
  end
28
34
 
29
- context "when the process has a scope" do
35
+ context "when the process has a different scope than the organization" do
30
36
  let(:participatory_space_scope) { create(:scope, organization: organization) }
37
+ it { is_expected.to be_truthy }
38
+ end
39
+
40
+ context "when the process has the same scope as the organization" do
41
+ let(:participatory_space_scope) { scope }
31
42
  it { is_expected.to be_falsey }
32
43
  end
33
44
 
@@ -36,4 +47,30 @@ shared_examples "scope helpers" do
36
47
  it { is_expected.to be_falsey }
37
48
  end
38
49
  end
50
+
51
+ describe "scope_name_for_picker" do
52
+ let(:global_name) { "Global name" }
53
+ subject { helper.scope_name_for_picker(scope, global_name) }
54
+
55
+ context "when a scope is given" do
56
+ context "when the scope has a scope type" do
57
+ it { is_expected.to include(scope.name["en"]) }
58
+ it { is_expected.to include(scope.scope_type.name["en"]) }
59
+ end
60
+
61
+ context "when the scope has no type" do
62
+ before do
63
+ scope.scope_type = nil
64
+ end
65
+
66
+ it { is_expected.to eq(scope.name["en"]) }
67
+ end
68
+ end
69
+
70
+ context "when no scope is given" do
71
+ let(:scope) { nil }
72
+
73
+ it { is_expected.to eq("Global name") }
74
+ end
75
+ end
39
76
  end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_context "simple event" do
6
+ subject do
7
+ described_class.new(
8
+ resource: resource,
9
+ event_name: event_name,
10
+ user: user,
11
+ extra: extra
12
+ )
13
+ end
14
+
15
+ let(:organization) do
16
+ if resource.respond_to?(:organization)
17
+ resource.organization
18
+ else
19
+ create :organization
20
+ end
21
+ end
22
+ let(:user) { create :user, organization: organization }
23
+ let(:extra) { {} }
24
+ let(:resource_path) { resource_locator(resource).path }
25
+ let(:resource_url) { resource_locator(resource).url }
26
+ let(:resource_title) { resource.title["en"] }
27
+ let(:author) { resource.author }
28
+ let(:author_presenter) { Decidim::UserPresenter.new(author) }
29
+ end
30
+
31
+ shared_examples_for "an simple event" do
32
+ describe "types" do
33
+ subject { described_class }
34
+
35
+ it "supports notifications" do
36
+ expect(subject.types).to include :notification
37
+ end
38
+
39
+ it "supports emails" do
40
+ expect(subject.types).to include :email
41
+ end
42
+ end
43
+
44
+ describe "email_subject" do
45
+ it "is generated correctly" do
46
+ expect(subject.email_subject).to be_kind_of(String)
47
+ end
48
+ end
49
+
50
+ describe "email_intro" do
51
+ it "is generated correctly" do
52
+ expect(subject.email_intro).to be_kind_of(String)
53
+ end
54
+ end
55
+
56
+ describe "email_outro" do
57
+ it "is generated correctly" do
58
+ expect(subject.email_outro).to be_kind_of(String)
59
+ end
60
+ end
61
+
62
+ describe "email_greeting" do
63
+ it "is generated correctly" do
64
+ expect(subject.email_greeting).to be_kind_of(String)
65
+ end
66
+ end
67
+
68
+ describe "notification_title" do
69
+ it "is generated correctly" do
70
+ expect(subject.notification_title).to be_kind_of(String)
71
+ end
72
+ end
73
+ end
@@ -4,7 +4,7 @@ module Decidim
4
4
  # This holds the decidim-core version.
5
5
  module Core
6
6
  def self.version
7
- "0.8.4"
7
+ "0.9.0"
8
8
  end
9
9
  end
10
10
  end
@@ -5,5 +5,7 @@ module Decidim
5
5
  autoload :BaseEvent, "decidim/events/base_event"
6
6
  autoload :EmailEvent, "decidim/events/email_event"
7
7
  autoload :NotificationEvent, "decidim/events/notification_event"
8
+ autoload :SimpleEvent, "decidim/events/simple_event"
9
+ autoload :AuthorEvent, "decidim/events/author_event"
8
10
  end
9
11
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Events
5
+ # This module is used to be included in event classes inheriting from SimpleEvent
6
+ # whose resource has an author.
7
+ #
8
+ # It adds the author_name, author_nickname, author_path and author_url to the i18n interpolations.
9
+ module AuthorEvent
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ i18n_attributes :author_name, :author_nickname, :author_path, :author_url
14
+
15
+ def author_nickname
16
+ author_presenter.nickname
17
+ end
18
+
19
+ def author_name
20
+ author_presenter.name
21
+ end
22
+
23
+ def author_path
24
+ author_presenter.profile_path
25
+ end
26
+
27
+ def author_url
28
+ author_presenter.profile_url
29
+ end
30
+
31
+ def author_presenter
32
+ @author ||= Decidim::UserPresenter.new(author)
33
+ end
34
+
35
+ def author
36
+ resource.author if resource.respond_to?(:author)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -6,6 +6,9 @@ module Decidim
6
6
  # add more logic to a `Decidim::Notification` and are used to render them in the
7
7
  # notifications dashboard and to generate other notifications (emails, for example).
8
8
  class BaseEvent
9
+ class_attribute :types
10
+ self.types = []
11
+
9
12
  # Public: Stores all the notification types this event can create. Please, do not
10
13
  # overwrite this method, consider it final. Instead, add values to the array via
11
14
  # modules, take the `NotificationEvent` module as an example:
@@ -16,7 +19,7 @@ module Decidim
16
19
  # extend ActiveSupport::Concern
17
20
  #
18
21
  # included do
19
- # types << :web_push_notifications
22
+ # type :web_push_notifications
20
23
  # end
21
24
  # end
22
25
  #
@@ -25,8 +28,8 @@ module Decidim
25
28
  # end
26
29
  #
27
30
  # MyEvent.types # => [:web_push_notifications]
28
- def self.types
29
- @types ||= []
31
+ def self.type(type)
32
+ self.types += Array(type)
30
33
  end
31
34
 
32
35
  # Initializes the class.
@@ -58,10 +61,32 @@ module Decidim
58
61
  @resource_url ||= resource_locator.url
59
62
  end
60
63
 
64
+ # Whether this event should be notified or not. Useful when you want the
65
+ # event to decide based on the params.
66
+ #
67
+ # It returns false when the resource or any element in the chain is a
68
+ # `Decidim::Publicable` and it isn't published.
69
+ def notifiable?
70
+ return false if resource.is_a?(Decidim::Publicable) && !resource.published?
71
+ return false if participatory_space.is_a?(Decidim::Publicable) && !participatory_space&.published?
72
+ return false unless feature&.published?
73
+
74
+ true
75
+ end
76
+
61
77
  private
62
78
 
63
79
  attr_reader :event_name, :resource, :user, :extra
64
80
 
81
+ def feature
82
+ return resource.feature if resource.is_a?(Decidim::HasFeature)
83
+ return resource if resource.is_a?(Decidim::Feature)
84
+ end
85
+
86
+ def participatory_space
87
+ return feature.participatory_space if feature
88
+ end
89
+
65
90
  def resource_title
66
91
  resource.title.is_a?(Hash) ? resource.title[I18n.locale.to_s] : resource.title
67
92
  end
@@ -16,7 +16,7 @@ module Decidim
16
16
  extend ActiveSupport::Concern
17
17
 
18
18
  included do
19
- types << :email
19
+ type :email
20
20
 
21
21
  def email_subject
22
22
  I18n.t("decidim.events.email_event.email_subject", resource_title: resource_title)
@@ -17,7 +17,7 @@ module Decidim
17
17
  extend ActiveSupport::Concern
18
18
 
19
19
  included do
20
- types << :notification
20
+ type :notification
21
21
 
22
22
  def notification_title
23
23
  I18n.t(
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Events
5
+ # Extends the BaseEvent to add common features to most events so you don't
6
+ # need to write each time the same code.
7
+ #
8
+ # The only convention you need to keep in mind is that the event name will be
9
+ # used as the i18n scope to search for the keys.
10
+ class SimpleEvent < BaseEvent
11
+ include Decidim::Events::EmailEvent
12
+ include Decidim::Events::NotificationEvent
13
+
14
+ class_attribute :i18n_interpolations
15
+ self.i18n_interpolations = []
16
+
17
+ # Public: A method to add values to pass as interpolations to the I18n.t method.
18
+ #
19
+ # By default the resource_path, resource_title and resource_url are already included.
20
+ #
21
+ # attribute - A Symbol of the method name (and interpolation value) to add.
22
+ #
23
+ # Example:
24
+ #
25
+ # class MyEvent < Decidim::Events::SimpleEvent
26
+ # i18n_attributes :participatory_space_title
27
+ # end
28
+ def self.i18n_attributes(*attributes)
29
+ self.i18n_interpolations += Array(attributes)
30
+ end
31
+
32
+ def email_subject
33
+ I18n.t("email_subject", i18n_options).html_safe
34
+ end
35
+
36
+ def email_intro
37
+ I18n.t("email_intro", i18n_options).html_safe
38
+ end
39
+
40
+ def email_outro
41
+ I18n.t("email_outro", i18n_options).html_safe
42
+ end
43
+
44
+ def notification_title
45
+ I18n.t("notification_title", i18n_options).html_safe
46
+ end
47
+
48
+ # Public: The String to use as scope to search for the keys
49
+ # when using I18n.t
50
+ #
51
+ # By default is the same value as the event name.
52
+ def i18n_scope
53
+ event_name
54
+ end
55
+
56
+ # Public: The Hash of options to pass to the I18.t method.
57
+ def i18n_options
58
+ default_i18n_options.merge(event_interpolations)
59
+ end
60
+
61
+ private
62
+
63
+ def event_interpolations
64
+ Array(self.class.i18n_interpolations).inject({}) do |all, attribute|
65
+ all.update(attribute => send(attribute))
66
+ end
67
+ end
68
+
69
+ def default_i18n_options
70
+ {
71
+ resource_path: resource_path,
72
+ resource_title: resource_title,
73
+ resource_url: resource_url,
74
+ scope: i18n_scope
75
+ }
76
+ end
77
+ end
78
+ end
79
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable Metrics/ParameterLists
4
3
  require "decidim/form_builder"
5
4
 
6
5
  module Decidim
@@ -41,8 +40,8 @@ module Decidim
41
40
  end
42
41
  end
43
42
 
44
- # Wrap the scopes select in a custom fieldset.
45
- def scopes_select(method, options = {})
43
+ # Wrap the scopes picker in a custom fieldset.
44
+ def scopes_picker(method, options = {})
46
45
  fieldset_wrapper options[:legend_title] do
47
46
  super(method, options)
48
47
  end
@@ -25,6 +25,7 @@ module Decidim
25
25
  def collection_check_boxes(attribute, collection, value_attribute, text_attribute, options = {}, html_options = {})
26
26
  super + error_and_help_text(attribute, options)
27
27
  end
28
+ # rubocop:enable Metrics/ParameterLists
28
29
 
29
30
  # Public: Generates an form field for each locale.
30
31
  #
@@ -131,29 +132,28 @@ module Decidim
131
132
  select(name, @template.options_for_select(categories, selected: selected, disabled: disabled), options, html_options)
132
133
  end
133
134
 
134
- # Public: Generates a select field with the scopes.
135
+ # Public: Generates a picker field for scope selection.
135
136
  #
136
- # name - The name of the field (usually scope_id)
137
- # collection - A collection of scopes.
138
- # options - An optional Hash with options:
139
- # - prompt - An optional String with the text to display as prompt.
137
+ # name - The name of the field (usually scope_id)
138
+ # options - An optional Hash with options:
139
+ # - multiple - Multiple mode, to allow multiple scopes selection.
140
+ # - label - Show label?
141
+ #
142
+ # Also it should receive a block that returns a Hash with :url and :text for each selected scope (and for null scope for prompt)
140
143
  #
141
144
  # Returns a String.
142
- def scopes_select(name, options = {})
143
- selected = object.send(name)
144
- if selected.present?
145
- selected = selected.values if selected.is_a?(Hash)
146
- selected = [selected] unless selected.is_a?(Array)
147
- scopes = Decidim::Scope.where(id: selected.map(&:to_i)).map { |scope| [scope.name[I18n.locale.to_s], scope.id] }
148
- else
149
- scopes = []
150
- end
151
- prompt = options.delete(:prompt)
152
- remote_path = options.delete(:remote_path) || false
153
- multiple = options.delete(:multiple) || false
154
- html_options = { multiple: multiple, class: "select2", "data-remote-path" => remote_path, "data-placeholder" => prompt }
145
+ def scopes_picker(attribute, options = {})
146
+ picker_options = { id: "#{@object_name}_#{attribute}", class: "picker-#{options[:multiple] ? "multiple" : "single"}",
147
+ name: "#{@object_name}[#{attribute}]" }
148
+ picker_options[:class] += " is-invalid-input" if error?(attribute)
155
149
 
156
- select(name, @template.options_for_select(scopes, selected: selected), options, html_options)
150
+ prompt_params = yield(nil)
151
+ scopes = selected_scopes(attribute).map { |scope| [scope, yield(scope)] }
152
+ template = ""
153
+ template += label(attribute, label_for(attribute) + required_for_attribute(attribute)) unless options[:label] == false
154
+ template += @template.render("decidim/scopes/scopes_picker_input", picker_options: picker_options, prompt_params: prompt_params, scopes: scopes)
155
+ template += error_and_help_text(attribute, options)
156
+ template.html_safe
157
157
  end
158
158
 
159
159
  # Public: Override so checkboxes are rendered before the label.
@@ -259,6 +259,17 @@ module Decidim
259
259
  template.html_safe
260
260
  end
261
261
 
262
+ # Public: Returns the translated name for the given attribute.
263
+ #
264
+ # attribute - The String name of the attribute to return the name.
265
+ def label_for(attribute)
266
+ if object.class.respond_to?(:human_attribute_name)
267
+ object.class.human_attribute_name(attribute)
268
+ else
269
+ attribute.to_s.humanize
270
+ end
271
+ end
272
+
262
273
  private
263
274
 
264
275
  # Private: Override from FoundationRailsHelper in order to render
@@ -461,14 +472,6 @@ module Decidim
461
472
  end
462
473
  end
463
474
 
464
- def label_for(attribute)
465
- if object.class.respond_to?(:human_attribute_name)
466
- object.class.human_attribute_name(attribute)
467
- else
468
- attribute.to_s.humanize
469
- end
470
- end
471
-
472
475
  def name_with_locale(name, locale)
473
476
  "#{name}_#{locale.to_s.gsub("-", "__")}"
474
477
  end
@@ -506,5 +509,14 @@ module Decidim
506
509
  end
507
510
  "".html_safe
508
511
  end
512
+
513
+ # Private: Returns an array of scopes related to object attribute
514
+ def selected_scopes(attribute)
515
+ selected = object.send(attribute) || []
516
+ selected = selected.values if selected.is_a?(Hash)
517
+ selected = [selected] unless selected.is_a?(Array)
518
+ selected = Decidim::Scope.where(id: selected.map(&:to_i)) unless selected.first.is_a?(Decidim::Scope)
519
+ selected
520
+ end
509
521
  end
510
522
  end