Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cutoff modes #2115

Merged
merged 4 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading