decidim-reporting_proposals 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +32 -0
  3. data/.erb-lint.yml +30 -0
  4. data/.eslintignore +3 -0
  5. data/.eslintrc.json +239 -0
  6. data/.github/workflows/codeql-analysis.yml +74 -0
  7. data/.github/workflows/lint.yml +45 -0
  8. data/.github/workflows/test_integration.yml +125 -0
  9. data/.github/workflows/test_unit.yml +51 -0
  10. data/.gitignore +27 -0
  11. data/.rspec +3 -0
  12. data/.rubocop.yml +3 -0
  13. data/.rubocop_rails.yml +87 -0
  14. data/.rubocop_ruby.yml +1754 -0
  15. data/.ruby-version +1 -0
  16. data/.simplecov +13 -0
  17. data/CODE_OF_CONDUCT.md +74 -0
  18. data/Gemfile +40 -0
  19. data/Gemfile.lock +815 -0
  20. data/LICENSE-AGPLv3.txt +661 -0
  21. data/README.md +166 -0
  22. data/Rakefile +40 -0
  23. data/app/cells/decidim/reporting_proposals/edit_note_modal/show.erb +20 -0
  24. data/app/cells/decidim/reporting_proposals/edit_note_modal_cell.rb +37 -0
  25. data/app/commands/concerns/decidim/reporting_proposals/admin/create_category_override.rb +32 -0
  26. data/app/commands/concerns/decidim/reporting_proposals/admin/update_category_override.rb +32 -0
  27. data/app/commands/concerns/decidim/reporting_proposals/create_report_override.rb +19 -0
  28. data/app/commands/decidim/reporting_proposals/admin/update_proposal.rb +46 -0
  29. data/app/commands/decidim/reporting_proposals/admin/update_proposal_note.rb +36 -0
  30. data/app/commands/decidim/reporting_proposals/create_reporting_proposal.rb +68 -0
  31. data/app/controllers/concerns/decidim/reporting_proposals/admin/categories_controller_override.rb +16 -0
  32. data/app/controllers/concerns/decidim/reporting_proposals/admin/needs_header_snippets.rb +50 -0
  33. data/app/controllers/concerns/decidim/reporting_proposals/admin/proposal_answer_templates_controller_override.rb +18 -0
  34. data/app/controllers/concerns/decidim/reporting_proposals/admin/proposal_answers_controller_override.rb +35 -0
  35. data/app/controllers/concerns/decidim/reporting_proposals/admin/proposals_controller_override.rb +28 -0
  36. data/app/controllers/concerns/decidim/reporting_proposals/needs_proposal_extra_validations_snippets.rb +51 -0
  37. data/app/controllers/concerns/decidim/reporting_proposals/proposals_controller_override.rb +113 -0
  38. data/app/controllers/decidim/reporting_proposals/admin/application_controller.rb +18 -0
  39. data/app/controllers/decidim/reporting_proposals/admin/proposal_notes_controller.rb +38 -0
  40. data/app/controllers/decidim/reporting_proposals/admin/proposals_controller.rb +61 -0
  41. data/app/controllers/decidim/reporting_proposals/application_controller.rb +11 -0
  42. data/app/controllers/decidim/reporting_proposals/geolocation_controller.rb +32 -0
  43. data/app/forms/concerns/decidim/reporting_proposals/admin/category_form_override.rb +19 -0
  44. data/app/forms/concerns/decidim/reporting_proposals/form_builder_override.rb +48 -0
  45. data/app/forms/concerns/decidim/reporting_proposals/map_builder_override.rb +60 -0
  46. data/app/forms/decidim/reporting_proposals/admin/proposal_photo_form.rb +23 -0
  47. data/app/forms/decidim/reporting_proposals/proposal_form.rb +33 -0
  48. data/app/helpers/concerns/decidim/reporting_proposals/admin/proposals_helper_override.rb +63 -0
  49. data/app/helpers/concerns/decidim/reporting_proposals/proposal_wizard_helper_override.rb +61 -0
  50. data/app/jobs/decidim/reporting_proposals/assign_proposal_valuators_job.rb +51 -0
  51. data/app/models/concerns/decidim/reporting_proposals/category_override.rb +28 -0
  52. data/app/models/concerns/decidim/reporting_proposals/participatory_space_role_config/valuator_override.rb +17 -0
  53. data/app/models/concerns/decidim/reporting_proposals/participatory_space_user_role_override.rb +25 -0
  54. data/app/models/decidim/reporting_proposals/category_valuator.rb +28 -0
  55. data/app/overrides/decidim/admin/categories/_form/add_valuators_field.html.erb.deface +3 -0
  56. data/app/overrides/decidim/admin/categories/index/add_table_column_name.html.erb.deface +3 -0
  57. data/app/overrides/decidim/admin/categories/index/add_valuators.html.erb.deface +3 -0
  58. data/app/overrides/decidim/proposals/admin/proposal_notes/_proposal_notes/add_edit_link.html.erb.deface +3 -0
  59. data/app/overrides/decidim/proposals/admin/proposal_notes/_proposal_notes/add_links_to_note.html.erb.deface +3 -0
  60. data/app/overrides/decidim/proposals/admin/proposals/_proposal-tr/add_td_hide_action.html.erb.deface +3 -0
  61. data/app/overrides/decidim/proposals/admin/proposals/_proposal-tr/add_valuators_name.html.erb.deface +9 -0
  62. data/app/overrides/decidim/proposals/admin/proposals/_proposal-tr/replace_td_title.html.erb.deface +3 -0
  63. data/app/overrides/decidim/proposals/admin/proposals/show/add_photo_management.html.erb.deface +3 -0
  64. data/app/overrides/decidim/proposals/admin/proposals/show/add_send_email_btn.html.erb.deface +3 -0
  65. data/app/overrides/decidim/proposals/admin/proposals/show/remove_photos.html.erb.deface +4 -0
  66. data/app/overrides/decidim/proposals/admin/proposals/show/replace_valuators.html.erb.deface +3 -0
  67. data/app/overrides/decidim/proposals/proposals/_proposal_similar/add_distance_badge.html.erb.deface +5 -0
  68. data/app/overrides/decidim/proposals/proposals/_wizard_header/replace_title.html.erb.deface +14 -0
  69. data/app/overrides/decidim/proposals/proposals/edit/add_user_group.html.erb.deface +3 -0
  70. data/app/overrides/decidim/proposals/proposals/edit/replace_javascript.html.erb.deface +8 -0
  71. data/app/overrides/decidim/proposals/proposals/edit/replace_partial_edit_form_fields.html.erb.deface +3 -0
  72. data/app/overrides/decidim/proposals/proposals/edit_draft/add_user_group.html.erb.deface +3 -0
  73. data/app/overrides/decidim/proposals/proposals/edit_draft/replace_javascript.html.erb.deface +8 -0
  74. data/app/overrides/decidim/proposals/proposals/edit_draft/replace_partial_edit_form_fields.html.erb.deface +3 -0
  75. data/app/overrides/decidim/proposals/proposals/index/add_additional_button.html.erb.deface +3 -0
  76. data/app/overrides/decidim/proposals/proposals/new/remove_title.html.erb.deface +1 -0
  77. data/app/overrides/decidim/proposals/proposals/new/replace_body.html.erb.deface +3 -0
  78. data/app/overrides/decidim/proposals/proposals/new/replace_javascript.html.erb.deface +8 -0
  79. data/app/overrides/decidim/proposals/proposals/show/add_additional_button.html.erb.deface +3 -0
  80. data/app/overrides/layouts/decidim/_process_header_steps/always_show_new_proposals.html.erb.deface +3 -0
  81. data/app/packs/entrypoints/decidim_reporting_proposals.js +6 -0
  82. data/app/packs/entrypoints/decidim_reporting_proposals_camera.js +2 -0
  83. data/app/packs/entrypoints/decidim_reporting_proposals_geocoding.js +2 -0
  84. data/app/packs/entrypoints/decidim_reporting_proposals_js_validations.js +1 -0
  85. data/app/packs/entrypoints/decidim_reporting_proposals_list_component_admin.js +1 -0
  86. data/app/packs/entrypoints/decidim_reporting_proposals_manage_component_admin.js +1 -0
  87. data/app/packs/images/.keep +0 -0
  88. data/app/packs/src/decidim/reporting_proposals/proposal_extra_validations.js +89 -0
  89. data/app/packs/src/decidim/reporting_proposals/proposals/add_proposal.js +66 -0
  90. data/app/packs/src/decidim/reporting_proposals/reverse_geocoding.js +54 -0
  91. data/app/packs/src/decidim/reporting_proposals/user_camera_inputs.js +49 -0
  92. data/app/packs/stylesheets/decidim/reporting_proposals/geocoding_addons.scss +34 -0
  93. data/app/packs/stylesheets/decidim/reporting_proposals/list_component_admin.scss +27 -0
  94. data/app/packs/stylesheets/decidim/reporting_proposals/manage_component_admin.scss +31 -0
  95. data/app/packs/stylesheets/decidim/reporting_proposals/proposals/add_proposal.scss +12 -0
  96. data/app/packs/stylesheets/decidim/reporting_proposals/user_camera_inputs.scss +19 -0
  97. data/app/permissions/concerns/decidim/reporting_proposals/admin/permissions_override.rb +27 -0
  98. data/app/permissions/decidim/reporting_proposals/admin/permissions.rb +79 -0
  99. data/app/permissions/decidim/reporting_proposals/permissions.rb +17 -0
  100. data/app/queries/decidim/reporting_proposals/nearby_proposals.rb +57 -0
  101. data/app/serializers/decidim/reporting_proposals/proposal_serializer_override.rb +77 -0
  102. data/app/validators/concerns/decidim/reporting_proposals/component_validator_override.rb +25 -0
  103. data/app/views/decidim/proposals/admin/proposal_notes/_editing_note.html.erb +18 -0
  104. data/app/views/decidim/proposals/admin/proposal_notes/_proposal_notes_body.html.erb +6 -0
  105. data/app/views/decidim/proposals/admin/proposals/_send_email_button.html.erb +4 -0
  106. data/app/views/decidim/proposals/proposals/_additional_button.html.erb +6 -0
  107. data/app/views/decidim/reporting_proposals/admin/categories/_column_valuators.html.erb +1 -0
  108. data/app/views/decidim/reporting_proposals/admin/categories/_valuators.html.erb +1 -0
  109. data/app/views/decidim/reporting_proposals/admin/categories/_valuators_field.html.erb +7 -0
  110. data/app/views/decidim/reporting_proposals/admin/proposals/_photo_form.html.erb +24 -0
  111. data/app/views/decidim/reporting_proposals/admin/proposals/_photo_gallery.html.erb +21 -0
  112. data/app/views/decidim/reporting_proposals/admin/proposals/_photos.html.erb +14 -0
  113. data/app/views/decidim/reporting_proposals/admin/proposals/_proposal_td_hide.html.erb +20 -0
  114. data/app/views/decidim/reporting_proposals/admin/proposals/_proposal_td_title.html.erb +41 -0
  115. data/app/views/decidim/reporting_proposals/proposals/_additional_button_for_show.html.erb +6 -0
  116. data/app/views/decidim/reporting_proposals/proposals/_new_proposal_fields.html.erb +7 -0
  117. data/app/views/decidim/reporting_proposals/proposals/_reporting_proposal_fields.html.erb +113 -0
  118. data/app/views/decidim/reporting_proposals/proposals/_user_group.html.erb +5 -0
  119. data/bin/rails +6 -0
  120. data/bin/webpack-dev-server +6 -0
  121. data/codecov.yml +11 -0
  122. data/config/assets.rb +13 -0
  123. data/config/i18n-tasks.yml +13 -0
  124. data/config/locales/ca.yml +366 -0
  125. data/config/locales/de.yml +366 -0
  126. data/config/locales/en.yml +426 -0
  127. data/config/locales/es.yml +366 -0
  128. data/crowdin.yml +45 -0
  129. data/db/migrate/20221219151846_create_decidim_categories_valuators.rb +17 -0
  130. data/decidim-reporting_proposals.gemspec +34 -0
  131. data/lib/decidim/api/reporting_proposals_type.rb +10 -0
  132. data/lib/decidim/reporting_proposals/admin.rb +8 -0
  133. data/lib/decidim/reporting_proposals/admin_engine.rb +31 -0
  134. data/lib/decidim/reporting_proposals/component.rb +490 -0
  135. data/lib/decidim/reporting_proposals/config.rb +53 -0
  136. data/lib/decidim/reporting_proposals/engine.rb +96 -0
  137. data/lib/decidim/reporting_proposals/test/factories.rb +13 -0
  138. data/lib/decidim/reporting_proposals/version.rb +15 -0
  139. data/lib/decidim/reporting_proposals.rb +13 -0
  140. data/package-lock.json +7844 -0
  141. data/package.json +195 -0
  142. metadata +319 -0
