Skip to content

Commit

Permalink
Merge pull request #2115 from tf/cutoff
Browse files Browse the repository at this point in the history
Cutoff modes
  • Loading branch information
tf authored Jun 20, 2024
2 parents c2a7d3d + 18aa818 commit 853c3e0
Show file tree
Hide file tree
Showing 33 changed files with 843 additions and 69 deletions.
1 change: 1 addition & 0 deletions admins/pageflow/accounts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ module Pageflow
end

controller do
helper Pageflow::Admin::CutoffModesHelper
helper Pageflow::Admin::FeaturesHelper
helper Pageflow::Admin::FormHelper
helper Pageflow::Admin::LocalesHelper
Expand Down
4 changes: 3 additions & 1 deletion admins/pageflow/sites.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ module Pageflow
:copyright_link_url,
:copyright_link_label,
:privacy_link_url,
:home_url
:home_url,
:cutoff_mode_name
] + permitted_admin_form_input_params
end

controller do
helper Pageflow::Admin::CutoffModesHelper
helper Pageflow::Admin::FormHelper

before_create do |site|
Expand Down
12 changes: 12 additions & 0 deletions app/helpers/pageflow/admin/cutoff_modes_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Pageflow
module Admin
# @api private
module CutoffModesHelper
def cutoff_modes_collection(config)
config.cutoff_modes.names.map do |name|
[t(name, scope: 'pageflow.cutoff_modes'), name]
end
end
end
end
end
4 changes: 4 additions & 0 deletions app/models/pageflow/draft_entry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ def translations(scope = -> { self }, **)
)
end

def cutoff_mode_enabled_for?(_request)
false
end

def create_file!(file_type, attributes)
check_foreign_key_custom_attributes(file_type.custom_attributes, attributes)

Expand Down
4 changes: 4 additions & 0 deletions app/models/pageflow/published_entry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ def translations(scope = -> { self }, include_noindex: false)
end
end

def cutoff_mode_enabled_for?(request)
Pageflow.config.cutoff_modes.enabled_for?(self, request)
end

def stylesheet_model
custom_revision? ? revision : entry
end
Expand Down
9 changes: 8 additions & 1 deletion app/models/pageflow/site.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ class Site < ApplicationRecord
scope :with_home_url, -> { where.not(home_url: '') }
scope :for_request, ->(request) { Pageflow.config.site_request_scope.call(all, request) }

validates :account, :presence => true
validates :account, presence: true
validates_inclusion_of :cutoff_mode_name, in: :available_cutoff_mode_names, allow_blank: true

delegate :enabled_feature_names, to: :account

Expand Down Expand Up @@ -67,5 +68,11 @@ def self.ransackable_attributes(_auth_object = nil)
def self.ransackable_associations(_auth_object = nil)
%w[account]
end

private

def available_cutoff_mode_names
Pageflow.config_for(account).cutoff_modes.names
end
end
end
6 changes: 6 additions & 0 deletions app/views/admin/sites/_fields.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
<%= f.input :copyright_link_url %>
<%= f.input :privacy_link_url %>

<% if cutoff_modes_collection(account_config).present? %>
<%= f.input(:cutoff_mode_name,
collection: cutoff_modes_collection(account_config),
include_blank: t('pageflow.cutoff_modes.none')) %>
<% end %>

