decidim-core 0.0.8.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/decidim_core_manifest.js +0 -1
  3. data/app/assets/javascripts/decidim/form_filter.component.js.es6 +12 -2
  4. data/app/assets/stylesheets/decidim/_decidim.scss +1 -2
  5. data/app/assets/stylesheets/decidim/extras/_embed.scss +21 -0
  6. data/app/assets/stylesheets/decidim/modules/_cards.scss +1 -1
  7. data/app/assets/stylesheets/decidim/modules/_icons.scss +1 -1
  8. data/app/commands/decidim/create_registration.rb +1 -1
  9. data/app/commands/decidim/invite_user.rb +7 -8
  10. data/app/controllers/concerns/decidim/filter_resource.rb +2 -3
  11. data/app/controllers/concerns/decidim/payload_info.rb +1 -1
  12. data/app/controllers/decidim/authorizations_controller.rb +0 -4
  13. data/app/controllers/decidim/pages_controller.rb +8 -11
  14. data/app/controllers/decidim/participatory_process_groups_controller.rb +1 -1
  15. data/app/controllers/decidim/participatory_process_widgets_controller.rb +4 -0
  16. data/app/controllers/decidim/widgets_controller.rb +7 -3
  17. data/app/forms/decidim/registration_form.rb +4 -4
  18. data/app/helpers/decidim/layout_helper.rb +1 -1
  19. data/app/helpers/decidim/map_helper.rb +21 -21
  20. data/app/helpers/decidim/resource_helper.rb +4 -4
  21. data/app/helpers/decidim/widget_urls_helper.rb +2 -2
  22. data/app/mailers/decidim/export_mailer.rb +29 -0
  23. data/app/middleware/decidim/current_organization.rb +1 -1
  24. data/app/models/decidim/feature.rb +5 -0
  25. data/app/models/decidim/organization.rb +1 -1
  26. data/app/models/decidim/participatory_process.rb +1 -1
  27. data/app/models/decidim/user.rb +1 -1
  28. data/app/presenters/decidim/home_stats_presenter.rb +74 -0
  29. data/app/queries/decidim/stats_users_count.rb +24 -0
  30. data/app/services/decidim/public_processes.rb +4 -2
  31. data/app/services/decidim/resource_search.rb +1 -1
  32. data/app/services/decidim/static_map_generator.rb +1 -3
  33. data/app/uploaders/decidim/image_uploader.rb +1 -1
  34. data/app/views/decidim/export_mailer/export.html.erb +1 -0
  35. data/app/views/decidim/participatory_process_widgets/show.html.erb +16 -27
  36. data/app/views/decidim/participatory_processes/show.html.erb +7 -7
  37. data/app/views/decidim/widgets/show.js.erb +27 -17
  38. data/app/views/layouts/decidim/widget.html.erb +55 -3
  39. data/app/views/pages/home/_statistics.html.erb +2 -10
  40. data/config/i18n-tasks.yml +1 -0
  41. data/config/initializers/devise.rb +11 -4
  42. data/config/locales/ca.yml +14 -3
  43. data/config/locales/en.yml +14 -3
  44. data/config/locales/es.yml +13 -2
  45. data/config/locales/eu.yml +0 -2
  46. data/config/locales/fi.yml +0 -2
  47. data/config/locales/fr.yml +386 -1
  48. data/config/locales/nl.yml +1 -3
  49. data/db/seeds.rb +1 -1
  50. data/lib/decidim/core.rb +10 -2
  51. data/lib/decidim/core/api/decidim_type.rb +4 -0
  52. data/lib/decidim/core/api/translated_field_type.rb +2 -2
  53. data/lib/decidim/core/engine.rb +13 -0
  54. data/lib/decidim/core/test/shared_examples/comments_examples.rb +16 -18
  55. data/lib/decidim/core/test/shared_examples/manage_moderations_examples.rb +2 -2
  56. data/lib/decidim/core/test/shared_examples/reports_examples.rb +9 -9
  57. data/lib/decidim/core/version.rb +1 -1
  58. data/lib/decidim/exporters.rb +9 -0
  59. data/lib/decidim/exporters/csv.rb +54 -0
  60. data/lib/decidim/exporters/export_data.rb +22 -0
  61. data/lib/decidim/exporters/exporter.rb +28 -0
  62. data/lib/decidim/exporters/json.rb +22 -0
  63. data/lib/decidim/feature_manifest.rb +18 -0
  64. data/lib/decidim/file_zipper.rb +28 -0
  65. data/lib/decidim/form_builder.rb +27 -14
  66. data/lib/decidim/has_reference.rb +1 -1
  67. data/lib/decidim/i18n_exceptions.rb +3 -2
  68. data/lib/decidim/query_extensions.rb +1 -1
  69. data/lib/decidim/reportable.rb +1 -1
  70. data/lib/decidim/resource_manifest.rb +0 -7
  71. data/lib/decidim/stats_registry.rb +110 -0
  72. data/vendor/assets/javascripts/form_datepicker.js.es6 +3 -1
  73. metadata +53 -29
  74. data/app/assets/stylesheets/decidim/widget.scss.erb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3668d75cf2fd8dbfe3c88982c0a7aa8593a75cb4
