pageflow 15.6.1 → 15.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (274) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +253 -11
  3. data/README.md +1 -2
  4. data/admins/pageflow/entry.rb +28 -57
  5. data/admins/pageflow/membership.rb +5 -1
  6. data/admins/pageflow/user.rb +1 -3
  7. data/app/assets/images/pageflow/admin/icons/buttons/editor.svg +2 -0
  8. data/app/assets/images/pageflow/admin/icons/buttons/preview.svg +2 -0
  9. data/app/assets/images/pageflow/admin/icons/buttons/show_public.svg +2 -0
  10. data/app/assets/images/pageflow/admin/icons/delete.svg +9 -0
  11. data/app/assets/images/pageflow/admin/icons/done.svg +6 -0
  12. data/app/assets/images/pageflow/admin/icons/edit.svg +7 -0
  13. data/app/assets/images/pageflow/admin/icons/editor.svg +2 -0
  14. data/app/assets/images/pageflow/admin/icons/folder.svg +8 -0
  15. data/app/assets/images/pageflow/admin/icons/folder_active.svg +8 -0
  16. data/app/assets/images/pageflow/admin/icons/info.svg +3 -0
  17. data/app/assets/images/pageflow/admin/icons/new.svg +5 -0
  18. data/app/assets/images/pageflow/admin/icons/preview.svg +2 -0
  19. data/app/assets/images/pageflow/admin/icons/published.svg +2 -0
  20. data/app/assets/images/pageflow/admin/icons/published_with_password.svg +2 -0
  21. data/app/assets/images/pageflow/admin/icons/show_public.svg +2 -0
  22. data/app/assets/images/pageflow/editor/blank_entry/logo.png +0 -0
  23. data/app/assets/images/pageflow/themes/default/embed_opt_in.svg +3 -0
  24. data/app/assets/images/pageflow/themes/default/embed_opt_out_info.svg +16 -0
  25. data/app/assets/javascripts/pageflow/admin/entries.js +9 -57
  26. data/app/assets/javascripts/pageflow/dist/editor.js +11890 -0
  27. data/app/assets/javascripts/pageflow/dist/frontend.js +5800 -0
  28. data/app/assets/javascripts/pageflow/dist/react-client.js +22 -0
  29. data/app/assets/javascripts/pageflow/dist/react-server.js +19 -0
  30. data/app/assets/javascripts/pageflow/dist/ui.js +127 -10
  31. data/app/assets/stylesheets/pageflow/admin/active_admin_patches.scss +18 -16
  32. data/app/assets/stylesheets/pageflow/admin/badge_list.scss +25 -35
  33. data/app/assets/stylesheets/pageflow/admin/columns.scss +13 -11
  34. data/app/assets/stylesheets/pageflow/admin/embed_code.scss +1 -4
  35. data/app/assets/stylesheets/pageflow/admin/entries/folders.scss +44 -19
  36. data/app/assets/stylesheets/pageflow/admin/entries.scss +15 -31
  37. data/app/assets/stylesheets/pageflow/admin/features.scss +3 -1
  38. data/app/assets/stylesheets/pageflow/admin/forms.scss +14 -12
  39. data/app/assets/stylesheets/pageflow/admin/hint.scss +8 -14
  40. data/app/assets/stylesheets/pageflow/admin/icon_button.scss +25 -14
  41. data/app/assets/stylesheets/pageflow/admin/icon_link.scss +31 -15
  42. data/app/assets/stylesheets/pageflow/admin/publication_state_indicator.scss +14 -7
  43. data/app/assets/stylesheets/pageflow/admin/status_tags.scss +5 -4
  44. data/app/assets/stylesheets/pageflow/admin/tabs_view.scss +36 -34
  45. data/app/assets/stylesheets/pageflow/admin/tooltip_bubble.scss +15 -11
  46. data/app/assets/stylesheets/pageflow/admin.scss +12 -0
  47. data/app/assets/stylesheets/pageflow/editor/background_positioning.scss +15 -61
  48. data/app/assets/stylesheets/pageflow/editor/base.scss +28 -13
  49. data/app/assets/stylesheets/pageflow/editor/blank_entry.scss +6 -6
  50. data/app/assets/stylesheets/pageflow/editor/change_theme.scss +28 -71
  51. data/app/assets/stylesheets/pageflow/editor/composables.scss +2 -2
  52. data/app/assets/stylesheets/pageflow/editor/confirm_encoding.scss +18 -36
  53. data/app/assets/stylesheets/pageflow/editor/confirm_upload.scss +12 -39
  54. data/app/assets/stylesheets/pageflow/editor/dialogs.scss +39 -12
  55. data/app/assets/stylesheets/pageflow/editor/disabled_atmo_indicator.scss +3 -3
  56. data/app/assets/stylesheets/pageflow/editor/drop_down_button.scss +7 -10
  57. data/app/assets/stylesheets/pageflow/editor/emulation_mode_button.scss +3 -8
  58. data/app/assets/stylesheets/pageflow/editor/failures.scss +3 -3
  59. data/app/assets/stylesheets/pageflow/editor/file_import.scss +22 -38
  60. data/app/assets/stylesheets/pageflow/editor/file_meta_data.scss +3 -7
  61. data/app/assets/stylesheets/pageflow/editor/file_settings_dialog.scss +4 -24
  62. data/app/assets/stylesheets/pageflow/editor/file_stages.scss +10 -11
  63. data/app/assets/stylesheets/pageflow/editor/file_thumbnails.scss +4 -8
  64. data/app/assets/stylesheets/pageflow/editor/files.scss +7 -6
  65. data/app/assets/stylesheets/pageflow/editor/files_explorer.scss +13 -30
  66. data/app/assets/stylesheets/pageflow/editor/files_gallery.scss +15 -11
  67. data/app/assets/stylesheets/pageflow/editor/filtered_files.scss +6 -7
  68. data/app/assets/stylesheets/pageflow/editor/help.scss +19 -14
  69. data/app/assets/stylesheets/pageflow/editor/help_image.scss +1 -1
  70. data/app/assets/stylesheets/pageflow/editor/info_box.scss +19 -0
  71. data/app/assets/stylesheets/pageflow/editor/inputs/file_input.scss +7 -11
  72. data/app/assets/stylesheets/pageflow/editor/inputs/file_processing_state_display.scss +0 -2
  73. data/app/assets/stylesheets/pageflow/editor/inputs/reference.scss +7 -11
  74. data/app/assets/stylesheets/pageflow/editor/list.scss +13 -10
  75. data/app/assets/stylesheets/pageflow/editor/loading.scss +1 -1
  76. data/app/assets/stylesheets/pageflow/editor/locked.scss +9 -5
  77. data/app/assets/stylesheets/pageflow/editor/menu.scss +5 -5
  78. data/app/assets/stylesheets/pageflow/editor/notifications.scss +15 -14
  79. data/app/assets/stylesheets/pageflow/editor/other_entry_item.scss +7 -3
  80. data/app/assets/stylesheets/pageflow/editor/outline.scss +57 -19
  81. data/app/assets/stylesheets/pageflow/editor/page_links.scss +10 -8
  82. data/app/assets/stylesheets/pageflow/editor/page_selection.scss +2 -29
  83. data/app/assets/stylesheets/pageflow/editor/publish_entry.scss +5 -6
  84. data/app/assets/stylesheets/pageflow/editor/quotas.scss +2 -3
  85. data/app/assets/stylesheets/pageflow/editor/select_button.scss +12 -6
  86. data/app/assets/stylesheets/pageflow/editor/sidebar_footer.scss +1 -5
  87. data/app/assets/stylesheets/pageflow/editor/storyline_picker.scss +6 -2
  88. data/app/assets/stylesheets/pageflow/editor/text_tracks.scss +6 -22
  89. data/app/assets/stylesheets/pageflow/editor/widgets.scss +2 -2
  90. data/app/assets/stylesheets/pageflow/editor/wysihtml5.scss +35 -29
  91. data/app/assets/stylesheets/pageflow/mixins/background_icons.scss +3 -3
  92. data/app/assets/stylesheets/pageflow/mixins/buttons.scss +50 -68
  93. data/app/assets/stylesheets/pageflow/themes/default/base.scss +2 -0
  94. data/app/assets/stylesheets/pageflow/themes/default/consent/bar.scss +156 -0
  95. data/app/assets/stylesheets/pageflow/themes/default/consent/vendor_list.scss +62 -0
  96. data/app/assets/stylesheets/pageflow/themes/default/consent.scss +2 -0
  97. data/app/assets/stylesheets/pageflow/themes/default/logo/alignment.scss +7 -0
  98. data/app/assets/stylesheets/pageflow/themes/default/page/shadow.scss +44 -0
  99. data/app/assets/stylesheets/pageflow/themes/default/third_party_embed_consent.scss +103 -0
  100. data/app/assets/stylesheets/pageflow/ui/forms.scss +79 -84
  101. data/app/assets/stylesheets/pageflow/ui/functions.scss +56 -0
  102. data/app/assets/stylesheets/pageflow/ui/input/check_box_group_input.scss +2 -3
  103. data/app/assets/stylesheets/pageflow/ui/input/color_input.scss +6 -6
  104. data/app/assets/stylesheets/pageflow/ui/input/extended_select_input.scss +63 -50
  105. data/app/assets/stylesheets/pageflow/ui/normalize/forms.scss +153 -0
  106. data/app/assets/stylesheets/pageflow/ui/normalize.scss +278 -0
  107. data/app/assets/stylesheets/pageflow/ui/properties.scss +44 -0
  108. data/app/assets/stylesheets/pageflow/ui/table_cells/delete_row_table_cell.scss +1 -1
  109. data/app/assets/stylesheets/pageflow/ui/table_view.scss +14 -18
  110. data/app/assets/stylesheets/pageflow/ui/tabs_view.scss +8 -11
  111. data/app/assets/stylesheets/pageflow/ui/tooltip.scss +6 -8
  112. data/app/assets/stylesheets/pageflow/ui/validation_error_messages.scss +6 -0
  113. data/app/assets/stylesheets/pageflow/ui.scss +4 -0
  114. data/app/controllers/pageflow/edit_locks_controller.rb +3 -1
  115. data/app/helpers/pageflow/admin/entries_helper.rb +2 -12
  116. data/app/helpers/pageflow/embed_code_helper.rb +1 -1
  117. data/app/helpers/pageflow/entries_helper.rb +41 -2
  118. data/app/helpers/pageflow/file_background_images_helper.rb +1 -1
  119. data/app/helpers/pageflow/page_types_helper.rb +1 -1
  120. data/app/helpers/pageflow/themes_helper.rb +1 -1
  121. data/app/jobs/pageflow/poll_meta_data_from_zencoder_job.rb +1 -1
  122. data/app/jobs/pageflow/poll_zencoder_job.rb +1 -9
  123. data/app/models/pageflow/audio_file.rb +17 -0
  124. data/app/models/pageflow/audio_file_url_templates.rb +4 -1
  125. data/app/models/pageflow/customized_theme.rb +37 -0
  126. data/app/models/pageflow/draft_entry.rb +6 -59
  127. data/app/models/pageflow/entry.rb +8 -0
  128. data/app/models/pageflow/entry_at_revision.rb +68 -0
  129. data/app/models/pageflow/entry_role_query.rb +44 -24
  130. data/app/models/pageflow/image_file_css_background_image_urls.rb +8 -2
  131. data/app/models/pageflow/published_entry.rb +9 -56
  132. data/app/models/pageflow/theme_customization.rb +46 -0
  133. data/app/models/pageflow/theme_customization_file.rb +58 -0
  134. data/app/models/pageflow/video_file.rb +11 -1
  135. data/app/models/pageflow/video_file_url_templates.rb +1 -0
  136. data/app/policies/pageflow/entry_policy.rb +4 -0
  137. data/app/state_machines/pageflow/media_encoding_state_machine.rb +23 -4
  138. data/app/views/admin/entries/_form.html.erb +50 -0
  139. data/app/views/admin/entries/entry_type_name_input.html.erb +5 -0
  140. data/app/views/admin/features/_form.html.erb +1 -1
  141. data/app/views/admin/memberships/_form.html.erb +2 -3
  142. data/app/views/admin/users/_form.html.erb +1 -1
  143. data/app/views/admin/users/invitation.html.erb +2 -2
  144. data/app/views/components/pageflow/admin/entry_user_badge_list.rb +10 -9
  145. data/app/views/components/pageflow/admin/members_tab.rb +5 -1
  146. data/app/views/components/pageflow/admin/revisions_tab.rb +13 -3
  147. data/app/views/components/pageflow/admin/timestamp.rb +20 -0
  148. data/app/views/components/pageflow/admin/user_account_badge_list.rb +5 -6
  149. data/app/views/pageflow/admin/entries/_cannot_add_user.html.erb +9 -5
  150. data/app/views/pageflow/admin/entries/_entry_type_name_input.html.erb +7 -0
  151. data/app/views/pageflow/audio_files/_audio_file.json.jbuilder +13 -0
  152. data/app/views/pageflow/editor/encoding_confirmations/_intro.html.erb +0 -0
  153. data/app/views/pageflow/editor/encoding_confirmations/check.json.jbuilder +14 -2
  154. data/config/initializers/paperclip.rb +16 -1
  155. data/config/locales/de.yml +24 -28
  156. data/config/locales/en.yml +19 -10
  157. data/db/migrate/20210528073122_create_pageflow_theme_customizations.rb +11 -0
  158. data/db/migrate/20210531090654_create_pageflow_theme_customization_files.rb +15 -0
  159. data/db/migrate/20210531102228_add_selected_file_ids_to_theme_customizations.rb +5 -0
  160. data/db/migrate/20211020085902_add_canonical_entry_url_prefix_to_themings.rb +5 -0
  161. data/db/migrate/20220503150010_add_peak_data_to_audio_files.rb +5 -0
  162. data/db/migrate/20220705084830_add_trailing_slash_in_canonical_urls_to_themings.rb +5 -0
  163. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +256 -124
  164. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/frontend.js +566 -167
  165. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-client.js +5 -5
  166. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-server.js +4 -4
  167. data/entry_types/paged/app/helpers/pageflow_paged/third_party_embed_consent_helper.rb +38 -0
  168. data/entry_types/paged/app/views/pageflow_paged/third_party_embed_consent/_opt_in.html.erb +12 -0
  169. data/entry_types/paged/app/views/pageflow_paged/third_party_embed_consent/_opt_out_info.html.erb +10 -0
  170. data/entry_types/paged/config/initializers/features.rb +2 -0
  171. data/entry_types/paged/config/locales/new/video_contain.de.yml +7 -0
  172. data/entry_types/paged/config/locales/new/video_contain.en.yml +7 -0
  173. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +3 -0
  174. data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +1 -0
  175. data/entry_types/scrolled/app/helpers/pageflow_scrolled/packs_helper.rb +58 -0
  176. data/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb +37 -3
  177. data/entry_types/scrolled/app/helpers/pageflow_scrolled/themes_helper.rb +92 -6
  178. data/entry_types/scrolled/app/helpers/pageflow_scrolled/webpack_public_path_helper.rb +20 -0
  179. data/entry_types/scrolled/app/models/pageflow_scrolled/content_element.rb +7 -0
  180. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_head.html.erb +5 -2
  181. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_seed.json.jbuilder +5 -1
  182. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +5 -4
  183. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +16 -0
  184. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_theme.json.jbuilder +13 -2
  185. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_widget.json.jbuilder +2 -0
  186. data/entry_types/scrolled/config/locales/de.yml +1 -8
  187. data/entry_types/scrolled/config/locales/en.yml +1 -9
  188. data/entry_types/scrolled/config/locales/new/before_after_slider.de.yml +8 -0
  189. data/entry_types/scrolled/config/locales/new/before_after_slider.en.yml +8 -0
  190. data/entry_types/scrolled/config/locales/new/center_ragged.de.yml +8 -0
  191. data/entry_types/scrolled/config/locales/new/center_ragged.en.yml +9 -0
  192. data/entry_types/scrolled/config/locales/new/consent.de.yml +25 -0
  193. data/entry_types/scrolled/config/locales/new/consent.en.yml +24 -0
  194. data/entry_types/scrolled/config/locales/new/content_element_categories.de.yml +39 -0
  195. data/entry_types/scrolled/config/locales/new/content_element_categories.en.yml +39 -0
  196. data/entry_types/scrolled/config/locales/new/default_transition.de.yml +14 -0
  197. data/entry_types/scrolled/config/locales/new/default_transition.en.yml +14 -0
  198. data/entry_types/scrolled/config/locales/new/header_line_breaks.de.yml +28 -0
  199. data/entry_types/scrolled/config/locales/new/header_line_breaks.en.yml +27 -0
  200. data/entry_types/scrolled/config/locales/new/header_size.de.yml +17 -0
  201. data/entry_types/scrolled/config/locales/new/header_size.en.yml +17 -0
  202. data/entry_types/scrolled/config/locales/new/iframe_embed.de.yml +39 -0
  203. data/entry_types/scrolled/config/locales/new/iframe_embed.en.yml +39 -0
  204. data/entry_types/scrolled/config/locales/new/inline_loops.de.yml +26 -0
  205. data/entry_types/scrolled/config/locales/new/inline_loops.en.yml +26 -0
  206. data/entry_types/scrolled/config/locales/new/portrait_inline_image.de.yml +9 -0
  207. data/entry_types/scrolled/config/locales/new/portrait_inline_image.en.yml +9 -0
  208. data/entry_types/scrolled/config/locales/new/section_width.de.yml +10 -0
  209. data/entry_types/scrolled/config/locales/new/section_width.en.yml +10 -0
  210. data/entry_types/scrolled/config/locales/new/typography_variants.de.yml +7 -0
  211. data/entry_types/scrolled/config/locales/new/typography_variants.en.yml +7 -0
  212. data/entry_types/scrolled/config/locales/new/video_embed_poster.de.yml +8 -0
  213. data/entry_types/scrolled/config/locales/new/video_embed_poster.en.yml +8 -0
  214. data/entry_types/scrolled/config/locales/new/waveform_styles.de.yml +11 -0
  215. data/entry_types/scrolled/config/locales/new/waveform_styles.en.yml +12 -0
  216. data/entry_types/scrolled/config/locales/new/widgets.de.yml +6 -0
  217. data/entry_types/scrolled/config/locales/new/widgets.en.yml +6 -0
  218. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/install_generator.rb +29 -5
  219. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/themes_plugin.rb.tt +8 -6
  220. data/entry_types/scrolled/lib/pageflow_scrolled/additional_packs.rb +37 -0
  221. data/entry_types/scrolled/lib/pageflow_scrolled/additional_seed_data.rb +57 -0
  222. data/entry_types/scrolled/lib/pageflow_scrolled/configuration.rb +49 -0
  223. data/entry_types/scrolled/lib/pageflow_scrolled/plugin.rb +8 -0
  224. data/entry_types/scrolled/lib/pageflow_scrolled/react_widget_type.rb +42 -0
  225. data/entry_types/scrolled/lib/pageflow_scrolled.rb +17 -1
  226. data/entry_types/scrolled/package/contentElements-editor.js +323 -89
  227. data/entry_types/scrolled/package/contentElements-frontend.css +1 -1
  228. data/entry_types/scrolled/package/contentElements-frontend.js +719 -529
  229. data/entry_types/scrolled/package/editor.js +459 -261
  230. data/entry_types/scrolled/package/frontend/{EditableText-7093fd0e.js → EditableInlineText.module-b9923660.js} +284 -362
  231. data/entry_types/scrolled/package/frontend/{i18n-4dc6c377.js → PhonePlatformContext-9fb97827.js} +199 -106
  232. data/entry_types/scrolled/package/frontend/{Viewer-e49e7807.js → Viewer-e2290ea0.js} +196 -79
  233. data/entry_types/scrolled/package/frontend/{Wavesurfer-0adf5667.js → Wavesurfer-7d9cf1b7.js} +16 -58
  234. data/entry_types/scrolled/package/frontend/{components-6a6793ca.js → components-6ab26015.js} +664 -671
  235. data/entry_types/scrolled/package/frontend/{getPrototypeOf-63c7c8e8.js → createSuper-d0f30da3.js} +34 -5
  236. data/entry_types/scrolled/package/frontend/index.css +1 -9
  237. data/entry_types/scrolled/package/frontend/index.js +1919 -2386
  238. data/entry_types/scrolled/package/frontend/{useBrowserFeature-91a4c29d.js → usePhonePlatform-2857c22b.js} +9 -8
  239. data/entry_types/scrolled/package/frontend-server.js +3 -6
  240. data/entry_types/scrolled/package/package.json +16 -8
  241. data/entry_types/scrolled/package/testHelpers.js +456 -0
  242. data/entry_types/scrolled/package/values/breakpoints.module.css +9 -0
  243. data/entry_types/scrolled/package/values/colors.module.css +5 -0
  244. data/entry_types/scrolled/package/widgets/defaultNavigation.css +9 -0
  245. data/entry_types/scrolled/package/widgets/defaultNavigation.js +612 -0
  246. data/entry_types/scrolled/spec/fixtures/image.svg +1 -0
  247. data/lib/pageflow/ability_mixin.rb +4 -0
  248. data/lib/pageflow/built_in_widget_type.rb +4 -0
  249. data/lib/pageflow/built_in_widget_types_plugin.rb +7 -0
  250. data/lib/pageflow/configuration.rb +34 -1
  251. data/lib/pageflow/entry_type.rb +11 -2
  252. data/lib/pageflow/entry_type_configuration.rb +2 -0
  253. data/lib/pageflow/file_type.rb +24 -0
  254. data/lib/pageflow/paperclip_processors/audio_waveform.rb +42 -0
  255. data/lib/pageflow/paperclip_processors/noop.rb +10 -0
  256. data/lib/pageflow/theme_customizations.rb +61 -0
  257. data/lib/pageflow/user_mixin.rb +6 -0
  258. data/lib/pageflow/version.rb +1 -1
  259. data/lib/pageflow.rb +9 -0
  260. data/package/config/jest/index.js +2 -1
  261. data/package/config/postcss/scaleFunctions.js +71 -0
  262. data/package/editor.js +95 -85
  263. data/package/frontend.js +521 -161
  264. data/package/package.json +5 -3
  265. data/package/testHelpers.js +26 -5
  266. data/package/ui.js +124 -11
  267. data/spec/factories/draft_entries.rb +19 -1
  268. data/spec/factories/entries.rb +4 -0
  269. data/spec/factories/published_entries.rb +6 -0
  270. data/spec/fixtures/audio.ogg +0 -0
  271. metadata +123 -15
  272. data/app/views/admin/entries/_not_allowed_to_see_entry_types.json.jbuilder +0 -2
  273. data/app/views/admin/entries/entry_types.json.jbuilder +0 -4
  274. data/package/config/jest/transformers/upwardBabel.js +0 -5
