spina-admin-conferences 1.3.3

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.
Files changed (212) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +101 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/config/spina_admin_conferences_manifest.js +4 -0
  6. data/app/assets/javascripts/spina/admin/conferences/application.es6 +20 -0
  7. data/app/assets/javascripts/spina/admin/conferences/controllers/conference_events_form_controller.es6 +175 -0
  8. data/app/assets/javascripts/spina/admin/conferences/controllers/presentation_attachments_form_controller.es6 +175 -0
  9. data/app/assets/javascripts/spina/admin/conferences/controllers/select_options_controller.es6 +216 -0
  10. data/app/assets/stylesheets/spina/admin/conferences/application.sass +14 -0
  11. data/app/controllers/spina/admin/conferences/application_controller.rb +20 -0
  12. data/app/controllers/spina/admin/conferences/conferences_controller.rb +148 -0
  13. data/app/controllers/spina/admin/conferences/delegates_controller.rb +116 -0
  14. data/app/controllers/spina/admin/conferences/dietary_requirements_controller.rb +106 -0
  15. data/app/controllers/spina/admin/conferences/events_controller.rb +24 -0
  16. data/app/controllers/spina/admin/conferences/institutions_controller.rb +106 -0
  17. data/app/controllers/spina/admin/conferences/presentation_attachment_types_controller.rb +104 -0
  18. data/app/controllers/spina/admin/conferences/presentation_attachments_controller.rb +24 -0
  19. data/app/controllers/spina/admin/conferences/presentation_types_controller.rb +109 -0
  20. data/app/controllers/spina/admin/conferences/presentations_controller.rb +124 -0
  21. data/app/controllers/spina/admin/conferences/rooms_controller.rb +109 -0
  22. data/app/controllers/spina/admin/conferences/sessions_controller.rb +118 -0
  23. data/app/helpers/spina/admin/conferences/conferences_helper.rb +44 -0
  24. data/app/jobs/spina/admin/conferences/application_job.rb +11 -0
  25. data/app/jobs/spina/admin/conferences/delegate_import_job.rb +37 -0
  26. data/app/jobs/spina/admin/conferences/import_job.rb +26 -0
  27. data/app/jobs/spina/admin/conferences/presentation_import_job.rb +38 -0
  28. data/app/mailers/spina/admin/conferences/application_mailer.rb +13 -0
  29. data/app/models/spina/admin/conferences.rb +11 -0
  30. data/app/models/spina/admin/conferences/application_record.rb +14 -0
  31. data/app/models/spina/admin/conferences/conference.rb +152 -0
  32. data/app/models/spina/admin/conferences/date_part.rb +15 -0
  33. data/app/models/spina/admin/conferences/delegate.rb +89 -0
  34. data/app/models/spina/admin/conferences/dietary_requirement.rb +33 -0
  35. data/app/models/spina/admin/conferences/email_address_part.rb +21 -0
  36. data/app/models/spina/admin/conferences/event.rb +120 -0
  37. data/app/models/spina/admin/conferences/institution.rb +46 -0
  38. data/app/models/spina/admin/conferences/part.rb +20 -0
  39. data/app/models/spina/admin/conferences/presentation.rb +143 -0
  40. data/app/models/spina/admin/conferences/presentation_attachment.rb +27 -0
  41. data/app/models/spina/admin/conferences/presentation_attachment_type.rb +35 -0
  42. data/app/models/spina/admin/conferences/presentation_type.rb +60 -0
  43. data/app/models/spina/admin/conferences/room.rb +52 -0
  44. data/app/models/spina/admin/conferences/session.rb +56 -0
  45. data/app/models/spina/admin/conferences/time_part.rb +53 -0
  46. data/app/models/spina/admin/conferences/url_part.rb +21 -0
  47. data/app/validators/spina/admin/conferences/conference_date_validator.rb +20 -0
  48. data/app/validators/spina/admin/conferences/email_address_validator.rb +28 -0
  49. data/app/validators/spina/admin/conferences/finish_date_validator.rb +20 -0
  50. data/app/validators/spina/admin/conferences/finish_time_validator.rb +20 -0
  51. data/app/validators/spina/admin/conferences/http_url_validator.rb +28 -0
  52. data/app/views/layouts/spina/admin/conferences/conferences.html.haml +19 -0
  53. data/app/views/layouts/spina/admin/conferences/delegates.html.haml +10 -0
  54. data/app/views/layouts/spina/admin/conferences/dietary_requirements.html.haml +10 -0
  55. data/app/views/layouts/spina/admin/conferences/institutions.html.haml +17 -0
  56. data/app/views/layouts/spina/admin/conferences/presentation_attachment_types.html.haml +10 -0
  57. data/app/views/layouts/spina/admin/conferences/presentations.html.haml +10 -0
  58. data/app/views/spina/admin/conferences/application/_empty_list.html.haml +3 -0
  59. data/app/views/spina/admin/conferences/application/_errors.html.haml +11 -0
  60. data/app/views/spina/admin/conferences/application/_errors.js.erb +2 -0
  61. data/app/views/spina/admin/conferences/conferences/_conference.html.haml +9 -0
  62. data/app/views/spina/admin/conferences/conferences/_event_fields.html.haml +39 -0
  63. data/app/views/spina/admin/conferences/conferences/_event_row.html.haml +5 -0
  64. data/app/views/spina/admin/conferences/conferences/_form.html.haml +23 -0
  65. data/app/views/spina/admin/conferences/conferences/_form_conference_details.html.haml +29 -0
  66. data/app/views/spina/admin/conferences/conferences/_form_delegates.html.haml +12 -0
  67. data/app/views/spina/admin/conferences/conferences/_form_parts.html.haml +15 -0
  68. data/app/views/spina/admin/conferences/conferences/_form_presentation_types.html.haml +12 -0
  69. data/app/views/spina/admin/conferences/conferences/_form_presentations.html.haml +12 -0
  70. data/app/views/spina/admin/conferences/conferences/_form_rooms.html.haml +12 -0
  71. data/app/views/spina/admin/conferences/conferences/_form_structure.html.haml +19 -0
  72. data/app/views/spina/admin/conferences/conferences/_form_structure_item.html.haml +13 -0
  73. data/app/views/spina/admin/conferences/conferences/edit.html.haml +1 -0
  74. data/app/views/spina/admin/conferences/conferences/index.html.haml +18 -0
  75. data/app/views/spina/admin/conferences/conferences/new.html.haml +1 -0
  76. data/app/views/spina/admin/conferences/delegates/_delegate.html.haml +13 -0
  77. data/app/views/spina/admin/conferences/delegates/_form.html.haml +23 -0
  78. data/app/views/spina/admin/conferences/delegates/_form_conferences.html.haml +14 -0
  79. data/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml +38 -0
  80. data/app/views/spina/admin/conferences/delegates/_form_presentations.html.haml +12 -0
  81. data/app/views/spina/admin/conferences/delegates/edit.html.haml +1 -0
  82. data/app/views/spina/admin/conferences/delegates/index.html.haml +23 -0
  83. data/app/views/spina/admin/conferences/delegates/new.html.haml +1 -0
  84. data/app/views/spina/admin/conferences/dietary_requirements/_dietary_requirement.html.haml +6 -0
  85. data/app/views/spina/admin/conferences/dietary_requirements/_form.html.haml +23 -0
  86. data/app/views/spina/admin/conferences/dietary_requirements/_form_delegates.html.haml +12 -0
  87. data/app/views/spina/admin/conferences/dietary_requirements/_form_dietary_requirement_details.html.haml +9 -0
  88. data/app/views/spina/admin/conferences/dietary_requirements/edit.html.haml +1 -0
  89. data/app/views/spina/admin/conferences/dietary_requirements/index.html.haml +15 -0
  90. data/app/views/spina/admin/conferences/dietary_requirements/new.html.haml +1 -0
  91. data/app/views/spina/admin/conferences/events/new.js.erb +27 -0
  92. data/app/views/spina/admin/conferences/institutions/_form.html.haml +23 -0
  93. data/app/views/spina/admin/conferences/institutions/_form_delegates.html.haml +12 -0
  94. data/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml +35 -0
  95. data/app/views/spina/admin/conferences/institutions/_form_rooms.html.haml +12 -0
  96. data/app/views/spina/admin/conferences/institutions/_institution.html.haml +7 -0
  97. data/app/views/spina/admin/conferences/institutions/edit.html.haml +1 -0
  98. data/app/views/spina/admin/conferences/institutions/index.html.haml +16 -0
  99. data/app/views/spina/admin/conferences/institutions/new.html.haml +1 -0
  100. data/app/views/spina/admin/conferences/presentation_attachment_types/_form.html.haml +23 -0
  101. data/app/views/spina/admin/conferences/presentation_attachment_types/_presentation_attachment_type.html.haml +6 -0
  102. data/app/views/spina/admin/conferences/presentation_attachment_types/edit.html.haml +1 -0
  103. data/app/views/spina/admin/conferences/presentation_attachment_types/index.html.haml +15 -0
  104. data/app/views/spina/admin/conferences/presentation_attachment_types/new.html.haml +1 -0
  105. data/app/views/spina/admin/conferences/presentation_attachments/new.js.erb +21 -0
  106. data/app/views/spina/admin/conferences/presentation_types/_form.html.haml +23 -0
  107. data/app/views/spina/admin/conferences/presentation_types/_form_presentation_type_details.html.haml +20 -0
  108. data/app/views/spina/admin/conferences/presentation_types/_form_presentations.html.haml +12 -0
  109. data/app/views/spina/admin/conferences/presentation_types/_form_sessions.html.haml +12 -0
  110. data/app/views/spina/admin/conferences/presentation_types/_presentation_type.html.haml +8 -0
  111. data/app/views/spina/admin/conferences/presentation_types/edit.html.haml +1 -0
  112. data/app/views/spina/admin/conferences/presentation_types/index.html.haml +17 -0
  113. data/app/views/spina/admin/conferences/presentation_types/new.html.haml +1 -0
  114. data/app/views/spina/admin/conferences/presentations/_attachment_fields.html.haml +27 -0
  115. data/app/views/spina/admin/conferences/presentations/_attachment_row.html.haml +2 -0
  116. data/app/views/spina/admin/conferences/presentations/_form.html.haml +23 -0
  117. data/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml +55 -0
  118. data/app/views/spina/admin/conferences/presentations/_form_presenters.html.haml +12 -0
  119. data/app/views/spina/admin/conferences/presentations/_presentation.html.haml +11 -0
  120. data/app/views/spina/admin/conferences/presentations/edit.html.haml +1 -0
  121. data/app/views/spina/admin/conferences/presentations/index.html.haml +23 -0
  122. data/app/views/spina/admin/conferences/presentations/new.html.haml +1 -0
  123. data/app/views/spina/admin/conferences/rooms/_form.html.haml +23 -0
  124. data/app/views/spina/admin/conferences/rooms/_form_presentations.html.haml +12 -0
  125. data/app/views/spina/admin/conferences/rooms/_form_room_details.html.haml +18 -0
  126. data/app/views/spina/admin/conferences/rooms/_room.html.haml +8 -0
  127. data/app/views/spina/admin/conferences/rooms/edit.html.haml +1 -0
  128. data/app/views/spina/admin/conferences/rooms/index.html.haml +17 -0
  129. data/app/views/spina/admin/conferences/rooms/new.html.haml +1 -0
  130. data/app/views/spina/admin/conferences/sessions/_form.html.haml +23 -0
  131. data/app/views/spina/admin/conferences/sessions/_form_presentations.html.haml +12 -0
  132. data/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml +23 -0
  133. data/app/views/spina/admin/conferences/sessions/_session.html.haml +8 -0
  134. data/app/views/spina/admin/conferences/sessions/edit.html.haml +1 -0
  135. data/app/views/spina/admin/conferences/sessions/index.html.haml +17 -0
  136. data/app/views/spina/admin/conferences/sessions/new.html.haml +1 -0
  137. data/app/views/spina/admin/hooks/conferences/_head.html.haml +2 -0
  138. data/app/views/spina/admin/hooks/conferences/_primary_navigation.html.haml +20 -0
  139. data/app/views/spina/admin/hooks/conferences/_settings_secondary_navigation.html.haml +4 -0
  140. data/app/views/spina/admin/partables/admin/conferences/date_parts/_form.html.haml +5 -0
  141. data/app/views/spina/admin/partables/admin/conferences/email_address_parts/_form.html.haml +5 -0
  142. data/app/views/spina/admin/partables/admin/conferences/time_parts/_form.html.haml +7 -0
  143. data/app/views/spina/admin/partables/admin/conferences/url_parts/_form.html.haml +5 -0
  144. data/config/initializers/assets.rb +13 -0
  145. data/config/initializers/types.rb +13 -0
  146. data/config/locales/en.yml +354 -0
  147. data/config/routes.rb +27 -0
  148. data/db/migrate/20180907141228_create_spina_dates.rb +11 -0
  149. data/db/migrate/20180907141229_create_spina_email_addresses.rb +11 -0
  150. data/db/migrate/20180907141230_create_spina_urls.rb +11 -0
  151. data/db/migrate/20180907141231_create_spina_conferences_institutions.rb +12 -0
  152. data/db/migrate/20180907141232_create_spina_conferences_delegates.rb +15 -0
  153. data/db/migrate/20180907141234_create_spina_conferences_dietary_requirements.rb +11 -0
  154. data/db/migrate/20180907141235_create_spina_conferences_conferences.rb +12 -0
  155. data/db/migrate/20180907141236_create_spina_conferences_presentation_types.rb +13 -0
  156. data/db/migrate/20180907141238_create_join_table_spina_conferences_conference_delegate.rb +7 -0
  157. data/db/migrate/20180907141239_create_join_table_spina_conferences_delegate_presentation.rb +7 -0
  158. data/db/migrate/20180907141240_create_join_table_spina_conferences_delegate_dietary_requirement.rb +7 -0
  159. data/db/migrate/20180907141242_add_type_to_spina_pages.rb +7 -0
  160. data/db/migrate/20180907141243_create_spina_conferences_conference_page_parts.rb +14 -0
  161. data/db/migrate/20180914121905_add_logo_ref_to_spina_conferences_institutions.rb +7 -0
  162. data/db/migrate/20180916135431_create_spina_conferences_rooms.rb +13 -0
  163. data/db/migrate/20180916135432_create_spina_conferences_room_possessions.rb +10 -0
  164. data/db/migrate/20180916135433_create_spina_conferences_room_uses.rb +10 -0
  165. data/db/migrate/20180916135434_create_spina_conferences_presentations.rb +15 -0
  166. data/db/migrate/20181009122503_create_spina_times.rb +11 -0
  167. data/db/migrate/20181009130631_rename_spina_page_parts.rb +10 -0
  168. data/db/migrate/20181012190811_rename_spina_conferences_page_parts.rb +10 -0
  169. data/db/migrate/20181012213049_change_start_time_in_spina_conferences_conferences.rb +15 -0
  170. data/db/migrate/20181012214813_rename_start_time_in_spina_conferences_conferences.rb +7 -0
  171. data/db/migrate/20181017155705_add_dependent_option_to_foreign_keys.rb +36 -0
  172. data/db/migrate/20190408131354_change_spina_resources.rb +56 -0
  173. data/db/migrate/20190622131423_create_spina_conferences_parts.rb +12 -0
  174. data/db/migrate/20190701174807_remove_spina_conference_pages.rb +199 -0
  175. data/db/migrate/20190704135524_add_constraints_to_columns.rb +24 -0
  176. data/db/migrate/20200126034441_create_spina_conferences_presentation_attachment_types.rb +11 -0
  177. data/db/migrate/20200126213718_create_spina_conferences_presentation_attachments.rb +19 -0
  178. data/db/migrate/20200420104603_create_spina_conferences_dietary_requirement_name_translations.rb +19 -0
  179. data/db/migrate/20200420104740_create_spina_conferences_institution_name_and_city_translations.rb +20 -0
  180. data/db/migrate/20200420105057_create_spina_conferences_presentation_title_and_abstract_translations.rb +20 -0
  181. data/db/migrate/20200420105144_create_spina_conferences_presentation_attachment_type_name_translations.rb +20 -0
  182. data/db/migrate/20200420105201_create_spina_conferences_presentation_type_name_translations.rb +19 -0
  183. data/db/migrate/20200420105458_create_spina_conferences_room_building_and_number_translations.rb +20 -0
  184. data/db/migrate/20200420110407_move_attributes_to_translation_tables.rb +161 -0
  185. data/db/migrate/20200420120706_remove_name_from_spina_conferences_dietary_requirements.rb +7 -0
  186. data/db/migrate/20200420120759_remove_name_and_city_from_spina_conferences_institutions.rb +8 -0
  187. data/db/migrate/20200420120946_remove_title_and_abstract_from_spina_conferences_presentations.rb +8 -0
  188. data/db/migrate/20200420121310_remove_name_from_spina_conferences_presentation_attachment_types.rb +7 -0
  189. data/db/migrate/20200420121321_remove_name_from_spina_conferences_presentation_types.rb +7 -0
  190. data/db/migrate/20200420121443_remove_building_and_number_from_spina_conferences_rooms.rb +8 -0
  191. data/db/migrate/20200502133408_create_spina_conferences_conference_name_translations.rb +19 -0
  192. data/db/migrate/20200502183409_set_name_for_spina_conferences_conferences.rb +47 -0
  193. data/db/migrate/20200502183410_remove_institution_from_spina_conferences_conferences.rb +8 -0
  194. data/db/migrate/20200502183719_remove_spina_conferences_room_possessions.rb +60 -0
  195. data/db/migrate/20200503230732_rename_spina_conferences_room_uses.rb +8 -0
  196. data/db/migrate/20200510125131_create_spina_conferences_session_name_translations.rb +19 -0
  197. data/db/migrate/20200802165242_create_spina_conferences_events.rb +13 -0
  198. data/db/migrate/20200802184921_create_spina_conferences_event_name_description_and_location_translations.rb +21 -0
  199. data/db/migrate/20200911161632_update_spina_conferences_parts.rb +23 -0
  200. data/db/migrate/20200911161651_update_spina_parts.rb +37 -0
  201. data/db/migrate/20200911161726_move_presentation_parts.rb +101 -0
  202. data/db/migrate/20200911161739_move_conference_parts.rb +219 -0
  203. data/db/migrate/20201002122517_remove_spina_conferences_conference_page_parts.rb +14 -0
  204. data/db/migrate/20201007125625_add_timestamps_to_spina_conferences_parts.rb +9 -0
  205. data/lib/spina/admin/conferences.rb +20 -0
  206. data/lib/spina/admin/conferences/engine.rb +26 -0
  207. data/lib/spina/admin/conferences/migration/renaming.rb +81 -0
  208. data/lib/spina/admin/conferences/railtie.rb +34 -0
  209. data/lib/spina/admin/conferences/types/interval_type.rb +29 -0
  210. data/lib/spina/admin/conferences/version.rb +10 -0
  211. data/lib/tasks/spina/admin/conferences_tasks.rake +4 -0
  212. metadata +561 -0
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ module Spina
6
+ module Admin
7
+ module Conferences
8
+ # Job for importing CSV files.
9
+ class ImportJob < ApplicationJob
10
+ CSV::Converters[:json] = lambda do |field|
11
+ JSON.parse field, symbolize_names: true
12
+ rescue JSON::ParserError
13
+ field
14
+ end
15
+
16
+ # Performs the job.
17
+ # @param file [String] the UTF-8-encoded string to parse as a CSV
18
+ # @yieldparam row [Hash] the current row of the CSV
19
+ def import(file)
20
+ csv_rows = CSV.parse file, encoding: 'UTF-8', headers: true, header_converters: :symbol, converters: [:json]
21
+ csv_rows.each { |row| yield(row) }
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Job for importing {Presentation} objects
7
+ # @see Presentation
8
+ class PresentationImportJob < ImportJob
9
+ queue_as :default
10
+
11
+ # Performs the job.
12
+ # @param csv [String] the UTF-8-encoded string to parse as a CSV
13
+ # == Columns
14
+ # The CSV should has the following columns. Make sure to include the column names in the header row.
15
+ # +session_id+:: The id of the associated session.
16
+ # +date+:: The date of the presentation, in ISO 8601 format.
17
+ # +start_time+:: The start time of the presentation, in HH:MM format.
18
+ # +title+:: The title of the presentation for the default locale.
19
+ # +abstract+:: The presentation's abstract.
20
+ # +presenter_ids+:: The ids of the presenters.
21
+ #
22
+ # @return [void]
23
+ def perform(csv)
24
+ Presentation.transaction do
25
+ import(csv) { |row| Presentation.create! presentation_params(row.to_h) }
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def presentation_params(params)
32
+ params = ActionController::Parameters.new(params)
33
+ params.permit :title, :date, :start_time, :abstract, :session_id, presenter_ids: []
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # @abstract Abstract mailer from which all others inherit.
7
+ class ApplicationMailer < ActionMailer::Base
8
+ default from: 'from@example.com'
9
+ layout 'mailer'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences # rubocop:disable Style/Documentation
6
+ def self.table_name_prefix
7
+ 'spina_conferences_'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # @abstract Subclass to implement a custom record.
7
+ class ApplicationRecord < ActiveRecord::Base
8
+ extend Mobility
9
+
10
+ self.abstract_class = true
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Conference records.
7
+ #
8
+ # = Validators
9
+ # Presence:: {#name}, {#start_date}, {#finish_date}, {#year}.
10
+ # Conference date (using {FinishDateValidator}):: {#finish_date}.
11
+ # @see FinishDateValidator
12
+ #
13
+ # = Translations
14
+ # - {#name}
15
+ class Conference < ApplicationRecord
16
+ include Partable
17
+
18
+ default_scope { includes(:translations) }
19
+
20
+ # @!attribute [rw] dates
21
+ # @return [Range<Date>, nil] the dates of the conference
22
+
23
+ # @!attribute [rw] name
24
+ # @return [String, nil] the translated name of the conference
25
+ translates :name, fallbacks: true
26
+
27
+ # @return [ActiveRecord::Relation] all conferences, ordered by date
28
+ scope :sorted, -> { order dates: :desc }
29
+
30
+ # @!attribute [rw] presentation_types
31
+ # @return [ActiveRecord::Relation] directly associated presentation types
32
+ # @note A conference cannot be destroyed if it has dependent presentation types.
33
+ # @see PresentationType
34
+ has_many :presentation_types, -> { includes(:translations) }, inverse_of: :conference, dependent: :restrict_with_error
35
+ # @!attribute [rw] events
36
+ # @return [ActiveRecord::Relation] directly associated events
37
+ # @note Destroying a conference destroys dependent events.
38
+ # @see Event
39
+ has_many :events, -> { includes(:translations) }, inverse_of: :conference, dependent: :destroy
40
+ # @!attribute [rw] events
41
+ # @return [ActiveRecord::Relation] directly associated events
42
+ # @note Destroying a conference destroys dependent events.
43
+ # @see Event
44
+ has_many :parts, as: :pageable, dependent: :destroy
45
+ # @!attribute [rw] sessions
46
+ # @return [ActiveRecord::Relation] Sessions associated with {#presentation_types}
47
+ # @see Session
48
+ # @see PresentationType#sessions
49
+ has_many :sessions, -> { distinct.includes(:translations) }, through: :presentation_types
50
+ # @!attribute [rw] presentations
51
+ # @return [ActiveRecord::Relation] Presentations associated with {#sessions}
52
+ # @see Presentation
53
+ # @see Session#presentations
54
+ has_many :presentations, -> { distinct.includes(:translations) }, through: :sessions
55
+ # @!attribute [rw] rooms
56
+ # @return [ActiveRecord::Relation] Rooms associated with {#sessions}
57
+ # @see Room
58
+ # @see Session#rooms
59
+ has_many :rooms, -> { distinct.includes(:translations) }, through: :sessions
60
+ # @!attribute [rw] institutions
61
+ # @return [ActiveRecord::Relation] Institutions associated with {#rooms}
62
+ # @see Institution
63
+ # @see Room#institutions
64
+ has_many :institutions, -> { distinct.includes(:translations) }, through: :rooms
65
+ # @!attribute [rw] delegates
66
+ # @return [ActiveRecord::Relation] directly associated delegates
67
+ # @see Delegate
68
+ has_and_belongs_to_many :delegates, foreign_key: :spina_conferences_conference_id, # rubocop:disable Rails/HasAndBelongsToMany
69
+ association_foreign_key: :spina_conferences_delegate_id
70
+ accepts_nested_attributes_for :events, allow_destroy: true
71
+ accepts_nested_attributes_for :parts, allow_destroy: true
72
+
73
+ validates :name, :start_date, :finish_date, :year, presence: true
74
+ validates :finish_date, 'spina/admin/conferences/finish_date': true, unless: proc { |conference| conference.start_date.blank? }
75
+
76
+ # @return [Date, nil] the start date of the conference. Nil if the conference has no dates
77
+ def start_date
78
+ return if dates.blank?
79
+
80
+ dates.begin
81
+ end
82
+
83
+ # Sets the start date of the conference.
84
+ # @param date [Date] the new start date
85
+ # @return [void]
86
+ def start_date=(date)
87
+ self.dates = date.try(:to_date)..finish_date
88
+ end
89
+
90
+ # @return [Date, nil] the finish date of the conference. Nil if the conference has no dates
91
+ def finish_date
92
+ return if dates.blank?
93
+
94
+ if dates.exclude_end?
95
+ dates.end - 1.day if dates.end.is_a? Date
96
+ else
97
+ dates.end
98
+ end
99
+ end
100
+
101
+ # Sets the finish date of the conference.
102
+ # @param date [Date] the new finish date
103
+ # @return [void]
104
+ def finish_date=(date)
105
+ self.dates = start_date..date.try(:to_date)
106
+ end
107
+
108
+ # @return [Integer, nil] the year of the conference. Nil if the conference has no dates
109
+ def year
110
+ return if start_date.blank?
111
+
112
+ start_date.try(:year)
113
+ end
114
+
115
+ # @return [Array<Hash{Symbol=>String}>, nil] an array of hashes containing the date in ISO 8601 format and as a localised string
116
+ # Nil if the conference has no dates.
117
+ def localized_dates
118
+ return if dates.blank?
119
+
120
+ dates.entries.collect { |date| { date: date.to_formatted_s(:iso8601), localization: I18n.l(date, format: :long) } }
121
+ end
122
+
123
+ # @return [String] the names of each institution associated with the conference
124
+ def location
125
+ institutions.collect(&:name).to_sentence
126
+ end
127
+
128
+ # @return [Icalendar::Event] the conference as an iCal event
129
+ def to_event # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
130
+ event = Icalendar::Event.new
131
+ return event if invalid?
132
+
133
+ event.dtstart = start_date
134
+ event.dtstart.ical_param(:value, 'DATE')
135
+ event.dtend = finish_date
136
+ event.dtend.ical_param(:value, 'DATE')
137
+ event.location = location
138
+ event.contact = Spina::Account.first.email
139
+ event.categories = Conference.model_name.human(count: 0)
140
+ event.summary = name
141
+ event
142
+ end
143
+
144
+ # @param (see #to_event)
145
+ # @deprecated Use {#to_event} instead
146
+ def to_ics
147
+ to_event
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Date parts, without associated times.
7
+ class DatePart < ApplicationRecord
8
+ has_many :page_parts, as: :page_partable
9
+ has_many :parts, as: :partable
10
+ has_many :layout_parts, as: :layout_partable
11
+ has_many :structure_parts, as: :structure_partable
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Delegate records.
7
+ #
8
+ # = Validators
9
+ # Presence:: {#first_name}, {#last_name}.
10
+ # Email address (using {EmailAddressValidator}):: {#email_address}.
11
+ # HTTP(S) URL (using {HttpUrlValidator}):: {#url}.
12
+ # @see EmailAddressValidator
13
+ # @see HttpUrlValidator
14
+ class Delegate < ApplicationRecord
15
+ # @!attribute [rw] first_name
16
+ # @return [String, nil] the first name of the delegate
17
+ # @!attribute [rw] last_name
18
+ # @return [String, nil] the last name of the delegate
19
+ # @!attribute [rw] email_address
20
+ # @return [String, nil] the email address of the delegate
21
+ # @!attribute [rw] url
22
+ # @return [String, nil] the website belonging to the delegate
23
+
24
+ # @return [ActiveRecord::Relation] all delegates, ordered by last name and first name
25
+ scope :sorted, -> { order :last_name, :first_name }
26
+
27
+ # @!attribute [rw] institution
28
+ # @return [Institution, nil] directly associated institution
29
+ # @see Institution
30
+ belongs_to :institution, inverse_of: :delegates, touch: true
31
+ # @!attribute [rw] conferences
32
+ # @return [ActiveRecord::Relation] directly associated conferences
33
+ # @see Conference
34
+ has_and_belongs_to_many :conferences, -> { includes(:translations) }, foreign_key: :spina_conferences_delegate_id, # rubocop:disable Rails/HasAndBelongsToMany
35
+ association_foreign_key: :spina_conferences_conference_id
36
+ # @!attribute [rw] presentations
37
+ # @return [ActiveRecord::Relation] directly associated presentations
38
+ # @see Presentation
39
+ has_and_belongs_to_many :presentations, -> { includes(:translations) }, foreign_key: :spina_conferences_delegate_id, # rubocop:disable Rails/HasAndBelongsToMany
40
+ association_foreign_key: :spina_conferences_presentation_id
41
+ # @!attribute [rw] dietary_requirements
42
+ # @return [ActiveRecord::Relation] directly associated dietary requirements
43
+ # @see DietaryRequirement
44
+ has_and_belongs_to_many :dietary_requirements, -> { includes(:translations) }, foreign_key: :spina_conferences_delegate_id, # rubocop:disable Rails/HasAndBelongsToMany
45
+ association_foreign_key: :spina_conferences_dietary_requirement_id
46
+
47
+ validates :first_name, :last_name, presence: true
48
+ validates :email_address, 'spina/admin/conferences/email_address': true
49
+ validates :url, 'spina/admin/conferences/http_url': true
50
+
51
+ # Imports a conference from CSV.
52
+ # @param file [String] the CSV file to be read
53
+ # @return [void]
54
+ # @see DelegateImportJob
55
+ def self.import(file)
56
+ DelegateImportJob.perform_later Pathname.new(file).read
57
+ end
58
+
59
+ # @return [String] the first name and last name of the delegate
60
+ def full_name
61
+ return if first_name.blank? || last_name.blank?
62
+
63
+ Delegate.human_attribute_name :full_name, first_name: first_name, last_name: last_name
64
+ end
65
+
66
+ # @return [String] the full name and institution of the delegate
67
+ def full_name_and_institution
68
+ return if full_name.blank? || institution.blank?
69
+
70
+ Delegate.human_attribute_name :name_and_institution, name: full_name, institution: institution.name
71
+ end
72
+
73
+ # @return [String] the last name and first name of the delegate
74
+ def reversed_name
75
+ return if first_name.blank? || last_name.blank?
76
+
77
+ Delegate.human_attribute_name :reversed_name, first_name: first_name, last_name: last_name
78
+ end
79
+
80
+ # @return [String] the reversed name and institution of the delegate
81
+ def reversed_name_and_institution
82
+ return if reversed_name.blank? || institution.blank?
83
+
84
+ Delegate.human_attribute_name :name_and_institution, name: reversed_name, institution: institution.name
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Dietary requirement records.
7
+ #
8
+ # = Validators
9
+ # Presence:: {#name}.
10
+ #
11
+ # = Translations
12
+ # - {#name}
13
+ class DietaryRequirement < ApplicationRecord
14
+ default_scope { includes(:translations) }
15
+
16
+ # @!attribute [rw] name
17
+ # @return [String, nil] the name of the dietary requirement
18
+ translates :name, fallbacks: true
19
+
20
+ # @return [ActiveRecord::Relation] all dietary requirements, ordered by name
21
+ scope :sorted, -> { i18n.order :name }
22
+
23
+ # @!attribute [rw] delegates
24
+ # @return [ActiveRecord::Relation] directly associated delegates
25
+ # @see Delegate
26
+ has_and_belongs_to_many :delegates, foreign_key: :spina_conferences_dietary_requirement_id, # rubocop:disable Rails/HasAndBelongsToMany
27
+ association_foreign_key: :spina_conferences_delegate_id
28
+
29
+ validates :name, presence: true
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Email address parts. The format is validated.
7
+ #
8
+ # = Validators
9
+ # Email address (using {EmailAddressValidator}):: {#content}.
10
+ # @see EmailAddressValidator
11
+ class EmailAddressPart < ApplicationRecord
12
+ has_many :page_parts, as: :page_partable
13
+ has_many :parts, as: :partable
14
+ has_many :layout_parts, as: :layout_partable
15
+ has_many :structure_parts, as: :structure_partable
16
+
17
+ validates :content, 'spina/admin/conferences/email_address': true, allow_blank: true
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Events during conferences.
7
+ #
8
+ # = Validators
9
+ # Presence:: {#name}, {#start_time}, {#finish_time}.
10
+ # Conference date (using {ConferenceDateValidator}):: {#start_time}, {#finish_time}.
11
+ # @see ConferenceDateValidator
12
+ #
13
+ # = Translations
14
+ # - {#name}
15
+ # - {#description}
16
+ # - {#location}
17
+ class Event < ApplicationRecord
18
+ default_scope { includes(:translations) }
19
+
20
+ # @!attribute [rw] name
21
+ # @return [String, nil] the translated name of the conference
22
+ # @!attribute [rw] description
23
+ # @return [String, nil] the translated description of the conference
24
+ # @!attribute [rw] location
25
+ # @return [String, nil] the translated location of the conference
26
+ translates :name, :description, :location, fallbacks: true
27
+
28
+ # @return [ActiveRecord::Relation] all events, ordered by name
29
+ scope :sorted, -> { i18n.order :name }
30
+
31
+ # @!attribute [rw] conference
32
+ # @return [Conference, nil] directly associated conferences
33
+ belongs_to :conference, -> { includes(:translations) }, inverse_of: :events, touch: true
34
+
35
+ validates :name, :date, :start_time, :start_datetime, :finish_time, :finish_datetime, :location, presence: true
36
+ validates :date, 'spina/admin/conferences/conference_date': true
37
+ validates :finish_time, 'spina/admin/conferences/finish_time': true
38
+
39
+ # @return [Date, nil] the start date of the event. Nil if the event has no start date and time
40
+ def date
41
+ return if start_datetime.blank?
42
+
43
+ start_datetime.to_date
44
+ end
45
+
46
+ # Sets the date of the presentation.
47
+ # @param date [Date] the new date
48
+ # @return [void]
49
+ def date=(date)
50
+ if date.blank? || date.to_date.blank?
51
+ self.start_datetime = nil
52
+ return
53
+ end
54
+
55
+ self.start_datetime = date.to_date + (start_datetime.try(:seconds_since_midnight) || 0).seconds
56
+ end
57
+
58
+ # @return [ActiveSupport::TimeWithZone, nil] the start time of the event. Nil if the event has no start date and time
59
+ def start_time
60
+ return if start_datetime.blank?
61
+
62
+ start_datetime
63
+ end
64
+
65
+ # Sets the start time of the event.
66
+ # @param start_time [ActiveSupport::TimeWithZone] the new start time
67
+ # @return [void]
68
+ def start_time=(start_time)
69
+ if start_time.blank?
70
+ self.start_datetime = nil
71
+ return
72
+ end
73
+
74
+ self.start_datetime = Time.parse(start_time, date).to_datetime.in_time_zone
75
+ end
76
+
77
+ # @return [ActiveSupport::TimeWithZone, nil] the finish time of the event. Nil if the event has no finish date and time
78
+ def finish_time
79
+ return if finish_datetime.blank?
80
+
81
+ finish_datetime
82
+ end
83
+
84
+ # Sets the finish time of the event.
85
+ # @param finish_time [ActiveSupport::TimeWithZone] the new finish time
86
+ # @return [void]
87
+ def finish_time=(finish_time)
88
+ if finish_time.blank?
89
+ self.finish_datetime = nil
90
+ return
91
+ end
92
+
93
+ self.finish_datetime = Time.parse(finish_time, date).to_datetime.in_time_zone
94
+ end
95
+
96
+ # @return [Icalendar::Event] the event as an iCal event
97
+ def to_event # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
98
+ event = Icalendar::Event.new
99
+ return event if invalid?
100
+
101
+ event.dtstart = start_datetime
102
+ event.dtend = finish_datetime
103
+ event.location = location
104
+ event.contact = Spina::Account.first.email
105
+ event.categories = Event.model_name.human(count: 0)
106
+ event.summary = name
107
+ event.append_custom_property('alt_description', description.try(:html_safe))
108
+ event.description = description.try(:gsub, %r{</?[^>]*>}, '')
109
+ event
110
+ end
111
+
112
+ # @param (see #to_event)
113
+ # @deprecated Use {#to_event} instead
114
+ def to_ics
115
+ to_event
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end