4
- data.tar.gz: acc926a4029093ffe432873e2098a147873dc478
3
+ metadata.gz: abd55b4bc86a454e483127b15d235ed2a056e718
4
+ data.tar.gz: 4d29c9e66aea8a4c43110cda9b6487310d5c8429
5
5
  SHA512:
6
- metadata.gz: 3a06d36ae7005c0e40ead54624635638e0c5f21a07049a68ab35f050d79fe96dc4be797c18065cc6abef48422feb397aa745549a0bb2c9d5964b3a1cd1d85a43
7
- data.tar.gz: 75ebe0193d06c570996545553101d291d77727e4c53bd5944d8845214cd7f68f66a9907e83c1ffe9961ae2d65c9722e0c062cb37c9b9c13da1655230cd99bf74
6
+ metadata.gz: a2e6c3415e64aa2e6430062cfca573d1aef0e28dc42d04ff7dec6332e7018b20672d9e76c1efd95974c5d6f1f362655515c3fa96d5d813364e178b0dc1f259cf
7
+ data.tar.gz: df609842f94d94b53b37c5611988c853f710453bc5e2a98b46bd370c39879a867f9764c5ee3adf1ecbff4614030a20d7e22ce614fa19eafdc3d64962cb8d6158
@@ -6,5 +6,4 @@
6
6
  //= link decidim/map.js
7
7
  //= link decidim/map.css
8
8
  //= link_directory ../../../vendor/assets/javascripts/datepicker-locales
9
- //= link decidim/widget.css
10
9
  //= link decidim/widget.js
@@ -9,6 +9,7 @@
9
9
  class FormFilterComponent {
10
10
  constructor($form) {
11
11
  this.$form = $form;
12
+ this.id = this.$form.attr('id') || this._getUID();
12
13
  this.mounted = false;
13
14
 
14
15
  this._onFormChange = this._onFormChange.bind(this);
@@ -24,7 +25,7 @@
24
25
  if (this.mounted) {
25
26
  this.mounted = false;
26
27
  this.$form.off('change', 'input, select', this._onFormChange);
27
- exports.Decidim.History.unregisterCallback(`filters-${this.$form.attr('id')}`)
28
+ exports.Decidim.History.unregisterCallback(`filters-${this.id}`)
28
29
  }
29
30
  }
30
31
 
@@ -37,7 +38,7 @@
37
38
  if (this.$form.length > 0 && !this.mounted) {
38
39
  this.mounted = true;
39
40
  this.$form.on('change', 'input, select', this._onFormChange);
40
- exports.Decidim.History.registerCallback(`filters-${this.$form.attr('id')}`, () => {
41
+ exports.Decidim.History.registerCallback(`filters-${this.id}`, () => {
41
42
  this._onPopState();
42
43
  });
43
44
  }
@@ -187,6 +188,15 @@
187
188
 
188
189
  exports.Decidim.History.pushState(newUrl);
189
190
  }
191
+
192
+ /**
193
+ * Generates a unique identifier for the form.
194
+ * @private
195
+ * @returns {String} - Returns a unique identifier
196
+ */
197
+ _getUID() {
198
+ return `filter-form-${new Date().setUTCMilliseconds()}-${Math.floor(Math.random() * 10000000)}`;
199
+ }
190
200
  }
191
201
 
192
202
  exports.Decidim = exports.Decidim || {};
@@ -1,4 +1,3 @@
1
- //@import compass
2
1
  @import "variables";
3
2
  @import "utils/*";
4
3
 
@@ -7,4 +6,4 @@
7
6
 
8
7
  @import "modules/modules";
9
8
  @import "layouts/*";
10
- @import "extras/*";
9
+ @import "extras/*";
@@ -9,3 +9,24 @@
9
9
  overflow-y: auto;
10
10
  }