@@ -5,6 +5,7 @@ module Pageflow
5
5
  m4a: url_template(:m4a),
6
6
  mp3: url_template(:mp3),
7
7
  ogg: url_template(:ogg),
8
+ peak_data: url_template(:peak_data)
8
9
  }
9
10
  end
10
11
 
@@ -15,7 +16,9 @@ module Pageflow
15
16
  end
16
17
 
17
18
  def example_file
18
- @example_file ||= AudioFile.new(id: 0, file_name: ':basename.mp3')
19
+ @example_file ||= AudioFile.new(id: 0,
20
+ file_name: ':basename.mp3',
21
+ peak_data_file_name: 'audio.json')
19
22
  end
20
23
  end
21
24
  end
@@ -0,0 +1,37 @@
1
+ module Pageflow
2
+ # @api private
3
+ class CustomizedTheme < SimpleDelegator
4
+ def initialize(theme, overrides, files)
5
+ super(theme)
6
+ @options = __getobj__.options.deep_merge(overrides || {})
7
+ @files = files
8
+ end
9
+
10
+ attr_reader :options, :files
11
+
12
+ def self.find(entry:, theme:)
13
+ build(
14
+ entry: entry,
15
+ theme: theme,
16
+ theme_customization: Pageflow.theme_customizations.get(
17
+ account: entry.account,
18
+ entry_type_name: entry.type_name
19
+ )
20
+ )
21
+ end
22
+
23
+ def self.build(entry:, theme:, theme_customization:)
24
+ config = Pageflow.config_for(entry)
25
+
26
+ new(theme,
27
+ config.transform_theme_customization_overrides.call(
28
+ theme_customization.overrides,
29
+ entry
30
+ ),
31
+ config.transform_theme_customization_files.call(
32
+ theme_customization.selected_files.transform_values(&:urls),
33
+ entry
34
+ ))
35
+ end
36
+ end
37
+ end
@@ -1,42 +1,13 @@
1
1
  module Pageflow
