spina-admin-conferences 2.0.1 → 2.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4422ca6e7b9b65669d3442a22035ef7f22e4ab3ea7ce817ba416fe73682e04a6
4
- data.tar.gz: af3da71b479742ac85a894c2ada05967ee7307a07cde2205d353374898e5ae13
3
+ metadata.gz: da95a8481d7f0d2b5d04a979dda9bc04455b083180c9e70106da172c604fa91c
4
+ data.tar.gz: 66514dbf26e695164135b6b4acd9e6acb6f22a5107b678fac6fc2b9e6e6cc22c
5
5
  SHA512:
6
- metadata.gz: 92eefe536ddfffab205b45a0888f3f9a88c133a26352810788b5cf927909c83cb016215f4614bed25f3f5fc93e4377f6a081c02359dc854d69a24d26337920c8
7
- data.tar.gz: d8e69093d00ecf8f14c1f6cedbfdfd1f419de19d8e485f466fb57b9974229b883120949230d1af63b3aa34dcfc9751ceeacd4bcaf9f432ce58c17cfd6a4658e1
6
+ metadata.gz: 9305b4aa9ae413dd88b35f4a4ff1d9e5363639289d7943d014d2f8f7f8e3c96085c48da590bed5cdf03986f8b7c21218a04ca9968068054219dfa3cb1ca0a779
7
+ data.tar.gz: 3296d9701c96c415b8219807591baee28631425448c6a4302e933d668a25b2e50c85448fcea6e324e2a36cebccbfefd88a37863d47ffd43b881d16f2c2677604
@@ -12,7 +12,7 @@ module Spina
12
12
  #
13
13
  # = Translations
14
14
  # - {#name}
15
- class Conference < ApplicationRecord
15
+ class Conference < ApplicationRecord # rubocop:disable Metrics/ClassLength
16
16
  include AttrJson::Record
17
17
  include AttrJson::NestedAttributes
18
18
  include Spina::Partable
@@ -70,6 +70,67 @@ module Spina
70
70
  validates :name, :start_date, :finish_date, :year, presence: true
71
71
  validates :finish_date, 'spina/admin/conferences/finish_date': true, unless: proc { |conference| conference.start_date.blank? }
72
72
 
73
+ class << self
74
+ # @return [Array<TZInfo::TimezonePeriod>] the time zone periods for the conferences
75
+ def time_zone_periods
76
+ pluck(:dates).compact.collect(&:begin).collect(&:at_beginning_of_day).collect(&:period)
77
+ end
78
+
79
+ # @return [String] a set of conferences as an iCalendar
80
+ def to_ics
81
+ Rails.cache.fetch [all, 'calendar'] do
82
+ calendar = Icalendar::Calendar.new
83
+ calendar.x_wr_calname = (Current.account || Spina::Account.first).name
84
+ calendar.add_timezone(ical_timezone)
85
+ conference_events.each { |event| calendar.add_event(event) }
86
+ calendar.publish
87
+ calendar.to_ical
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def conference_events
94
+ Rails.cache.fetch [all, 'events'] do
95
+ all.in_batches.each_record.collect do |conference|
96
+ Rails.cache.fetch([conference, 'event']) { conference.to_event }
97
+ end
98
+ end
99
+ end
100
+
101
+ def ical_timezone
102
+ Rails.cache.fetch [self, 'time_zone'] do
103
+ Icalendar::Timezone.new do |timezone|
104
+ timezone.tzid = Time.zone.name
105
+ daylight_periods.each { |daylight_period| timezone.add_daylight(daylight_period) }
106
+ standard_periods.each { |standard_period| timezone.add_daylight(standard_period) }
107
+ end
108
+ end
109
+ end
110
+
111
+ def daylight_periods
112
+ time_zone_periods.select(&:dst?).each do |period|
113
+ Icalendar::Timezone::Daylight.new do |ical_period|
114
+ ical_period.tzoffsetfrom = period.offset.ical_offset
115
+ ical_period.tzoffsetto = period.offset.ical_offset
116
+ ical_period.tzname = period.abbreviation
117
+ ical_period.dtstart = period.starts_at.to_datetime
118
+ end
119
+ end
120
+ end
121
+
122
+ def standard_periods
123
+ time_zone_periods.reject(&:dst?).each do |period|
124
+ Icalendar::Timezone::Standard.new do |ical_period|
125
+ ical_period.tzoffsetfrom = period.offset.ical_offset
126
+ ical_period.tzoffsetto = period.offset.ical_offset
127
+ ical_period.tzname = period.abbreviation
128
+ ical_period.dtstart = period.starts_at.to_datetime
129
+ end
130
+ end
131
+ end
132
+ end
133
+
73
134
  # @return [Date, nil] the start date of the conference. Nil if the conference has no dates
