pageflow 12.0.4 → 12.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of pageflow might be problematic. Click here for more details.

Files changed (217) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +158 -374
  3. data/README.md +24 -3
  4. data/Rakefile +2 -2
  5. data/admins/pageflow/accounts.rb +30 -4
  6. data/admins/pageflow/entry.rb +59 -9
  7. data/admins/pageflow/membership.rb +57 -6
  8. data/admins/pageflow/user.rb +25 -4
  9. data/app/assets/images/pageflow/themes/default/preview.png +0 -0
  10. data/app/assets/images/pageflow/themes/default/preview_thumbnail.png +0 -0
  11. data/app/assets/javascripts/pageflow/admin/entries.js +5 -3
  12. data/app/assets/javascripts/pageflow/admin/users.js +33 -0
  13. data/app/assets/javascripts/pageflow/admin.js +4 -1
  14. data/app/assets/javascripts/pageflow/audio_context.js +28 -0
  15. data/app/assets/javascripts/pageflow/audio_player/get_media_element_method.js +5 -0
  16. data/app/assets/javascripts/pageflow/audio_player.js +2 -0
  17. data/app/assets/javascripts/pageflow/base.js +4 -22
  18. data/app/assets/javascripts/pageflow/dist/react.js +323 -242
  19. data/app/assets/javascripts/pageflow/editor/api/widget_type.js +23 -0
  20. data/app/assets/javascripts/pageflow/editor/api/widget_types.js +53 -0
  21. data/app/assets/javascripts/pageflow/editor/api.js +9 -1
  22. data/app/assets/javascripts/pageflow/editor/base.js +0 -1
  23. data/app/assets/javascripts/pageflow/editor/collections/pages_collection.js +1 -0
  24. data/app/assets/javascripts/pageflow/editor/collections/subset_collection.js +21 -1
  25. data/app/assets/javascripts/pageflow/editor/collections/themes_collection.js +13 -0
  26. data/app/assets/javascripts/pageflow/editor/collections/widgets_collection.js +23 -8
  27. data/app/assets/javascripts/pageflow/editor/controllers/sidebar_controller.js +7 -1
  28. data/app/assets/javascripts/pageflow/editor/initializers/setup_collections.js +10 -3
  29. data/app/assets/javascripts/pageflow/editor/initializers/setup_widget_types.js +5 -1
  30. data/app/assets/javascripts/pageflow/editor/initializers/stylesheet_reloading.js +8 -3
  31. data/app/assets/javascripts/pageflow/editor/models/edit_lock_container.js +1 -1
  32. data/app/assets/javascripts/pageflow/editor/models/entry.js +7 -4
  33. data/app/assets/javascripts/pageflow/editor/models/entry_configuration.js +1 -1
  34. data/app/assets/javascripts/pageflow/editor/models/file_stage.js +1 -0
  35. data/app/assets/javascripts/pageflow/editor/models/page.js +3 -1
  36. data/app/assets/javascripts/pageflow/editor/models/preview_entry_data.js +2 -2
  37. data/app/assets/javascripts/pageflow/editor/models/theme.js +25 -0
  38. data/app/assets/javascripts/pageflow/editor/models/theming.js +1 -19
  39. data/app/assets/javascripts/pageflow/editor/models/widget.js +22 -1
  40. data/app/assets/javascripts/pageflow/editor/models/widget_configuration.js +5 -0
  41. data/app/assets/javascripts/pageflow/editor/routers/sidebar_router.js +1 -0
  42. data/app/assets/javascripts/pageflow/editor/templates/change_theme_dialog.jst.ejs +23 -0
  43. data/app/assets/javascripts/pageflow/editor/templates/edit_widget.jst.ejs +1 -2
  44. data/app/assets/javascripts/pageflow/editor/templates/inputs/reference.jst.ejs +2 -2
  45. data/app/assets/javascripts/pageflow/editor/templates/static_thumbnail.jst.ejs +1 -0
  46. data/app/assets/javascripts/pageflow/editor/templates/theme_item.jst.ejs +5 -0
  47. data/app/assets/javascripts/pageflow/editor/templates/widget_item.jst.ejs +3 -0
  48. data/app/assets/javascripts/pageflow/editor/utils/stylesheet.js +23 -0
  49. data/app/assets/javascripts/pageflow/editor/views/change_theme_dialog_view.js +76 -0
  50. data/app/assets/javascripts/pageflow/editor/views/configuration_editors/groups/options.js +4 -2
  51. data/app/assets/javascripts/pageflow/editor/views/edit_meta_data_view.js +17 -4
  52. data/app/assets/javascripts/pageflow/editor/views/edit_widget_view.js +11 -21
  53. data/app/assets/javascripts/pageflow/editor/views/edit_widgets_view.js +1 -3
  54. data/app/assets/javascripts/pageflow/editor/views/file_meta_data_item_value_view.js +10 -1
  55. data/app/assets/javascripts/pageflow/editor/views/inputs/reference_input_view.js +36 -4
  56. data/app/assets/javascripts/pageflow/editor/views/inputs/theme_input_view.js +26 -0
  57. data/app/assets/javascripts/pageflow/editor/views/model_thumbnail_view.js +28 -14
  58. data/app/assets/javascripts/pageflow/editor/views/static_thumbnail_view.js +20 -0
  59. data/app/assets/javascripts/pageflow/editor/views/theme_item_view.js +41 -0
  60. data/app/assets/javascripts/pageflow/editor/views/widget_item_view.js +49 -0
  61. data/app/assets/javascripts/pageflow/history.js +7 -1
  62. data/app/assets/javascripts/pageflow/media_player/volume_fading/interval.js +65 -0
  63. data/app/assets/javascripts/pageflow/media_player/volume_fading/noop.js +5 -0
  64. data/app/assets/javascripts/pageflow/media_player/volume_fading/web_audio.js +109 -0
  65. data/app/assets/javascripts/pageflow/media_player/volume_fading.js +14 -65
  66. data/app/assets/javascripts/pageflow/slideshow/dom_order_scroll_navigator.js +5 -2
  67. data/app/assets/javascripts/pageflow/slideshow.js +19 -8
  68. data/app/assets/javascripts/pageflow/ui/views/configuration_editor_view.js +4 -0
  69. data/app/assets/javascripts/pageflow/ui/views/inputs/text_area_input_view.js +10 -5
  70. data/app/assets/javascripts/pageflow/ui/views/inputs/text_input_view.js +4 -48
  71. data/app/assets/javascripts/pageflow/ui/views/mixins/input_with_placeholder_text.js +58 -0
  72. data/app/assets/javascripts/pageflow/vendor.js +16 -0
  73. data/app/assets/javascripts/pageflow/video_player/get_media_element_method.js +6 -0
  74. data/app/assets/javascripts/pageflow/video_player.js +2 -0
  75. data/app/assets/stylesheets/pageflow/admin/entries.scss +1 -1
  76. data/app/assets/stylesheets/pageflow/admin/quotas.scss +1 -1
  77. data/app/assets/stylesheets/pageflow/admin.scss +2 -0
  78. data/app/assets/stylesheets/pageflow/base.scss +0 -1
  79. data/app/assets/stylesheets/pageflow/editor/base.scss +2 -0
  80. data/app/assets/stylesheets/pageflow/editor/change_theme.scss +114 -0
  81. data/app/assets/stylesheets/pageflow/editor/static_thumbnails.scss +4 -0
  82. data/app/assets/stylesheets/pageflow/editor/widgets.scss +26 -2
  83. data/app/assets/stylesheets/pageflow/page.scss +1 -14
  84. data/app/assets/stylesheets/pageflow/themes/default/indicators.scss +12 -0
  85. data/app/assets/stylesheets/pageflow/themes/default/loading_spinner.scss +11 -0
  86. data/app/assets/stylesheets/pageflow/themes/default/logo/alignment.scss +27 -0
  87. data/app/assets/stylesheets/pageflow/themes/default/logo/variant/background_image.scss +20 -2
  88. data/app/assets/stylesheets/pageflow/themes/default/logo/variant/watermark.scss +4 -1
  89. data/app/assets/stylesheets/pageflow/themes/default/page/line_lengths.scss +113 -0
  90. data/app/assets/stylesheets/pageflow/themes/default/page.scss +1 -0
  91. data/app/controllers/pageflow/editor/widgets_controller.rb +15 -1
  92. data/app/controllers/pageflow/entries_controller.rb +1 -1
  93. data/app/helpers/pageflow/admin/entries_helper.rb +0 -9
  94. data/app/helpers/pageflow/admin/memberships_helper.rb +43 -123
  95. data/app/helpers/pageflow/admin/users_helper.rb +15 -0
  96. data/app/helpers/pageflow/entries_helper.rb +3 -1
  97. data/app/helpers/pageflow/entry_json_seed_helper.rb +9 -3
  98. data/app/helpers/pageflow/public_i18n_helper.rb +2 -2
  99. data/app/helpers/pageflow/quota_helper.rb +2 -2
  100. data/app/helpers/pageflow/social_share_helper.rb +3 -2
  101. data/app/helpers/pageflow/themes_helper.rb +11 -3
  102. data/app/helpers/pageflow/widgets_helper.rb +10 -2
  103. data/app/jobs/pageflow/prune_auto_snapshots_job.rb +9 -0
  104. data/app/mailers/pageflow/user_mailer.rb +11 -1
  105. data/app/models/concerns/pageflow/feature_target.rb +1 -1
  106. data/app/models/concerns/pageflow/hosted_file.rb +9 -0
  107. data/app/models/concerns/pageflow/output_source.rb +2 -1
  108. data/app/models/concerns/pageflow/serialization_blacklist.rb +19 -0
  109. data/app/models/concerns/pageflow/serialized_configuration.rb +17 -0
  110. data/app/models/concerns/pageflow/theme_referencer.rb +23 -0
  111. data/app/models/pageflow/account.rb +6 -1
  112. data/app/models/pageflow/account_member_query.rb +6 -12
  113. data/app/models/pageflow/account_role_query.rb +68 -0
  114. data/app/models/pageflow/application_query.rb +13 -0
  115. data/app/models/pageflow/application_record.rb +5 -0
  116. data/app/models/pageflow/audio_file.rb +1 -1
  117. data/app/models/pageflow/auto_snapshot_pruning.rb +26 -0
  118. data/app/models/pageflow/chapter.rb +4 -8
  119. data/app/models/pageflow/draft_entry.rb +2 -1
  120. data/app/models/pageflow/edit_lock.rb +11 -5
  121. data/app/models/pageflow/encoding_confirmation.rb +2 -1
  122. data/app/models/pageflow/entry.rb +13 -2
  123. data/app/models/pageflow/entry_publication.rb +2 -0
  124. data/app/models/pageflow/entry_role_query.rb +24 -9
  125. data/app/models/pageflow/entry_title_or_account_name_query.rb +33 -0
  126. data/app/models/pageflow/file_usage.rb +3 -7
  127. data/app/models/pageflow/folder.rb +1 -1
  128. data/app/models/pageflow/home_button.rb +1 -1
  129. data/app/models/pageflow/image_file.rb +22 -4
  130. data/app/models/pageflow/invitation_form.rb +10 -4
  131. data/app/models/pageflow/managed_user_query.rb +44 -0
  132. data/app/models/pageflow/membership.rb +1 -1
  133. data/app/models/pageflow/overview_button.rb +3 -4
  134. data/app/models/pageflow/page.rb +3 -7
  135. data/app/models/pageflow/potential_memberships.rb +112 -0
  136. data/app/models/pageflow/published_entry.rb +2 -1
  137. data/app/models/pageflow/revision.rb +13 -4
  138. data/app/models/pageflow/storyline.rb +3 -4
  139. data/app/models/pageflow/text_track_file.rb +1 -1
  140. data/app/models/pageflow/theming.rb +15 -10
  141. data/app/models/pageflow/url_template.rb +8 -2
  142. data/app/models/pageflow/user_name_query.rb +30 -0
  143. data/app/models/pageflow/video_file.rb +5 -1
  144. data/app/models/pageflow/widget.rb +3 -1
  145. data/app/models/pageflow/zencoder_attachment.rb +16 -5
  146. data/app/policies/pageflow/account_policy.rb +31 -61
  147. data/app/policies/pageflow/application_policy.rb +6 -0
  148. data/app/policies/pageflow/entry_policy.rb +11 -3
  149. data/app/policies/pageflow/membership_policy.rb +1 -2
  150. data/app/policies/pageflow/user_policy.rb +20 -1
  151. data/app/views/admin/accounts/_form.html.erb +4 -4
  152. data/app/views/admin/accounts/_theming_defaults_inline_help.html.erb +5 -0
  153. data/app/views/admin/memberships/_form.html.erb +9 -14
  154. data/app/views/admin/memberships/_role_hint.html.arb +1 -1
  155. data/app/views/admin/users/invitation.html.erb +18 -9
  156. data/app/views/admin/users/me.html.erb +2 -2
  157. data/app/views/admin/users/quota_state.html.erb +1 -0
  158. data/app/views/components/pageflow/admin/add_membership_button.rb +81 -0
  159. data/app/views/components/pageflow/admin/members_tab.rb +6 -4
  160. data/app/views/components/pageflow/admin/revisions_tab.rb +16 -4
  161. data/app/views/components/pageflow/admin/user_accounts_tab.rb +8 -2
  162. data/app/views/components/pageflow/admin/user_entries_tab.rb +6 -2
  163. data/app/views/components/pageflow/admin/users_tab.rb +9 -5
  164. data/app/views/layouts/pageflow/application.html.erb +2 -1
  165. data/app/views/pageflow/admin/users/_quota_exhausted.html.erb +1 -0
  166. data/app/views/pageflow/admin/users/_quota_state.html.erb +7 -0
  167. data/app/views/pageflow/config/_editor_seeds.json.jbuilder +2 -0
  168. data/app/views/pageflow/editor/entries/_entry.json.jbuilder +1 -0
  169. data/app/views/pageflow/editor/entries/seed.json.erb +3 -1
  170. data/app/views/pageflow/editor/image_files/_image_file.json.jbuilder +1 -1
  171. data/app/views/pageflow/editor/themings/_theming.json.jbuilder +0 -7
  172. data/app/views/pageflow/editor/widgets/_widget.json.jbuilder +1 -1
  173. data/app/views/pageflow/entries/_entry.html.erb +5 -5
  174. data/app/views/pageflow/entries/edit.html.erb +1 -1
  175. data/app/views/pageflow/entries/show.html.erb +1 -1
  176. data/app/views/pageflow/entry_json_seed/_entry.json.jbuilder +1 -0
  177. data/app/views/pageflow/themes/_theme.json.jbuilder +13 -0
  178. data/config/initializers/admin_resource_tabs.rb +19 -6
  179. data/config/initializers/features.rb +1 -0
  180. data/config/locales/de.yml +26 -3
  181. data/config/locales/en.yml +26 -3
  182. data/db/migrate/20170201074328_add_configuration_to_widgets.rb +5 -0
  183. data/db/migrate/20170222124848_update_video_file_output_presences.rb +1 -1
  184. data/db/migrate/20170315130000_add_theme_name_to_revisions.rb +12 -0
  185. data/db/migrate/20170912165050_reset_copied_snapshot_type.rb +24 -0
  186. data/lib/generators/pageflow/routes/routes_generator.rb +11 -1
  187. data/lib/generators/pageflow/seeds/seeds_generator.rb +5 -0
  188. data/lib/generators/pageflow/seeds/templates/seeds.rb +5 -3
  189. data/lib/generators/pageflow/theme/templates/preview.png +0 -0
  190. data/lib/generators/pageflow/theme/templates/preview_thumbnail.png +0 -0
  191. data/lib/generators/pageflow/theme/theme_generator.rb +3 -0
  192. data/lib/pageflow/ability_mixin.rb +27 -6
  193. data/lib/pageflow/active_admin_can_can_fix.rb +34 -0
  194. data/lib/pageflow/configuration/permissions.rb +27 -0
  195. data/lib/pageflow/configuration.rb +28 -0
  196. data/lib/pageflow/engine.rb +25 -19
  197. data/lib/pageflow/images/palette.png +0 -0
  198. data/lib/pageflow/seeds.rb +1 -1
  199. data/lib/pageflow/theme.rb +8 -0
  200. data/lib/pageflow/version.rb +1 -1
  201. data/lib/pageflow/widget_type.rb +13 -0
  202. data/lib/pageflow/zencoder_video_output_definition.rb +16 -16
  203. data/lib/tasks/pageflow_tasks.rake +14 -0
  204. data/spec/factories/entries.rb +4 -0
  205. data/spec/factories/revisions.rb +10 -0
  206. data/spec/factories/users.rb +6 -0
  207. data/spec/factories/video_files.rb +4 -0
  208. data/vendor/assets/javascripts/audio5.min.js +3 -0
  209. metadata +78 -15
  210. data/app/assets/javascripts/pageflow/editor/models/mixins/widget_subject.js +0 -37
  211. data/app/assets/javascripts/pageflow/editor/utils/reload_stylesheet.js +0 -9
  212. data/app/assets/stylesheets/pageflow/text_variants.scss +0 -24
  213. data/app/views/admin/accounts/_widgets_inline_help.html.erb +0 -5
  214. data/app/views/admin/memberships/_entity_account_input.html.erb +0 -5
  215. data/app/views/admin/memberships/_entity_entry_input.html.erb +0 -5
  216. data/app/views/admin/users/_quota_exhausted.html.erb +0 -1
  217. data/app/views/components/pageflow/admin/add_membership_button_if_needed.rb +0 -62
