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,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Institution records.
7
+ #
8
+ # = Validators
9
+ # Presence:: {#name}, {#city}.
10
+ #
11
+ # = Translations
12
+ # - {#name}
13
+ # - {#city}
14
+ class Institution < ApplicationRecord
15
+ default_scope { includes(:translations) }
16
+
17
+ # @!attribute [rw] name
18
+ # @return [String, nil] the name of the institution
19
+ # @!attribute [rw] city
20
+ # @return [String, nil] the city of the institution
21
+ translates :name, :city, fallbacks: true
22
+
23
+ # @return [ActiveRecord::Relation] all institutions, ordered by name
24
+ scope :sorted, -> { i18n.order :name }
25
+
26
+ # @!attribute [rw] logo
27
+ # @return [Spina::Image, nil] directly associated image
28
+ belongs_to :logo, class_name: 'Spina::Image', optional: true
29
+ # @!attribute [rw] rooms
30
+ # @return [ActiveRecord::Relation] directly associated rooms
31
+ # @note An institution cannot be destroyed if it has dependent rooms.
32
+ # @see Room
33
+ has_many :rooms, -> { includes(:translations) }, inverse_of: :institution, dependent: :restrict_with_error
34
+ # @!attribute [rw] delegates
35
+ # @return [ActiveRecord::Relation] directly associated delegates
36
+ # @note This relation accepts nested attributes.
37
+ # @note An institution cannot be destroyed if it has dependent delegates.
38
+ # @see Delegate
39
+ has_many :delegates, inverse_of: :institution, dependent: :restrict_with_error
40
+ accepts_nested_attributes_for :rooms
41
+
42
+ validates :name, :city, presence: true
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Join records between partables and pageables.
7
+ class Part < ApplicationRecord
8
+ include Spina::Part
9
+ include Spina::Optionable
10
+
11
+ belongs_to :pageable, inverse_of: :parts, polymorphic: true, touch: true
12
+ belongs_to :partable, polymorphic: true, optional: true
13
+
14
+ accepts_nested_attributes_for :partable
15
+
16
+ validates :name, uniqueness: { scope: :pageable_id }
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Presentation records.
7
+ #
8
+ # = Validators
9
+ # Presence:: {#title}, {#date}, {#start_time}, {#start_datetime}, {#abstract}, {#presenters}.
10
+ # Conference date (using {ConferenceDateValidator}):: {#date}.
11
+ # @see ConferenceDateValidator
12
+ #
13
+ # = Translations
14
+ # - {#name}
15
+ # - {#title}
16
+ # - {#abstract}
17
+ class Presentation < ApplicationRecord
18
+ default_scope { includes(:translations) }
19
+
20
+ # @!attribute [rw] title
21
+ # @return [String, nil] the presentation title
22
+ # @!attribute [rw] abstract
23
+ # @return [String, nil] the presentation abstract
24
+ translates :title, :abstract, fallbacks: true
25
+
26
+ # @return [ActiveRecord::Relation] all conferences, ordered by date
27
+ scope :sorted, -> { order start_datetime: :desc }
28
+
29
+ # @!attribute [rw] name
30
+ # @return [String, nil] the presentation title (alias)
31
+ # @see #title
32
+ alias_attribute :name, :title
33
+
34
+ # @!attribute [rw] session
35
+ # @return [Session, nil] directly associated session
36
+ # @see Session
37
+ belongs_to :session, -> { includes(:translations) }, inverse_of: :presentations, touch: true
38
+ # @!attribute [rw] presentation_type
39
+ # @return [PresentationType, nil] Presentation type associated with {#session}
40
+ # @see PresentationType
41
+ # @see Session#presentation_type
42
+ has_one :presentation_type, -> { includes(:translations) }, through: :session
43
+ # @!attribute [rw] room
44
+ # @return [Room, nil] Room associated with {#session}
45
+ # @see Session
46
+ # @see Session#room
47
+ has_one :room, -> { includes(:translations) }, through: :session
48
+ # @!attribute [rw] conference
49
+ # @return [Conference, nil] Conference associated with {#presentation_type}
50
+ # @see Conference
51
+ # @see PresentationType#conference
52
+ has_one :conference, -> { includes(:translations) }, through: :presentation_type
53
+ # @!attribute [rw] attachments
54
+ # @return [ActiveRecord::Relation] directly associated presentation attachments
55
+ # @note This relation accepts nested attributes.
56
+ # @note Destroying a presentation destroys associated attachments.
57
+ # @see Attachment
58
+ has_many :attachments, class_name: 'Spina::Admin::Conferences::PresentationAttachment', dependent: :destroy,
59
+ inverse_of: :presentation
60
+ # @!attribute [rw] presenters
61
+ # @return [ActiveRecord::Relation] directly associated delegates
62
+ # @see Delegate
63
+ has_and_belongs_to_many :presenters, class_name: 'Spina::Admin::Conferences::Delegate', # rubocop:disable Rails/HasAndBelongsToMany
64
+ foreign_key: :spina_conferences_presentation_id,
65
+ association_foreign_key: :spina_conferences_delegate_id
66
+ accepts_nested_attributes_for :attachments, allow_destroy: true
67
+
68
+ validates :title, :date, :start_time, :start_datetime, :abstract, :presenters, presence: true
69
+ validates :date, 'spina/admin/conferences/conference_date': true
70
+ validates_associated :presenters
71
+ validates_associated :attachments
72
+
73
+ # Imports a presentation from CSV.
74
+ # @param file [String] the CSV file to be read
75
+ # @return [void]
76
+ # @see PresentationImportJob#perform
77
+ def self.import(file)
78
+ PresentationImportJob.perform_later IO.read(file)
79
+ end
80
+
81
+ # @return [Date, nil] the start date of the presentation. Nil if the presentation has no start date and time
82
+ def date
83
+ return if start_datetime.blank?
84
+
85
+ start_datetime.to_date
86
+ end
87
+
88
+ # Sets the date of the presentation.
89
+ # @param date [Date] the new date
90
+ # @return [void]
91
+ def date=(date)
92
+ if date.blank? || date.to_date.blank?
93
+ self.start_datetime = nil
94
+ return
95
+ end
96
+
97
+ self.start_datetime = date.to_date + (start_datetime.try(:seconds_since_midnight) || 0).seconds
98
+ end
99
+
100
+ # @return [ActiveSupport::TimeWithZone, nil] the start time of the presentation. Nil if the presentation has no start date and time
101
+ def start_time
102
+ return if start_datetime.blank?
103
+
104
+ start_datetime
105
+ end
106
+
107
+ # Sets the start time of the presentation.
108
+ # @param start_time [ActiveSupport::TimeWithZone] the new start time
109
+ # @return [void]
110
+ def start_time=(start_time)
111
+ if start_time.blank?
112
+ self.start_datetime = nil
113
+ return
114
+ end
115
+
116
+ self.start_datetime = Time.parse(start_time, date).to_datetime.in_time_zone
117
+ end
118
+
119
+ # @return [Icalendar::Event] the presentation as an iCal event
120
+ def to_event # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
121
+ event = Icalendar::Event.new
122
+ return event if invalid?
123
+
124
+ event.dtstart = start_datetime
125
+ event.dtend = start_datetime + presentation_type.duration
126
+ event.location = session.room_name
127
+ presenters.each { |presenter| event.contact = presenter.full_name_and_institution }
128
+ event.categories = Presentation.model_name.human(count: 0)
129
+ event.summary = title
130
+ event.append_custom_property('alt_description', abstract.try(:html_safe))
131
+ event.description = abstract.try(:gsub, %r{</?[^>]*>}, '')
132
+ event
133
+ end
134
+
135
+ # @param (see #to_event)
136
+ # @deprecated Use {#to_event} instead
137
+ def to_ics
138
+ to_event
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Presentation attachment records.
7
+ class PresentationAttachment < ApplicationRecord
8
+ # @!attribute [rw] presentation
9
+ # @return [Presentation, nil] directly associated presentation
10
+ belongs_to :presentation, -> { includes(:translations) }, inverse_of: :attachments, touch: true
11
+ # @!attribute [rw] presentation_attachment_type
12
+ # @return [PresentationAttachmentType, nil] directly associated presentation attachment type
13
+ belongs_to :attachment_type, -> { includes(:translations) }, class_name: 'Spina::Admin::Conferences::PresentationAttachmentType',
14
+ inverse_of: :presentation_attachments,
15
+ touch: true
16
+ # @!attribute [rw] attachment
17
+ # @return [Spina::Attachment, nil] directly associated attachment
18
+ belongs_to :attachment, class_name: 'Spina::Attachment'
19
+
20
+ # @!method name
21
+ # @return [String, nil] name of associated presentation attachment type
22
+ # @note Delegated to {#presentation_attachment_type}.
23
+ delegate :name, to: :attachment_type, allow_nil: true
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Presentation attachment type records.
7
+ #
8
+ # = Validators
9
+ # Presence:: {#name}.
10
+ #
11
+ # = Translations
12
+ # - {#name}
13
+ class PresentationAttachmentType < ApplicationRecord
14
+ default_scope { includes(:translations) }
15
+
16
+ # @!attribute [rw] name
17
+ # @return [String, nil] the name of the presentation attachment type
18
+ translates :name, fallbacks: true
19
+
20
+ # @return [ActiveRecord::Relation] all presentation attachment types, ordered by name
21
+ scope :sorted, -> { i18n.order :name }
22
+
23
+ # @!attribute [rw] presentation_attachments
24
+ # @return [ActiveRecord::Relation] directly associated presentation attachments
25
+ # @see PresentationAttachment
26
+ has_many :presentation_attachments, class_name: 'Spina::Admin::Conferences::PresentationAttachment',
27
+ foreign_key: 'attachment_type_id',
28
+ dependent: :destroy,
29
+ inverse_of: :attachment_type
30
+
31
+ validates :name, presence: true
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Presentation type records.
7
+ #
8
+ # = Validators
9
+ # Presence:: {#name}, {#minutes}. {#duration}.
10
+ #
11
+ # = Translations
12
+ # - {#name}
13
+ class PresentationType < ApplicationRecord
14
+ default_scope { includes(:translations) }
15
+
16
+ # @!attribute [rw] name
17
+ # @return [String, nil] the name of the presentation type
18
+ translates :name, fallbacks: true
19
+
20
+ # @return [ActiveRecord::Relation] all presentation types, ordered by name
21
+ scope :sorted, -> { i18n.order :name }
22
+
23
+ # @!attribute [rw] duration
24
+ # @return [ActiveSupport::Duration, nil] the duration of dependent presentations
25
+ attribute :duration, :interval
26
+
27
+ # @!attribute [rw] conference
28
+ # @return [Conference, nil] directly associated conference
29
+ belongs_to :conference, -> { includes(:translations) }, inverse_of: :presentation_types, touch: true
30
+ # @!attribute [rw] sessions
31
+ # @return [ActiveRecord::Relation] directly associated sessions
32
+ # @note A presentation type cannot be destroyed if it has dependent sessions.
33
+ # @see Session
34
+ has_many :sessions, -> { includes(:translations) }, inverse_of: :presentation_type, dependent: :restrict_with_error
35
+ # @!attribute [rw] presentations
36
+ # @return [ActiveRecord::Relation] Presentations associated with {#sessions}
37
+ # @see Presentation
38
+ # @see Session#presentations
39
+ has_many :presentations, -> { distinct.includes(:translations) }, through: :sessions
40
+
41
+ validates :name, :minutes, :duration, presence: true
42
+ validates :minutes, numericality: { greater_than_or_equal_to: 1 }
43
+
44
+ # @return [Integer, nil] duration in minutes. Nil if the conference has no duration
45
+ def minutes
46
+ return if duration.blank?
47
+
48
+ duration.to_i / ActiveSupport::Duration::PARTS_IN_SECONDS[:minutes]
49
+ end
50
+
51
+ # Sets the duration of the conference.
52
+ # @param minutes [#to_i] the new duration in minutes
53
+ # @return [void]
54
+ def minutes=(minutes)
55
+ self.duration = minutes.to_i.minutes
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Room records.
7
+ #
8
+ # = Validators
9
+ # Presence:: {#number}, {#building}.
10
+ #
11
+ # = Translations
12
+ # - {#number}
13
+ # - {#building}
14
+ class Room < ApplicationRecord
15
+ default_scope { includes(:translations) }
16
+
17
+ # @!attribute [rw] number
18
+ # @return [String, nil] the number of the room
19
+ # @!attribute [rw] building
20
+ # @return [String, nil] the building of the room
21
+ translates :building, :number, fallbacks: true
22
+
23
+ # @return [ActiveRecord::Relation] all rooms, ordered by building and number
24
+ scope :sorted, -> { i18n.order :building, :number }
25
+
26
+ # @!attribute [rw] institution
27
+ # @return [Institution, nil] directly associated institution
28
+ # @see Institution
29
+ belongs_to :institution, -> { includes(:translations) }, inverse_of: :rooms, autosave: true, touch: true
30
+ # @!attribute [rw] sessions
31
+ # @return [ActiveRecord::Relation] directly associated sessions
32
+ # @note A room cannot be destroyed if it has dependent sessions.
33
+ # @see Session
34
+ has_many :sessions, -> { includes(:translations) }, inverse_of: :room, dependent: :restrict_with_error
35
+ # @!attribute [rw] presentations
36
+ # @return [ActiveRecord::Relation] Presentations associated with {#sessions}
37
+ # @see Presentation
38
+ # @see Session#presentations
39
+ has_many :presentations, -> { distinct.includes(:translations) }, through: :sessions
40
+
41
+ validates :number, :building, presence: true
42
+
43
+ # @return [String] the building and number of the room
44
+ def name
45
+ return if building.blank? || number.blank?
46
+
47
+ Room.human_attribute_name :name, building: building, number: number
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Admin
5
+ module Conferences
6
+ # Session records.
7
+ #
8
+ # = Validators
9
+ # Presence:: {#name}.
10
+ #
11
+ # = Translations
12
+ # - {#name}
13
+ class Session < ApplicationRecord
14
+ default_scope { includes(:translations) }
15
+
16
+ # @!attribute [rw] name
17
+ # @return [String, nil] the name of the session
18
+ translates :name, fallbacks: true
19
+
20
+ # @!attribute [rw] room
21
+ # @return [Room, nil] directly associated room
22
+ belongs_to :room, -> { includes(:translations) }, inverse_of: :sessions, touch: true
23
+ # @!attribute [rw] room
24
+ # @return [PresentationType, nil] directly associated presentation type
25
+ # @see PresentationType
26
+ belongs_to :presentation_type, -> { includes(:translations) }, inverse_of: :sessions, touch: true
27
+ # @!attribute [rw] conference
28
+ # @return [Conference, nil] Conference associated with {#presentation_type}
29
+ # @see Conference
30
+ # @see PresentationType#conference
31
+ has_one :conference, -> { includes(:translations) }, through: :presentation_type
32
+ # @!attribute [rw] institution
33
+ # @return [Institution, nil] Institution associated with {#room}
34
+ # @see Institution
35
+ # @see Room#institution
36
+ has_one :institution, -> { includes(:translations) }, through: :room
37
+ # @!attribute [rw] presentations
38
+ # @return [ActiveRecord::Relation] directly associated presentations
39
+ # @note A session cannot be destroyed if it has dependent presentations.
40
+ # @see Presentation
41
+ has_many :presentations, inverse_of: :session, dependent: :restrict_with_error
42
+
43
+ validates :name, presence: true
44
+
45
+ # @!method room_name
46
+ # @return [String, nil] name of associated room
47
+ # @note Delegated to {#room}.
48
+ delegate :name, to: :room, prefix: true, allow_nil: true
49
+ # @!method presentation_type_name
50
+ # @return [String, nil] name of associated presentation type
51
+ # @note Delegated to {#presentation_type}.
52
+ delegate :name, to: :presentation_type, prefix: true, allow_nil: true
53
+ end
54
+ end
55
+ end
56
+ end