74
135
  def start_date
75
136
  return if dates.blank?
@@ -127,10 +188,8 @@ module Spina
127
188
  event = Icalendar::Event.new
128
189
  return event if invalid?
129
190
 
130
- event.dtstart = start_date
131
- event.dtstart.ical_param(:value, 'DATE')
132
- event.dtend = finish_date
133
- event.dtend.ical_param(:value, 'DATE')
191
+ event.dtstart = Icalendar::Values::Date.new(dates.begin)
192
+ event.dtend = Icalendar::Values::Date.new(dates.exclude_end? ? dates.end : dates.end + 1.day)
134
193
  event.location = location
135
194
  event.contact = Spina::Account.first.email
136
195
  event.categories = Conference.model_name.human(count: 0)
@@ -138,10 +197,71 @@ module Spina
138
197
  event
139
198
  end
140
199
 
141
- # @param (see #to_event)
142
- # @deprecated Use {#to_event} instead
200
+ # @return [TZInfo::TimezonePeriod, nil] the time zone period for the conference event
201
+ def time_zone_period
202
+ return if start_date.blank?
203
+
204
+ start_date.at_beginning_of_day.period
205
+ end
206
+
207
+ # @return [String, nil] the conference as an iCalendar
143
208
  def to_ics
144
- to_event
209
+ Rails.cache.fetch [self, presentations, 'calendar'] do
210
+ calendar = Icalendar::Calendar.new
211
+ return if invalid?
212
+
213
+ calendar.x_wr_calname = name
214
+ calendar.add_timezone(ical_timezone)
215
+ eventables_events.each { |event| calendar.add_event(event) }
216
+ calendar.publish
217
+ calendar.to_ical
218
+ end
219
+ end
220
+
221
+ private
222
+
223
+ def eventables
224
+ [self, *events, *presentations]
225
+ end
226
+
227
+ def eventables_events
228
+ Rails.cache.fetch [self, *presentations, 'events'] do
229
+ eventables.collect do |eventable|
230
+ Rails.cache.fetch([eventable, 'event']) { eventable.to_event }
231
+ end
232
+ end
233
+ end
234
+
235
+ def ical_timezone
236
+ Rails.cache.fetch [self, presentations, 'time_zone'] do
237
+ Icalendar::Timezone.new do |timezone|
238
+ timezone.tzid = Time.zone.name
239
+ daylight_periods.each { |daylight_period| timezone.add_daylight(daylight_period) }
240
+ standard_periods.each { |standard_period| timezone.add_daylight(standard_period) }
241
+ end
242
+ end
243
+ end
244
+
245
+ def daylight_periods
246
+ time_zone_periods.select(&:dst?).each do |period|
247
+ Icalendar::Timezone::Daylight.new do |ical_period|
248
+ ical_period.tzoffsetfrom = period.offset.ical_offset
249
+ ical_period.tzoffsetto = period.offset.ical_offset
250
+ ical_period.tzname = period.abbreviation
251
+ ical_period.dtstart = period.starts_at.to_datetime
252
+ end
253
+ end
254
+ end
255
+
256
+ def standard_periods
257
+ time_zone_periods.reject(&:dst?).each do |period|
258
+ Icalendar::Timezone::Standard.new do |ical_period|
259
+ ical_period.tzoffsetfrom = period.offset.ical_offset
260
+ ical_period.tzoffsetto = period.offset.ical_offset
261
+ ical_period.tzname = period.abbreviation
262
+ ical_period.dtstart = period.starts_at.to_datetime
263
+ end
264
+ end
145
265
  end