@@ -36,17 +36,23 @@ module Pageflow
36
36
  initial_account && initial_account.users.find_by_email(user.email)
37
37
  end
38
38
 
39
+ def initial_account
40
+ @initial_account ||=
41
+ if initial_account_id
42
+ available_accounts.find_by_id(initial_account_id)
43
+ else
44
+ available_accounts.first
45
+ end
46
+ end
47
+
39
48
  private
40
49
 
41
50
  def existing_user
42
51
  @existing_user ||=
52
+ Pageflow.config.allow_multiaccount_users &&
43
53
  User.find_by_email(user.email)
44
54
  end
45
55
 
46
- def initial_account
47
- @initial_account ||= available_accounts.find_by_id(initial_account_id)
48
- end
49
-
50
56
  def initial_account_id
51
57
  @attributes.fetch(:membership, {})[:entity_id]
52
58
  end
@@ -0,0 +1,44 @@
1
+ module Pageflow
2
+ # @api private
3
+ class ManagedUserQuery < ApplicationQuery
4
+ class Scope < Scope
5
+ def initialize(current_user, scope)
6
+ @current_user = current_user
7
+ @scope = scope
8
+ end
9
+
10
+ def resolve
11
+ if current_user.admin?
12
+ scope.all
13
+ else
14
+ scope
15
+ .distinct
16
+ .joins(account_memberships)
17
+ .joins(account_manager_memberships_of_current_user)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :current_user, :scope
24
+
25
+ def account_memberships
26
+ <<-SQL
27
+ INNER JOIN pageflow_memberships account_memberships ON
28
+ account_memberships.user_id = users.id AND
29
+ account_memberships.entity_type = "Pageflow::Account"
30
+ SQL
31
+ end
32
+
33
+ def account_manager_memberships_of_current_user
34
+ sanitize_sql(<<-SQL, user_id: current_user.id)
35
+ INNER JOIN pageflow_memberships account_manager_memberships ON
36
+ account_manager_memberships.entity_type = account_memberships.entity_type AND
37
+ account_manager_memberships.entity_id = account_memberships.entity_id AND
38
+ account_manager_memberships.user_id = :user_id AND
39
+ account_manager_memberships.role = "manager"
40
+ SQL
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,5 +1,5 @@
1
1
  module Pageflow
2
- class Membership < ActiveRecord::Base
2
+ class Membership < ApplicationRecord
3
3
  belongs_to :user
4
4
  belongs_to :entity, polymorphic: true
5
5
  belongs_to :entry,
@@ -1,15 +1,14 @@
1
1
  module Pageflow
2
2
  class OverviewButton
3
- attr_reader :revision, :theming
3
+ attr_reader :revision
4
4
 
5
- def initialize(revision, theming)
5
+ def initialize(revision)
6
6
  @revision = revision
7
- @theming = theming
8
7
  end
9
8
 
10
9
  def enabled?
11
10
  revision.overview_button_enabled? &&
12
- theming.theme.has_overview_button?
11
+ revision.theme.has_overview_button?
13
12
  end
14
13
 
15
14
  def enabled_value
@@ -1,13 +1,13 @@
1
1
  module Pageflow
2
- class Page < ActiveRecord::Base
2
+ class Page < ApplicationRecord
3
+ include SerializedConfiguration
4
+
3
5
  belongs_to :chapter, :touch => true
4
6
 
5
7
  attr_accessor :is_first
6
8
 
7
9
  validates_inclusion_of :template, :in => ->(_) { Pageflow.config.page_types.names }
8
10
 
9
- serialize :configuration, JSON
10
-
11
11
  scope :displayed_in_navigation, -> { where(:display_in_navigation => true) }