<%= f.input :feeds_enabled, hint: t('pageflow.admin.sites.feeds_hint',
site_host: @site&.persisted? ? @site.host : '<host>') %>
<%= f.input :sitemap_enabled, hint: t('pageflow.admin.sites.sitemap_hint',
Expand Down
1 change: 1 addition & 0 deletions app/views/pageflow/editor/sites/_site.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
json.(site, :cutoff_mode_name)
json.pretty_url pretty_site_url(site)
14 changes: 14 additions & 0 deletions config/locales/new/cutoff_modes.de.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
de:
pageflow:
cutoff_modes:
none: "(Kein)"
pageflow_scrolled:
editor:
section_item:
set_cutoff: "Paywall Grenze oberhalb setzen"
reset_cutoff: "Paywall Grenze entfernen"
cutoff: "Paywall Grenze"
activerecord:
attributes:
pageflow/site:
cutoff_mode_name: "Cutoff-Modus"
14 changes: 14 additions & 0 deletions config/locales/new/cutoff_modes.en.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
en:
pageflow:
cutoff_modes:
none: "(None)"
pageflow_scrolled:
editor:
section_item:
set_cutoff: "Set paywall cutoff above"
reset_cutoff: "Remove paywall cutoff"
cutoff: "Paywall cutoff"
activerecord:
attributes:
pageflow/site:
cutoff_mode_name: "Cutoff mode"
5 changes: 5 additions & 0 deletions db/migrate/20240612110434_add_cutoff_mode_name_to_sites.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddCutoffModeNameToSites < ActiveRecord::Migration[5.2]
def change
add_column :pageflow_sites, :cutoff_mode_name, :string
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,27 @@ def scrolled_entry_json_seed_script_tag(scrolled_entry, options = {})
end

def scrolled_entry_json_seed(json, scrolled_entry, options = {})
main_storyline = Storyline.all_for_revision(scrolled_entry.revision).first
main_storyline ||= Storyline.new
main_storyline = Storyline.all_for_revision(scrolled_entry.revision).first || Storyline.new
sections = scrolled_entry_json_seed_sections(scrolled_entry, main_storyline)

json.partial!('pageflow_scrolled/entry_json_seed/entry',
chapters: main_storyline.chapters,
entry: scrolled_entry,
entry_config: Pageflow.config_for(scrolled_entry),
sections: main_storyline.sections,
content_elements: main_storyline.content_elements,
chapters: main_storyline.chapters,
sections:,
content_elements: main_storyline.content_elements.where(section: sections),
widgets: scrolled_entry.resolve_widgets(insert_point: :react),
options:)
end

private

def scrolled_entry_json_seed_sections(scrolled_entry, main_storyline)
if scrolled_entry.cutoff_mode_enabled_for?(request)
main_storyline.sections_before_cutoff_section
else
main_storyline.sections
end
end
end
end
14 changes: 14 additions & 0 deletions entry_types/scrolled/app/models/pageflow_scrolled/storyline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,19 @@ class Storyline < Pageflow::ApplicationRecord
through: :sections

nested_revision_components :chapters

def sections_before_cutoff_section
sections_before(cutoff_section)
end

private

def sections_before(section)
section ? sections[0...sections.index(section)] : sections
end

def cutoff_section
sections.find_by_perma_id(revision.configuration['cutoff_section_perma_id'])
end
end
end
22 changes: 22 additions & 0 deletions entry_types/scrolled/package/spec/editor/models/Cutoff-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {useEditorGlobals, useFakeXhr} from 'support';
import '@testing-library/jest-dom/extend-expect';

describe('Cutoff', () => {
useFakeXhr();

const {createEntry} = useEditorGlobals();

it('resets metadata configuration when deleting the cutoff section', () => {
const entry = createEntry({
metadata: {configuration: {cutoff_section_perma_id: 100}},
sections: [
{id: 1, permaId: 100},
{id: 2, permaId: 101},
]
});

entry.sections.get(1).destroy();

expect(entry.metadata.configuration.get('cutoff_section_perma_id')).toBeUndefined();
});
});
159 changes: 159 additions & 0 deletions entry_types/scrolled/package/spec/editor/views/SectionItemView-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import {SectionItemView} from 'editor/views/SectionItemView';

import {useEditorGlobals, useFakeXhr, useReactBasedBackboneViews} from 'support';
import userEvent from '@testing-library/user-event';
import {useFakeTranslations} from 'pageflow/testHelpers';
import '@testing-library/jest-dom/extend-expect';

describe('SectionItemView', () => {
useFakeXhr();

useFakeTranslations({
'pageflow_scrolled.editor.section_item.set_cutoff': 'Set cutoff point',
'pageflow_scrolled.editor.section_item.reset_cutoff': 'Remove cutoff point',
'pageflow_scrolled.editor.section_item.cutoff': 'Cutoff point',
});

const {createEntry} = useEditorGlobals();
const {render} = useReactBasedBackboneViews();

it('does not offer menu item to set cutoff section by default', () => {
const entry = createEntry({
sections: [
{id: 1, permaId: 100}
]
});
const view = new SectionItemView({
entry,
model: entry.sections.get(1)
});

const {queryByRole} = render(view);

expect(queryByRole('link', {name: 'Set cutoff point'})).toBeNull();
});

it('offers menu item to set cutoff section if site has cutoff mode', async () => {
const entry = createEntry({
site: {
cutoff_mode_name: 'subscription_headers'
},
sections: [
{id: 1, permaId: 100}
]
});
const view = new SectionItemView({
entry,
model: entry.sections.get(1)
});

const user = userEvent.setup();
const {getByRole} = render(view);
await user.click(getByRole('link', {name: 'Set cutoff point'}));

expect(entry.metadata.configuration.get('cutoff_section_perma_id')).toEqual(100);
});

it('offers menu item to reset cutoff section if site has cutoff mode', async () => {
const entry = createEntry({
site: {
cutoff_mode_name: 'subscription_headers'
},
metadata: {configuration: {cutoff_section_perma_id: 101}},
sections: [
{id: 1, permaId: 100},
{id: 2, permaId: 101}
]
});
const view = new SectionItemView({
entry,
model: entry.sections.get(2)
});

const user = userEvent.setup();
const {getByRole} = render(view);
await user.click(getByRole('link', {name: 'Remove cutoff point'}));

expect(entry.metadata.configuration.get('cutoff_section_perma_id')).toBeUndefined();
});

it('updates menu item when cutoff section changes', () => {
const entry = createEntry({
site: {
cutoff_mode_name: 'subscription_headers'
},
sections: [
{id: 1, permaId: 100},
{id: 2, permaId: 101}
]
});
const view = new SectionItemView({
entry,
model: entry.sections.get(2)
});

const {queryByRole} = render(view);
entry.metadata.configuration.set('cutoff_section_perma_id', 101)

expect(queryByRole('link', {name: 'Remove cutoff point'})).not.toBeNull();
});

it('renders cutoff indicator', () => {
const entry = createEntry({
site: {
cutoff_mode_name: 'subscription_headers'
},
sections: [
{id: 1, permaId: 100},
{id: 2, permaId: 101}
]
});
const view = new SectionItemView({
entry,
model: entry.sections.get(2)
});

const {queryByText} = render(view);
entry.metadata.configuration.set('cutoff_section_perma_id', 101)

expect(queryByText('Cutoff point')).toBeVisible();
});

it('does not render cutoff indicator if cutoff section not set', () => {
const entry = createEntry({
site: {
cutoff_mode_name: 'subscription_headers'
},
sections: [
{id: 1, permaId: 100},
{id: 2, permaId: 101}
]
});
const view = new SectionItemView({
entry,
model: entry.sections.get(2)
});

const {queryByText} = render(view);

expect(queryByText('Cutoff point')).not.toBeVisible();
});

it('does not render cutoff indicator if site does not have cutoff mode', () => {
const entry = createEntry({
metadata: {configuration: {cutoff_section_perma_id: 101}},
sections: [
{id: 1, permaId: 100},
{id: 2, permaId: 101}
]
});
const view = new SectionItemView({
entry,
model: entry.sections.get(2)
});

const {queryByText} = render(view);

expect(queryByText('Cutoff point')).not.toBeVisible();
});
});
7 changes: 5 additions & 2 deletions entry_types/scrolled/package/spec/support/useEditorGlobals.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {editor, FilesCollection} from 'pageflow/editor';
import {editor, FilesCollection, Site} from 'pageflow/editor';
import {ScrolledEntry} from 'editor/models/ScrolledEntry';

import {setupGlobals} from 'pageflow/testHelpers';
Expand All @@ -23,12 +23,15 @@ export function useEditorGlobals() {
return {
createEntry(options) {
const {
metadata,
imageFiles, videoFiles, audioFiles, textTrackFiles,
site,
...seedOptions
} = options;

const {entry} = setGlobals({
entry: factories.entry(ScrolledEntry, {}, {
entry: factories.entry(ScrolledEntry, {metadata}, {
site: new Site(site),
files: FilesCollection.createForFileTypes(
[
editor.fileTypes.findByCollectionName('image_files'),
Expand Down
Loading

0 comments on commit 853c3e0

Please sign in to comment.