2
- class DraftEntry
3
- include ActiveModel::Conversion
4
-
2
+ # A merged view of an entry and its draft revision
3
+ class DraftEntry < EntryAtRevision
5
4
  class InvalidForeignKeyCustomAttributeError < StandardError; end
6
5
 
7
- attr_reader :entry, :draft
8
-
9
- delegate(:id, :slug,
10
- :entry_type,
11
- :edit_lock, :account, :theming, :slug,
12
- :enabled_feature_names,
13
- :published_until, :published?,
14
- :password_digest,
15
- :to_model, :to_key, :persisted?, :to_json,
16
- :first_published_at,
17
- :type_name,
18
- :to => :entry)
19
-
20
- delegate(:title, :summary, :credits,
21
- :widgets,
22
- :storylines, :main_storyline_chapters, :chapters, :pages,
23
- :share_url, :share_image_id, :share_image_x, :share_image_y,
24
- :share_providers, :active_share_providers,
25
- :find_files, :find_file, :find_file_by_perma_id,
26
- :image_files, :video_files, :audio_files,
27
- :locale,
28
- :author, :publisher, :keywords,
29
- :theme,
30
- :published_at,
31
- :configuration,
32
- :to => :draft)
33
-
34
6
  def initialize(entry, draft = nil)
35
- @entry = entry
36
- @draft = draft || entry.draft
7
+ super(entry, draft || entry.draft)
37
8
  end