@@ -0,0 +1,27 @@
1
+ .table__title-block {
2
+ display: flex;
3
+ align-items: flex-start;
4
+ }
5
+
6
+ .table__title-icon {
7
+ width: 20px;
8
+ padding: 3px;
9
+ margin-right: 5px;
10
+ float: left;
11
+ }
12
+
13
+ .table__list-title {
14
+ display: flex;
15
+ flex-direction: column;
16
+ align-items: start;
17
+ }
18
+
19
+ .table__list-title a {
20
+ text-align: start;
21
+ }
22
+
23
+ .help-text-overdue {
24
+ font-style: italic;
25
+ font-size: .8125rem;
26
+ text-align: start;
27
+ }
@@ -0,0 +1,31 @@
1
+ .global-settings,
2
+ .step-settings {
3
+ .readonly_container {
4
+ display: none;
5
+ }
6
+ }
7
+
8
+ .proposal-photo.gallery__item {
9
+ position: relative;
10
+ margin: 0 0 1rem;
11
+ border: 1px solid rgba(0, 0, 0, .2);
12
+ border-radius: 0;
13
+ background-color: white;
14
+ color: #202734;
15
+ }
16
+
17
+ .proposal-photo .thumbnail {
18
+ margin-bottom: 0;
19
+ }
20
+
21
+ .delete-proposal__button {
22
+ position: absolute;
23
+ right: 0;
24
+ top: 7px;
25
+ width: 2rem;
26
+ height: 2rem;
27
+ background: rgba(var(--primary-rgb), .8);
28
+ color: #fff;
29
+ border-radius: 50%;
30
+ text-align: center;
31
+ }
@@ -0,0 +1,12 @@
1
+ .has_no_address {
2
+ text-align: right;
3
+ }
4
+
5
+ .editor {
6
+ .form-error {
7
+ margin: -1rem 0 1rem;
8
+ font-size: .75rem;
9
+ font-weight: 600;
10
+ color: var(--alert);
11
+ }
12
+ }
@@ -0,0 +1,19 @@
1
+ button.user-device-camera {
2
+ border-radius: 4px !important;
3
+ max-height: 3rem;
4
+ }
5
+
6
+ .has_no_image {
7
+ margin-top: -1rem;
8
+ text-align: right;
9
+ }
10
+
11
+ @media only screen and (max-width: 596px) {
12
+ .gallery__container .input-group .input-group-button {
13
+ display: block;
14
+ }
15
+
16
+ .has_no_image {
17
+ margin-top: -.5rem;
18
+ }
19
+ }
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ReportingProposals
5
+ module Admin
6
+ module PermissionsOverride
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ private
11
+
12
+ def valuator_can_unassign_valuator_from_proposals?
13
+ can_unassign_valuator_from_proposals? if user == context.fetch(:valuator, nil)
14
+
15
+ can_add_valuators?
16
+ end
17
+
18
+ def can_add_valuators?
19
+ return unless permission_action.action == :assign_to_valuator && permission_action.subject == :proposals
20
+
21
+ toggle_allow(Decidim::ReportingProposals.valuators_assign_other_valuators)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ReportingProposals
5
+ module Admin
6
+ class Permissions < Decidim::Proposals::Admin::Permissions
7
+ def permissions
8
+ return permission_action if permission_action.scope != :admin
9
+ return permission_action unless user
10
+ return permission_action if current_organization != user.organization
11
+
12
+ hide_content_action?
13
+ edit_photos_action?
14
+ edit_proposal_note?
15
+ super
16
+ end
17
+
18
+ private
19
+
20
+ def current_organization
21
+ context[:proposal].try(:organization) || context[:current_organization]
22
+ end
23
+
24
+ def component_settings
25
+ context[:component_settings] || component.try(:settings)
26
+ end
27
+
28
+ def component
29
+ context[:proposal].try(:component) || context[:current_component]
30
+ end
31
+
32
+ def user_author_note?
33
+ context[:proposal_note].try(:author) == user
34
+ end
35
+
36
+ def hide_content_action?
37
+ return unless permission_action.action == :hide_proposal && permission_action.subject == :proposals
38
+
39
+ toggle_allow((admin_hide_proposals_enabled? && user_allowed_or_assigned?) || user_administrator?)
40
+ end
41
+
42
+ def edit_photos_action?
43
+ return unless permission_action.action == :edit_photos && permission_action.subject == :proposals
44
+
45
+ toggle_allow(admin_proposal_photo_editing_enabled? && (user_allowed_or_assigned? || user_administrator?))
46
+ end
47
+
48
+ def edit_proposal_note?
49
+ return unless permission_action.action == :edit_note && permission_action.subject == :proposal_note
50
+
51
+ toggle_allow(user_author_note?)
52
+ end
53
+
54
+ def admin_proposal_photo_editing_enabled?
55
+ Decidim::ReportingProposals.allow_proposal_photo_editing.present? &&
56
+ component_settings.try(:proposal_photo_editing_enabled)
57
+ end
58
+
59
+ def admin_hide_proposals_enabled?
60
+ Decidim::ReportingProposals.allow_admins_to_hide_proposals.present?
61
+ end
62
+
63
+ def user_allowed_or_assigned?
64
+ user.admin? || (user_is_valuator? && valuator_assigned_to_proposal?)
65
+ end
66
+
67
+ def user_administrator?
68
+ process = Decidim::ParticipatoryProcess.where(organization: context[:proposal].try(:organization))
69
+
70
+ admin = Decidim::User.where(id: Decidim::ParticipatoryProcessUserRole
71
+ .where(participatory_process: process, role: :admin)
72
+ .select(user.id))
73
+
74
+ admin.exists? ? user : nil
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ReportingProposals
5
+ class Permissions < Decidim::DefaultPermissions
6
+ def permissions
7
+ return permission_action unless user
8
+
9
+ return Decidim::ReportingProposals::Admin::Permissions.new(user, permission_action, context).permissions if permission_action.scope == :admin
10
+
11
+ allow! if permission_action.action == :locate && permission_action.subject == :geolocation
12
+
13
+ permission_action
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ReportingProposals
5
+ # Class used to retrieve similar proposals.
6
+ class NearbyProposals < Rectify::Query
7
+ # Syntactic sugar to initialize the class and return the queried objects.
8
+ #
9
+ # components - Decidim::CurrentComponent
10
+ # proposal - Decidim::Proposals::Proposal
11
+ def self.for(components, proposal)
12
+ new(components, proposal).query
13
+ end
14
+
15
+ # Initializes the class.
16
+ #
17
+ # components - Decidim::CurrentComponent
18
+ # proposal - Decidim::Proposals::Proposal
19
+ def initialize(components, proposal)
20
+ @components = components
21
+ @proposal = proposal
22
+ @radius = proposal.component.settings.geocoding_comparison_radius
23
+ @newer_than = proposal.component.settings.geocoding_comparison_newer_than
24
+ end
25
+
26
+ # Retrieves similar proposals by distance
27
+ def query
28
+ return Decidim::Proposals::Proposal.none if query_ids.blank?
29
+
30
+ Decidim::Proposals::Proposal
31
+ .where(id: query_ids)
32
+ .order([Arel.sql("array_position(ARRAY[?], id)"), query_ids])
33
+ end
34
+
35
+ private
36
+
37
+ # we won't return directly this query due a problem with the method "count" in the geocoder gem
38
+ # see https://github.com/alexreisner/geocoder#note-on-rails-41-and-greater
39
+ def query_ids
40
+ base_query
41
+ .near([@proposal.latitude, @proposal.longitude], @radius.to_f / 1000, units: :km)
42
+ .limit(Decidim::Proposals.similarity_limit).map(&:id)
43
+ end
44
+
45
+ def base_query
46
+ @base_query = Decidim::Proposals::Proposal
47
+ .where(component: @components)
48
+ .published
49
+ .not_hidden
50
+
51
+ return @base_query if @newer_than.zero?
52
+
53
+ @base_query.where("published_at > ?", @newer_than.days.ago)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ReportingProposals
5
+ module ProposalSerializerOverride
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ include ActionView::Helpers::DateHelper
10
+ include Decidim::Proposals::Admin::ProposalsHelper
11
+
12
+ def serialize
13
+ {
14
+ id: proposal.id,
15
+ category: {
16
+ id: proposal.category.try(:id),
17
+ name: proposal.category.try(:name) || empty_translatable
18
+ },
19
+ scope: {
20
+ id: proposal.scope.try(:id),
21
+ name: proposal.scope.try(:name) || empty_translatable
22
+ },
23
+ participatory_space: {
24
+ id: proposal.participatory_space.id,
25
+ url: Decidim::ResourceLocatorPresenter.new(proposal.participatory_space).url
26
+ },
27
+ component: { id: component.id },
28
+ title: proposal.title,
29
+ body: proposal.body,
30
+ address: proposal.address,
31
+ latitude: proposal.latitude,
32
+ longitude: proposal.longitude,
33
+ state: proposal.state.to_s,
34
+ reference: proposal.reference,
35
+ answer: ensure_translatable(proposal.answer),
36
+ answer_time: answer_time,
37
+ supports: proposal.proposal_votes_count,
38
+ endorsements: {
39
+ total_count: proposal.endorsements.size,
40
+ user_endorsements: user_endorsements
41
+ },
42
+ comments: proposal.comments_count,
43
+ attachments: proposal.attachments.size,
44
+ followers: proposal.follows.size,
45
+ published_at: proposal.published_at,
46
+ url: url,
47
+ meeting_urls: meetings,
48
+ related_proposals: related_proposals,
49
+ is_amend: proposal.emendation?,
50
+ original_proposal: {
51
+ title: proposal&.amendable&.title,
52
+ url: original_proposal_url
53
+ }
54
+ }
55
+ end
56
+
57
+ def answer_time
58
+ if unanswered_proposals_overdue?(proposal)
59
+ time_ago_in_words(last_day_to_answer(proposal),
60
+ scope: "decidim.reporting_proposals.admin.answer_overdue.datetime.distance_in_words")
61
+ elsif evaluating_proposals_overdue?(proposal)
62
+ time_ago_in_words(last_day_to_evaluate(proposal),
63
+ scope: "decidim.reporting_proposals.admin.answer_overdue.datetime.distance_in_words")
64
+ elsif grace_period_unanswered?(proposal)
65
+ time_ago_in_words(last_day_to_answer(proposal),
66
+ scope: "decidim.reporting_proposals.admin.answer_pending.datetime.distance_in_words")
67
+ elsif grace_period_evaluating?(proposal)
68
+ time_ago_in_words(last_day_to_evaluate(proposal),
69
+ scope: "decidim.reporting_proposals.admin.evaluate_pending.datetime.distance_in_words")
70
+ elsif proposal.accepted? || proposal.rejected?
71
+ "#{I18n.t("decidim.reporting_proposals.admin.resolution_time")}: #{time_elapsed_to_answer(proposal)}"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ReportingProposals
5
+ # Exposes the proposal resource so users can view and create them.
6
+ module ComponentValidatorOverride
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ # The actual validator method. It is called when ActiveRecord iterates
11
+ # over all the validators.
12
+ def validate_each(record, attribute, component)
13
+ unless component
14
+ record.errors[attribute] << :blank
15
+ return
16
+ end
17
+ manifests = [options[:manifest].to_s]
18
+ manifests << "reporting_proposals" if manifests.first == "proposals"
19
+
20
+ record.errors[attribute] << :invalid unless component.manifest_name.to_s.in?(manifests)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ <% if note.author == current_user %>
2
+ <%= cell("decidim/reporting_proposals/edit_note_modal", note, modal_id: "editNoteModal#{note.id}", note: note, proposal: proposal) %>
3
+ <button type="button" class="link-alt m-xs"
4
+ data-open="<%= current_user.present? ? "editNoteModal#{note.id}" : "loginModal" %>"
5
+ title="<%= t("modal.title", scope: "decidim.reporting_proposals.admin.proposal_notes") %>"
6
+ aria-controls="<%= current_user.present? ? "editNoteModal#{note.id}" : "loginModal" %>"
7
+ aria-haspopup="true"
8
+ tabindex="0"
9
+ style="color:#97a2b2; cursor: pointer">
10
+ <%= icon "pencil", aria_hidden: true, class: "action-icon--preview", role: "img", "aria-hidden": true %>
11
+ </button>
12
+ <% end %>
13
+ <% if note.created_at != note.updated_at %>
14
+ <span class="text-muted">
15
+ <%= t("update.edited", scope: "decidim.reporting_proposals.admin.proposal_notes") %>
16
+ <%= l note.updated_at, format: :short %>
17
+ </span>
18
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <% note.body.split("\n").each_with_index do |paragraph, index| %>
2
+ <%= Decidim::ContentRenderers::LinkRenderer.new(paragraph.gsub(URI.regexp, '<a href="\0" target="_blank">\0</a>')).render.html_safe %>
3
+ <% unless index == note.body.split("\n").size - 1 %>
4
+ <br>
5
+ <% end %>
6
+ <% end %>
@@ -0,0 +1,4 @@
1
+ <p>
2
+ <%= link_to t(".send_mail"), "mailto:#{presented_author.email}?subject=#{translated_attribute(proposal.title)}&body=#{resource_locator(proposal).url}",
3
+ class: "button tiny", target: "_blank" %>
4
+ </p>
@@ -0,0 +1,6 @@
1
+ <% if current_component.settings.try(:additional_buttons_show) &&
2
+ current_component.settings.additional_button_text.present? &&
3
+ current_component.settings.additional_button_link.present? %>
4
+ <%= link_to translated_attribute(component_settings.additional_button_text),
5
+ component_settings.additional_button_link, class: "title-action__action button small ml-s" %>
6
+ <% end %>
@@ -0,0 +1 @@
1
+ <th><%= t("valuators_column", scope: "decidim.reporting_proposals.admin.categories.index") %></th>
@@ -0,0 +1 @@
1
+ <td><%= category.valuator_names.join(", ") %></td>
@@ -0,0 +1,7 @@
1
+
2
+ <div class="row column">
3
+ <%= form.select :valuator_ids,
4
+ find_valuators_for_select(current_participatory_space),
5
+ { help_text: t("form.valuators_help", scope: "decidim.reporting_proposals.admin.categories") },
6
+ { multiple: true } %>
7
+ </div>
@@ -0,0 +1,24 @@
1
+ <%= decidim_form_for(@photo_form, url: decidim_admin_reporting_proposals.add_photos_path(id: proposal.id),
2
+ method: :post,
3
+ html: { multipart: true, class: "form edit_proposal proposal_form_admin" }) do |f| %>
4
+ <div class="row column gallery__container">
5
+ <fieldset>
6
+ <legend><%= t(".gallery_legend") %></legend>
7
+ <% if proposal.photos.any? %>
8
+ <div class="gallery row">
9
+ <% proposal.photos.each do |photo| %>
10
+ <div class="callout gallery__item">
11
+ <%= f.hidden_field :photos, multiple: true, value: photo.id, id: "photo-#{photo.id}" %>
12
+ </div>
13
+ <% end %>
14
+ </div>
15
+ <% end %>
16
+ <div class="row column">
17
+ <%= f.file_field :add_photos, multiple: true %>
18
+ </div>
19
+ <div class="actions">
20
+ <%= f.submit t(".action") %>
21
+ </div>
22
+ </fieldset>
23
+ </div>
24
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <% if proposal.photos.any? %>
2
+ <div class="row column">
3
+ <strong><%= t(".photos") %>:</strong>
4
+ <div id="photos" class="gallery row flex--fsc proposal-<%= proposal.id %>">
5
+ <% proposal.photos.each do |photo| %>
6
+ <div class="proposal-photo gallery__item" id="photo-<%= photo.id %>">
7
+ <%= link_to photo.big_url, target: "_blank", rel: "noopener" do %>
8
+ <%= image_tag photo.thumbnail_url, class: "thumbnail", alt: strip_tags(translated_attribute(photo.title)) %>
9
+ <% if admin_allowed_to? :edit_photos, :proposals, extra_context = { proposal: proposal }, chain = [::Decidim::ReportingProposals::Admin::Permissions] %>
10
+ <%= icon_link_to "x",
11
+ decidim_admin_reporting_proposals.remove_photo_path(id: proposal.id, photo_id: photo.id),
12
+ t(".delete_image"),
13
+ method: :delete,
14
+ class: "delete-proposal__button", style: "color:white;" %>
15
+ <% end %>
16
+ <% end %>
17
+ </div>
18
+ <% end %>
19
+ </div>
20
+ </div>
21
+ <% end %>
@@ -0,0 +1,14 @@
1
+ <% if proposal.photos.any? || component_settings.attachments_allowed? %>
2
+ <div class="card">
3
+ <div class="card-divider">
4
+ <h2 class="card-title"><%= t(".title") %></h2>
5
+ </div>
6
+ <div class="card-section">
7
+ <%= render partial: "decidim/reporting_proposals/admin/proposals/photo_gallery" %>
8
+
9
+ <% if admin_allowed_to? :edit_photos, :proposals, extra_context = { proposal: proposal }, chain = [::Decidim::ReportingProposals::Admin::Permissions] %>
10
+ <%= render partial: "decidim/reporting_proposals/admin/proposals/photo_form" %>
11
+ <% end %>
12
+ </div>
13
+ </div>
14
+ <% end %>
@@ -0,0 +1,20 @@
1
+ <% if admin_allowed_to?(:hide_proposal, :proposals, extra_context = { proposal: proposal }, chain = [::Decidim::ReportingProposals::Admin::Permissions]) %>
2
+ <% if proposal.reported? %>
3
+ <%= icon_link_to "trash", decidim_admin_reporting_proposals.hide_proposal_path(id: proposal),
4
+ t("actions.hide", scope: "decidim.moderations"), method: :put, class: "action-icon" %>
5
+ <% else %>
6
+ <%= cell("decidim/flag_modal", proposal, modal_id: "flagModal#{proposal.id}") %>
7
+ <button type="button" class="link-alt"
8
+ data-open="<%= current_user.present? ? "flagModal#{proposal.id}" : "loginModal" %>"
9
+ title="<%= t("report", scope: "decidim.proposals.proposals.show") %>"
10
+ aria-controls="<%= current_user.present? ? "flagModal#{proposal.id}" : "loginModal" %>"
11
+ aria-haspopup="true"
12
+ tabindex="0"
13
+ style="color:#97a2b2; cursor: pointer">
14
+ <%= icon "flag", aria_hidden: true, class: "action-icon--preview", role: "img", "aria-hidden": true %>
15
+ <span class="show-for-sr">
16
+ <%= t("report", scope: "decidim.proposals.proposals.show") %>
17
+ </span>
18
+ </button>
19
+ <% end %>
20
+ <% end %>
@@ -0,0 +1,41 @@
1
+ <div class="table__title-block">
2
+ <span class="table__title-icon">
3
+ <% if unanswered_proposals_overdue?(proposal) || evaluating_proposals_overdue?(proposal) %>
4
+ <%= icon "datetime", class: "text-alert" %>
5
+ <% elsif grace_period_unanswered?(proposal) || grace_period_evaluating?(proposal) %>
6
+ <%= icon "timer", class: "text-warning" %>
7
+ <% end %>
8
+ </span>
9
+ <div class="table__list-title">
10
+ <%= link_to(
11
+ decidim_html_escape(present(proposal).title).html_safe,
12
+ proposal_path(proposal)
13
+ ) %>
14
+ <% if unanswered_proposals_overdue?(proposal) %>
15
+ <div class="help-text-overdue text-alert">
16
+ <%= time_ago_in_words(last_day_to_answer(proposal),
17
+ scope: "decidim.reporting_proposals.admin.answer_overdue.datetime.distance_in_words") %>
18
+ </div>
19
+ <% elsif evaluating_proposals_overdue?(proposal) %>
20
+ <div class="help-text-overdue text-alert">
21
+ <%= time_ago_in_words(last_day_to_evaluate(proposal),
22
+ scope: "decidim.reporting_proposals.admin.answer_overdue.datetime.distance_in_words") %>
23
+ </div>
24
+ <% elsif grace_period_unanswered?(proposal) %>
25
+ <div class="help-text-overdue text-warning">
26
+ <%= time_ago_in_words(last_day_to_answer(proposal),
27
+ scope: "decidim.reporting_proposals.admin.answer_pending.datetime.distance_in_words") %>
28
+ </div>
29
+ <% elsif grace_period_evaluating?(proposal) %>
30
+ <div class="help-text-overdue text-warning">
31
+ <%= time_ago_in_words(last_day_to_evaluate(proposal),
32
+ scope: "decidim.reporting_proposals.admin.evaluate_pending.datetime.distance_in_words") %>
33
+ </div>
34
+ <% elsif proposal.accepted? || proposal.rejected? %>
35
+ <div class="help-text-overdue text-success">
36
+ <%= t("decidim.reporting_proposals.admin.resolution_time") %>:
37
+ <%= time_elapsed_to_answer(proposal) %>
38
+ </div>
39
+ <% end %>
40
+ </div>
41
+ </div>
@@ -0,0 +1,6 @@
1
+ <% if current_component.settings.try(:additional_buttons_for_show_proposal_show) &&
2
+ current_component.settings.additional_button_for_show_proposal_text.present? &&
3
+ current_component.settings.additional_button_for_show_proposal_link.present? %>
4
+ <%= link_to translated_attribute(component_settings.additional_button_for_show_proposal_text),
5
+ component_settings.additional_button_for_show_proposal_link, class: "title-action__action button small ml-s" %>
6
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <div class="field hashtags__container">
2
+ <%= form.text_field :title, class: "js-hashtags" %>
3
+ </div>
4
+
5
+ <div class="field hashtags__container">
6
+ <%= text_editor_for_proposal_body(form) %>
7
+ </div>