11
11
  }
12
+
13
+ $widget-padding: 8px;
14
+
15
+ body.widget {
16
+ background: #fff;
17
+ padding: $widget-padding;
18
+ margin: 0;
19
+
20
+ .participatory-process{
21
+ margin-bottom: $widget-padding;
22
+ }
23
+
24
+ .card {
25
+ margin: 0;
26
+ }
27
+
28
+ .organization {
29
+ margin-top: $widget-padding;
30
+ text-align: right;
31
+ }
32
+ }
@@ -73,8 +73,8 @@ $datetime-bg: $primary;
73
73
  font-weight: 800;
74
74
  letter-spacing: .05em;
75
75
  color: $muted;
76
- align-self: flex-start;
77
76
  display: flex;
77
+ align-self: flex-start;
78
78
  align-items: center;
79
79
  .icon{
80
80
  width: 14px;
@@ -29,4 +29,4 @@ a:hover .icon--action{
29
29
  margin-bottom: -2px;
30
30
  width: 12px;
31
31
  height: 12px;
32
- }
32
+ }
@@ -21,7 +21,7 @@ module Decidim
21
21
 
22
22
  transaction do
23
23
  create_user
24
- create_user_group if form.is_user_group?
24
+ create_user_group if form.user_group?
25
25
  end
26
26
 
27
27
  broadcast(:ok, @user)
@@ -36,14 +36,13 @@ module Decidim
36
36
 
37
37
  def invite_user