38
9
 
39
- alias revision draft
10
+ alias draft revision
40
11
 
41
12
  # So we can always get to the original Entry title.
42
13
  def entry_title
@@ -50,8 +21,8 @@ module Pageflow
50
21
  f.entry = entry
51
22
  end
52
23
 
53
- usage = @draft.file_usages.create_with_lock!(file: file,
54
- configuration: attributes[:configuration])
24
+ usage = revision.file_usages.create_with_lock!(file: file,
25
+ configuration: attributes[:configuration])
55
26
  UsedFile.new(file, usage)
56
27
  end
57
28
 
@@ -106,30 +77,6 @@ module Pageflow
106
77
  draft.cache_key
107
78
  end
108
79
 
109
- def home_button
110
- HomeButton.new(draft, theming)
111
- end
112
-
113
- def overview_button
114
- OverviewButton.new(draft)
115
- end
116
-
117
- def manual_start
118
- revision.configuration['manual_start']
119
- end
120
-
121
- def emphasize_chapter_beginning
122
- revision.configuration['emphasize_chapter_beginning']
123
- end
124
-
125
- def emphasize_new_pages
126
- revision.configuration['emphasize_new_pages']
127
- end
128
-
129
- def resolve_widgets(options = {})
130
- widgets.resolve(Pageflow.config_for(entry), options)
131
- end
132
-
133
80
  private
