decidim-meetings 0.28.5 → 0.29.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of decidim-meetings might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/cells/decidim/meetings/attending_organizations_list_cell.rb +1 -1
- data/app/cells/decidim/meetings/cancel_registration_meeting_button_cell.rb +1 -2
- data/app/cells/decidim/meetings/dates_and_map/show.erb +3 -5
- data/app/cells/decidim/meetings/dates_and_map_cell.rb +1 -1
- data/app/cells/decidim/meetings/highlighted_meetings_for_component_cell.rb +1 -2
- data/app/cells/decidim/meetings/join_meeting_button/remaining_slots.erb +1 -0
- data/app/cells/decidim/meetings/join_meeting_button_cell.rb +0 -3
- data/app/cells/decidim/meetings/meeting_card_metadata_cell.rb +0 -3
- data/app/cells/decidim/meetings/meeting_cell.rb +0 -1
- data/app/cells/decidim/meetings/meeting_l_cell.rb +4 -7
- data/app/cells/decidim/meetings/meeting_url/show.erb +5 -5
- data/app/cells/decidim/meetings/meeting_url_cell.rb +0 -1
- data/app/cells/decidim/meetings/online_meeting_link_cell.rb +0 -2
- data/app/cells/decidim/meetings/question_responses/show.erb +7 -3
- data/app/cells/decidim/meetings/question_responses_cell.rb +0 -2
- data/app/commands/decidim/meetings/admin/copy_meeting.rb +2 -2
- data/app/commands/decidim/meetings/admin/create_agenda.rb +9 -37
- data/app/commands/decidim/meetings/admin/create_meeting.rb +28 -61
- data/app/commands/decidim/meetings/admin/destroy_meeting.rb +4 -33
- data/app/commands/decidim/meetings/admin/update_agenda.rb +7 -35
- data/app/commands/decidim/meetings/admin/update_meeting.rb +30 -68
- data/app/commands/decidim/meetings/admin/update_question_status.rb +1 -1
- data/app/commands/decidim/meetings/admin/update_questionnaire.rb +19 -11
- data/app/commands/decidim/meetings/admin/update_registrations.rb +20 -46
- data/app/commands/decidim/meetings/create_answer.rb +5 -4
- data/app/commands/decidim/meetings/create_meeting.rb +38 -62
- data/app/commands/decidim/meetings/join_meeting.rb +18 -19
- data/app/commands/decidim/meetings/update_meeting.rb +6 -7
- data/app/commands/decidim/meetings/withdraw_meeting.rb +1 -1
- data/app/controllers/concerns/decidim/meetings/admin/invites/filterable.rb +33 -0
- data/app/controllers/decidim/meetings/admin/agenda_controller.rb +1 -1
- data/app/controllers/decidim/meetings/admin/invites_controller.rb +6 -6
- data/app/controllers/decidim/meetings/admin/meetings_controller.rb +2 -2
- data/app/controllers/decidim/meetings/admin/meetings_poll_controller.rb +12 -0
- data/app/controllers/decidim/meetings/application_controller.rb +1 -1
- data/app/controllers/decidim/meetings/live_events_controller.rb +1 -1
- data/app/controllers/decidim/meetings/meetings_controller.rb +3 -33
- data/app/controllers/decidim/meetings/polls/answers_controller.rb +10 -2
- data/app/controllers/decidim/meetings/registrations_controller.rb +3 -3
- data/app/forms/decidim/meetings/admin/close_meeting_form.rb +1 -1
- data/app/forms/decidim/meetings/admin/meeting_agenda_items_form.rb +1 -1
- data/app/forms/decidim/meetings/admin/meeting_form.rb +1 -1
- data/app/forms/decidim/meetings/admin/meeting_registrations_form.rb +3 -3
- data/app/forms/decidim/meetings/admin/question_form.rb +8 -4
- data/app/forms/decidim/meetings/answer_form.rb +4 -4
- data/app/forms/decidim/meetings/meeting_form.rb +1 -1
- data/app/helpers/decidim/meetings/application_helper.rb +1 -5
- data/app/mailers/decidim/meetings/close_meeting_reminder_mailer.rb +1 -1
- data/app/models/decidim/meetings/meeting.rb +10 -4
- data/app/models/decidim/meetings/poll.rb +8 -0
- data/app/models/decidim/meetings/question.rb +1 -0
- data/app/models/decidim/meetings/questionnaire.rb +0 -6
- data/app/packs/src/decidim/meetings/admin/meetings_form.js +3 -3
- data/app/packs/src/decidim/meetings/meetings_form.js +3 -3
- data/app/packs/src/decidim/meetings/meetings_polls.js +5 -0
- data/app/packs/src/decidim/meetings/poll.component.js +32 -4
- data/app/packs/stylesheets/decidim/meetings/_item.scss +126 -6
- data/app/packs/stylesheets/decidim/meetings/_live_event.scss +0 -94
- data/app/permissions/decidim/meetings/permissions.rb +22 -7
- data/app/presenters/decidim/meetings/meeting_presenter.rb +10 -3
- data/app/services/decidim/meetings/calendar/component_calendar.rb +1 -1
- data/app/services/decidim/meetings/calendar/meeting_to_event.rb +1 -1
- data/app/services/decidim/meetings/close_meeting_reminder_generator.rb +1 -1
- data/app/services/decidim/meetings/meeting_iframe_embedder.rb +2 -2
- data/app/views/decidim/meetings/_calendar_modal.html.erb +1 -1
- data/app/views/decidim/meetings/admin/agenda/_agenda_item.html.erb +3 -3
- data/app/views/decidim/meetings/admin/agenda/_agenda_item_child.html.erb +3 -3
- data/app/views/decidim/meetings/admin/agenda/_agenda_item_fields.html.erb +3 -3
- data/app/views/decidim/meetings/admin/invite_join_meeting_mailer/invite.html.erb +3 -1
- data/app/views/decidim/meetings/admin/invites/_form.html.erb +4 -4
- data/app/views/decidim/meetings/admin/invites/index.html.erb +4 -34
- data/app/views/decidim/meetings/admin/meetings/_form.html.erb +8 -8
- data/app/views/decidim/meetings/admin/meetings/_service.html.erb +3 -3
- data/app/views/decidim/meetings/admin/meetings/index.html.erb +2 -2
- data/app/views/decidim/meetings/admin/poll/_answer_option.html.erb +1 -1
- data/app/views/decidim/meetings/admin/poll/_answer_option_template.html.erb +1 -1
- data/app/views/decidim/meetings/admin/poll/_form.html.erb +26 -25
- data/app/views/decidim/meetings/admin/poll/_question.html.erb +18 -16
- data/app/views/decidim/meetings/admin/poll/edit.html.erb +4 -6
- data/app/views/decidim/meetings/admin/registrations/edit.html.erb +2 -4
- data/app/views/decidim/meetings/close_meeting_reminder_mailer/close_meeting_reminder.html.erb +1 -1
- data/app/views/decidim/meetings/layouts/live_event.html.erb +1 -15
- data/app/views/decidim/meetings/meetings/_datetime.html.erb +4 -4
- data/app/views/decidim/meetings/meetings/_form.html.erb +17 -17
- data/app/views/decidim/meetings/meetings/_meeting.html.erb +2 -1
- data/app/views/decidim/meetings/meetings/_meeting_agenda.html.erb +2 -2
- data/app/views/decidim/meetings/meetings/_meeting_aside.html.erb +3 -1
- data/app/views/decidim/meetings/meetings/_meeting_minutes.html.erb +1 -1
- data/app/views/decidim/meetings/meetings/_meeting_poll_actions.html.erb +15 -0
- data/app/views/decidim/meetings/polls/answers/_multiple_option.html.erb +6 -10
- data/app/views/decidim/meetings/polls/answers/_single_option.html.erb +4 -10
- data/app/views/decidim/meetings/polls/answers/admin.html.erb +34 -0
- data/app/views/decidim/meetings/polls/answers/index.html.erb +36 -0
- data/app/views/decidim/meetings/polls/questions/_closed_question.html.erb +8 -2
- data/app/views/decidim/meetings/polls/questions/_index_admin.html.erb +27 -24
- data/app/views/decidim/meetings/polls/questions/_published_question.html.erb +14 -11
- data/app/views/decidim/meetings/polls/questions/_question.html.erb +1 -1
- data/app/views/decidim/meetings/polls/questions/index.js.erb +3 -3
- data/app/views/decidim/meetings/polls/questions/index_admin.js.erb +3 -3
- data/app/views/decidim/meetings/registration_mailer/confirmation.html.erb +1 -1
- data/app/views/devise/mailer/join_meeting.html.erb +3 -1
- data/app/views/devise/mailer/join_meeting.text.erb +3 -1
- data/config/locales/ar.yml +1 -13
- data/config/locales/bg.yml +45 -12
- data/config/locales/ca.yml +45 -13
- data/config/locales/cs.yml +28 -16
- data/config/locales/de.yml +114 -82
- data/config/locales/el.yml +1 -13
- data/config/locales/en.yml +44 -12
- data/config/locales/es-MX.yml +47 -15
- data/config/locales/es-PY.yml +47 -15
- data/config/locales/es.yml +48 -16
- data/config/locales/eu.yml +79 -47
- data/config/locales/fi-plain.yml +46 -14
- data/config/locales/fi.yml +56 -24
- data/config/locales/fr-CA.yml +48 -16
- data/config/locales/fr.yml +48 -16
- data/config/locales/ga-IE.yml +0 -8
- data/config/locales/gl.yml +3 -11
- data/config/locales/hu.yml +3 -12
- data/config/locales/id-ID.yml +1 -12
- data/config/locales/is-IS.yml +1 -12
- data/config/locales/it.yml +3 -16
- data/config/locales/ja.yml +47 -15
- data/config/locales/lb.yml +1 -7
- data/config/locales/lt.yml +3 -12
- data/config/locales/lv.yml +1 -12
- data/config/locales/nl.yml +1 -13
- data/config/locales/no.yml +1 -12
- data/config/locales/pl.yml +45 -12
- data/config/locales/pt-BR.yml +23 -17
- data/config/locales/pt.yml +1 -14
- data/config/locales/ro-RO.yml +2 -15
- data/config/locales/ru.yml +1 -12
- data/config/locales/sk.yml +1 -12
- data/config/locales/sv.yml +108 -206
- data/config/locales/tr-TR.yml +2 -17
- data/config/locales/uk.yml +1 -12
- data/config/locales/zh-CN.yml +1 -15
- data/config/locales/zh-TW.yml +1 -13
- data/db/migrate/20240130135858_add_withdrawn_fields_on_meetings.rb +23 -0
- data/decidim-meetings.gemspec +2 -2
- data/lib/decidim/api/meeting_type.rb +3 -12
- data/lib/decidim/api/meetings_type.rb +3 -1
- data/lib/decidim/meetings/component.rb +2 -2
- data/lib/decidim/meetings/engine.rb +5 -3
- data/lib/decidim/meetings/meeting_serializer.rb +3 -38
- data/lib/decidim/meetings/seeds.rb +13 -18
- data/lib/decidim/meetings/test/factories.rb +1 -7
- data/lib/decidim/meetings/test/notifications_handling.rb +1 -1
- data/lib/decidim/meetings/version.rb +1 -1
- data/lib/tasks/decidim_meetings.rake +1 -1
- metadata +24 -22
- data/app/views/decidim/meetings/admin/agenda/show.html.erb +0 -0
- data/config/locales/bn-BD.yml +0 -1
- data/config/locales/bs-BA.yml +0 -8
@@ -15,9 +15,9 @@ module Decidim
|
|
15
15
|
helper Decidim::ShortLinkHelper
|
16
16
|
include Decidim::AttachmentsHelper
|
17
17
|
|
18
|
-
helper_method :meetings, :meeting, :registration, :search, :
|
18
|
+
helper_method :meetings, :meeting, :registration, :search, :tab_panel_items
|
19
19
|
|
20
|
-
before_action :
|
20
|
+
before_action :add_additional_csp_directives, only: [:show]
|
21
21
|
|
22
22
|
def new
|
23
23
|
enforce_permission_to :create, :meeting
|
@@ -76,7 +76,7 @@ module Decidim
|
|
76
76
|
|
77
77
|
@form = meeting_form.from_params(params)
|
78
78
|
|
79
|
-
UpdateMeeting.call(@form,
|
79
|
+
UpdateMeeting.call(@form, meeting) do
|
80
80
|
on(:ok) do |meeting|
|
81
81
|
flash[:notice] = I18n.t("meetings.update.success", scope: "decidim.meetings")
|
82
82
|
redirect_to Decidim::ResourceLocatorPresenter.new(meeting).path
|
@@ -110,36 +110,6 @@ module Decidim
|
|
110
110
|
@meeting ||= Meeting.not_hidden.where(component: current_component).find_by(id: params[:id])
|
111
111
|
end
|
112
112
|
|
113
|
-
def next_meeting
|
114
|
-
return if search_collection.size < 2
|
115
|
-
|
116
|
-
search_collection.order(:start_time, :id).where(
|
117
|
-
Decidim::Meetings::Meeting.arel_table[:start_time].gt(meeting.start_time).or(
|
118
|
-
Decidim::Meetings::Meeting.arel_table[:start_time].eq(meeting.start_time).and(
|
119
|
-
Decidim::Meetings::Meeting.arel_table[:id].gt(meeting.id)
|
120
|
-
)
|
121
|
-
)
|
122
|
-
).first
|
123
|
-
end
|
124
|
-
|
125
|
-
def prev_meeting
|
126
|
-
return if search_collection.size < 2
|
127
|
-
|
128
|
-
search_collection.order(:start_time, :id).where(
|
129
|
-
Decidim::Meetings::Meeting.arel_table[:start_time].lt(meeting.start_time).or(
|
130
|
-
Decidim::Meetings::Meeting.arel_table[:start_time].eq(meeting.start_time).and(
|
131
|
-
Decidim::Meetings::Meeting.arel_table[:id].lt(meeting.id)
|
132
|
-
)
|
133
|
-
)
|
134
|
-
).last
|
135
|
-
end
|
136
|
-
|
137
|
-
def nav_paths
|
138
|
-
return {} if meeting.blank?
|
139
|
-
|
140
|
-
{ prev_path: prev_meeting, next_path: next_meeting }.compact_blank.transform_values { |meeting| meeting_path(meeting) }
|
141
|
-
end
|
142
|
-
|
143
113
|
def meetings
|
144
114
|
is_past_meetings = params.dig("filter", "with_any_date")&.include?("past")
|
145
115
|
@meetings ||= paginate(search.result.order(start_time: is_past_meetings ? :desc : :asc))
|
@@ -9,11 +9,19 @@ module Decidim
|
|
9
9
|
|
10
10
|
helper_method :question
|
11
11
|
|
12
|
+
def admin
|
13
|
+
enforce_permission_to(:update, :poll, meeting:)
|
14
|
+
end
|
15
|
+
|
16
|
+
def index
|
17
|
+
enforce_permission_to(:reply_poll, :meeting, meeting:)
|
18
|
+
end
|
19
|
+
|
12
20
|
def create
|
13
21
|
enforce_permission_to(:create, :answer, question:)
|
14
|
-
@form = form(AnswerForm).from_params(params
|
22
|
+
@form = form(AnswerForm).from_params(params.merge(question:, current_user:))
|
15
23
|
|
16
|
-
CreateAnswer.call(@form,
|
24
|
+
CreateAnswer.call(@form, questionnaire) do
|
17
25
|
# Both :ok and :invalid render the same template, because
|
18
26
|
# validation errors are displayed in the template
|
19
27
|
respond_to do |format|
|
@@ -11,7 +11,7 @@ module Decidim
|
|
11
11
|
|
12
12
|
@form = form(Decidim::Forms::QuestionnaireForm).from_params(params, session_token:)
|
13
13
|
|
14
|
-
JoinMeeting.call(meeting,
|
14
|
+
JoinMeeting.call(meeting, @form) do
|
15
15
|
on(:ok) do
|
16
16
|
flash[:notice] = I18n.t("registrations.create.success", scope: "decidim.meetings")
|
17
17
|
redirect_to after_answer_path
|
@@ -32,9 +32,9 @@ module Decidim
|
|
32
32
|
def create
|
33
33
|
enforce_permission_to(:register, :meeting, meeting:)
|
34
34
|
|
35
|
-
@form = JoinMeetingForm.from_params(params)
|
35
|
+
@form = JoinMeetingForm.from_params(params).with_context(current_user:)
|
36
36
|
|
37
|
-
JoinMeeting.call(meeting,
|
37
|
+
JoinMeeting.call(meeting, @form) do
|
38
38
|
on(:ok) do
|
39
39
|
flash[:notice] = I18n.t("registrations.create.success", scope: "decidim.meetings")
|
40
40
|
redirect_after_path
|
@@ -7,7 +7,7 @@ module Decidim
|
|
7
7
|
class CloseMeetingForm < Decidim::Form
|
8
8
|
include TranslatableAttributes
|
9
9
|
|
10
|
-
translatable_attribute :closing_report,
|
10
|
+
translatable_attribute :closing_report, String
|
11
11
|
attribute :video_url, String
|
12
12
|
attribute :audio_url, String
|
13
13
|
attribute :closing_visible, Boolean, default: true
|
@@ -8,7 +8,7 @@ module Decidim
|
|
8
8
|
include TranslatableAttributes
|
9
9
|
|
10
10
|
translatable_attribute :title, String
|
11
|
-
translatable_attribute :description,
|
11
|
+
translatable_attribute :description, String
|
12
12
|
|
13
13
|
attribute :duration, Integer, default: 0
|
14
14
|
attribute :parent_id, Integer
|
@@ -23,7 +23,7 @@ module Decidim
|
|
23
23
|
attribute :iframe_access_level, String
|
24
24
|
|
25
25
|
translatable_attribute :title, String
|
26
|
-
translatable_attribute :description,
|
26
|
+
translatable_attribute :description, String
|
27
27
|
translatable_attribute :location, String
|
28
28
|
translatable_attribute :location_hints, String
|
29
29
|
|
@@ -15,8 +15,8 @@ module Decidim
|
|
15
15
|
attribute :available_slots, Integer
|
16
16
|
attribute :reserved_slots, Integer
|
17
17
|
|
18
|
-
translatable_attribute :registration_terms,
|
19
|
-
translatable_attribute :registration_email_custom_content,
|
18
|
+
translatable_attribute :registration_terms, String
|
19
|
+
translatable_attribute :registration_email_custom_content, String
|
20
20
|
|
21
21
|
validates :registration_terms, translatable_presence: true, if: ->(form) { form.registrations_enabled? }
|
22
22
|
validates :available_slots, :reserved_slots, presence: true, if: ->(form) { form.registrations_enabled? }
|
@@ -37,7 +37,7 @@ module Decidim
|
|
37
37
|
|
38
38
|
# We need this method to ensure the form object will always have an ID,
|
39
39
|
# and thus its `to_param` method will always return a significant value.
|
40
|
-
# If we remove this method, get an error
|
40
|
+
# If we remove this method, get an error on the `update` action and try
|
41
41
|
# to resubmit the form, the form will not hold an ID, so the `to_param`
|
42
42
|
# method will return an empty string and Rails will treat this as a
|
43
43
|
# `create` action, thus raising an error since this action is not defined
|
@@ -18,10 +18,10 @@ module Decidim
|
|
18
18
|
translatable_attribute :description, String
|
19
19
|
|
20
20
|
validates :position, numericality: { greater_than_or_equal_to: 0 }
|
21
|
-
validates :question_type, inclusion: { in: Decidim::Meetings::Question::QUESTION_TYPES }
|
22
|
-
validates :max_choices, numericality: { only_integer: true, greater_than: 1, less_than_or_equal_to: ->(form) { form.number_of_options } }, allow_blank: true
|
21
|
+
validates :question_type, inclusion: { in: Decidim::Meetings::Question::QUESTION_TYPES }, if: :editable?
|
22
|
+
validates :max_choices, numericality: { only_integer: true, greater_than: 1, less_than_or_equal_to: ->(form) { form.number_of_options } }, allow_blank: true, if: :editable?
|
23
23
|
validates :body, translatable_presence: true, if: :requires_body?
|
24
|
-
validates :answer_options, presence: true
|
24
|
+
validates :answer_options, presence: true, if: :editable?
|
25
25
|
|
26
26
|
def to_param
|
27
27
|
return id if id.present?
|
@@ -29,6 +29,10 @@ module Decidim
|
|
29
29
|
"questionnaire-question-id"
|
30
30
|
end
|
31
31
|
|
32
|
+
def editable?
|
33
|
+
@editable ||= id.blank? || Decidim::Meetings::Question.unpublished.unanswered.exists?(id:)
|
34
|
+
end
|
35
|
+
|
32
36
|
def number_of_options
|
33
37
|
answer_options.size
|
34
38
|
end
|
@@ -36,7 +40,7 @@ module Decidim
|
|
36
40
|
private
|
37
41
|
|
38
42
|
def requires_body?
|
39
|
-
!deleted
|
43
|
+
editable? && !deleted
|
40
44
|
end
|
41
45
|
end
|
42
46
|
end
|
@@ -24,8 +24,8 @@ module Decidim
|
|
24
24
|
@answer ||= Decidim::Meetings::Answer.find_by(decidim_user_id: current_user.id, decidim_question_id: question_id) if current_user
|
25
25
|
end
|
26
26
|
|
27
|
-
def label
|
28
|
-
base =
|
27
|
+
def label
|
28
|
+
base = translated_attribute(question.body)
|
29
29
|
base += " (#{max_choices_label})" if question.max_choices
|
30
30
|
base
|
31
31
|
end
|
@@ -43,13 +43,13 @@ module Decidim
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def selected_choices
|
46
|
-
choices.select(&:
|
46
|
+
choices.select(&:answer_option_id)
|
47
47
|
end
|
48
48
|
|
49
49
|
private
|
50
50
|
|
51
51
|
def max_choices
|
52
|
-
errors.add(:choices, :too_many) if selected_choices.size > question.max_choices
|
52
|
+
errors.add(:choices, :too_many, count: question.max_choices) if selected_choices.size > question.max_choices
|
53
53
|
end
|
54
54
|
|
55
55
|
def mandatory_label
|
@@ -56,7 +56,7 @@ module Decidim
|
|
56
56
|
|
57
57
|
alias component current_component
|
58
58
|
|
59
|
-
# Finds the Scope from the given decidim_scope_id, uses the
|
59
|
+
# Finds the Scope from the given decidim_scope_id, uses the component scope if missing.
|
60
60
|
#
|
61
61
|
# Returns a Decidim::Scope
|
62
62
|
def scope
|
@@ -59,11 +59,7 @@ module Decidim
|
|
59
59
|
|
60
60
|
# If the content is safe, HTML tags are sanitized, otherwise, they are stripped.
|
61
61
|
def render_meeting_body(meeting)
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
def render_meeting_sanitize_field(meeting, field)
|
66
|
-
sanitized = render_sanitized_content(meeting, field)
|
62
|
+
sanitized = render_sanitized_content(meeting, :description)
|
67
63
|
if safe_content?
|
68
64
|
Decidim::ContentProcessor.render_without_format(sanitized).html_safe
|
69
65
|
else
|
@@ -61,13 +61,14 @@ module Decidim
|
|
61
61
|
scope :past, -> { where(arel_table[:end_time].lteq(Time.current)) }
|
62
62
|
scope :upcoming, -> { where(arel_table[:end_time].gteq(Time.current)) }
|
63
63
|
scope :withdrawn, -> { where(state: "withdrawn") }
|
64
|
-
scope :
|
64
|
+
scope :withdrawn, -> { where.not(withdrawn_at: nil) }
|
65
|
+
scope :not_withdrawn, -> { where(withdrawn_at: nil) }
|
65
66
|
scope :with_availability, lambda { |state_key|
|
66
67
|
case state_key
|
67
68
|
when "withdrawn"
|
68
69
|
withdrawn
|
69
70
|
else
|
70
|
-
|
71
|
+
not_withdrawn
|
71
72
|
end
|
72
73
|
}
|
73
74
|
scope_search_multi :with_any_date, [:upcoming, :past]
|
@@ -271,7 +272,7 @@ module Decidim
|
|
271
272
|
#
|
272
273
|
# Returns Boolean.
|
273
274
|
def withdrawn?
|
274
|
-
|
275
|
+
withdrawn_at.present?
|
275
276
|
end
|
276
277
|
|
277
278
|
# Checks whether the user can withdraw the given meeting.
|
@@ -282,6 +283,11 @@ module Decidim
|
|
282
283
|
user && !withdrawn? && !past? && authored_by?(user)
|
283
284
|
end
|
284
285
|
|
286
|
+
def withdraw!
|
287
|
+
self.withdrawn_at = Time.zone.now
|
288
|
+
save
|
289
|
+
end
|
290
|
+
|
285
291
|
# Overwrites method from Paddable to add custom rules in order to know
|
286
292
|
# when to display a pad or not.
|
287
293
|
def pad_is_visible?
|
@@ -323,7 +329,7 @@ module Decidim
|
|
323
329
|
|
324
330
|
# Public: Overrides the `reported_searchable_content_extras` Reportable concern method.
|
325
331
|
def reported_searchable_content_extras
|
326
|
-
[
|
332
|
+
[author_name]
|
327
333
|
end
|
328
334
|
|
329
335
|
def has_contributions?
|
@@ -14,6 +14,14 @@ module Decidim
|
|
14
14
|
delegate :organization, to: :meeting
|
15
15
|
|
16
16
|
QUESTION_TYPES = %w(single_option multiple_option).freeze
|
17
|
+
|
18
|
+
def has_questions?
|
19
|
+
questionnaire&.questions&.exists?
|
20
|
+
end
|
21
|
+
|
22
|
+
def has_open_questions?
|
23
|
+
has_questions? && questionnaire.questions.not_closed.exists?
|
24
|
+
end
|
17
25
|
end
|
18
26
|
end
|
19
27
|
end
|
@@ -28,6 +28,7 @@ module Decidim
|
|
28
28
|
validates :question_type, inclusion: { in: QUESTION_TYPES }
|
29
29
|
|
30
30
|
scope :visible, -> { where(status: [:published, :closed]) }
|
31
|
+
scope :unanswered, -> { where.missing(:answers) }
|
31
32
|
|
32
33
|
def multiple_choice?
|
33
34
|
%w(single_option multiple_option).include?(question_type)
|
@@ -11,12 +11,6 @@ module Decidim
|
|
11
11
|
has_many :questions, -> { order(:position) }, class_name: "Question", foreign_key: "decidim_questionnaire_id", dependent: :destroy
|
12
12
|
has_many :answers, class_name: "Answer", foreign_key: "decidim_questionnaire_id", dependent: :destroy
|
13
13
|
|
14
|
-
# Public: returns whether the questionnaire questions can be modified or not.
|
15
|
-
def questions_editable?
|
16
|
-
has_component = questionnaire_for.meeting.respond_to? :component
|
17
|
-
(has_component && !questionnaire_for.meeting.component.published?) || answers.empty?
|
18
|
-
end
|
19
|
-
|
20
14
|
def all_questions_unpublished?
|
21
15
|
questions.all?(&:unpublished?)
|
22
16
|
end
|
@@ -117,9 +117,9 @@ $(() => {
|
|
117
117
|
toggleDependsOnSelect($meetingRegistrationType, $meetingRegistrationUrl, "on_different_platform");
|
118
118
|
|
119
119
|
const $meetingTypeOfMeeting = $form.find("#meeting_type_of_meeting");
|
120
|
-
const $meetingOnlineFields = $form.find("
|
121
|
-
const $meetingInPersonFields = $form.find("
|
122
|
-
const $meetingOnlineAccessLevelFields = $form.find("
|
120
|
+
const $meetingOnlineFields = $form.find("[data-meeting-type='online']");
|
121
|
+
const $meetingInPersonFields = $form.find("[data-meeting-type='in_person']");
|
122
|
+
const $meetingOnlineAccessLevelFields = $form.find("[data-meeting-type='online-access-level']");
|
123
123
|
const $meetingIframeEmbedType = $form.find("#meeting_iframe_embed_type");
|
124
124
|
|
125
125
|
const toggleTypeDependsOnSelect = ($target, $showDiv, type) => {
|
@@ -11,9 +11,9 @@ $(() => {
|
|
11
11
|
const $form = $(".meetings_form");
|
12
12
|
if ($form.length > 0) {
|
13
13
|
const $meetingTypeOfMeeting = $form.find("#meeting_type_of_meeting");
|
14
|
-
const $meetingOnlineFields = $form.find("
|
15
|
-
const $meetingInPersonFields = $form.find("
|
16
|
-
const $meetingOnlineAccessLevelFields = $form.find("
|
14
|
+
const $meetingOnlineFields = $form.find("[data-meeting-type='online']");
|
15
|
+
const $meetingInPersonFields = $form.find("[data-meeting-type='in_person']");
|
16
|
+
const $meetingOnlineAccessLevelFields = $form.find("[data-meeting-type='online-access-level']");
|
17
17
|
|
18
18
|
const toggleDependsOnSelect = ($target, $showDiv, type) => {
|
19
19
|
const value = $target.val();
|
@@ -9,6 +9,8 @@ $(() => {
|
|
9
9
|
if ($container.length) {
|
10
10
|
const poll = new MeetingsPollComponent($container, $container.data("decidim-meetings-poll"), $counter);
|
11
11
|
|
12
|
+
poll.mountComponent();
|
13
|
+
|
12
14
|
$(".meeting-polls__action-list").on("click", (event) => {
|
13
15
|
event.preventDefault();
|
14
16
|
|
@@ -29,6 +31,9 @@ $(() => {
|
|
29
31
|
|
30
32
|
if ($adminContainer.length) {
|
31
33
|
const adminPoll = new MeetingsPollComponent($adminContainer, $adminContainer.data("decidim-admin-meetings-poll"));
|
34
|
+
|
35
|
+
adminPoll.mountComponent();
|
36
|
+
|
32
37
|
$(".meeting-polls__action-administrate").on("click", (event) => {
|
33
38
|
event.preventDefault();
|
34
39
|
|
@@ -4,7 +4,7 @@ import createOptionAttachedInputs from "src/decidim/forms/option_attached_inputs
|
|
4
4
|
import createMaxChoicesAlertComponent from "src/decidim/forms/max_choices_alert.component"
|
5
5
|
|
6
6
|
/**
|
7
|
-
* A plain
|
7
|
+
* A plain JavaScript component that handles questions from polls in meetings:
|
8
8
|
* - fetches them via Ajax
|
9
9
|
* - enables a polling to automatically update them
|
10
10
|
*
|
@@ -24,9 +24,11 @@ export default class PollComponent {
|
|
24
24
|
this.$element = $element;
|
25
25
|
this.$counter = $counter;
|
26
26
|
this.questionsUrl = config.questionsUrl;
|
27
|
-
this.pollingInterval = config.pollingInterval ||
|
27
|
+
this.pollingInterval = config.pollingInterval || 10000;
|
28
28
|
this.mounted = false;
|
29
29
|
this.questions = {};
|
30
|
+
this.questionsStatuses = {};
|
31
|
+
this.answersStatuses = {};
|
30
32
|
}
|
31
33
|
|
32
34
|
/**
|
@@ -66,7 +68,9 @@ export default class PollComponent {
|
|
66
68
|
* @returns {Void} - Returns nothing
|
67
69
|
*/
|
68
70
|
_fetchQuestions() {
|
69
|
-
|
71
|
+
$("#content").addClass("spinner-container")
|
72
|
+
|
73
|
+
// Store current questions state (open / closed) before overwriting them with the Ajax call
|
70
74
|
// response.
|
71
75
|
this._storeQuestionState(this.$element);
|
72
76
|
|
@@ -79,6 +83,8 @@ export default class PollComponent {
|
|
79
83
|
this._setQuestionsState(this.$element);
|
80
84
|
this._pollQuestions();
|
81
85
|
this._addValidations();
|
86
|
+
|
87
|
+
$("#content").removeClass("spinner-container")
|
82
88
|
});
|
83
89
|
}
|
84
90
|
|
@@ -92,6 +98,12 @@ export default class PollComponent {
|
|
92
98
|
$("[data-question]", $parent).each((_i, el) => {
|
93
99
|
const $el = $(el);
|
94
100
|
const questionId = $el.data("question");
|
101
|
+
const elForm = $el.find("form");
|
102
|
+
|
103
|
+
this.questionsStatuses[questionId] = $el.data("status");
|
104
|
+
if (elForm.length > 0) {
|
105
|
+
this.answersStatuses[questionId] = Object.fromEntries(new FormData(elForm[0]));
|
106
|
+
}
|
95
107
|
if ($el[0].open === true) {
|
96
108
|
this.questions[questionId] = OPEN;
|
97
109
|
} else {
|
@@ -124,12 +136,28 @@ export default class PollComponent {
|
|
124
136
|
const questionId = $el.data("question");
|
125
137
|
// Current question state
|
126
138
|
const state = this.questions[questionId];
|
139
|
+
const questionStatus = this.questionsStatuses[questionId];
|
140
|
+
const answersStatuses = this.answersStatuses[questionId];
|
141
|
+
|
127
142
|
// New questions have a special class
|
128
143
|
if (!state) {
|
129
144
|
$el.addClass("is-new");
|
130
145
|
} else if (state === OPEN) {
|
131
146
|
$el.prop(OPEN, true);
|
132
147
|
}
|
148
|
+
|
149
|
+
if ($el.data("status") === CLOSED && $el.data("status") !== questionStatus) {
|
150
|
+
$el.data("status", `${CLOSED}-new`);
|
151
|
+
document.getElementById(`closed-announcement-${questionId}`).hidden = false;
|
152
|
+
}
|
153
|
+
|
154
|
+
if (answersStatuses) {
|
155
|
+
for (const [key, value] of Object.entries(answersStatuses)) {
|
156
|
+
if (key.includes("[choices]")) {
|
157
|
+
$el.find(`[name='${key}'][value='${value}']`).prop("checked", true);
|
158
|
+
}
|
159
|
+
}
|
160
|
+
}
|
133
161
|
}
|
134
162
|
|
135
163
|
/**
|
@@ -177,7 +205,7 @@ export default class PollComponent {
|
|
177
205
|
});
|
178
206
|
});
|
179
207
|
|
180
|
-
$.unique($(".js-check-box-collection").parents("
|
208
|
+
$.unique($(".js-check-box-collection").parents("[data-max-choices]")).each((idx, el) => {
|
181
209
|
const maxChoices = $(el).data("max-choices");
|
182
210
|
if (maxChoices) {
|
183
211
|
createMaxChoicesAlertComponent({
|
@@ -6,17 +6,29 @@
|
|
6
6
|
}
|
7
7
|
|
8
8
|
&__calendar {
|
9
|
-
@apply
|
9
|
+
@apply w-14 flex flex-col justify-start rounded bg-background text-center;
|
10
10
|
|
11
11
|
&:only-child &-month {
|
12
12
|
@apply rounded-t;
|
13
13
|
}
|
14
14
|
|
15
15
|
&-container {
|
16
|
-
@apply
|
16
|
+
@apply grid grid-cols-[auto_1fr] md:grid-cols-[auto_1fr_1fr] items-center gap-0 md:gap-x-5 border-4 border-background rounded md:h-[140px] overflow-hidden;
|
17
17
|
|
18
|
-
|
19
|
-
@apply
|
18
|
+
> *:nth-child(2) {
|
19
|
+
@apply p-4 md:p-0;
|
20
|
+
|
21
|
+
&:not(:last-child) {
|
22
|
+
@apply col-span-2 md:col-auto order-2 md:order-1;
|
23
|
+
}
|
24
|
+
|
25
|
+
&:last-child {
|
26
|
+
@apply md:col-span-2 pr-4;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
> *:nth-child(3) {
|
31
|
+
@apply order-1 md:order-2 h-[135px] md:h-full;
|
20
32
|
}
|
21
33
|
}
|
22
34
|
|
@@ -43,7 +55,7 @@
|
|
43
55
|
}
|
44
56
|
|
45
57
|
&__lg {
|
46
|
-
@apply
|
58
|
+
@apply w-fit justify-center [&>*]:px-2 min-w-24 h-[8.5rem];
|
47
59
|
}
|
48
60
|
|
49
61
|
&__lg &-month {
|
@@ -113,13 +125,17 @@
|
|
113
125
|
}
|
114
126
|
|
115
127
|
&::-webkit-progress-bar {
|
116
|
-
@apply bg-white;
|
128
|
+
@apply bg-gray lg:bg-white;
|
117
129
|
}
|
118
130
|
|
119
131
|
&::-moz-progress-bar {
|
120
132
|
@apply bg-success;
|
121
133
|
}
|
122
134
|
}
|
135
|
+
|
136
|
+
&-label {
|
137
|
+
@apply text-sm font-bold lg:hidden;
|
138
|
+
}
|
123
139
|
}
|
124
140
|
|
125
141
|
&-block {
|
@@ -163,3 +179,107 @@
|
|
163
179
|
}
|
164
180
|
}
|
165
181
|
}
|
182
|
+
|
183
|
+
// layout reset stuff
|
184
|
+
.meeting-poll__layout {
|
185
|
+
header,
|
186
|
+
main h1,
|
187
|
+
footer {
|
188
|
+
@apply hidden md:block;
|
189
|
+
}
|
190
|
+
|
191
|
+
.layout-1col {
|
192
|
+
padding: 0;
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
.meeting-polls {
|
197
|
+
@apply m-0 md:mt-10 md:mb-24;
|
198
|
+
|
199
|
+
counter-reset: question;
|
200
|
+
|
201
|
+
&__question {
|
202
|
+
@apply bg-white;
|
203
|
+
|
204
|
+
summary {
|
205
|
+
@apply p-4 font-normal text-black text-md transition bg-background cursor-pointer marker:text-secondary;
|
206
|
+
|
207
|
+
transition: background-color 0.2s ease-in-out;
|
208
|
+
|
209
|
+
& > span:first-child::after {
|
210
|
+
counter-increment: question;
|
211
|
+
content: "#" counter(question);
|
212
|
+
}
|
213
|
+
|
214
|
+
& > span:last-child:not(:only-child) {
|
215
|
+
@apply text-sm font-semibold float-right;
|
216
|
+
}
|
217
|
+
|
218
|
+
& + * {
|
219
|
+
@apply mt-4 mb-8 md:mb-16 pr-4 pl-[calc(1rem+14px)] md:px-0 space-y-6;
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
&[open] summary {
|
224
|
+
@apply bg-secondary md:bg-background marker:text-white md:marker:text-secondary text-white md:text-black;
|
225
|
+
}
|
226
|
+
|
227
|
+
&.is-new {
|
228
|
+
animation: animateHighlight 5s ease-in-out forwards;
|
229
|
+
}
|
230
|
+
|
231
|
+
& + & {
|
232
|
+
@apply mt-4;
|
233
|
+
}
|
234
|
+
|
235
|
+
@keyframes animateHighlight {
|
236
|
+
0%,
|
237
|
+
80% {
|
238
|
+
background-color: rgba(var(--warning-rgb), 0.1);
|
239
|
+
}
|
240
|
+
}
|
241
|
+
}
|
242
|
+
|
243
|
+
&__answer {
|
244
|
+
label {
|
245
|
+
@apply block p-4 ring-4 ring-background rounded transition;
|
246
|
+
|
247
|
+
&:not(:has([disabled])) {
|
248
|
+
@apply hover:ring-tertiary hover:cursor-pointer;
|
249
|
+
}
|
250
|
+
}
|
251
|
+
|
252
|
+
label + label,
|
253
|
+
& + & {
|
254
|
+
@apply mt-4;
|
255
|
+
}
|
256
|
+
|
257
|
+
&--value {
|
258
|
+
@apply flex gap-2 justify-between text-gray-2 text-lg;
|
259
|
+
|
260
|
+
> *:last-child {
|
261
|
+
@apply w-1/6 flex-none text-gray text-right;
|
262
|
+
}
|
263
|
+
}
|
264
|
+
|
265
|
+
&--bar {
|
266
|
+
@apply w-full h-2.5 overflow-hidden rounded bg-background;
|
267
|
+
|
268
|
+
> * {
|
269
|
+
@apply bg-success h-full rounded;
|
270
|
+
}
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
274
|
+
&__admin-action {
|
275
|
+
@apply py-4 grid grid-cols-2 gap-x-4 gap-y-8 border-t border-t-gray [&>*:nth-child(2)]:ml-auto [&>*:nth-child(3)]:col-span-2;
|
276
|
+
}
|
277
|
+
|
278
|
+
&__topbar {
|
279
|
+
@apply my-4 md:my-0 px-4 md:px-0 py-2 md:py-10 flex justify-between gap-4 bg-background md:bg-transparent;
|
280
|
+
|
281
|
+
&.is-admin {
|
282
|
+
@apply mt-0 bg-tertiary md:bg-transparent text-black;
|
283
|
+
}
|
284
|
+
}
|
285
|
+
}
|