38
38
  @user = Decidim::User.create(
39
- {
40
- name: form.name,
41
- email: form.email.downcase,
42
- organization: form.organization,
43
- roles: form.roles,
44
- comments_notifications: true,
45
- replies_notifications: true
46
- })
39
+ name: form.name,
40
+ email: form.email.downcase,
41
+ organization: form.organization,
42
+ roles: form.roles,
43
+ comments_notifications: true,
44
+ replies_notifications: true
45
+ )
47
46
  @user.invite!(
48
47
  form.invited_by,
49
48
  invitation_instructions: form.invitation_instructions
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # rubocop:disable Metrics/BlockLength
3
2
  require "active_support/concern"
4
3
 
5
4
  module Decidim
@@ -16,11 +15,11 @@ module Decidim
16
15
  end
17
16
 
18
17
  def method_missing(method_name, *_arguments)
19
- @filter.present? && @filter.key?(method_name) ? @filter[method_name] : super
18
+ @filter.present? && @filter.has_key?(method_name) ? @filter[method_name] : super
20
19
  end
21
20
 
22
21
  def respond_to_missing?(method_name, include_private = false)
23
- @filter.present? && @filter.key?(method_name) || super
22
+ @filter.present? && @filter.has_key?(method_name) || super
24
23
  end
25
24
  end
26
25
 
@@ -16,7 +16,7 @@ module Decidim
16
16
  payload[:referer] = request.referer.to_s
17
17
  payload[:request_id] = request.uuid
18
18
  payload[:user_agent] = request.user_agent
19
- payload[:xhr] = request.xhr? ? 'true' : 'false'
19
+ payload[:xhr] = request.xhr? ? "true" : "false"
20
20
  end
21
21
  end
22
22
  end
@@ -49,10 +49,6 @@ module Decidim
49
49
  @handler ||= AuthorizationHandler.handler_for(handler_name, handler_params)
50
50
  end
51
51
 
52
- def handlers
53
- @handlers ||= Decidim.authorization_handlers
54
- end
55
-
56
52
  protected
57
53
 
58
54
  def stored_location
@@ -11,7 +11,7 @@ module Decidim
11
11
 
12
12
  authorize_resource :public_pages, class: false
13
13
  delegate :page, to: :page_finder
14
- helper_method :page, :promoted_participatory_processes, :highlighted_participatory_processes, :participatory_processes, :users
14
+ helper_method :page, :promoted_participatory_processes, :highlighted_participatory_processes, :stats
15
15
 
16
16
  def index
17
17
  @pages = current_organization.static_pages.all.to_a.sort do |a, b|
@@ -23,21 +23,18 @@ module Decidim
23
23
  @page_finder ||= Decidim::PageFinder.new(params[:id], current_organization)
24
24
  end
25
25
 
26
- def users
27
- @users ||= Decidim::User.where(organization: current_organization)
28
- end
29
-
30
- # This should be deleted once the statistics are done properly.
31
- def participatory_processes
32
- @processes ||= OrganizationParticipatoryProcesses.new(current_organization) | PublicParticipatoryProcesses.new
33
- end
34
-
35
26
  def promoted_participatory_processes
36
- @promoted_processes ||= participatory_processes | PromotedParticipatoryProcesses.new
27
+ @promoted_processes ||= OrganizationParticipatoryProcesses.new(current_organization) | PublicParticipatoryProcesses.new | PromotedParticipatoryProcesses.new
37
28
  end
38
29
 
39
30
  def highlighted_participatory_processes
40
31
  @promoted_processes ||= OrganizationParticipatoryProcesses.new(current_organization) | HighlightedParticipatoryProcesses.new
41
32
  end
33
+
34
+ private
35
+
36
+ def stats
37
+ @stats ||= HomeStatsPresenter.new(organization: current_organization)
38
+ end
42
39
  end
43
40
  end
@@ -14,7 +14,7 @@ module Decidim
14
14
  def participatory_processes
15
15
  @participatory_processes ||= group.participatory_processes.published
16
16
  end
17
- alias_method :collection, :participatory_processes
17
+ alias collection participatory_processes
18
18
 
19
19
  def group
20
20
  Decidim::ParticipatoryProcessGroup.find(params[:id])
@@ -10,6 +10,10 @@ module Decidim
10
10
  @model ||= ParticipatoryProcess.find(params[:participatory_process_id])
11
11
  end
12
12
 
13
+ def current_participatory_process
14
+ model
15
+ end
16
+
13
17
  def iframe_url
14
18
  @iframe_url ||= participatory_process_participatory_process_widget_url(model)
15
19
  end
@@ -3,12 +3,12 @@
3
3
  module Decidim
4
4
  class WidgetsController < Decidim::ApplicationController
5
5
  skip_authorization_check only: :show
6
- skip_before_filter :verify_authenticity_token
6
+ skip_before_action :verify_authenticity_token
7
7
  after_action :allow_iframe, only: :show
8
8
 
9
- layout 'decidim/widget'
9
+ layout "decidim/widget"
10
10
 
11
- helper_method :iframe_url
11
+ helper_method :model, :iframe_url, :current_participatory_process
12
12
 
13
13
  def show
14
14
  respond_to do |format|
@@ -19,6 +19,10 @@ module Decidim
19
19
 
20
20
  private
21
21
 
22
+ def current_participatory_process
23
+ @current_participatory_process ||= model.feature.participatory_process
24
+ end
25
+
22
26
  def iframe_url
23
27
  raise NotImplementedError
24
28
  end
@@ -23,13 +23,13 @@ module Decidim
23
23
  validates :password, presence: true, confirmation: true, length: { in: Decidim::User.password_length }
24
24
  validates :tos_agreement, allow_nil: false, acceptance: true
25
25
 
26
- validates :user_group_name, presence: true, if: :is_user_group?
27
- validates :user_group_document_number, presence: true, if: :is_user_group?
28
- validates :user_group_phone, presence: true, if: :is_user_group?
26
+ validates :user_group_name, presence: true, if: :user_group?
27
+ validates :user_group_document_number, presence: true, if: :user_group?
28
+ validates :user_group_phone, presence: true, if: :user_group?
29
29
 
30
30
  validate :email_unique_in_organization
31
31
 
32
- def is_user_group?
32
+ def user_group?
33
33
  sign_up_as == "user_group"
34
34
  end
35
35
 
@@ -44,7 +44,7 @@ module Decidim
44
44
  html_properties["class"] = (["icon--#{name}"] + _icon_classes(options)).join(" ")
45
45
 
46
46
  content_tag :svg, html_properties do
47
- content_tag :use, nil, "xlink:href" => "#{asset_url("decidim/icons.svg")}#icon-#{name}"
47
+ content_tag :use, nil, "xlink:href" => "#{asset_path("decidim/icons.svg")}#icon-#{name}"
48
48
  end
49
49
  end
50
50
 
@@ -9,32 +9,32 @@ module Decidim
9
9
  # options - An optional hash of options (default: { zoom: 17 })
10
10
  # * zoom: A number to represent the zoom value of the map
11
11
  def static_map_link(resource, options = {})
12
- if resource.geocoded?
13
- zoom = options[:zoom] || 17
14
- latitude = resource.latitude
15
- longitude = resource.longitude
12
+ return unless resource.geocoded?
16
13
 
17
- map_url = "https://www.openstreetmap.org/?mlat=#{latitude}&mlon=#{longitude}#map=#{zoom}/#{latitude}/#{longitude}"
14
+ zoom = options[:zoom] || 17
15
+ latitude = resource.latitude
16
+ longitude = resource.longitude
18
17
 
19
- link_to map_url, target: "_blank" do
20
- image_tag decidim.static_map_path(sgid: resource.to_sgid.to_s)
21
- end
18
+ map_url = "https://www.openstreetmap.org/?mlat=#{latitude}&mlon=#{longitude}#map=#{zoom}/#{latitude}/#{longitude}"
19
+
20
+ link_to map_url, target: "_blank" do
21
+ image_tag decidim.static_map_path(sgid: resource.to_sgid.to_s)
22
22
  end
23
23
  end
24
24
 
25
- def dynamic_map_for(markers_data, &block)
26
- if Decidim.geocoder.present?
27
- map_html_options = {
28
- class: "google-map",
29
- id: "map",
30
- "data-markers-data" => markers_data.to_json,
31
- "data-here-app-id" => Decidim.geocoder[:here_app_id],
32
- "data-here-app-code" => Decidim.geocoder[:here_app_code]
33
- }
34
- content = capture { block.call }
35
- content_tag :div, class: "row column" do
36
- content_tag(:div, "", map_html_options) + content
37
- end
25
+ def dynamic_map_for(markers_data)
26
+ return unless Decidim.geocoder.present?
27
+
28
+ map_html_options = {
29
+ class: "google-map",
30
+ id: "map",
31
+ "data-markers-data" => markers_data.to_json,
32
+ "data-here-app-id" => Decidim.geocoder[:here_app_id],
33
+ "data-here-app-code" => Decidim.geocoder[:here_app_code]
34
+ }
35
+ content = capture { yield }
36
+ content_tag :div, class: "row column" do
37
+ content_tag(:div, "", map_html_options) + content
38
38
  end
39
39
  end
40
40
  end
@@ -65,8 +65,8 @@ module Decidim
65
65
  def linked_classes_for(klass)
66
66
  return [] unless klass.respond_to?(:linked_classes_for)
67
67
 
68
- klass.linked_classes_for(current_feature).map do |klass|
69
- [klass.underscore, t(klass.demodulize.downcase, scope: "decidim.filters.linked_classes")]
68
+ klass.linked_classes_for(current_feature).map do |k|
69
+ [k.underscore, t(k.demodulize.downcase, scope: "decidim.filters.linked_classes")]
70
70
  end
71
71
  end
72
72
 
@@ -91,7 +91,7 @@ module Decidim
91
91
  # Returns a String.
92
92
  def _decidim_resource_route(resource, route_type, options)
93
93
  manifest = resource.class.resource_manifest
94
- engine = send(manifest.mounted_engine_name)
94
+ engine = manifest.feature_manifest.engine
95
95
 
96
96
  url_params = {
97
97
  id: resource.id,
@@ -99,7 +99,7 @@ module Decidim
99
99
  participatory_process_id: resource.feature.participatory_process.id
100
100
  }
101
101
 
102
- engine.send("#{manifest.route_name}_#{route_type}", url_params.merge(options))
102
+ engine.routes.url_helpers.send("#{manifest.route_name}_#{route_type}", url_params.merge(options))
103
103
  end
104
104
  end
105
105
  end
@@ -2,8 +2,8 @@
2
2
  module Decidim
3
3
  module WidgetUrlsHelper
4
4
  def embed_modal_for(url)
5
- js_embed_code = "#{content_tag(:script, '', src: url)}"
6
- embed_code = "#{content_tag(:noscript, content_tag(:iframe, '', src: url.gsub(".js", ".html"), frameborder: 0, scrolling: "vertical"))}"
5
+ js_embed_code = String.new(content_tag(:script, "", src: url))
6
+ embed_code = String.new(content_tag(:noscript, content_tag(:iframe, "", src: url.gsub(".js", ".html"), frameborder: 0, scrolling: "vertical")))
7
7
  render partial: "decidim/shared/embed_modal", locals: { js_embed_code: js_embed_code, embed_code: embed_code }
8
8
  end
9
9
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ # This mailer sends a notification email containing the export as an
4
+ # attachment.
5
+ class ExportMailer < ApplicationMailer
6
+ # Public: Sends a notification email with the result of an export in a
7
+ # zipped file.
8
+ #
9
+ # user - The user to be notified.
10
+ # name - The name of the export.
11
+ # export_data - The data containing the result of the export.
12
+ #
13
+ # Returns nothing.
14
+ def export(user, name, export_data)
15
+ @user = user
16
+ @organization = user.organization
17
+
18
+ original_file_name = "#{name}.#{export_data.extension}"
19
+
20
+ attachments["#{name}.zip"] = FileZipper.new(
21
+ original_file_name, export_data.read
22
+ ).zip
23
+
24
+ with_user(user) do
25
+ mail(to: "#{user.name} <#{user.email}>", subject: I18n.t("decidim.export_mailer.subject", name: original_file_name))
26
+ end
27
+ end
28
+ end
29
+ end
@@ -24,7 +24,7 @@ module Decidim
24
24
 
25
25
  location = new_location_for(env, organization.host)
26
26
 
27
- [301, { "Location" => location, 'Content-Type' => 'text/html', 'Content-Length' => '0'}, []]
27
+ [301, { "Location" => location, "Content-Type" => "text/html", "Content-Length" => "0" }, []]
28
28
  end
29
29
  end
30
30
 
@@ -81,6 +81,11 @@ module Decidim
81
81
  step_settings.fetch(active_step.id.to_s)
82
82
  end
83
83
 
84
+ # Public: Returns the value of the registered primary stat.
85
+ def primary_stat
86
+ @primary_stat ||= manifest.stats.filter(primary: true).with_context([self]).map { |name, value| [name, value] }.first&.last
87
+ end
88
+
84
89
  private
85
90
 
86
91
  def serialize_settings(schema, value)