134
81
 
135
82
  def check_foreign_key_custom_attributes(custom_attributes, attributes)
@@ -126,6 +126,14 @@ module Pageflow
126
126
  [:title, [:title, :id]]
127
127
  end
128
128
 
129
+ def self.ransackable_attributes(_auth_object)
130
+ %w[title type_name created_at edited_at first_published_at]
131
+ end
132
+
133
+ def self.ransackable_associations(_auth_object)
134
+ %w[account published_revision]
135
+ end
136
+
129
137
  def self.ransackable_scopes(_)
130
138
  [:with_publication_state, :published]
131
139
  end
@@ -0,0 +1,68 @@
1
+ module Pageflow
2
+ # A simplified view of an entry at a given revision. Hides the
3
+ # revision concept and makes revision attributes available along
4
+ # with entry attributes.
5
+ class EntryAtRevision
6
+ include ActiveModel::Conversion
7
+
8
+ attr_reader :entry, :revision
9
+
10
+ def initialize(entry, revision, theme: nil)
11
+ @entry = entry
12
+ @revision = revision
13
+ @theme = theme
14
+ end
15
+
16
+ delegate(:id, :slug,
17
+ :entry_type,
18
+ :account, :theming,
19
+ :feature_state, :enabled_feature_names,
20
+ :edit_lock,
21
+ :password_digest,
22
+ :to_model, :to_key, :to_param, :persisted?, :to_json,
23
+ :first_published_at, :published_until, :published?,
24
+ :type_name,
25
+ to: :entry)
26
+
27
+ delegate(:title, :summary, :credits,
28
+ :widgets,
29
+ :storylines, :main_storyline_chapters, :chapters, :pages,
30
+ :share_url, :share_image_id, :share_image_x, :share_image_y,
31
+ :share_providers, :active_share_providers,
32
+ :find_files, :find_file, :find_file_by_perma_id,
33
+ :image_files, :video_files, :audio_files,
34
+ :locale,
35
+ :author, :publisher, :keywords,
36
+ :published_at,
37
+ :configuration,
38
+ to: :revision)
39
+
40
+ def resolve_widgets(options = {})
41
+ widgets.resolve(Pageflow.config_for(entry), options)
42
+ end
43
+
44
+ def theme
45
+ @theme ||= CustomizedTheme.find(entry: self, theme: revision.theme)
46
+ end
47
+
48
+ def home_button
49
+ HomeButton.new(revision, theming)
50
+ end
51
+
52
+ def overview_button
53
+ OverviewButton.new(revision)
54
+ end
55
+
56
+ def manual_start
57
+ revision.configuration['manual_start']
58
+ end
59
+
60
+ def emphasize_chapter_beginning
61
+ revision.configuration['emphasize_chapter_beginning']
62
+ end
63
+
64
+ def emphasize_new_pages
65
+ revision.configuration['emphasize_new_pages']
66
+ end
67
+ end
68
+ end
@@ -11,33 +11,39 @@ module Pageflow
11
11
 
