decidim-meetings 0.15.2 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/cells/decidim/meetings/highlighted_meetings/show.erb +3 -0
- data/app/cells/decidim/meetings/highlighted_meetings_cell.rb +25 -0
- data/app/cells/decidim/meetings/highlighted_meetings_for_component/show.erb +33 -0
- data/app/cells/decidim/meetings/highlighted_meetings_for_component_cell.rb +37 -0
- data/app/cells/decidim/meetings/join_meeting_button/show.erb +19 -10
- data/app/commands/decidim/meetings/admin/close_meeting.rb +2 -1
- data/app/commands/decidim/meetings/admin/copy_meeting.rb +1 -1
- data/app/commands/decidim/meetings/admin/create_meeting.rb +3 -2
- data/app/commands/decidim/meetings/admin/update_meeting.rb +1 -1
- data/app/commands/decidim/meetings/admin/update_registrations.rb +2 -1
- data/app/commands/decidim/meetings/admin/validate_registration_code.rb +1 -1
- data/app/commands/decidim/meetings/join_meeting.rb +35 -6
- data/app/commands/decidim/meetings/leave_meeting.rb +10 -0
- data/app/controllers/decidim/meetings/admin/registration_form_controller.rb +30 -0
- data/app/controllers/decidim/meetings/calendars_controller.rb +23 -0
- data/app/controllers/decidim/meetings/directory/meetings_controller.rb +4 -0
- data/app/controllers/decidim/meetings/registrations_controller.rb +43 -0
- data/app/events/decidim/meetings/close_meeting_event.rb +7 -0
- data/app/events/decidim/meetings/create_meeting_event.rb +3 -0
- data/app/events/decidim/meetings/meeting_registration_notification_event.rb +22 -0
- data/app/events/decidim/meetings/meeting_registrations_enabled_event.rb +3 -0
- data/app/events/decidim/meetings/meeting_registrations_over_percentage_event.rb +4 -0
- data/app/events/decidim/meetings/registration_code_validated_event.rb +4 -0
- data/app/events/decidim/meetings/upcoming_meeting_event.rb +3 -0
- data/app/events/decidim/meetings/update_meeting_event.rb +3 -0
- data/app/forms/decidim/meetings/admin/meeting_registrations_form.rb +1 -0
- data/app/helpers/decidim/meetings/meetings_helper.rb +18 -0
- data/app/jobs/decidim/meetings/upcoming_meeting_notification_job.rb +1 -1
- data/app/mailers/decidim/meetings/registration_mailer.rb +1 -9
- data/app/models/decidim/meetings/meeting.rb +18 -0
- data/app/permissions/decidim/meetings/admin/permissions.rb +14 -0
- data/app/presenters/decidim/meetings/admin_log/value_types/meeting_title_description_presenter.rb +1 -1
- data/app/presenters/decidim/meetings/meeting_presenter.rb +50 -22
- data/app/queries/decidim/meetings/metrics/meeting_followers_metric_measure.rb +31 -0
- data/app/serializers/decidim/meetings/registration_serializer.rb +19 -1
- data/app/services/decidim/meetings/calendar/base_calendar.rb +61 -0
- data/app/services/decidim/meetings/calendar/component_calendar.rb +41 -0
- data/app/services/decidim/meetings/calendar/meeting_to_event.rb +70 -0
- data/app/services/decidim/meetings/calendar/organization_calendar.rb +33 -0
- data/app/services/decidim/meetings/calendar_renderer.rb +16 -0
- data/app/views/decidim/meetings/_calendar_modal.html.erb +13 -0
- data/app/views/decidim/meetings/admin/meetings/_form.html.erb +2 -2
- data/app/views/decidim/meetings/admin/meetings/index.html.erb +4 -1
- data/app/views/decidim/meetings/admin/registrations/_form.html.erb +5 -0
- data/app/views/decidim/meetings/directory/meetings/_meetings.html.erb +9 -2
- data/app/views/decidim/meetings/meetings/_meetings.html.erb +8 -1
- data/app/views/decidim/meetings/meetings/show.html.erb +17 -4
- data/config/locales/ca.yml +31 -10
- data/config/locales/de.yml +30 -10
- data/config/locales/en.yml +30 -9
- data/config/locales/es-PY.yml +31 -10
- data/config/locales/es.yml +30 -9
- data/config/locales/eu.yml +31 -10
- data/config/locales/fi-pl.yml +31 -10
- data/config/locales/fi.yml +31 -10
- data/config/locales/fr.yml +30 -9
- data/config/locales/gl.yml +30 -9
- data/config/locales/hu.yml +31 -10
- data/config/locales/id-ID.yml +28 -7
- data/config/locales/it.yml +31 -10
- data/config/locales/nl.yml +30 -9
- data/config/locales/pl.yml +32 -11
- data/config/locales/pt-BR.yml +31 -10
- data/config/locales/pt.yml +31 -10
- data/config/locales/ru.yml +7 -12
- data/config/locales/sv.yml +30 -9
- data/config/locales/tr-TR.yml +30 -9
- data/config/locales/uk.yml +7 -12
- data/db/migrate/20180801150031_add_registration_form_enabled_to_decidim_meetings.rb +7 -0
- data/db/migrate/20181107175558_add_questionnaire_to_existing_meetings.rb +15 -0
- data/lib/decidim/meetings.rb +1 -0
- data/lib/decidim/meetings/admin_engine.rb +1 -0
- data/lib/decidim/meetings/component.rb +26 -0
- data/lib/decidim/meetings/directory_engine.rb +1 -0
- data/lib/decidim/meetings/engine.rb +19 -30
- data/lib/decidim/meetings/meeting_serializer.rb +77 -0
- data/lib/decidim/meetings/test/factories.rb +3 -0
- data/lib/decidim/meetings/version.rb +1 -1
- metadata +44 -15
- data/app/views/decidim/participatory_spaces/_highlighted_meetings.html.erb +0 -19
- data/app/views/decidim/participatory_spaces/_meeting.html.erb +0 -1
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen-string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Meetings
|
5
|
+
class MeetingRegistrationNotificationEvent < Decidim::Events::BaseEvent
|
6
|
+
include Decidim::Events::NotificationEvent
|
7
|
+
|
8
|
+
def notification_title
|
9
|
+
I18n.t("notification_title", i18n_options).html_safe
|
10
|
+
end
|
11
|
+
|
12
|
+
def i18n_options
|
13
|
+
{
|
14
|
+
resource_title: resource_title,
|
15
|
+
resource_url: resource_url,
|
16
|
+
scope: event_name,
|
17
|
+
registration_code: extra["registration_code"]
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -87,6 +87,24 @@ module Decidim
|
|
87
87
|
end
|
88
88
|
html.html_safe
|
89
89
|
end
|
90
|
+
|
91
|
+
def registration
|
92
|
+
@registration ||= Decidim::Meetings::Registration
|
93
|
+
.where(decidim_user_id: current_user)
|
94
|
+
.find_by(decidim_meeting_id: @meeting.id)
|
95
|
+
end
|
96
|
+
|
97
|
+
def registration_code_help_text
|
98
|
+
t("registration_code_help_text", scope: "decidim.meetings.meetings.show")
|
99
|
+
end
|
100
|
+
|
101
|
+
def registration_validation_state
|
102
|
+
if @registration.validated_at
|
103
|
+
t("validated", scope: "decidim.meetings.meetings.show.registration_state")
|
104
|
+
else
|
105
|
+
t("validation_pending", scope: "decidim.meetings.meetings.show.registration_state")
|
106
|
+
end
|
107
|
+
end
|
90
108
|
end
|
91
109
|
end
|
92
110
|
end
|
@@ -32,15 +32,7 @@ module Decidim
|
|
32
32
|
|
33
33
|
def add_calendar_attachment
|
34
34
|
calendar = Icalendar::Calendar.new
|
35
|
-
calendar.event
|
36
|
-
event.dtstart = Icalendar::Values::DateTime.new(@meeting.start_time)
|
37
|
-
event.dtend = Icalendar::Values::DateTime.new(@meeting.end_time)
|
38
|
-
event.summary = present(@meeting).title
|
39
|
-
event.description = strip_tags(present(@meeting).description)
|
40
|
-
event.location = @meeting.address
|
41
|
-
event.geo = [@meeting.latitude, @meeting.longitude]
|
42
|
-
event.url = @locator.url
|
43
|
-
end
|
35
|
+
calendar.add_event(Calendar::MeetingToEvent.new(@meeting).event)
|
44
36
|
|
45
37
|
attachments["meeting-calendar-info.ics"] = calendar.to_ical
|
46
38
|
end
|
@@ -18,6 +18,8 @@ module Decidim
|
|
18
18
|
include Decidim::Traceable
|
19
19
|
include Decidim::Loggable
|
20
20
|
include Decidim::Hashtaggable
|
21
|
+
include Decidim::Forms::HasQuestionnaire
|
22
|
+
include Decidim::Paddable
|
21
23
|
|
22
24
|
belongs_to :organizer, foreign_key: "organizer_id", class_name: "Decidim::User", optional: true
|
23
25
|
has_many :registrations, class_name: "Decidim::Meetings::Registration", foreign_key: "decidim_meeting_id", dependent: :destroy
|
@@ -143,6 +145,22 @@ module Decidim
|
|
143
145
|
def resource_visible?
|
144
146
|
!private_meeting? || transparent?
|
145
147
|
end
|
148
|
+
|
149
|
+
# Overwrites method from Paddable to add custom rules in order to know
|
150
|
+
# when to display a pad or not.
|
151
|
+
def pad_is_visible?
|
152
|
+
return false unless pad
|
153
|
+
|
154
|
+
(start_time - Time.current) <= 24.hours
|
155
|
+
end
|
156
|
+
|
157
|
+
# Overwrites method from Paddable to add custom rules in order to know
|
158
|
+
# when a pad is writable or not.
|
159
|
+
def pad_is_writable?
|
160
|
+
return false unless pad_is_visible?
|
161
|
+
|
162
|
+
(Time.current - end_time) < 72.hours
|
163
|
+
end
|
146
164
|
end
|
147
165
|
end
|
148
166
|
end
|
@@ -8,6 +8,7 @@ module Decidim
|
|
8
8
|
return permission_action unless user
|
9
9
|
return permission_action unless permission_action.scope == :admin
|
10
10
|
|
11
|
+
allowed_registration_form_action?
|
11
12
|
allowed_meeting_action?
|
12
13
|
allowed_agenda_action?
|
13
14
|
allowed_minutes_action?
|
@@ -29,6 +30,10 @@ module Decidim
|
|
29
30
|
@minutes ||= context.fetch(:minutes, nil)
|
30
31
|
end
|
31
32
|
|
33
|
+
def registration_form
|
34
|
+
@registration_form ||= context.fetch(:questionnaire, nil)
|
35
|
+
end
|
36
|
+
|
32
37
|
def allowed_meeting_action?
|
33
38
|
return unless permission_action.subject == :meeting
|
34
39
|
|
@@ -42,6 +47,15 @@ module Decidim
|
|
42
47
|
end
|
43
48
|
end
|
44
49
|
|
50
|
+
def allowed_registration_form_action?
|
51
|
+
return unless permission_action.subject == :questionnaire
|
52
|
+
|
53
|
+
case permission_action.action
|
54
|
+
when :update
|
55
|
+
toggle_allow(registration_form.present?)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
45
59
|
def allowed_agenda_action?
|
46
60
|
return unless permission_action.subject == :agenda
|
47
61
|
|
@@ -7,45 +7,73 @@ module Decidim
|
|
7
7
|
#
|
8
8
|
class MeetingPresenter < SimpleDelegator
|
9
9
|
include Decidim::TranslationsHelper
|
10
|
+
include Decidim::ResourceHelper
|
10
11
|
|
11
12
|
def meeting
|
12
13
|
__getobj__
|
13
14
|
end
|
14
15
|
|
15
|
-
def title
|
16
|
+
def title(links: false, all_locales: false)
|
16
17
|
return unless meeting
|
17
|
-
|
18
|
-
|
18
|
+
|
19
|
+
handle_locales(meeting.title, all_locales) do |content|
|
20
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(content)
|
21
|
+
renderer.render(links: links).html_safe
|
22
|
+
end
|
19
23
|
end
|
20
24
|
|
21
|
-
def
|
25
|
+
def description(links: false, all_locales: false)
|
22
26
|
return unless meeting
|
23
|
-
|
24
|
-
|
27
|
+
|
28
|
+
handle_locales(meeting.description, all_locales) do |content|
|
29
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(content)
|
30
|
+
renderer.render(links: links).html_safe
|
31
|
+
end
|
25
32
|
end
|
26
33
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
renderer.render_without_link.html_safe
|
34
|
+
# Next methods are used for present a Meeting As Proposal Author
|
35
|
+
def name
|
36
|
+
title
|
31
37
|
end
|
32
38
|
|
33
|
-
def
|
34
|
-
|
35
|
-
renderer = Decidim::ContentRenderers::HashtagRenderer.new(translated_attribute(meeting.description))
|
36
|
-
renderer.render.html_safe
|
39
|
+
def nickname
|
40
|
+
""
|
37
41
|
end
|
38
42
|
|
39
|
-
def
|
40
|
-
|
41
|
-
renderer = Decidim::ContentRenderers::HashtagRenderer.new(meeting.title)
|
42
|
-
renderer.render_without_link
|
43
|
+
def badge
|
44
|
+
""
|
43
45
|
end
|
44
46
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
def profile_path
|
48
|
+
resource_locator(meeting).path
|
49
|
+
end
|
50
|
+
|
51
|
+
def avatar_url
|
52
|
+
ActionController::Base.helpers.asset_path("decidim/meetings/icon.svg")
|
53
|
+
end
|
54
|
+
|
55
|
+
def deleted?
|
56
|
+
false
|
57
|
+
end
|
58
|
+
|
59
|
+
def can_be_contacted?
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
def has_tooltip?
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def handle_locales(content, all_locales)
|
70
|
+
if all_locales
|
71
|
+
content.each_with_object({}) do |(locale, string), parsed_content|
|
72
|
+
parsed_content[locale] = yield(string)
|
73
|
+
end
|
74
|
+
else
|
75
|
+
yield(translated_attribute(content))
|
76
|
+
end
|
49
77
|
end
|
50
78
|
end
|
51
79
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Meetings
|
5
|
+
module Metrics
|
6
|
+
# Searches for unique Users following the next objects
|
7
|
+
# - Meetings
|
8
|
+
class MeetingFollowersMetricMeasure < Decidim::MetricMeasure
|
9
|
+
def valid?
|
10
|
+
super && @resource.is_a?(Decidim::Component)
|
11
|
+
end
|
12
|
+
|
13
|
+
def calculate
|
14
|
+
meetings = Decidim::Meetings::Meeting.where(component: @resource).joins(:component)
|
15
|
+
|
16
|
+
meetings_followers = Decidim::Follow.where(followable: meetings).joins(:user)
|
17
|
+
.where("decidim_follows.created_at <= ?", end_time)
|
18
|
+
cumulative_users = meetings_followers.pluck(:decidim_user_id)
|
19
|
+
|
20
|
+
meetings_followers = meetings_followers.where("decidim_follows.created_at >= ?", start_time)
|
21
|
+
quantity_users = meetings_followers.pluck(:decidim_user_id)
|
22
|
+
|
23
|
+
{
|
24
|
+
cumulative_users: cumulative_users.uniq,
|
25
|
+
quantity_users: quantity_users.uniq
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module Decidim
|
4
4
|
module Meetings
|
5
5
|
class RegistrationSerializer < Decidim::Exporters::Serializer
|
6
|
+
include Decidim::TranslationsHelper
|
6
7
|
# Serializes a registration
|
7
8
|
def serialize
|
8
9
|
{
|
@@ -11,9 +12,26 @@ module Decidim
|
|
11
12
|
user: {
|
12
13
|
name: resource.user.name,
|
13
14
|
email: resource.user.email
|
14
|
-
}
|
15
|
+
},
|
16
|
+
registration_form_answers: serialize_answers
|
15
17
|
}
|
16
18
|
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def serialize_answers
|
23
|
+
questions = resource.meeting.questionnaire.questions
|
24
|
+
answers = resource.meeting.questionnaire.answers.where(user: resource.user)
|
25
|
+
questions.each_with_index.inject({}) do |serialized, (question, idx)|
|
26
|
+
answer = answers.find_by(question: question)
|
27
|
+
serialized.update("#{idx + 1}. #{translated_attribute(question.body)}" => normalize_body(answer))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def normalize_body(answer)
|
32
|
+
return "" unless answer
|
33
|
+
answer.body || answer.choices.pluck(:body)
|
34
|
+
end
|
17
35
|
end
|
18
36
|
end
|
19
37
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Meetings
|
5
|
+
module Calendar
|
6
|
+
# This class serves as a base class to render calendars. Please, inherit
|
7
|
+
# from it and overwrite the `events` with whatever logic you need to do
|
8
|
+
# it. After that, modify the `Decidim::Meetings::Calendar.for` method to
|
9
|
+
# include your new class.
|
10
|
+
class BaseCalendar
|
11
|
+
# Convenience method to shorten the calls. Converts the resource
|
12
|
+
# meetings to the ICalendar format.
|
13
|
+
#
|
14
|
+
# resource - a resource that has meetings.
|
15
|
+
#
|
16
|
+
# Returns a String.
|
17
|
+
def self.for(resource)
|
18
|
+
new(resource).calendar
|
19
|
+
end
|
20
|
+
|
21
|
+
# Initializes the class.
|
22
|
+
#
|
23
|
+
# resource - a resource that has meetings.
|
24
|
+
def initialize(resource)
|
25
|
+
@resource = resource
|
26
|
+
end
|
27
|
+
|
28
|
+
# Converts the resource meetings to the ICalendar format.
|
29
|
+
#
|
30
|
+
# Returns a String.
|
31
|
+
def calendar
|
32
|
+
return if events.blank?
|
33
|
+
<<~CALENDAR.gsub("\n\n", "\n")
|
34
|
+
BEGIN:VCALENDAR\r
|
35
|
+
VERSION:2.0\r
|
36
|
+
PRODID:icalendar-ruby\r
|
37
|
+
CALSCALE:GREGORIAN\r
|
38
|
+
#{events}
|
39
|
+
END:VCALENDAR\r
|
40
|
+
CALENDAR
|
41
|
+
end
|
42
|
+
|
43
|
+
# Internal: this method is supposed to be overwritten by classes
|
44
|
+
# inheriting from this one. It should find the relevant meetings that
|
45
|
+
# will be exported, and convert them to ICalendar events. Please use the
|
46
|
+
# `MeetingToEvent` class to do so. Since this method returns a String,
|
47
|
+
# you can cache its contents. Check existing implementations for an
|
48
|
+
# example of how to achieve it.
|
49
|
+
#
|
50
|
+
# Returns a String.
|
51
|
+
def events
|
52
|
+
raise "Please, overwrite this method. You can use the `MeetingToEvent` class to convert a meeting to the correct ICalendar format."
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
attr_reader :resource
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|