diff --git a/app/assets/images/lock.svg b/app/assets/images/lock.svg new file mode 100644 index 000000000..c614a38db --- /dev/null +++ b/app/assets/images/lock.svg @@ -0,0 +1,3 @@ + diff --git a/app/controllers/admin/pages_controller.rb b/app/controllers/admin/pages_controller.rb index 5a52ce503..19c54438e 100644 --- a/app/controllers/admin/pages_controller.rb +++ b/app/controllers/admin/pages_controller.rb @@ -3,13 +3,14 @@ module Admin layout "admin" def index - @pages = Page.all + @pages = Page.all.order(created_at: :desc) @code_of_conduct = Page.find_by(slug: "code-of-conduct") @privacy = Page.find_by(slug: "privacy") @terms = Page.find_by(slug: "terms") end def new + @landing_page = Page.find_by(landing_page: true) if (slug = params[:slug]) prepopulate_new_form(slug) else @@ -19,13 +20,12 @@ module Admin def edit @page = Page.find(params[:id]) + @landing_page = Page.find_by(landing_page: true) end def update @page = Page.find(params[:id]) - @page.assign_attributes(page_params) - if @page.valid? - @page.update!(page_params) + if update_and_overwrite_landing_page flash[:success] = "Page has been successfully updated." redirect_to admin_pages_path else @@ -36,8 +36,7 @@ module Admin def create @page = Page.new(page_params) - if @page.valid? - @page.save! + if create_and_overwrite_landing_page flash[:success] = "Page has been successfully created." redirect_to admin_pages_path else @@ -57,7 +56,7 @@ module Admin def page_params allowed_params = %i[title slug body_markdown body_html body_json description template is_top_level_path - social_image] + social_image landing_page overwrite_landing_page] params.require(:page).permit(allowed_params) end @@ -96,5 +95,31 @@ module Admin Page.new end end + + def update_and_overwrite_landing_page + if page_params["overwrite_landing_page"] == "true" + Page.transaction do + current_landing_page = Page.find_by(landing_page: true) + current_landing_page&.update(landing_page: false) + + @page.update(page_params) + end + else + @page.update(page_params) + end + end + + def create_and_overwrite_landing_page + if page_params["overwrite_landing_page"] == "true" + Page.transaction do + current_landing_page = Page.find_by(landing_page: true) + current_landing_page&.update(landing_page: false) + + @page.save + end + else + @page.save + end + end end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 65b96c532..770c55134 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -54,8 +54,12 @@ class ApplicationController < ActionController::Base return if self.class.module_parent.to_s == "Admin" return if user_signed_in? || Settings::UserExperience.public + @page = Page.landing_page + if api_action? authenticate! + elsif @page + render template: "pages/show" else @user ||= User.new render template: "devise/registrations/new" diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index 53c2dac86..6f46d6cf2 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -22,6 +22,12 @@ class PagesController < ApplicationController set_surrogate_key_header "about_listings_page" end + def badge + @html_variant = HtmlVariant.find_for_test([], "badge_landing_page") + render layout: false + set_surrogate_key_header "badge_page" + end + def bounty @page = Page.find_by(slug: "security") render :show if @page @@ -52,22 +58,16 @@ class PagesController < ApplicationController set_surrogate_key_header "faq_page" end - def privacy - @page = Page.find_by(slug: "privacy") - render :show if @page - set_surrogate_key_header "privacy_page" - end - def post_a_job @page = Page.find_by(slug: "post-a-job") render :show if @page set_surrogate_key_header "post_a_job_page" end - def terms - @page = Page.find_by(slug: "terms") + def privacy + @page = Page.find_by(slug: "privacy") render :show if @page - set_surrogate_key_header "terms_page" + set_surrogate_key_header "privacy_page" end def tag_moderation @@ -76,10 +76,10 @@ class PagesController < ApplicationController set_surrogate_key_header "tag_moderation_page" end - def badge - @html_variant = HtmlVariant.find_for_test([], "badge_landing_page") - render layout: false - set_surrogate_key_header "badge_page" + def terms + @page = Page.find_by(slug: "terms") + render :show if @page + set_surrogate_key_header "terms_page" end def report_abuse diff --git a/app/javascript/admin/controllers/landing_page_modal_controller.js b/app/javascript/admin/controllers/landing_page_modal_controller.js new file mode 100644 index 000000000..5480e7b66 --- /dev/null +++ b/app/javascript/admin/controllers/landing_page_modal_controller.js @@ -0,0 +1,26 @@ +import ModalController from './modal_controller'; + +export default class LandingPageModalController extends ModalController { + static targets = ['overwrite', 'landingPageCheckbox']; + + openModal() { + if (this.landingPageCheckboxTarget.checked) { + this.toggleModal(); + } + } + + confirm(event) { + event.preventDefault(); + + this.overwriteTarget.value = true; + this.closeModal(); + } + + cancel(event) { + event.preventDefault(); + + this.landingPageCheckboxTarget.checked = false; + this.overwriteTarget.value = false; + this.closeModal(); + } +} diff --git a/app/models/page.rb b/app/models/page.rb index 2dcaf5774..ac0eff45b 100644 --- a/app/models/page.rb +++ b/app/models/page.rb @@ -1,4 +1,6 @@ class Page < ApplicationRecord + attr_accessor :overwrite_landing_page + TEMPLATE_OPTIONS = %w[contained full_within_layout json].freeze validates :title, presence: true @@ -7,6 +9,7 @@ class Page < ApplicationRecord validates :template, inclusion: { in: TEMPLATE_OPTIONS } validate :body_present validate :unique_slug_including_users_and_orgs, if: :slug_changed? + validate :single_landing_page, if: :will_save_change_to_landing_page? before_validation :set_default_template before_save :evaluate_markdown @@ -23,6 +26,10 @@ class Page < ApplicationRecord "page_#{slug}" end + def self.landing_page + find_by(landing_page: true) + end + private def evaluate_markdown @@ -56,6 +63,17 @@ class Page < ApplicationRecord errors.add(:slug, "is taken.") end + def single_landing_page + # Only add errors if we are trying to modify a landing page + # while another landing page is already being used to ensure + # that only one can be set to "true" at a time. + + landing_page = Page.where.not(id: id).find_by(landing_page: true) + return unless landing_page + + errors.add(:base, "Only one page at a time can be used as a 'locked screen.'") + end + def bust_cache Pages::BustCacheWorker.perform_async(slug) end diff --git a/app/views/admin/pages/_form.html.erb b/app/views/admin/pages/_form.html.erb index 89ef86d99..9077fa04a 100644 --- a/app/views/admin/pages/_form.html.erb +++ b/app/views/admin/pages/_form.html.erb @@ -1,4 +1,9 @@ -
(Determines if it is accessible by /page-slug vs /page/page-slug) Be careful! ⚠️
Determines if it is accessible by /page-slug vs /page/page-slug Be careful! ⚠️
Determines if this page will be used as a landing page for anonymous viewers.
+
<%= link_to "Feature Flag", "/admin/feature_flags" %>
@@ -58,12 +85,12 @@
+ Only one page at a time can be used as a "locked screen." If you proceed, this page will no longer show as "locked screen":
+
+
+
+ <%= link_to "Current Locked Screen: #{page.title}", page.path, target: :_blank, rel: :noopener %>
+
+
+
+
+
+
+
#{Faker::Hipster.paragraph(sentence_count: 2)}
", + title: "#{Faker::Lorem.word} #{rand(100)}", + description: "A test page", + is_top_level_path: true, + landing_page: false, + ) + end +end diff --git a/spec/system/admin/admin_creates_new_page_spec.rb b/spec/system/admin/admin_creates_new_page_spec.rb index 63415c4c5..36892a2ab 100644 --- a/spec/system/admin/admin_creates_new_page_spec.rb +++ b/spec/system/admin/admin_creates_new_page_spec.rb @@ -13,6 +13,7 @@ RSpec.describe "Admin creates new page", type: :system do expect(find_field("page[title]").value).to eq("Code of Conduct") expect(find_field("page[slug]").value).to eq("code-of-conduct") expect(find_field("page[is_top_level_path]").value).to eq("1") + expect(find_field("page[landing_page]").value).to eq("1") text = "All participants of #{community_name} are expected to abide by our Code of Conduct" expect(find_field("page[body_html]").value).to include(text) diff --git a/spec/system/admin/admin_manages_pages_spec.rb b/spec/system/admin/admin_manages_pages_spec.rb index 072dcface..636283dfc 100644 --- a/spec/system/admin/admin_manages_pages_spec.rb +++ b/spec/system/admin/admin_manages_pages_spec.rb @@ -9,7 +9,8 @@ RSpec.describe "Admin manages pages", type: :system do body_html: "