146
266
  end
147
267
  end
@@ -20,14 +20,15 @@ module Spina
20
20
  # @!attribute [rw] name
21
21
  # @return [String, nil] the translated name of the event
22
22
  # @!attribute [rw] description
23
- # @return [String, nil] the translated description of the event
23
+ # @return [ActionText::RichText, nil] the translated description of the event
24
24
  # @!attribute [rw] start_datetime
25
25
  # @return [ActiveSupport::TimeWithZone, nil] the start time of the event
26
26
  # @!attribute [rw] finish_datetime
27
27
  # @return [ActiveSupport::TimeWithZone, nil] the finish time of the event
28
28
  # @!attribute [rw] location
29
29
  # @return [String, nil] the translated location of the event
30
- translates :name, :description, :location, fallbacks: true
30
+ translates :name, :location, fallbacks: true
31
+ translates :description, backend: :action_text, fallbacks: true
31
32
 
32
33
  # @return [ActiveRecord::Relation] all events, ordered by name
33
34
  scope :sorted, -> { i18n.order :name }
@@ -56,27 +57,28 @@ module Spina
56
57
  start_datetime.to_date
57
58
  end
58
59
 
60
+ # @return [TZInfo::TimezonePeriod, nil] the time zone period for the event
61
+ def time_zone_period
62
+ return if start_datetime.blank?
63
+
64
+ start_datetime.period
65
+ end
66
+
59
67
  # @return [Icalendar::Event] the event as an iCal event
60
68
  def to_event # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
61
69
  event = Icalendar::Event.new
62
70
  return event if invalid?
63
71
 
64
- event.dtstart = start_datetime
65
- event.dtend = finish_datetime
72
+ event.dtstart = Icalendar::Values::DateTime.new(start_datetime, tzid: start_datetime.time_zone.tzinfo.name)
73
+ event.dtend = Icalendar::Values::DateTime.new(finish_datetime, tzid: start_datetime.time_zone.tzinfo.name)
66
74
  event.location = location
67
75
  event.contact = Spina::Account.first.email
68
76
  event.categories = Event.model_name.human(count: 0)
69
77
  event.summary = name
70
- event.append_custom_property('alt_description', description.try(:html_safe))
71
- event.description = description.try(:gsub, %r{</?[^>]*>}, '')
78
+ event.append_custom_property('alt_description', description.to_s)
79
+ event.description = description.try(:to_plain_text)
72
80
  event
73
81
  end
74
-
75
- # @param (see #to_event)
76
- # @deprecated Use {#to_event} instead
77
- def to_ics
78
- to_event
79
- end
80
82
  end
81
83
  end
82
84
  end
@@ -28,8 +28,9 @@ module Spina
28
28
  # @!attribute [rw] title
29
29
  # @return [String, nil] the presentation title
30
30
  # @!attribute [rw] abstract
31
- # @return [String, nil] the presentation abstract
32
- translates :title, :abstract, fallbacks: true
31
+ # @return [ActionText::RichText, nil] the presentation abstract
32
+ translates :title, fallbacks: true
33
+ translates :abstract, backend: :action_text, fallbacks: true
33
34
 
34
35
  # @return [ActiveRecord::Relation] all conferences, ordered by date
35
36
  scope :sorted, -> { order start_datetime: :desc }
@@ -98,27 +99,35 @@ module Spina
98
99
  start_datetime.to_date
99
100
  end
100
101
 
102
+ # @return [ActiveSupport::TimeWithZone, nil] the presentation end time. Nil if the presentation has no start date and time
103
+ def finish_datetime
104
+ return if start_datetime.blank?
105
+
106
+ start_datetime + presentation_type.duration
107
+ end
108
+
109
+ # @return [TZInfo::TimezonePeriod, nil] the time zone period for the presentation
110
+ def time_zone_period
111
+ return if start_datetime.blank?
112
+
113
+ start_datetime.period
114
+ end
115
+
101
116
  # @return [Icalendar::Event] the presentation as an iCal event
