decidim-core 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/config/decidim_core_manifest.js +1 -0
- data/app/assets/javascripts/decidim/notifications.js.es6 +33 -0
- data/app/assets/stylesheets/decidim/extras/_meeting-registrations.scss +11 -0
- data/app/assets/stylesheets/decidim/modules/_extra.scss +4 -0
- data/app/assets/stylesheets/decidim/modules/_process-nav.scss +14 -0
- data/app/commands/decidim/create_follow.rb +40 -0
- data/app/commands/decidim/create_omniauth_registration.rb +0 -2
- data/app/commands/decidim/create_registration.rb +1 -3
- data/app/commands/decidim/create_report.rb +7 -7
- data/app/commands/decidim/delete_follow.rb +37 -0
- data/app/commands/decidim/invite_user.rb +1 -3
- data/app/commands/decidim/update_notifications_settings.rb +1 -2
- data/app/constraints/decidim/current_feature.rb +3 -4
- data/app/controllers/concerns/decidim/settings.rb +1 -1
- data/app/controllers/decidim/features/base_controller.rb +5 -6
- data/app/controllers/decidim/follows_controller.rb +45 -0
- data/app/controllers/decidim/notifications_controller.rb +39 -0
- data/app/controllers/decidim/pages_controller.rb +2 -2
- data/app/controllers/decidim/scopes_controller.rb +2 -0
- data/app/controllers/decidim/widgets_controller.rb +3 -3
- data/app/forms/decidim/follow_form.rb +20 -0
- data/app/forms/decidim/invite_user_form.rb +1 -1
- data/app/forms/decidim/notifications_settings_form.rb +2 -4
- data/app/helpers/decidim/action_authorization_helper.rb +2 -1
- data/app/helpers/decidim/decidim_form_helper.rb +4 -0
- data/app/helpers/decidim/feature_path_helper.rb +2 -13
- data/app/helpers/decidim/icon_helper.rb +26 -8
- data/app/helpers/decidim/paginate_helper.rb +1 -1
- data/app/helpers/decidim/scopes_helper.rb +1 -1
- data/app/jobs/decidim/email_notification_generator_job.rb +12 -0
- data/app/jobs/decidim/export_job.rb +1 -3
- data/app/jobs/decidim/notification_generator_for_recipient_job.rb +14 -0
- data/app/jobs/decidim/notification_generator_job.rb +12 -0
- data/app/mailers/decidim/export_mailer.rb +6 -7
- data/app/mailers/decidim/notification_mailer.rb +20 -0
- data/app/mailers/decidim/reported_mailer.rb +3 -3
- data/app/models/decidim/abilities/admin_ability.rb +0 -1
- data/app/models/decidim/abilities/base_ability.rb +8 -0
- data/app/models/decidim/abilities/everyone_ability.rb +0 -2
- data/app/models/decidim/abilities/participatory_process_admin_ability.rb +1 -1
- data/app/models/decidim/abilities/participatory_process_collaborator_ability.rb +1 -1
- data/app/models/decidim/category.rb +4 -4
- data/app/models/decidim/feature.rb +29 -4
- data/app/models/decidim/follow.rb +10 -0
- data/app/models/decidim/moderation.rb +1 -1
- data/app/models/decidim/notification.rb +12 -0
- data/app/models/decidim/scope.rb +8 -8
- data/app/models/decidim/user.rb +11 -1
- data/app/presenters/decidim/home_stats_presenter.rb +1 -1
- data/app/presenters/decidim/resource_locator_presenter.rb +3 -18
- data/app/queries/decidim/participatory_processes_with_user_role.rb +1 -1
- data/app/services/decidim/email_notification_generator.rb +63 -0
- data/app/services/decidim/events_manager.rb +41 -0
- data/app/services/decidim/notification_generator.rb +51 -0
- data/app/services/decidim/notification_generator_for_recipient.rb +50 -0
- data/app/uploaders/decidim/attachment_uploader.rb +1 -1
- data/app/views/decidim/authorizations/first_login.html.erb +2 -2
- data/app/views/decidim/follows/update_button.js.erb +3 -0
- data/app/views/decidim/notification_mailer/event_received.html.erb +9 -0
- data/app/views/decidim/notifications/_notification.html.erb +18 -0
- data/app/views/decidim/notifications/index.html.erb +32 -0
- data/app/views/decidim/notifications_settings/show.html.erb +3 -10
- data/app/views/decidim/shared/_follow_button.html.erb +19 -0
- data/app/views/layouts/decidim/_head.html.erb +1 -0
- data/app/views/layouts/decidim/_head_extra.html.erb +7 -0
- data/app/views/layouts/decidim/_user_menu.html.erb +1 -0
- data/app/views/layouts/decidim/_wrapper.html.erb +3 -0
- data/app/views/layouts/decidim/widget.html.erb +3 -3
- data/app/views/pages/home/_hero.html.erb +1 -1
- data/app/views/pages/home/_highlighted_processes.html.erb +3 -3
- data/config/locales/ca.yml +29 -74
- data/config/locales/en.yml +23 -71
- data/config/locales/es.yml +31 -78
- data/config/locales/eu.yml +61 -65
- data/config/locales/fi.yml +91 -51
- data/config/locales/fr.yml +40 -83
- data/config/locales/it.yml +129 -54
- data/config/locales/nl.yml +90 -51
- data/config/locales/pl.yml +319 -10
- data/config/locales/uk.yml +400 -0
- data/config/routes.rb +8 -14
- data/db/migrate/20170720120231_make_moderations_polymorphic.rb +29 -0
- data/db/migrate/20170726145242_make_categories_polymorphic.rb +27 -0
- data/db/migrate/20170807123535_create_decidim_follows.rb +20 -0
- data/db/migrate/20170808071019_create_decidim_notifications.rb +13 -0
- data/db/migrate/20170906091718_add_extra_to_notifications.rb +7 -0
- data/db/migrate/20170912082054_add_emails_on_notifications_flag_to_user.rb +7 -0
- data/db/migrate/20170913092351_add_header_snippets_to_organizations.rb +7 -0
- data/db/migrate/20170914075721_remove_followable_index_from_follows.rb +7 -0
- data/db/migrate/20170914092116_remove_comment_and_replies_notifications_from_users.rb +8 -0
- data/db/seeds.rb +2 -108
- data/lib/decidim/core.rb +46 -8
- data/lib/decidim/core/engine.rb +20 -6
- data/lib/decidim/core/test.rb +3 -0
- data/lib/decidim/core/test/factories.rb +37 -75
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +0 -26
- data/lib/decidim/core/test/shared_examples/follows_examples.rb +37 -0
- data/lib/decidim/core/test/shared_examples/manage_moderations_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/process_announcements_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/reportable.rb +4 -4
- data/lib/decidim/core/test/shared_examples/reports_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/scope_helper_examples.rb +41 -0
- data/lib/decidim/core/test/shared_examples/user_localised_email_examples.rb +25 -0
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/engine_router.rb +54 -0
- data/lib/decidim/events.rb +9 -0
- data/lib/decidim/events/base_event.rb +70 -0
- data/lib/decidim/events/email_event.rb +39 -0
- data/lib/decidim/events/notification_event.rb +32 -0
- data/lib/decidim/exporters.rb +7 -0
- data/lib/decidim/exporters/export_data.rb +14 -0
- data/lib/decidim/feature_manifest.rb +2 -2
- data/lib/decidim/features/namer.rb +1 -1
- data/lib/decidim/followable.rb +13 -0
- data/lib/decidim/form_builder.rb +1 -1
- data/lib/decidim/has_feature.rb +1 -1
- data/lib/decidim/has_settings.rb +19 -15
- data/lib/decidim/manifest_registry.rb +1 -3
- data/lib/decidim/participable.rb +80 -0
- data/lib/decidim/participatory_space_manifest.rb +40 -0
- data/lib/decidim/query_extensions.rb +1 -1
- data/lib/decidim/resource_manifest.rb +1 -1
- data/lib/decidim/settings_manifest.rb +0 -4
- data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.uk.js +14 -0
- data/vendor/assets/javascripts/morphdom.js +14 -5
- metadata +70 -79
- data/app/assets/images/decidim/process.svg +0 -10
- data/app/constraints/decidim/current_participatory_process.rb +0 -35
- data/app/controllers/concerns/decidim/needs_participatory_process.rb +0 -46
- data/app/controllers/decidim/participatory_process_groups_controller.rb +0 -26
- data/app/controllers/decidim/participatory_process_steps_controller.rb +0 -18
- data/app/controllers/decidim/participatory_process_widgets_controller.rb +0 -19
- data/app/controllers/decidim/participatory_processes_controller.rb +0 -49
- data/app/helpers/decidim/participatory_process_helper.rb +0 -17
- data/app/helpers/decidim/participatory_process_steps_helper.rb +0 -18
- data/app/models/decidim/participatory_process.rb +0 -61
- data/app/models/decidim/participatory_process_group.rb +0 -15
- data/app/models/decidim/participatory_process_step.rb +0 -39
- data/app/presenters/decidim/participatory_process_stats_presenter.rb +0 -50
- data/app/queries/decidim/highlighted_participatory_processes.rb +0 -10
- data/app/queries/decidim/organization_participatory_process_groups.rb +0 -14
- data/app/queries/decidim/organization_participatory_processes.rb +0 -14
- data/app/queries/decidim/organization_prioritized_participatory_processes.rb +0 -18
- data/app/queries/decidim/organization_published_participatory_processes.rb +0 -17
- data/app/queries/decidim/prioritized_participatory_processes.rb +0 -11
- data/app/queries/decidim/promoted_participatory_processes.rb +0 -10
- data/app/queries/decidim/published_participatory_processes.rb +0 -10
- data/app/views/decidim/participatory_process_groups/_participatory_process_group.html.erb +0 -22
- data/app/views/decidim/participatory_process_groups/show.html.erb +0 -11
- data/app/views/decidim/participatory_process_steps/_participatory_process_step.html.erb +0 -16
- data/app/views/decidim/participatory_process_steps/_timeline.html.erb +0 -7
- data/app/views/decidim/participatory_process_steps/index.html.erb +0 -14
- data/app/views/decidim/participatory_process_widgets/show.html.erb +0 -17
- data/app/views/decidim/participatory_processes/_no_processes_yet.html.erb +0 -3
- data/app/views/decidim/participatory_processes/_order_by_processes.html.erb +0 -3
- data/app/views/decidim/participatory_processes/_participatory_process.html.erb +0 -28
- data/app/views/decidim/participatory_processes/_promoted_process.html.erb +0 -32
- data/app/views/decidim/participatory_processes/_statistics.html.erb +0 -10
- data/app/views/decidim/participatory_processes/index.html.erb +0 -17
- data/app/views/decidim/participatory_processes/show.html.erb +0 -85
- data/app/views/layouts/decidim/_process_header.html.erb +0 -65
- data/app/views/layouts/decidim/_process_header_steps.html.erb +0 -27
- data/app/views/layouts/decidim/participatory_process.html.erb +0 -30
- data/config/i18n-tasks.yml +0 -138
- data/db/migrate/20161005130108_add_participatory_processes.rb +0 -19
- data/db/migrate/20161010102356_translate_processes.rb +0 -17
- data/db/migrate/20161011125616_add_hero_image_to_processes.rb +0 -7
- data/db/migrate/20161011141033_add_banner_image_to_processes.rb +0 -7
- data/db/migrate/20161013134732_add_promoted_flag_to_processes.rb +0 -7
- data/db/migrate/20161017085822_add_participatory_process_steps.rb +0 -18
- data/db/migrate/20161019072016_add_active_flag_to_step.rb +0 -13
- data/db/migrate/20161020080756_add_position_to_steps.rb +0 -9
- data/db/migrate/20161025125300_add_published_at_to_processes.rb +0 -7
- data/db/migrate/20161107152228_remove_not_null_on_step_position.rb +0 -7
- data/db/migrate/20161110092735_add_index_for_process_slug_organization.rb +0 -10
- data/db/migrate/20161116115156_create_attachments.rb +0 -18
- data/db/migrate/20170116135237_loosen_step_requirements.rb +0 -8
- data/db/migrate/20170123134023_make_attachments_polymorphic.rb +0 -20
- data/db/migrate/20170125135937_rename_attachable_to_attached_to.rb +0 -13
- data/db/migrate/20170126151123_add_extra_info_to_processes.rb +0 -10
- data/db/migrate/20170206083118_rename_extra_info_on_processes.rb +0 -14
- data/db/migrate/20170220110740_remove_steps_short_description.rb +0 -23
- data/db/migrate/20170221094835_add_scopes_to_processes.rb +0 -8
- data/db/migrate/20170228142440_add_participatory_process_groups.rb +0 -17
- data/db/migrate/20170404132616_change_steps_end_and_start_date_to_date.rb +0 -8
- data/db/migrate/20170725085104_add_show_statistics_to_participatory_processes.rb +0 -7
- data/db/migrate/20170804125402_attachment_description_nullable.rb +0 -7
- data/db/migrate/20170808080905_add_announcement_to_participatory_processes.rb +0 -7
- data/db/migrate/20170809084005_add_scopes_enabled_to_participatory_processes.rb +0 -7
- data/db/seeds/Exampledocument.pdf +0 -0
- data/db/seeds/city.jpeg +0 -0
- data/db/seeds/city2.jpeg +0 -0
- data/lib/decidim/notifiable.rb +0 -22
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
class Follow < ApplicationRecord
|
5
|
+
belongs_to :followable, foreign_key: "decidim_followable_id", foreign_type: "decidim_followable_type", polymorphic: true
|
6
|
+
belongs_to :user, foreign_key: "decidim_user_id", class_name: "Decidim::User"
|
7
|
+
|
8
|
+
validates :user, uniqueness: { scope: [:followable] }
|
9
|
+
end
|
10
|
+
end
|
@@ -4,7 +4,7 @@ module Decidim
|
|
4
4
|
# A moderation belongs to a reportable and includes many reports
|
5
5
|
class Moderation < ApplicationRecord
|
6
6
|
belongs_to :reportable, foreign_key: "decidim_reportable_id", foreign_type: "decidim_reportable_type", polymorphic: true
|
7
|
-
belongs_to :
|
7
|
+
belongs_to :participatory_space, foreign_key: "decidim_participatory_space_id", foreign_type: "decidim_participatory_space_type", polymorphic: true
|
8
8
|
has_many :reports, foreign_key: "decidim_moderation_id", class_name: "Decidim::Report"
|
9
9
|
|
10
10
|
delegate :feature, :organization, to: :reportable
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
class Notification < ApplicationRecord
|
5
|
+
belongs_to :resource, foreign_key: "decidim_resource_id", foreign_type: "decidim_resource_type", polymorphic: true
|
6
|
+
belongs_to :user, foreign_key: "decidim_user_id", class_name: "Decidim::User"
|
7
|
+
|
8
|
+
def event_class_instance
|
9
|
+
@event_class_instance ||= event_class.constantize.new(resource: resource, event_name: event_name, user: user, extra: extra)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/app/models/decidim/scope.rb
CHANGED
@@ -46,11 +46,11 @@ module Decidim
|
|
46
46
|
organization.scopes.where("? = ANY(decidim_scopes.part_of)", id)
|
47
47
|
end
|
48
48
|
|
49
|
-
# Gets the scopes from the part_of list
|
49
|
+
# Gets the scopes from the part_of list in descending order (first the top level scope, last itself)
|
50
50
|
#
|
51
|
-
# Returns an
|
51
|
+
# Returns an array of Scope objects
|
52
52
|
def part_of_scopes
|
53
|
-
organization.scopes.where(id: part_of)
|
53
|
+
organization.scopes.where(id: part_of).sort { |s1, s2| part_of.index(s2.id) <=> part_of.index(s1.id) }
|
54
54
|
end
|
55
55
|
|
56
56
|
private
|
@@ -60,19 +60,19 @@ module Decidim
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def create_part_of
|
63
|
-
|
63
|
+
build_part_of
|
64
64
|
save if changed?
|
65
65
|
end
|
66
66
|
|
67
67
|
def update_part_of
|
68
|
-
|
68
|
+
build_part_of
|
69
69
|
end
|
70
70
|
|
71
|
-
def
|
71
|
+
def build_part_of
|
72
72
|
if parent
|
73
|
-
|
73
|
+
part_of.clear.append(id).concat(parent.reload.part_of)
|
74
74
|
else
|
75
|
-
|
75
|
+
part_of.clear.append(id)
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
data/app/models/decidim/user.rb
CHANGED
@@ -18,9 +18,11 @@ module Decidim
|
|
18
18
|
has_many :identities, foreign_key: "decidim_user_id", class_name: "Decidim::Identity"
|
19
19
|
has_many :memberships, class_name: "Decidim::UserGroupMembership", foreign_key: :decidim_user_id
|
20
20
|
has_many :user_groups, through: :memberships, class_name: "Decidim::UserGroup", foreign_key: :decidim_user_group_id
|
21
|
+
has_many :follows, foreign_key: "decidim_user_id", class_name: "Decidim::Follow", dependent: :destroy
|
22
|
+
has_many :notifications, foreign_key: "decidim_user_id", class_name: "Decidim::Notification", dependent: :destroy
|
21
23
|
|
22
24
|
validates :name, presence: true, unless: -> { deleted? }
|
23
|
-
validates :locale, inclusion: { in:
|
25
|
+
validates :locale, inclusion: { in: :available_locales }, allow_blank: true
|
24
26
|
validates :tos_agreement, acceptance: true, allow_nil: false, on: :create
|
25
27
|
validates :avatar, file_size: { less_than_or_equal_to: MAXIMUM_AVATAR_FILE_SIZE }
|
26
28
|
validates :email, uniqueness: { scope: :organization }, unless: -> { deleted? || managed? }
|
@@ -62,6 +64,10 @@ module Decidim
|
|
62
64
|
deleted_at.present?
|
63
65
|
end
|
64
66
|
|
67
|
+
def follows?(followable)
|
68
|
+
Decidim::Follow.where(user: self, followable: followable).any?
|
69
|
+
end
|
70
|
+
|
65
71
|
# Check if the user exists with the given email and the current organization
|
66
72
|
#
|
67
73
|
# warden_conditions - A hash with the authentication conditions
|
@@ -102,5 +108,9 @@ module Decidim
|
|
102
108
|
def all_roles_are_valid
|
103
109
|
errors.add(:roles, :invalid) unless roles.all? { |role| ROLES.include?(role) }
|
104
110
|
end
|
111
|
+
|
112
|
+
def available_locales
|
113
|
+
Decidim.available_locales.map(&:to_s)
|
114
|
+
end
|
105
115
|
end
|
106
116
|
end
|
@@ -75,7 +75,7 @@ module Decidim
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def published_features
|
78
|
-
@published_features ||= Feature.where(
|
78
|
+
@published_features ||= Feature.where(participatory_space: ParticipatoryProcesses::OrganizationPublishedParticipatoryProcesses.new(organization).query).published
|
79
79
|
end
|
80
80
|
end
|
81
81
|
end
|
@@ -42,14 +42,14 @@ module Decidim
|
|
42
42
|
#
|
43
43
|
# Returns a String.
|
44
44
|
def member_route(route_type, options)
|
45
|
-
route_proxy.send("#{member_route_name}_#{route_type}",
|
45
|
+
route_proxy.send("#{member_route_name}_#{route_type}", @resource, options)
|
46
46
|
end
|
47
47
|
|
48
48
|
# Private: Build the route to the associated collection of resources.
|
49
49
|
#
|
50
50
|
# Returns a String.
|
51
51
|
def collection_route(route_type, options)
|
52
|
-
route_proxy.send("#{collection_route_name}_#{route_type}",
|
52
|
+
route_proxy.send("#{collection_route_name}_#{route_type}", options)
|
53
53
|
end
|
54
54
|
|
55
55
|
def manifest
|
@@ -60,21 +60,6 @@ module Decidim
|
|
60
60
|
@resource.feature
|
61
61
|
end
|
62
62
|
|
63
|
-
def engine
|
64
|
-
manifest.feature_manifest.engine
|
65
|
-
end
|
66
|
-
|
67
|
-
def member_params
|
68
|
-
collection_params.merge(id: @resource.id)
|
69
|
-
end
|
70
|
-
|
71
|
-
def collection_params
|
72
|
-
{
|
73
|
-
feature_id: feature.id,
|
74
|
-
participatory_process_id: feature.participatory_process.id
|
75
|
-
}
|
76
|
-
end
|
77
|
-
|
78
63
|
def member_route_name
|
79
64
|
manifest.route_name
|
80
65
|
end
|
@@ -84,7 +69,7 @@ module Decidim
|
|
84
69
|
end
|
85
70
|
|
86
71
|
def route_proxy
|
87
|
-
@route_proxy ||=
|
72
|
+
@route_proxy ||= EngineRouter.main_proxy(feature)
|
88
73
|
end
|
89
74
|
end
|
90
75
|
end
|
@@ -28,7 +28,7 @@ module Decidim
|
|
28
28
|
# Returns an ActiveRecord::Relation.
|
29
29
|
def query
|
30
30
|
# Admin users have all role privileges for all organization processes
|
31
|
-
return OrganizationParticipatoryProcesses.new(user.organization).query if user.admin?
|
31
|
+
return ParticipatoryProcesses::OrganizationParticipatoryProcesses.new(user.organization).query if user.admin?
|
32
32
|
|
33
33
|
ParticipatoryProcess.where(id: process_ids)
|
34
34
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
# This class handles system events affecting resources and generates a
|
5
|
+
# notification for each recipient by scheduling a new
|
6
|
+
# `Decidim::NotificationMailer` job for each of them. This way we can
|
7
|
+
# easily control which jobs fail and retry them, so that we don't have
|
8
|
+
# duplicated notifications.
|
9
|
+
class EmailNotificationGenerator
|
10
|
+
# Initializes the class.
|
11
|
+
#
|
12
|
+
# event - A String with the name of the event.
|
13
|
+
# event_class - A class that wraps the event.
|
14
|
+
# resource - an instance of a class implementing the `Decidim::Resource` concern.
|
15
|
+
# extra - a Hash with extra information to be included in the notification.
|
16
|
+
def initialize(event, event_class, resource, recipient_ids, extra)
|
17
|
+
@event = event
|
18
|
+
@event_class = event_class
|
19
|
+
@resource = resource
|
20
|
+
@recipient_ids = recipient_ids
|
21
|
+
@extra = extra
|
22
|
+
end
|
23
|
+
|
24
|
+
# Schedules a job for each recipient to send the email. Returns `nil`
|
25
|
+
# if the resource is not resource or if it is not present.
|
26
|
+
#
|
27
|
+
# Returns nothing.
|
28
|
+
def generate
|
29
|
+
return unless resource
|
30
|
+
return unless event_class.types.include?(:email)
|
31
|
+
|
32
|
+
recipient_ids.each do |recipient_id|
|
33
|
+
send_email_to(recipient_id)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :event, :event_class, :resource, :recipient_ids, :extra
|
40
|
+
|
41
|
+
# Private: sends the notification email to the user if they have the
|
42
|
+
# `email_on_notification` flag active.
|
43
|
+
#
|
44
|
+
# recipient_id - The ID of the user that will receive the email.
|
45
|
+
#
|
46
|
+
# Returns nothing.
|
47
|
+
def send_email_to(recipient_id)
|
48
|
+
recipient = Decidim::User.where(id: recipient_id).first
|
49
|
+
return unless recipient
|
50
|
+
return unless recipient.email_on_notification?
|
51
|
+
|
52
|
+
NotificationMailer
|
53
|
+
.event_received(
|
54
|
+
event,
|
55
|
+
event_class.name,
|
56
|
+
resource,
|
57
|
+
recipient,
|
58
|
+
extra
|
59
|
+
)
|
60
|
+
.deliver_later
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
# This class acts as a wrapper of `ActiveSupport::Notifications`, so that if
|
5
|
+
# we ever need to change the API we just have to change it in a single point.
|
6
|
+
class EventsManager
|
7
|
+
# Publishes a event through the events channel. It requires the name of an
|
8
|
+
# event, a class that handles the event and the resource that received the action.
|
9
|
+
#
|
10
|
+
# event - a String representing the event that has happened. Ideally, it should
|
11
|
+
# start with `decidim.events` and include the name of the engine that publishes
|
12
|
+
# it.
|
13
|
+
# event_class - The event class must be a class that wraps the event name and
|
14
|
+
# the resource and builds the needed information to publish the event to
|
15
|
+
# the different subscribers in the system.
|
16
|
+
# resource - an instance of a class that received the event.
|
17
|
+
# recipient_ids - an Array of IDs of the users that will receive the event
|
18
|
+
# extra - a Hash with extra information to be included in the notification.
|
19
|
+
#
|
20
|
+
# Returns nothing.
|
21
|
+
def self.publish(event:, event_class: Decidim::Events::BaseEvent, resource:, recipient_ids:, extra: {})
|
22
|
+
ActiveSupport::Notifications.publish(
|
23
|
+
event,
|
24
|
+
event_class: event_class.name,
|
25
|
+
resource: resource,
|
26
|
+
recipient_ids: recipient_ids,
|
27
|
+
extra: extra
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Subscribes to the given event, and runs the block every time that event
|
32
|
+
# is received.
|
33
|
+
#
|
34
|
+
# event - a String or a RegExp to match against event names.
|
35
|
+
#
|
36
|
+
# Returns nothing.
|
37
|
+
def self.subscribe(event, &block)
|
38
|
+
ActiveSupport::Notifications.subscribe(event, &block)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
# This class handles system events affecting resources and generates a
|
5
|
+
# notification for each recipient by scheduling a new
|
6
|
+
# `Decidim::NotificationGeneratorForRecipientJob` job for each of them. This way
|
7
|
+
# we can easily control which jobs fail and retry them, so that we don't have
|
8
|
+
# duplicated notifications.
|
9
|
+
class NotificationGenerator
|
10
|
+
# Initializes the class.
|
11
|
+
#
|
12
|
+
# event - A String with the name of the event.
|
13
|
+
# event_class - A class that wraps the event.
|
14
|
+
# resource - an instance of a class implementing the `Decidim::Resource` concern.
|
15
|
+
# extra - a Hash with extra information for the event.
|
16
|
+
def initialize(event, event_class, resource, recipient_ids, extra)
|
17
|
+
@event = event
|
18
|
+
@event_class = event_class
|
19
|
+
@resource = resource
|
20
|
+
@recipient_ids = recipient_ids
|
21
|
+
@extra = extra
|
22
|
+
end
|
23
|
+
|
24
|
+
# Schedules a job for each recipient to create the notification. Returns `nil`
|
25
|
+
# if the resource is not resource or if it is not present.
|
26
|
+
#
|
27
|
+
# Returns nothing.
|
28
|
+
def generate
|
29
|
+
return unless resource
|
30
|
+
return unless event_class.types.include?(:notification)
|
31
|
+
|
32
|
+
recipient_ids.each do |recipient_id|
|
33
|
+
generate_notification_for(recipient_id)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :event, :event_class, :resource, :recipient_ids, :extra
|
40
|
+
|
41
|
+
def generate_notification_for(recipient_id)
|
42
|
+
NotificationGeneratorForRecipientJob.perform_later(
|
43
|
+
event,
|
44
|
+
event_class.name,
|
45
|
+
resource,
|
46
|
+
recipient_id,
|
47
|
+
extra
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
# This class generates a notification based on the given event, for the given
|
5
|
+
# resource/recipient couple. It is intended to be used by the
|
6
|
+
# `Decidim::NotificationGenerator` class, which schedules a job for each recipient
|
7
|
+
# of the event, so that we can easily control which jobs fail.
|
8
|
+
class NotificationGeneratorForRecipient
|
9
|
+
# Initializes the class.
|
10
|
+
#
|
11
|
+
# event - A String with the name of the event.
|
12
|
+
# event_class - The class that wraps the event, in order to decorate it.
|
13
|
+
# resource - an instance of a class implementing the `Decidim::Resource` concern.
|
14
|
+
# recipient - the ID of the User that will receive the notification.
|
15
|
+
# extra - a Hash with extra information to be included in the notification.
|
16
|
+
def initialize(event, event_class, resource, recipient_id, extra)
|
17
|
+
@event = event
|
18
|
+
@event_class = event_class
|
19
|
+
@resource = resource
|
20
|
+
@recipient_id = recipient_id
|
21
|
+
@extra = extra
|
22
|
+
end
|
23
|
+
|
24
|
+
# Generates the notification. Returns `nil` if the resource is not resource
|
25
|
+
# or if the resource or the user are not present.
|
26
|
+
#
|
27
|
+
# Returns a Decidim::Notification.
|
28
|
+
def generate
|
29
|
+
return unless event_class
|
30
|
+
return unless resource
|
31
|
+
return unless recipient
|
32
|
+
|
33
|
+
Notification.create!(
|
34
|
+
user: recipient,
|
35
|
+
event_class: event_class,
|
36
|
+
resource: resource,
|
37
|
+
event_name: event,
|
38
|
+
extra: extra
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :event, :event_class, :resource, :recipient_id, :extra
|
45
|
+
|
46
|
+
def recipient
|
47
|
+
@recipient ||= User.where(id: recipient_id).first
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Decidim
|
4
|
-
# This class deals with uploading attachments to a
|
4
|
+
# This class deals with uploading attachments to a participatory space.
|
5
5
|
class AttachmentUploader < ApplicationUploader
|
6
6
|
include CarrierWave::MiniMagick
|
7
7
|
|
@@ -11,9 +11,9 @@
|
|
11
11
|
<div class="card">
|
12
12
|
<div class="card__content">
|
13
13
|
<% handlers.each do |handler| %>
|
14
|
-
<%= link_to t(handler.handler_name, scope: "decidim
|
14
|
+
<%= link_to t("authorizations.first_login.actions.#{handler.handler_name}", scope: "decidim"), new_authorization_path(handler: handler.handler_name), class: "button expanded" %>
|
15
15
|
<% end %>
|
16
|
-
<p class="text-center skip"><%= t("decidim.authorizations.skip_verification", link: link_to(t("decidim.authorizations.current_participatory_processes"), participatory_processes_path).html_safe).html_safe %>.</p>
|
16
|
+
<p class="text-center skip"><%= t("decidim.authorizations.skip_verification", link: link_to(t("decidim.authorizations.current_participatory_processes"), decidim_participatory_processes.participatory_processes_path).html_safe).html_safe %>.</p>
|
17
17
|
</div>
|
18
18
|
</div>
|
19
19
|
</div>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<div class="card--list__item">
|
2
|
+
<div class="card--list__text">
|
3
|
+
<%= link_to notification.event_class_instance.resource_path do %>
|
4
|
+
<%= resource_icon notification.resource, class: "icon--chat card--list__icon" %>
|
5
|
+
<% end %>
|
6
|
+
<div>
|
7
|
+
<h5 class="card--list__heading">
|
8
|
+
<%= notification.event_class_instance.notification_title %>
|
9
|
+
</h5>
|
10
|
+
<span class="text-small"><%= l notification.created_at.to_date, format: :long %></span>
|
11
|
+
</div>
|
12
|
+
</div>
|
13
|
+
<div class="card--list__data">
|
14
|
+
<%= link_to notification, class: "mark-as-read-button card--list__data__icon", remote: true, method: :delete do %>
|
15
|
+
<%= icon "check", class: "icon icon--chevron-right" %>
|
16
|
+
<% end %>
|
17
|
+
</div>
|
18
|
+
</div>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<main class="wrapper" id="notifications">
|
2
|
+
<div class="row">
|
3
|
+
<div class="columns">
|
4
|
+
<div class="title-action" >
|
5
|
+
<h1 class="heading1 title-action__title"><%= t("title", scope: "layouts.decidim.notifications_dashboard") %></h1>
|
6
|
+
<%= link_to(
|
7
|
+
t("mark_all_as_read", scope: "layouts.decidim.notifications_dashboard"),
|
8
|
+
decidim.read_all_notifications_path,
|
9
|
+
class: "button title-action__action hollow mark-all-as-read-button",
|
10
|
+
method: :delete,
|
11
|
+
data: { disable: true },
|
12
|
+
remote: true
|
13
|
+
) %>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
<div class="row">
|
18
|
+
<div class="columns mediumlarge-12 large-12">
|
19
|
+
<p class="empty-notifications hide"><%= t("no_notifications", scope: "layouts.decidim.notifications_dashboard") %></p>
|
20
|
+
<% if notifications.any? %>
|
21
|
+
<section class="section" id="notifications-list">
|
22
|
+
<div class="card card--list">
|
23
|
+
<%= render notifications %>
|
24
|
+
</div>
|
25
|
+
</section>
|
26
|
+
<%= decidim_paginate notifications %>
|
27
|
+
<% end %>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</main>
|
31
|
+
|
32
|
+
<%= javascript_include_tag "decidim/notifications" %>
|