12
12
 
13
13
  before_save :ensure_perma_id
@@ -28,10 +28,6 @@ module Pageflow
28
28
  Pageflow.config.page_types.find_by_name!(template)
29
29
  end
30
30
 
31
- def configuration
32
- super || {}
33
- end
34
-
35
31
  def configuration=(value)
36
32
  self.display_in_navigation = value['display_in_navigation']
37
33
  super
@@ -0,0 +1,112 @@
1
+ module Pageflow
2
+ # @api private
3
+ class PotentialMemberships
4
+ def initialize(current_user)
5
+ @current_user = current_user
6
+ end
7
+
8
+ def self.creatable_by(user)
9
+ new(user)
10
+ end
11
+
12
+ def accounts_for_user(user)
13
+ exclude_accounts_with_membership(user, managed_accounts)
14
+ end
15
+
16
+ def entries_for_user(user)
17
+ exclude_entries_with_membership(user, entries_managed_by_current_user_in_accounts_of(user))
18
+ end
19
+
20
+ def users_for_account(account)
21
+ exclude_users_with_membership(account, users_of_managed_accounts)
22
+ end
23
+
24
+ def users_for_entry(entry)
25
+ return User.none unless manages_entry?(entry)
26
+ exclude_users_with_membership(entry, entry.account.users)
27
+ end
28
+
29
+ private
30
+
31
+ def managed_accounts
32
+ if @current_user.admin?
33
+ Account.all
34
+ else
35
+ AccountRoleQuery::Scope
36
+ .new(@current_user, Account)
37
+ .with_role_at_least(:manager)
38
+ end
39
+ end
40
+
41
+ def entries_managed_by_current_user_in_accounts_of(user)
42
+ EntryRoleQuery::Scope
43
+ .new(user, entries_managed_by_current_user, table_alias_prefix: 'member')
44
+ .with_account_role_at_least(:member)
45
+ end
46
+
47
+ def entries_managed_by_current_user
48
+ if @current_user.admin?
49
+ Entry.all
50
+ else
51
+ EntryRoleQuery::Scope
52
+ .new(@current_user, Entry, table_alias_prefix: 'manager')
53
+ .with_role_at_least(:manager)
54
+ end
55
+ end
56
+
57
+ def users_of_managed_accounts
58
+ ManagedUserQuery::Scope
59
+ .new(@current_user, User)
60
+ .resolve
61
+ end
62
+
63
+ def manages_entry?(entry)
64
+ @current_user.admin? ||
65
+ EntryRoleQuery.new(@current_user, entry).has_at_least_role?(:manager)
66
+ end
67
+
68
+ def exclude_accounts_with_membership(user, accounts)
69
+ accounts
70
+ .joins(existing_memberships_of(user, Account))
71
+ .where(existing_membership_is_missing)
72
+ end
73
+
74
+ def exclude_entries_with_membership(user, entries)
75
+ entries
76
+ .joins(existing_memberships_of(user, Entry))
77
+ .where(existing_membership_is_missing)
78
+ end
79
+
80
+ def exclude_users_with_membership(entity, users)
81
+ users
82
+ .joins(existing_memberships_on(entity))
83
+ .where(existing_membership_is_missing)
84
+ end
85
+
86
+ def existing_memberships_of(user, entity_model)
87
+ sanitize_sql_array(['LEFT OUTER JOIN pageflow_memberships existing_memberships ON ' \
88
+ 'existing_memberships.user_id = :user_id AND ' \
89
+ "existing_memberships.entity_id = #{entity_model.table_name}.id AND " \
90
+ 'existing_memberships.entity_type = :entity_type',
91
+ user_id: user.id,
92
+ entity_type: entity_model.name])
93
+ end
94
+
95
+ def existing_memberships_on(entity)
96
+ sanitize_sql_array(['LEFT OUTER JOIN pageflow_memberships existing_memberships ON ' \
97
+ 'existing_memberships.user_id = users.id AND ' \
98
+ 'existing_memberships.entity_id = :entity_id AND ' \
99
+ 'existing_memberships.entity_type = :entity_type',
100
+ entity_id: entity.id,
101
+ entity_type: entity.class.name])
102
+ end
103
+
104
+ def existing_membership_is_missing
105
+ 'existing_memberships.id IS NULL'
106
+ end
107
+
108
+ def sanitize_sql_array(array)
109
+ ActiveRecord::Base.send(:sanitize_sql_array, array)
110
+ end
111
+ end
112
+ end
@@ -23,6 +23,7 @@ module Pageflow
23
23
  :share_url, :share_image_id, :share_image_x, :share_image_y,