102
117
  def to_event # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
103
118
  event = Icalendar::Event.new
104
119
  return event if invalid?
105
120
 
106
- event.dtstart = start_datetime
107
- event.dtend = start_datetime + presentation_type.duration
121
+ event.dtstart = Icalendar::Values::DateTime.new(start_datetime, tzid: start_datetime.time_zone.tzinfo.name)
122
+ event.dtend = Icalendar::Values::DateTime.new(finish_datetime, tzid: finish_datetime.time_zone.tzinfo.name)
108
123
  event.location = session.room_name
109
124
  presenters.each { |presenter| event.contact = presenter.full_name_and_institution }
110
125
  event.categories = Presentation.model_name.human(count: 0)
111
126
  event.summary = title
112
- event.append_custom_property('alt_description', abstract.try(:html_safe))
113
- event.description = abstract.try(:gsub, %r{</?[^>]*>}, '')
127
+ event.append_custom_property('alt_description', abstract.to_s)
128
+ event.description = abstract.try(:to_plain_text)
114
129
  event
115
130
  end
116
-
117
- # @param (see #to_event)
118
- # @deprecated Use {#to_event} instead
119
- def to_ics
120
- to_event
121
- end
122
131
  end
123
132
  end
124
133
  end
@@ -22,8 +22,7 @@
22
22
  .structure-form-part
23
23
  .page-form-label= Spina::Admin::Conferences::Event.human_attribute_name :description
24
24
  .page-form-content
25
- .page-form-rich-text
26
- = render 'spina/admin/shared/rich_text_field', f: f, field: :description
25
+ .page-form-rich-text= f.rich_text_area :description
27
26
 
28
27
  = f.hidden_field :id
29
28
 
@@ -23,8 +23,7 @@
23
23
  .page-form-group
24
24
  .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :abstract
25
25
  .page-form-content
26
- .page-form-rich-text
27
- = render 'spina/admin/shared/rich_text_field', f: f, field: :abstract
26
+ .page-form-rich-text= f.rich_text_area :abstract
28
27
 
29
28
  .page-form-group