12
12
  def with_role_at_least(role)
13
13
  scope
14
- .joins(memberships_for_entries_with_at_least_role(role))
15
- .joins(memberships_for_account_of_entries_with_at_least_role(role))
16
- .where(either_membership_is_present)
14
+ .joins(memberships_for_account_of_entries)
15
+ .joins(memberships_for_entries)
16
+ .where(either_membership_has_at_least_role(role))
17
17
  end
18
18
 
19
19
  def with_account_role_at_least(role)
20
20
  scope
21
- .joins(memberships_for_account_of_entries_with_at_least_role(role))
22
- .where(entry_account_membership_is_present)
21
+ .joins(memberships_for_account_of_entries)
22
+ .where(entry_account_membership_has_at_least_role(role))
23
23
  end
24
24
 
25
25
  private
26
26
 
27
- def memberships_for_entries_with_at_least_role(role)
28
- join_memberships(table_alias: table_alias_for('entry'),
27
+ def memberships_for_account_of_entries
28
+ # Since every user with an entry membership also has a
29
+ # membership for the entry's account, we can use an INNER JOIN
30
+ # to prevent a full scan of the entries table. The database
31
+ # will first look up the account memberships and then get the
32
+ # entries using the index on `account_id`. Those are then
33
+ # filtered further based on entry memberships and roles.
34
+ join_memberships(join_type: 'INNER',
35
+ table_alias: table_alias_for('entry_account'),
29
36
  user_id: user.id,
30
- roles: Roles.at_least(role),
31
- entity_id_column: 'pageflow_entries.id',
32
- entity_type: 'Pageflow::Entry')
37
+ entity_id_column: 'pageflow_entries.account_id',
38
+ entity_type: 'Pageflow::Account')
33
39
  end
34
40
 
35
- def memberships_for_account_of_entries_with_at_least_role(role)
36
- join_memberships(table_alias: table_alias_for('entry_account'),
41
+ def memberships_for_entries
42
+ join_memberships(join_type: 'LEFT OUTER',
43
+ table_alias: table_alias_for('entry'),
37
44
  user_id: user.id,
38
- roles: Roles.at_least(role),
39
- entity_id_column: 'pageflow_entries.account_id',
40
- entity_type: 'Pageflow::Account')
45
+ entity_id_column: 'pageflow_entries.id',
46
+ entity_type: 'Pageflow::Entry')
41
47
  end
42
48
 
43
49
  def join_memberships(options)
@@ -45,25 +51,39 @@ module Pageflow
45
51
  entity_id_column = options[:entity_id_column]
46
52
 
47
53
  sanitize_sql(<<-SQL, options)
48
- LEFT OUTER JOIN pageflow_memberships as #{table_alias} ON
54
+ #{options[:join_type]} JOIN pageflow_memberships as #{table_alias} ON
49
55
  #{table_alias}.user_id = :user_id AND
50
- #{table_alias}.role IN (:roles) AND
51
56
  #{table_alias}.entity_id = #{entity_id_column} AND
52
57
  #{table_alias}.entity_type = :entity_type
53
58
  SQL
54
59
  end
55
60
 
56
- def either_membership_is_present
57
- [entry_membership_is_present,
58
- entry_account_membership_is_present].join(' OR ')
61
+ def either_membership_has_at_least_role(role)
62
+ [
63
+ entry_account_membership_has_at_least_role(role),
64
+ entry_membership_has_at_least_role(role)
65
+ ].join(' OR ')
66
+ end
67
+
68
+ def entry_account_membership_has_at_least_role(role)
69
+ membership_has_at_least_role(
70
+ table_alias: table_alias_for('entry_account'),
71
+ role: role
72
+ )
59
73
  end
60
74
 
61
- def entry_membership_is_present
62
- "#{table_alias_for(:entry)}.entity_id IS NOT NULL"
75
+ def entry_membership_has_at_least_role(role)
76
+ membership_has_at_least_role(
77
+ table_alias: table_alias_for('entry'),
78
+ role: role
79
+ )
63
80
  end
64
81
 
65
- def entry_account_membership_is_present
66
- "#{table_alias_for(:entry_account)}.entity_id IS NOT NULL"
82
+ def membership_has_at_least_role(table_alias:, role:)
83
+ sanitize_sql(
84
+ "#{table_alias}.role IN (:roles)",
85
+ roles: Roles.at_least(role)
86
+ )
67
87
  end