24
24
  :locale,
25
25
  :author, :publisher, :keywords,
26
+ :theme,
26
27
  :password_protected?,
27
28
  :to => :revision)
28
29
 
@@ -68,7 +69,7 @@ module Pageflow
68
69
  end
69
70
 
70
71
  def overview_button
71
- OverviewButton.new(revision, theming)
72
+ OverviewButton.new(revision)
72
73
  end
73
74
 
74
75
  def resolve_widgets(options = {})
@@ -1,21 +1,24 @@
1
1
  module Pageflow
2
- class Revision < ActiveRecord::Base
2
+ class Revision < ApplicationRecord
3
3
  PAGE_ORDER = [
4
4
  'pageflow_storylines.position ASC',
5
5
  'pageflow_chapters.position ASC',
6
6
  'pageflow_pages.position ASC'
7
7
  ].join(',')
8
8
 
9
+ include ThemeReferencer
10
+
9
11
  belongs_to :entry, touch: :edited_at
10
12
  belongs_to :creator, :class_name => 'User'
11
13
  belongs_to :restored_from, :class_name => 'Pageflow::Revision'
12
14
 
13
- has_many :widgets, :as => :subject
14
- has_many :storylines, -> { order('pageflow_storylines.position ASC') }
15
+ has_many :widgets, as: :subject, dependent: :destroy
16
+
17
+ has_many :storylines, -> { order('pageflow_storylines.position ASC') }, dependent: :destroy
15
18
  has_many :chapters, -> { order('position ASC') }, through: :storylines