30
29
  .page-form-label= Spina::Admin::Conferences::Presentation.human_attribute_name :presenters
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddLocaleToActionTextRichTexts < ActiveRecord::Migration[6.1]
4
+ def change
5
+ add_column :action_text_rich_texts, :locale, :string
6
+ remove_index :action_text_rich_texts, column: %i[record_type record_id name], name: :index_action_text_rich_texts_uniqueness,
7
+ unique: true
8
+ add_index :action_text_rich_texts, %i[record_type record_id name locale], name: :index_action_text_rich_texts_uniqueness,
9
+ unique: true
10
+ end
11
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MoveTextsToActionTextRichTexts < ActiveRecord::Migration[6.1] # :nodoc:
4
+ def change
5
+ create_mobility_tables
6
+
7
+ Spina.config.locales.each do |locale|
8
+ I18n.with_locale(locale) do
9
+ move_presentation_abstracts
10
+ move_event_descriptions
11
+ end
12
+ end
13
+
14
+ remove_column :spina_conferences_presentation_translations, :abstract, :text
15
+ remove_column :spina_conferences_event_translations, :description, :text
16
+ end
17
+
18
+ private
19
+
20
+ def create_mobility_tables
21
+ create_table :mobility_text_translations do |t| # rubocop:disable Rails/CreateTableWithTimestamps
22
+ t.string :record
23
+ end
24
+ create_table :mobility_string_translations do |t| # rubocop:disable Rails/CreateTableWithTimestamps
25
+ t.string :record
26
+ end
27
+ end
28
+
29
+ def move_presentation_abstracts
30
+ reversible do |dir|
31
+ Spina::Admin::Conferences::Presentation.in_batches.each_record do |presentation|
32
+ dir.up { presentation.update(abstract: presentation.presentation_translation.abstract) }
33
+ dir.down do
34
+ break if presentation.abstract.blank?
35
+
36
+ presentation.presentation_translation.update(abstract: presentation.abstract.read_attribute_before_type_cast('body'))
37
+ presentation.abstract.destroy
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def move_event_descriptions
44
+ reversible do |dir|
45
+ Spina::Admin::Conferences::Event.in_batches.each_record do |event|
46
+ dir.up { event.update(description: event.event_translation.description) }
47
+ dir.down do
48
+ break if event.description.blank?
49
+
50
+ event.event_translation.update(description: event.description.read_attribute_before_type_cast('body'))
51
+ event.description.destroy
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ module Spina
59
+ module Admin
60
+ module Conferences
61
+ class PresentationTranslation < ApplicationRecord
62
+ belongs_to :presentation, foreign_key: 'spina_conferences_presentation_id'
63
+ end
64
+
65
+ class EventTranslation < ApplicationRecord
66
+ belongs_to :event, foreign_key: 'spina_conferences_event_id'
67
+ end
68
+
69
+ class Presentation < ApplicationRecord
70
+ has_one :presentation_translation, -> { where locale: I18n.locale }, foreign_key: 'spina_conferences_presentation_id'
71
+
72
+ translates :abstract, backend: :action_text
73
+ end
74
+
75
+ class Event < ApplicationRecord
76
+ has_one :event_translation, -> { where locale: I18n.locale }, foreign_key: 'spina_conferences_event_id'
77
+
78
+ translates :description, backend: :action_text
79
+ end
80
+ end
81
+ end
82
+ end
@@ -7,6 +7,7 @@ require 'rails-i18n'
7
7
  require 'stimulus-rails'
8
8
  require 'turbo-rails'
9
9
  require 'icalendar'
10
+ require 'icalendar/tzinfo'
10
11
 
11
12
  # Spina content management system.
12
13
  # @see https://www.spinacms.com Spina website
@@ -20,12 +20,10 @@ module Spina
20
20
  Spina::Part.register(Spina::Parts::Admin::Conferences::EmailAddress)
21
21
  Spina::Part.register(Spina::Parts::Admin::Conferences::Time)
22
22
  Spina::Part.register(Spina::Parts::Admin::Conferences::Url)
23
+ end
23
24
 
24
- ActiveSupport::Deprecation
25
- .new('2.0', 'Spina::Admin::Conferences')
26
- .tap { |deprecator| deprecator.deprecate_methods(Conference, to_ics: :to_event) }
27
- .tap { |deprecator| deprecator.deprecate_methods(Presentation, to_ics: :to_event) }
28
- .tap { |deprecator| deprecator.deprecate_methods(Event, to_ics: :to_event) }
25
+ config.to_prepare do
26
+ require 'mobility/action_text'
29
27
  end
30
28
  end
31
29
  end
@@ -4,7 +4,7 @@ module Spina
4
4
  module Admin
5
5
  module Conferences
6
6
  # Version number.
7
- VERSION = '2.0.1'
7
+ VERSION = '2.1.0'
8
8
  end
9
9
  end
10
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spina-admin-conferences
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Malčić
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-16 00:00:00.000000000 Z
11
+ date: 2021-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: icalendar
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mobility-actiontext
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.2.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rails
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -553,6 +567,8 @@ files:
553
567
  - db/migrate/20210315164409_add_json_attributes_to_spina_conferences_presentations.rb
554
568
  - db/migrate/20210315164410_add_json_attributes_to_spina_conferences_conferences.rb
555
569
  - db/migrate/20210315164411_convert_partables_to_json.rb
570
+ - db/migrate/20210417102513_add_locale_to_action_text_rich_texts.rb
571
+ - db/migrate/20210417102514_move_texts_to_action_text_rich_texts.rb
556
572
  - lib/spina/admin/conferences.rb
557
573
  - lib/spina/admin/conferences/engine.rb
558
574
  - lib/spina/admin/conferences/migration/renaming.rb