68
88
 
69
89
  def table_alias_for(type)
@@ -1,10 +1,10 @@
1
1
  module Pageflow
2
2
  # @api private
3
3
  class ImageFileCssBackgroundImageUrls
4
- def call(image_file)
4
+ def call(image_file, entry:)
5
5
  {
6
6
  default: {
7
- desktop: image_file.ready? ? image_file.attachment.url(:large) : '',
7
+ desktop: image_file.ready? ? image_file.attachment.url(desktop_style(entry)) : '',
8
8
  mobile: image_file.ready? ? image_file.attachment.url(:medium) : ''
9
9
  },
10
10
  panorama: {
@@ -13,5 +13,11 @@ module Pageflow
13
13
  }
14
14
  }
15
15
  end
16
+
17
+ private
18
+
19
+ def desktop_style(entry)
20
+ entry.feature_state('highdef_background_images') ? :ultra : :large
21
+ end
16
22
  end
17
23
  end
@@ -1,56 +1,21 @@
1
1
  module Pageflow
2
- class PublishedEntry
3
- include ActiveModel::Conversion
2
+ # A merged view of an entry and its published revision.
3
+ class PublishedEntry < EntryAtRevision
4
4
  extend ActiveModel::Naming
5
5
 
6
- attr_reader :entry, :revision
7
6
  attr_accessor :share_target
8
7
 
9
- delegate(:id, :slug,
10
- :entry_type,
11
- :account, :theming,
12
- :enabled_feature_names,
13
- :to_model, :to_key, :persisted?,
14
- :authenticate,
15
- :first_published_at,
16
- :type_name,
17
- :to => :entry)
18
-
19
- delegate(:widgets,
20
- :storylines, :main_storyline_chapters, :chapters, :pages,
21
- :find_files, :find_file, :find_file_by_perma_id,
22
- :image_files, :video_files, :audio_files,
23
- :summary, :credits,
24
- :share_url, :share_image_id, :share_image_x, :share_image_y,
25
- :share_providers, :active_share_providers,
26
- :locale,
27
- :author, :publisher, :keywords,
28
- :theme,
29
- :password_protected?,
30
- :published_at,
31
- :configuration,
32
- :to => :revision)
33
-
34
- def initialize(entry, revision = nil)
35
- @entry = entry
36
- @revision = revision || entry.published_revision
37
- @custom_revision = !!revision
38
- end
8
+ delegate(:authenticate, to: :entry)
39
9
 
40
- def title
41
- revision.title.presence || entry.title
42
- end
10
+ delegate(:password_protected?, to: :revision)
43
11
 
44
- def manual_start
45
- revision.configuration['manual_start']
12
+ def initialize(entry, revision = nil, theme: nil)
13
+ super(entry, revision || entry.published_revision, theme: theme)
14
+ @custom_revision = revision
46
15
  end
47
16
 
48
- def emphasize_chapter_beginning
49
- revision.configuration['emphasize_chapter_beginning']
50
- end
51
-
52
- def emphasize_new_pages
53
- revision.configuration['emphasize_new_pages']
17
+ def title
18
+ revision.title.presence || entry.title
54
19
  end
55
20
 
56
21
  def stylesheet_model
@@ -98,18 +63,6 @@ module Pageflow
98
63
  ].compact.join('-').presence
99
64
  end
100
65
 
101
- def home_button
102
- HomeButton.new(revision, theming)
103
- end
104
-
105
- def overview_button
106
- OverviewButton.new(revision)
107
- end
108
-
109
- def resolve_widgets(options = {})
110
- widgets.resolve(Pageflow.config_for(entry), options)
111
- end
112
-
113
66
  private
114
67
 
115
68
  def custom_revision?
@@ -0,0 +1,46 @@
1
+ module Pageflow
2
+ # Override theme options and upload theme files for an entry type on
3
+ # a per account basis.
4
+ #
5
+ # @since 15.7
6
+ class ThemeCustomization < ApplicationRecord
7
+ belongs_to :account
8
+
9
+ serialize :overrides, JSON
10
+ serialize :selected_file_ids, JSON
11
+
12
+ has_many :uploaded_files, class_name: 'ThemeCustomizationFile'
13
+
14
+ # Options that were passed to [ThemeCustomizations#update].
15
+ #
16
+ # @return [Hash<Symbol, Object>]
17
+ def overrides
18
+ super&.deep_symbolize_keys || {}
19
+ end
20
+
21
+ # Theme customization files that have been assigned a role via
22
+ # [ThemeCustomizations#update].
23
+ #
24
+ # @return [Hash<Symbol, ThemeCustomizationFile>]
25
+ def selected_files
26
+ selected_file_ids.compact.transform_values do |id|
27
+ selected_files_by_id[id]
28
+ end
29
+ end
30
+
31
+ # @api private
32
+ def entry_type
33
+ Pageflow.config.entry_types.find_by_name!(entry_type_name)
34
+ end
35
+
36
+ private
37
+
38
+ def selected_file_ids
39
+ super&.deep_symbolize_keys || {}
40
+ end
41
+
42
+ def selected_files_by_id
43
+ @selected_files_by_id ||= uploaded_files.where(id: selected_file_ids.values).index_by(&:id)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,58 @@
1
+ module Pageflow
2
+ # A file that has been uploaded by the user to customize a theme,
3
+ # e.g., to use a custom logo.
4
+ #
5
+ # @since 15.7
6
+ class ThemeCustomizationFile < ApplicationRecord
7
+ belongs_to :theme_customization
8
+
9
+ has_attached_file(:attachment,
10
+ Pageflow
11
+ .config.paperclip_s3_default_options
12
+ .merge(styles: ->(attachment) { attachment.instance.attachment_styles }))
13
+
14
+ # Paperclip requires a content type validator for security
15
+ # reasons. Sub-classes are fine, though. The original validator
16
+ # does not provide a way to dynamically determine the permitted
17
+ # content types.
18
+ #
19
+ # @api private
20
+ class AttachmentContentTypeValidator < Paperclip::Validators::AttachmentContentTypeValidator
21
+ def validate_whitelist(record, attribute, value)
22
+ return if value =~ record.options_from_entry_type[:content_type]
23
+ record.errors.add(attribute, :invalid)
24
+ end
25
+
26
+ # Override to not require :content_type option.
27
+ def check_validity!
28
+ true
29
+ end
30
+ end
31
+
32
+ validates_with AttachmentContentTypeValidator, attributes: :attachment
33
+
34
+ # The name of the originally uploaded file
35
+ def file_name
36
+ attachment_file_name
37
+ end
38
+
39
+ # A hash of urls based on the styles that were defined when
40
+ # registering the entry type.
41
+ def urls
42
+ attachment_styles.map { |style, _|
43
+ [style, attachment.url(style)]
44
+ }.to_h
45
+ end
46
+
47
+ # @api private
48
+ def options_from_entry_type
49
+ theme_customization.entry_type.theme_files.fetch(type_name.to_sym, {})
50
+ end
51
+
52
+ # @api private
53
+ def attachment_styles
54
+ styles = options_from_entry_type.fetch(:styles, {})
55
+ styles.respond_to?(:call) ? styles.call(self) : styles
56
+ end
57
+ end
58
+ end
@@ -114,7 +114,10 @@ module Pageflow
114
114
  def hls_playlist