16
19
  has_many :pages, -> { reorder(PAGE_ORDER) }, through: :storylines
17
20
 
18
- has_many :file_usages
21
+ has_many :file_usages, dependent: :destroy
19
22
 
20
23
  has_many :image_files, -> { extending WithFileUsageExtension },
21
24
  :through => :file_usages, :source => :file, :source_type => 'Pageflow::ImageFile'
@@ -37,6 +40,8 @@ module Pageflow
37
40
 
38
41
  scope :publications, -> { where('published_at IS NOT NULL') }
39
42
  scope :publications_and_user_snapshots, -> { where('published_at IS NOT NULL OR snapshot_type = "user"') }
43
+ scope :user_snapshots, -> { where(snapshot_type: 'user') }
44
+ scope :auto_snapshots, -> { where(snapshot_type: 'auto') }
40
45
 
41
46
  validates :entry, :presence => true
42
47
  validates :creator, :presence => true, :if => :published?
@@ -148,5 +153,9 @@ module Pageflow
148
153
  def published_at_blank?
149
154
  published_at.blank?
150
155
  end
156
+
157
+ def available_themes
158
+ Pageflow.config_for(entry).themes
159
+ end
151
160
  end
152
161
  end
@@ -1,16 +1,15 @@
1
1
  module Pageflow
2
- class Storyline < ActiveRecord::Base
2
+ class Storyline < ApplicationRecord
3
+ include SerializedConfiguration
3
4
  include RevisionComponent
4
5
 
5
6
  belongs_to :revision, touch: true
6
7
 
7
- has_many :chapters, -> { order('pageflow_chapters.position ASC') }
8
+ has_many :chapters, -> { order('pageflow_chapters.position ASC') }, dependent: :destroy
8
9
  has_many :pages, through: :chapters
9
10
 
10
11
  delegate :entry, to: :revision
11
12
 
12
- serialize :configuration, JSON
13
-
14
13
  def copy_to(revision)
15
14
  storyline = dup
16
15
  revision.storylines << storyline
@@ -1,5 +1,5 @@
1
1
  module Pageflow
2
- class TextTrackFile < ActiveRecord::Base
2
+ class TextTrackFile < ApplicationRecord
3
3
  include HostedFile
4
4
 
5
5
  processing_state_machine do
@@ -1,7 +1,9 @@
1
1
  module Pageflow
2
- class Theming < ActiveRecord::Base
2
+ class Theming < ApplicationRecord
3
+ include ThemeReferencer
4
+
3
5
  belongs_to :account
4
- has_many :widgets, as: :subject
6
+ has_many :widgets, as: :subject, dependent: :destroy
5
7
 
6
8
  has_many :entries
7
9
 
@@ -9,7 +11,6 @@ module Pageflow
9
11
  scope :for_request, ->(request) { Pageflow.config.theming_request_scope.call(all, request) }
10
12
 
11
13
  validates :account, :presence => true
12
- validates_inclusion_of :theme_name, :in => ->(_) { Pageflow.config.themes.names }
13
14
 
14
15
  def resolve_widgets(options = {})
15
16
  widgets.resolve(Pageflow.config_for(account), options)
@@ -19,25 +20,29 @@ module Pageflow
19
20
  cname.split('.').pop(2).join('.')
20
21
  end
21
22
 
22
- def theme
23
- Pageflow.config.themes.get(theme_name)
24
- end
25
-
26
23
  def name
27
24
  I18n.t('pageflow.admin.themings.name', :account_name => account.name, :theme_name => theme_name)
28
25
  end
29
26
 
30
27
  def copy_defaults_to(revision)
31
28
  widgets.copy_all_to(revision)
32
- copy_default_meta_tags(revision)
29
+ copy_attributes_to(revision)
33
30
  end
34
31
 
35
- def copy_default_meta_tags(revision)
32
+ private
33
+
34
+ def copy_attributes_to(revision)
36
35
  revision.update(
37
36
  author: default_author.presence || Pageflow.config.default_author_meta_tag,
38
37
  publisher: default_publisher.presence || Pageflow.config.default_publisher_meta_tag,
39
- keywords: default_keywords.presence || Pageflow.config.default_keywords_meta_tag
38
+ keywords: default_keywords.presence || Pageflow.config.default_keywords_meta_tag,
39
+ theme_name: theme_name,
40
+ home_button_enabled: home_button_enabled_by_default
40
41
  )
