decidim-calendar 0.13.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-AGPLv3.txt +661 -0
  3. data/README.md +9 -0
  4. data/Rakefile +43 -0
  5. data/app/assets/config/decidim_calendar_manifest.css +2 -0
  6. data/app/assets/config/decidim_calendar_manifest.js +2 -0
  7. data/app/assets/images/decidim/calendar/icon.svg +51 -0
  8. data/app/assets/javascripts/decidim/calendar/calendar.js.es6 +6 -0
  9. data/app/assets/javascripts/decidim/calendar/gantt.js.es6 +1 -0
  10. data/app/assets/stylesheets/decidim/calendar/calendar.scss +102 -0
  11. data/app/assets/stylesheets/decidim/calendar/gantt.scss +1 -0
  12. data/app/commands/decidim/calendar/admin/create_external_event.rb +38 -0
  13. data/app/commands/decidim/calendar/admin/destroy_external_event.rb +27 -0
  14. data/app/commands/decidim/calendar/admin/update_external_event.rb +43 -0
  15. data/app/controllers/decidim/calendar/admin/application_controller.rb +23 -0
  16. data/app/controllers/decidim/calendar/admin/external_events_controller.rb +84 -0
  17. data/app/controllers/decidim/calendar/application_controller.rb +21 -0
  18. data/app/controllers/decidim/calendar/calendar_controller.rb +33 -0
  19. data/app/forms/decidim/calendar/admin/external_event_form.rb +21 -0
  20. data/app/helpers/decidim/calendar/calendar_helper.rb +57 -0
  21. data/app/models/decidim/calendar/application_record.rb +9 -0
  22. data/app/models/decidim/calendar/event.rb +25 -0
  23. data/app/models/decidim/calendar/external_event.rb +18 -0
  24. data/app/permissions/decidim/calendar/admin/permissions.rb +22 -0
  25. data/app/presenters/decidim/calendar/event_presenter.rb +104 -0
  26. data/app/queries/decidim/calendar/organization_calendar.rb +15 -0
  27. data/app/services/decidim/calendar/event_to_ical.rb +27 -0
  28. data/app/services/decidim/calendar/general_calendar.rb +13 -0
  29. data/app/services/decidim/calendar/meeting_to_event.rb +8 -0
  30. data/app/services/decidim/meetings/calendar/base_calendar.rb +61 -0
  31. data/app/views/decidim/calendar/admin/external_events/_form.html.erb +22 -0
  32. data/app/views/decidim/calendar/admin/external_events/edit.html.erb +6 -0
  33. data/app/views/decidim/calendar/admin/external_events/index.html.erb +66 -0
  34. data/app/views/decidim/calendar/admin/external_events/new.html.erb +6 -0
  35. data/app/views/decidim/calendar/calendar/gantt.html.erb +22 -0
  36. data/app/views/decidim/calendar/calendar/index.html.erb +63 -0
  37. data/app/views/decidim/shared/_extended_navigation_bar.html.erb +51 -0
  38. data/app/views/layouts/_calendar_navigation.html.erb +18 -0
  39. data/app/views/layouts/calendar.html.erb +4 -0
  40. data/config/locales/ca.yml +38 -0
  41. data/config/locales/de.yml +38 -0
  42. data/config/locales/en.yml +48 -0
  43. data/config/locales/es.yml +38 -0
  44. data/config/locales/fi.yml +38 -0
  45. data/config/locales/fr.yml +38 -0
  46. data/config/locales/it.yml +38 -0
  47. data/config/locales/pl.yml +38 -0
  48. data/config/locales/pt.yml +38 -0
  49. data/config/locales/ro.yml +38 -0
  50. data/config/locales/ru.yml +38 -0
  51. data/config/locales/sv.yml +38 -0
  52. data/config/locales/tr.yml +38 -0
  53. data/config/locales/uk.yml +38 -0
  54. data/db/migrate/20190312132654_create_decidim_calendar_external_events.rb +18 -0
  55. data/lib/decidim/calendar.rb +11 -0
  56. data/lib/decidim/calendar/admin.rb +9 -0
  57. data/lib/decidim/calendar/admin_engine.rb +30 -0
  58. data/lib/decidim/calendar/engine.rb +34 -0
  59. data/lib/decidim/calendar/participatory_space.rb +20 -0
  60. data/lib/decidim/calendar/test/factories.rb +12 -0
  61. data/lib/decidim/calendar/version.rb +10 -0
  62. data/vendor/assets/javascripts/frappe-gantt/frappe-gantt.css +119 -0
  63. data/vendor/assets/javascripts/frappe-gantt/frappe-gantt.js +1883 -0
  64. data/vendor/assets/javascripts/fullcalendar/bootstrap/main.css +33 -0
  65. data/vendor/assets/javascripts/fullcalendar/bootstrap/main.js +90 -0
  66. data/vendor/assets/javascripts/fullcalendar/bootstrap/main.min.css +5 -0
  67. data/vendor/assets/javascripts/fullcalendar/bootstrap/main.min.js +20 -0
  68. data/vendor/assets/javascripts/fullcalendar/core/locales-all.js +1353 -0
  69. data/vendor/assets/javascripts/fullcalendar/core/locales-all.min.js +6 -0
  70. data/vendor/assets/javascripts/fullcalendar/core/locales/af.js +30 -0
  71. data/vendor/assets/javascripts/fullcalendar/core/locales/ar-dz.js +31 -0
  72. data/vendor/assets/javascripts/fullcalendar/core/locales/ar-kw.js +31 -0
  73. data/vendor/assets/javascripts/fullcalendar/core/locales/ar-ly.js +31 -0
  74. data/vendor/assets/javascripts/fullcalendar/core/locales/ar-ma.js +31 -0
  75. data/vendor/assets/javascripts/fullcalendar/core/locales/ar-sa.js +31 -0
  76. data/vendor/assets/javascripts/fullcalendar/core/locales/ar-tn.js +31 -0
  77. data/vendor/assets/javascripts/fullcalendar/core/locales/ar.js +31 -0
  78. data/vendor/assets/javascripts/fullcalendar/core/locales/bg.js +31 -0
  79. data/vendor/assets/javascripts/fullcalendar/core/locales/bs.js +32 -0
  80. data/vendor/assets/javascripts/fullcalendar/core/locales/ca.js +30 -0
  81. data/vendor/assets/javascripts/fullcalendar/core/locales/cs.js +32 -0
  82. data/vendor/assets/javascripts/fullcalendar/core/locales/da.js +30 -0
  83. data/vendor/assets/javascripts/fullcalendar/core/locales/de.js +33 -0
  84. data/vendor/assets/javascripts/fullcalendar/core/locales/el.js +30 -0
  85. data/vendor/assets/javascripts/fullcalendar/core/locales/en-au.js +17 -0
  86. data/vendor/assets/javascripts/fullcalendar/core/locales/en-gb.js +17 -0
  87. data/vendor/assets/javascripts/fullcalendar/core/locales/en-nz.js +17 -0
  88. data/vendor/assets/javascripts/fullcalendar/core/locales/es-us.js +30 -0
  89. data/vendor/assets/javascripts/fullcalendar/core/locales/es.js +30 -0
  90. data/vendor/assets/javascripts/fullcalendar/core/locales/et.js +32 -0
  91. data/vendor/assets/javascripts/fullcalendar/core/locales/eu.js +30 -0
  92. data/vendor/assets/javascripts/fullcalendar/core/locales/fa.js +33 -0
  93. data/vendor/assets/javascripts/fullcalendar/core/locales/fi.js +30 -0
  94. data/vendor/assets/javascripts/fullcalendar/core/locales/fr-ca.js +27 -0
  95. data/vendor/assets/javascripts/fullcalendar/core/locales/fr-ch.js +31 -0
  96. data/vendor/assets/javascripts/fullcalendar/core/locales/fr.js +31 -0
  97. data/vendor/assets/javascripts/fullcalendar/core/locales/gl.js +30 -0
  98. data/vendor/assets/javascripts/fullcalendar/core/locales/he.js +27 -0
  99. data/vendor/assets/javascripts/fullcalendar/core/locales/hi.js +32 -0
  100. data/vendor/assets/javascripts/fullcalendar/core/locales/hr.js +32 -0
  101. data/vendor/assets/javascripts/fullcalendar/core/locales/hu.js +30 -0
  102. data/vendor/assets/javascripts/fullcalendar/core/locales/id.js +30 -0
  103. data/vendor/assets/javascripts/fullcalendar/core/locales/is.js +30 -0
  104. data/vendor/assets/javascripts/fullcalendar/core/locales/it.js +32 -0
  105. data/vendor/assets/javascripts/fullcalendar/core/locales/ja.js +28 -0
  106. data/vendor/assets/javascripts/fullcalendar/core/locales/ka.js +32 -0
  107. data/vendor/assets/javascripts/fullcalendar/core/locales/kk.js +32 -0
  108. data/vendor/assets/javascripts/fullcalendar/core/locales/ko.js +26 -0
  109. data/vendor/assets/javascripts/fullcalendar/core/locales/lb.js +30 -0
  110. data/vendor/assets/javascripts/fullcalendar/core/locales/lt.js +30 -0
  111. data/vendor/assets/javascripts/fullcalendar/core/locales/lv.js +32 -0
  112. data/vendor/assets/javascripts/fullcalendar/core/locales/mk.js +28 -0
  113. data/vendor/assets/javascripts/fullcalendar/core/locales/ms.js +32 -0
  114. data/vendor/assets/javascripts/fullcalendar/core/locales/nb.js +30 -0
  115. data/vendor/assets/javascripts/fullcalendar/core/locales/nl.js +30 -0
  116. data/vendor/assets/javascripts/fullcalendar/core/locales/nn.js +30 -0
  117. data/vendor/assets/javascripts/fullcalendar/core/locales/pl.js +30 -0
  118. data/vendor/assets/javascripts/fullcalendar/core/locales/pt-br.js +28 -0
  119. data/vendor/assets/javascripts/fullcalendar/core/locales/pt.js +30 -0
  120. data/vendor/assets/javascripts/fullcalendar/core/locales/ro.js +32 -0
  121. data/vendor/assets/javascripts/fullcalendar/core/locales/ru.js +32 -0
  122. data/vendor/assets/javascripts/fullcalendar/core/locales/sk.js +32 -0
  123. data/vendor/assets/javascripts/fullcalendar/core/locales/sl.js +30 -0
  124. data/vendor/assets/javascripts/fullcalendar/core/locales/sq.js +32 -0
  125. data/vendor/assets/javascripts/fullcalendar/core/locales/sr-cyrl.js +32 -0
  126. data/vendor/assets/javascripts/fullcalendar/core/locales/sr.js +32 -0
  127. data/vendor/assets/javascripts/fullcalendar/core/locales/sv.js +30 -0
  128. data/vendor/assets/javascripts/fullcalendar/core/locales/th.js +25 -0
  129. data/vendor/assets/javascripts/fullcalendar/core/locales/tr.js +30 -0
  130. data/vendor/assets/javascripts/fullcalendar/core/locales/uk.js +32 -0
  131. data/vendor/assets/javascripts/fullcalendar/core/locales/vi.js +32 -0
  132. data/vendor/assets/javascripts/fullcalendar/core/locales/zh-cn.js +33 -0
  133. data/vendor/assets/javascripts/fullcalendar/core/locales/zh-tw.js +26 -0
  134. data/vendor/assets/javascripts/fullcalendar/core/main.css +900 -0
  135. data/vendor/assets/javascripts/fullcalendar/core/main.js +8791 -0
  136. data/vendor/assets/javascripts/fullcalendar/core/main.min.css +5 -0
  137. data/vendor/assets/javascripts/fullcalendar/core/main.min.js +9 -0
  138. data/vendor/assets/javascripts/fullcalendar/daygrid/main.css +69 -0
  139. data/vendor/assets/javascripts/fullcalendar/daygrid/main.js +1630 -0
  140. data/vendor/assets/javascripts/fullcalendar/daygrid/main.min.css +5 -0
  141. data/vendor/assets/javascripts/fullcalendar/daygrid/main.min.js +20 -0
  142. data/vendor/assets/javascripts/fullcalendar/google-calendar/main.js +169 -0
  143. data/vendor/assets/javascripts/fullcalendar/google-calendar/main.min.js +20 -0
  144. data/vendor/assets/javascripts/fullcalendar/interaction/main.js +2155 -0
  145. data/vendor/assets/javascripts/fullcalendar/interaction/main.min.js +21 -0
  146. data/vendor/assets/javascripts/fullcalendar/list/main.css +101 -0
  147. data/vendor/assets/javascripts/fullcalendar/list/main.js +341 -0
  148. data/vendor/assets/javascripts/fullcalendar/list/main.min.css +5 -0
  149. data/vendor/assets/javascripts/fullcalendar/list/main.min.js +20 -0
  150. data/vendor/assets/javascripts/fullcalendar/luxon/main.js +162 -0
  151. data/vendor/assets/javascripts/fullcalendar/luxon/main.min.js +20 -0
  152. data/vendor/assets/javascripts/fullcalendar/moment-timezone/main.js +64 -0
  153. data/vendor/assets/javascripts/fullcalendar/moment-timezone/main.min.js +20 -0
  154. data/vendor/assets/javascripts/fullcalendar/moment/main.js +103 -0
  155. data/vendor/assets/javascripts/fullcalendar/moment/main.min.js +6 -0
  156. data/vendor/assets/javascripts/fullcalendar/rrule/main.js +127 -0
  157. data/vendor/assets/javascripts/fullcalendar/rrule/main.min.js +20 -0
  158. data/vendor/assets/javascripts/fullcalendar/timegrid/main.css +266 -0
  159. data/vendor/assets/javascripts/fullcalendar/timegrid/main.js +1339 -0
  160. data/vendor/assets/javascripts/fullcalendar/timegrid/main.min.css +5 -0
  161. data/vendor/assets/javascripts/fullcalendar/timegrid/main.min.js +20 -0
  162. metadata +247 -0
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ class ApplicationController < Decidim::ApplicationController
6
+ include NeedsPermission
7
+
8
+ private
9
+
10
+ def permission_class_chain
11
+ [
12
+ Decidim::Permissions
13
+ ]
14
+ end
15
+
16
+ def permission_scope
17
+ :public
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ class CalendarController < Decidim::Calendar::ApplicationController
6
+ helper Decidim::Calendar::CalendarHelper
7
+ include ParticipatorySpaceContext
8
+ layout "calendar"
9
+ def index
10
+ @events = Event.all(current_organization)
11
+ @resources = %w(consultation debate external_event meeting participatory_step)
12
+ end
13
+
14
+ def gantt
15
+ @events = Decidim::ParticipatoryProcessStep.all.order(decidim_participatory_process_id: :asc, position: :asc, start_date: :asc).map do |p|
16
+ Decidim::Calendar::EventPresenter.new(p) if p.organization == current_organization
17
+ end
18
+ end
19
+
20
+ def ical
21
+ filename = "#{current_organization.name.parameterize}-calendar"
22
+ response.headers['Content-Disposition'] = 'attachment; filename="' + filename + '.ical"'
23
+ render plain: GeneralCalendar.for(current_organization), content_type: "text/calendar"
24
+ end
25
+
26
+ private
27
+
28
+ def current_participatory_space_manifest
29
+ @current_participatory_space_manifest ||= Decidim.find_participatory_space_manifest(:calendar)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ module Admin
6
+ class ExternalEventForm < Decidim::Form
7
+ include TranslatableAttributes
8
+
9
+ translatable_attribute :title, String
10
+ attribute :start_at, Decidim::Attributes::TimeWithZone
11
+ attribute :end_at, Decidim::Attributes::TimeWithZone
12
+ attribute :url, String
13
+
14
+ validates :title, translatable_presence: true
15
+ validates :title, :start_at, :end_at, :url, presence: true
16
+ validates :start_at, date: { before: :end_at, allow_blank: false, if: proc { |obj| obj.end_at.present? } }
17
+ validates :end_at, date: { after: :start_at, allow_blank: true, if: proc { |obj| obj.start_at.present? } }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ module CalendarHelper
6
+ include Decidim::ApplicationHelper
7
+ include Decidim::TranslationsHelper
8
+ include Decidim::ResourceHelper
9
+ def calendar_resource(name)
10
+ %({
11
+ "id": "#{name}",
12
+ "title": "#{I18n.t(name, scope: "decidim.calendar.index.filters")}"
13
+ })
14
+ end
15
+ def calendar_event(event)
16
+ %({
17
+ "title": "#{translated_attribute event.full_title}",
18
+ "start": "#{event.start.strftime("%FT%R")}",
19
+ "end": "#{event.finish.strftime("%FT%R")}",
20
+ "color": "#{event.color}",
21
+ "url": "#{event.link}",
22
+ "resourceId": "#{event.type}",
23
+ "allDay": #{event.all_day?}
24
+ })
25
+ end
26
+
27
+ def participatory_gantt(event)
28
+ %({
29
+ "id": "#{event.full_id}",
30
+ "name": "#{translated_attribute event.full_title}",
31
+ "start": "#{event.start.strftime("%FT%R")}",
32
+ "dependencies": "#{event.parent}",
33
+ "end": "#{event.finish.strftime("%FT%R")}"
34
+ })
35
+ end
36
+
37
+ def participatory_space_wrapper(&block)
38
+ content_tag :main, class: "wrapper" do
39
+ concat(capture(&block))
40
+ end
41
+ end
42
+
43
+ def extended_navigation_bar(items, max_items: 5)
44
+ return unless items.any?
45
+ extra_items = []
46
+ active_item = items.find { |item| item[:active] }
47
+
48
+ render partial: "decidim/shared/extended_navigation_bar", locals: {
49
+ items: items,
50
+ extra_items: extra_items,
51
+ active_item: active_item,
52
+ max_items: 5
53
+ }
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ class ApplicationRecord < ActiveRecord::Base
6
+ self.abstract_class = true
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ module Event
6
+ MODELS = [
7
+ Decidim::Meetings::Meeting,
8
+ Decidim::ParticipatoryProcessStep,
9
+ Decidim::Debates::Debate,
10
+ Decidim::Consultation,
11
+ Decidim::Calendar::ExternalEvent
12
+ ].freeze
13
+
14
+ def self.all(current_organization)
15
+ events = []
16
+ MODELS.collect do |model|
17
+ model
18
+ .all
19
+ .map { |obj| events << Decidim::Calendar::EventPresenter.new(obj) if obj.organization == current_organization }
20
+ end
21
+ events
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ class ExternalEvent < Calendar::ApplicationRecord
6
+ include Decidim::Authorable
7
+
8
+ belongs_to :organization,
9
+ foreign_key: "decidim_organization_id",
10
+ class_name: "Decidim::Organization"
11
+
12
+ validates :title, :start_at, :end_at, presence: true
13
+ validates :start_at, date: { before: :end_at, allow_blank: false, if: proc { |obj| obj.end_at.present? } }
14
+ validates :end_at, date: { after: :start_at, allow_blank: true, if: proc { |obj| obj.start_at.present? } }
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ module Admin
6
+ class Permissions < Decidim::DefaultPermissions
7
+ def permissions
8
+ return permission_action unless user
9
+ return permission_action unless permission_action.scope == :admin
10
+
11
+ unless user.admin?
12
+ disallow!
13
+ return permission_action
14
+ end
15
+
16
+ allow!
17
+ permission_action
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ class EventPresenter < SimpleDelegator
6
+ def color
7
+ case __getobj__.class.name
8
+ when "Decidim::ParticipatoryProcessStep"
9
+ "#238ff7"
10
+ when "Decidim::Meetings::Meeting"
11
+ "#fabc6c"
12
+ when "Decidim::Calendar::ExternalEvent"
13
+ "#5fbd4c"
14
+ when "Decidim::Debates::Debate"
15
+ "#d87537"
16
+ when "Decidim::Consultation"
17
+ "#A854BD"
18
+ end
19
+ end
20
+
21
+ def type
22
+ case __getobj__.class.name
23
+ when "Decidim::ParticipatoryProcessStep"
24
+ "participatory_step"
25
+ when "Decidim::Meetings::Meeting"
26
+ "meeting"
27
+ when "Decidim::Calendar::ExternalEvent"
28
+ "external_event"
29
+ when "Decidim::Debates::Debate"
30
+ "debate"
31
+ when "Decidim::Consultation"
32
+ "consultation"
33
+ end
34
+ end
35
+
36
+ def full_id
37
+ case __getobj__.class.name
38
+ when "Decidim::ParticipatoryProcessStep"
39
+ "#{participatory_process.id}-#{id}"
40
+ else
41
+ id
42
+ end
43
+ end
44
+
45
+ def parent
46
+ case __getobj__.class.name
47
+ when "Decidim::ParticipatoryProcessStep"
48
+ "#{participatory_process.id}-#{participatory_process.steps.find_by(position: position - 1).id}" if position.positive?
49
+ end
50
+ end
51
+
52
+ def link
53
+ return url if respond_to?(:url)
54
+
55
+ @link ||= case __getobj__.class.name
56
+ when "Decidim::ParticipatoryProcessStep"
57
+ Decidim::ResourceLocatorPresenter.new(participatory_process).url
58
+ else
59
+ Decidim::ResourceLocatorPresenter.new(__getobj__).url
60
+ end
61
+ end
62
+
63
+ def start
64
+ # byebug
65
+ @start ||= if respond_to?(:start_date)
66
+ start_date
67
+ elsif respond_to?(:start_at)
68
+ start_at
69
+ elsif respond_to?(:start_voting_date)
70
+ start_voting_date
71
+ else
72
+ start_time
73
+ end
74
+ end
75
+
76
+ def finish
77
+ @finish ||= if respond_to?(:end_date)
78
+ end_date
79
+ elsif respond_to?(:end_at)
80
+ end_at
81
+ elsif respond_to?(:end_voting_date)
82
+ end_voting_date
83
+ else
84
+ end_time
85
+ end
86
+ end
87
+
88
+ def full_title
89
+ @full_title ||= case __getobj__.class.name
90
+ when "Decidim::ParticipatoryProcessStep"
91
+ participatory_process.title.merge(title) do |_k, v, o|
92
+ "#{v} - #{o}"
93
+ end
94
+ else
95
+ title
96
+ end
97
+ end
98
+
99
+ def all_day?
100
+ (start.to_date..finish.to_date).count > 1
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ class OrganizationCalendar < Rectify::Query
6
+ def initialize(organization)
7
+ @organization = organization
8
+ end
9
+
10
+ def query
11
+ Decidim::Assembly.where(organization: @organization)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ class EventToIcal
6
+ include ActionView::Helpers::SanitizeHelper
7
+ include Decidim::TranslationsHelper
8
+
9
+ def initialize(event)
10
+ @event = event
11
+ end
12
+
13
+ def ical
14
+ return @ical if @ical
15
+
16
+ @ical = Icalendar::Event.new
17
+ @ical.dtstart = Icalendar::Values::DateTime.new(@event.start)
18
+ @ical.dtend = Icalendar::Values::DateTime.new(@event.finish)
19
+ @ical.summary = translated_attribute @event.full_title
20
+ @ical.url = @event.link
21
+ @ical
22
+ end
23
+
24
+ delegate :to_ical, to: :ical
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ class GeneralCalendar < Decidim::Meetings::Calendar::BaseCalendar
6
+ def events
7
+ Event.all(resource).map do |event|
8
+ EventToIcal.new(event).to_ical
9
+ end.join
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Calendar
5
+ class MeetingToEvent < Decidim::Meetings::Calendar::MeetingToEvent
6
+ end
7
+ end
8
+ 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