115
115
  if Pageflow.config.zencoder_options[:hls_smil_suffix].present?
116
116
  ZencoderAttachment.new(self,
117
- 'hls-playlist.smil',
117
+ Pageflow.config.zencoder_options.fetch(
118
+ :hls_smil_file_name,
119
+ 'hls-playlist.smil'
120
+ ),
118
121
  host: :hls,
119
122
  url_suffix: Pageflow.config.zencoder_options[:hls_smil_suffix])
120
123
  else
@@ -153,5 +156,12 @@ module Pageflow
153
156
  :height,
154
157
  :output_presences)
155
158
  end
159
+
160
+ def post_process_encoded_files
161
+ self.thumbnail = URI.parse(zencoder_thumbnail.url(default_protocol: 'https'))
162
+ self.poster = URI.parse(zencoder_poster.url(default_protocol: 'https'))
163
+ rescue OpenURI::HTTPError
164
+ throw(:halt, :pending)
165
+ end
156
166
  end
157
167
  end
@@ -27,6 +27,7 @@ module Pageflow
27
27
  def example_file
28
28
  @example_file ||= VideoFile.new(id: 0).tap do |video_file|
29
29
  video_file.file_name = ':basename.mp4'
30
+ video_file.output_presences = {':pageflow_hls_qualities' => true}
30
31
  video_file.poster_file_name = video_file.zencoder_poster.original_filename
31
32
  end
32
33
  end
@@ -46,6 +46,10 @@ module Pageflow
46
46
  @entry
47
47
  end
48
48
 
49
+ def filter_by_type?
50
+ user.admin?
51
+ end
52
+
49
53
  def preview?
50
54
  query.has_at_least_role?(:previewer)
51
55
  end
@@ -22,9 +22,9 @@ module Pageflow
22
22
 
23
23
  event :retry_encoding do
24
24
  transition 'encoding_failed' => 'waiting_for_confirmation',
25
- if: -> { Pageflow.config.confirm_encoding_jobs }
25
+ if: ->(file) { Pageflow.config.confirm_encoding_jobs?(file) }
26
26
  transition 'encoded' => 'waiting_for_confirmation',
27
- if: -> { Pageflow.config.confirm_encoding_jobs }
27
+ if: ->(file) { Pageflow.config.confirm_encoding_jobs?(file) }
28
28
 
29
29
  transition 'encoding_failed' => 'waiting_for_encoding'
30
30
  transition 'encoded' => 'waiting_for_encoding'
@@ -39,7 +39,14 @@ module Pageflow
39
39
  job PollMetaDataFromZencoderJob do
40
40
  on_enter 'fetching_meta_data'
41
41
  result :pending, retry_after: 2.seconds
42
- result ok: 'waiting_for_confirmation'
42
+
43
+ result(
44
+ :ok,
45
+ state: 'waiting_for_confirmation',
46
+ if: ->(file) { Pageflow.config.confirm_encoding_jobs?(file) }
47
+ )
48
+ result ok: 'waiting_for_encoding'
49
+
43
50
  result error: 'fetching_meta_data_failed'
44
51
  end
45
52
 
@@ -51,6 +58,10 @@ module Pageflow
51
58
  Pageflow.config.hooks.invoke(:file_encoding_confirmed, file: file)
52
59
  end
53
60
 
61
+ after_transition any => 'waiting_for_encoding' do |file|
62
+ Pageflow.config.hooks.invoke(:file_encoding, file: file)
63
+ end
64
+
54
65
  job SubmitFileToZencoderJob do
55
66
  on_enter 'waiting_for_encoding'
56
67
  result ok: 'encoding'
@@ -76,7 +87,15 @@ module Pageflow
76
87
 
77
88
  # UploadableFile-overrides
78
89
  def retryable?
79
- can_retry_encoding? && !encoded?
90
+ # Calling `can_retry_encoding?` invokes
91
+ # `Pageflow.config.confirm_encoding_jobs` which might depend on
92
+ # accessing `file.entry.account`. If the file has been reused in
93
+ # a different entry and the original entry has been deleted, we
94
+ # default to making the file not retryable to prevent
95
+ # exceptions.
96
+ entry &&
97
+ can_retry_encoding? &&
98
+ !encoded?
80
99
  end
81
100
 
82
101
  def ready?