41
42
  end
43
+
44
+ def available_themes
45
+ Pageflow.config_for(account).themes
46
+ end
42
47
  end
43
48
  end
@@ -1,13 +1,19 @@
1
1
  module Pageflow
2
2
  module UrlTemplate
3
- module_function
3
+ extend self
4
4
 
5
5
  def from_attachment(attachment, *style)
6
6
  insert_id_partition_placeholder(attachment.url(*style))
7
7
  end
8
8
 
9
+ private
10
+
9
11
  def insert_id_partition_placeholder(url)
10
- url.gsub(%r'(\d{3}/)+', ':id_partition/')
12
+ replace_last_group_of_digit_segments(url, with: '/:id_partition/')
13
+ end
14
+
15
+ def replace_last_group_of_digit_segments(str, with:)
16
+ str.reverse.sub(%r'/(\d{3}/)+', with.reverse).reverse
11
17
  end
12
18
  end
13
19
  end
@@ -0,0 +1,30 @@
1
+ module Pageflow
2
+ # @api private
3
+ class UserNameQuery < ApplicationQuery
4
+ class Scope < Scope
5
+ def initialize(term, scope)
6
+ @term = term
7
+ @scope = scope
8
+ end
9
+
10
+ def resolve
11
+ scope.where(word_conditions(term))
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :term, :scope
17
+
18
+ def word_conditions(term)
19
+ term.split(' ').map { |word|
20
+ word_condition(word)
21
+ }.join(' AND ')
22
+ end
23
+
24
+ def word_condition(word)
25
+ sanitize_sql('(users.first_name LIKE :word OR users.last_name LIKE :word)',
26
+ word: "%#{word}%")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  module Pageflow
2
- class VideoFile < ActiveRecord::Base
2
+ class VideoFile < ApplicationRecord
3
3
  include HostedFile
4
4
  include EncodedFileStateMachine
5
5
  include OutputSource
@@ -43,6 +43,10 @@ module Pageflow
43
43
  "s3://#{File.join(attachment_on_s3.bucket_name, attachment_on_s3.path)}"
44
44
  end
45
45
 
46
+ def encode_highdef?
47
+ entry.feature_state('highdef_video_encoding')
48
+ end
49
+
46
50
  def mp4_4k
47
51
  ZencoderAttachment.new(self, '4k.mp4')
48
52
  end
@@ -1,5 +1,7 @@
1
1
  module Pageflow
2
- class Widget < ActiveRecord::Base
2
+ class Widget < ApplicationRecord
3
+ include SerializedConfiguration
4
+
3
5
  belongs_to :subject, polymorphic: true, touch: true
4
6
 
5
7
  validates :subject, presence: true
@@ -1,12 +1,13 @@
1
+ require 'uri'
2
+
1
3
  module Pageflow
2
4
  class ZencoderAttachment
3
-
4
5
  cattr_accessor :default_options
5
6
  self.default_options = {
6
- path: "/:zencoder_asset_version/:host/:class/:id_partition/:filename",
7
- url: ":zencoder_protocol//:zencoder_host_alias:zencoder_path",
8
- hls_url: ":zencoder_protocol//:zencoder_hls_host_alias:zencoder_path",
9
- hls_origin_url: ":zencoder_protocol//:zencoder_hls_origin_host_alias:zencoder_path"
7
+ path: '/:zencoder_asset_version/:host/:class/:id_partition/:filename',
8
+ url: ':zencoder_protocol//:zencoder_host_alias:zencoder_path',
9
+ hls_url: ':zencoder_protocol//:zencoder_hls_host_alias:zencoder_path',
10
+ hls_origin_url: ':zencoder_protocol//:zencoder_hls_origin_host_alias:zencoder_path'
10
11
  }
11
12
 
12
13
  attr_reader :file_name_pattern, :instance, :options, :styles
@@ -44,6 +45,16 @@ module Pageflow
44
45
  url_options)
45
46
  end
46
47
 
48
+ def url_relative_to(attachment)
49
+ dir_path = File.dirname(URI.parse(attachment.url).path)
50
+
51
+ unless URI.parse(url).path.start_with?(dir_path)
52
+ raise("Could not generate relative url for #{url} based on #{attachment.url}.")
53
+ end
54
+
55
+ url.split("#{dir_path}/", 2).last
56
+ end
57
+
47
58
  private
48
59
 
49
60
  def ensure_default_protocol(url, url_options)
@@ -1,18 +1,19 @@
1
1
  module Pageflow
2
2
  class AccountPolicy < ApplicationPolicy
3
3
  class Scope < Scope
4
- attr_reader :user, :scope
4
+ attr_reader :user, :scope, :query
5
5
 
6
6
  def initialize(user, scope)
7
7
  @user = user
8
8
  @scope = scope
9
+ @query = AccountRoleQuery::Scope.new(user, scope)
9
10
  end
10
11
 
11
12
  def resolve
12
13
  if user.admin?
13
14
  scope.all
14
15
  else
15
- scope.joins(memberships_for_account(user)).where(membership_is_present)
16
+ query.with_role_at_least(:member)
16
17
  end
17
18
  end
18
19
 
@@ -20,7 +21,7 @@ module Pageflow
20
21
  if user.admin?
21
22
  scope.all
22
23
  else
23
- scope.joins(publisher_memberships_for_account(user)).where(membership_is_present)
24
+ query.with_role_at_least(:publisher)
24
25
  end
25
26
  end
26
27
 
@@ -40,53 +41,21 @@ module Pageflow
40
41
  if user.admin?
41
42
  scope.all
42
43
  else
43
- scope.joins(manager_memberships_for_account(user)).where(membership_is_present)
44
+ query.with_role_at_least(:manager)
44
45
  end
45
46
  end
46
-
47
- private
48
-
49
- def memberships_for_account(user)
50
- sanitize_sql_array(['LEFT OUTER JOIN pageflow_memberships ON ' \
51
- 'pageflow_memberships.user_id = :user_id AND ' \
52
- 'pageflow_memberships.entity_id = pageflow_accounts.id AND ' \
53
- 'pageflow_memberships.entity_type = "Pageflow::Account" AND ' \
54
- 'pageflow_memberships.role IN '\
55
- '("member", "previewer", "editor", "publisher", "manager")',
56
- user_id: user.id])
57
- end
58
-
59
- def publisher_memberships_for_account(user)
60
- sanitize_sql_array(['LEFT OUTER JOIN pageflow_memberships ON ' \
61
- 'pageflow_memberships.user_id = :user_id AND ' \
62
- 'pageflow_memberships.entity_id = pageflow_accounts.id AND ' \
63
- 'pageflow_memberships.entity_type = "Pageflow::Account" AND ' \
64
- 'pageflow_memberships.role IN ("publisher", "manager")',
65
- user_id: user.id])
66
- end
67
-
68
- def manager_memberships_for_account(user)
69
- sanitize_sql_array(['LEFT OUTER JOIN pageflow_memberships ON ' \
70
- 'pageflow_memberships.user_id = :user_id AND ' \
71
- 'pageflow_memberships.entity_id = pageflow_accounts.id AND ' \
72
- 'pageflow_memberships.entity_type = "Pageflow::Account" AND ' \
73
- 'pageflow_memberships.role IN ("manager")',
74
- user_id: user.id])
75
- end
76
-
77
- def membership_is_present
78
- 'pageflow_memberships.entity_id IS NOT NULL'
79
- end
80
47
  end
81
48
 
49
+ attr_reader :user, :query
50
+
82
51
  def initialize(user, account)
83
52
  @user = user
84
53
  @account = account
54
+ @query = AccountRoleQuery.new(user, account)
85
55
  end
86
56
 
87
57
  def publish?
88
- @user.admin? ||
89
- allows?(%w(publisher manager))
58
+ user.admin? || query.has_at_least_role?(:publisher)
90
59
  end
91
60
 
92
61
  def configure_folder_on?
@@ -97,49 +66,50 @@ module Pageflow
97
66
  publish?
98
67
  end
99
68
 
100
- def manage?
101
- @user.admin? ||
102
- allows?(%w(manager))
103
- end
104
-
105
69
  def read?
106
- manage?
70
+ user.admin? ||
71
+ (query.has_at_least_role?(:manager) &&
72
+ Pageflow.config.allow_multiaccount_users)
107
73
  end
108
74
 
109
75
  def update?
110
- manage?
76
+ read?
77
+ end
78
+
79
+ def update_feature_configuration_on?
80
+ user.admin? ||
81
+ (!permissions_config.only_admins_may_update_features &&
82
+ read?)
111
83
  end
112
84
 
113
85
  def add_member_to?
114
- manage?
86
+ Pageflow.config.allow_multiaccount_users &&
87
+ (user.admin? ||
88
+ query.has_at_least_role?(:manager))
115
89
  end
116
90
 
117
91
  def edit_role_on?
118
- manage?
92
+ user.admin? || query.has_at_least_role?(:manager)
119
93
  end
120
94
 
121
95
  def destroy_membership_on?
122
- manage?
96
+ add_member_to?
123
97
  end
124
98
 
125
99
  def admin?
126
- @user.admin?
100
+ user.admin?
127
101
  end
128
102
 
129
103
  def see_badge_belonging_to?
130
- (@account.entries & @user.entries).any? ||
131
- @user.memberships.on_accounts.as_previewer_or_above.where(entity: @account).any? ||
132
- @user.admin?
104
+ (@account.entries & user.entries).any? ||
105
+ query.has_at_least_role?(:previewer) ||
106
+ user.admin?
133
107
  end
134
108
 
135
109
  def index?
136
- admin? || @user.memberships.on_accounts.as_manager.any?
137
- end
138
-
139
- private
140
-
141
- def allows?(roles)
142
- @user.memberships.where(role: roles, entity: @account).any?
110
+ admin? ||
111
+ (Pageflow.config.allow_multiaccount_users &&
112
+ @user.memberships.on_accounts.as_manager.any?)
143
113
  end
144
114
  end
145
115
  end
@@ -7,5 +7,11 @@ module Pageflow
7
7
  ActiveRecord::Base.send(:sanitize_sql_array, array)
8
8
  end
9
9
  end
10
+
11
+ protected
12
+
13
+ def permissions_config
14
+ Pageflow.config.permissions
15
+ end
10
16
  end
11
17
  end