Campaign settings (#6141) [deploy]
* feat: port over changes (+ suggestions) from https://github.com/thepracticaldev/dev.to/pull/5892/files * chore: add query over multiple lines * refactor: move the sql logic into the controller instead of in the template * chore: appease code climate
This commit is contained in:
parent
b8955f19fe
commit
39007b4dab
11 changed files with 149 additions and 3 deletions
|
|
@ -21,6 +21,8 @@ class Internal::ConfigsController < Internal::ApplicationController
|
|||
def config_params
|
||||
allowed_params = %i[
|
||||
default_site_email social_networks_handle
|
||||
campaign_hero_html_variant_name campaign_background_color
|
||||
campaign_text_color campaign_sidebar_enabled campaign_featured_tags
|
||||
main_social_image favicon_url logo_svg
|
||||
rate_limit_follow_count_daily
|
||||
ga_view_id ga_fetch_rate
|
||||
|
|
|
|||
|
|
@ -38,6 +38,20 @@ class StoriesController < ApplicationController
|
|||
|
||||
private
|
||||
|
||||
def assign_hero_html
|
||||
return if SiteConfig.campaign_hero_html_variant_name.blank?
|
||||
|
||||
@hero_html = HtmlVariant.relevant.select(:html).
|
||||
find_by(group: "campaign", name: SiteConfig.campaign_hero_html_variant_name)&.html
|
||||
end
|
||||
|
||||
def get_latest_campaign_articles
|
||||
@latest_campaign_articles = Article.tagged_with(SiteConfig.campaign_featured_tags, any: true).
|
||||
where("published_at > ?", 2.weeks.ago).where(approved: true).
|
||||
order("hotness_score DESC").
|
||||
pluck(:path, :title, :comments_count, :created_at)
|
||||
end
|
||||
|
||||
def redirect_to_changed_username_profile
|
||||
potential_username = params[:username].tr("@", "").downcase
|
||||
user_or_org = User.find_by("old_username = ? OR old_old_username = ?", potential_username, potential_username) ||
|
||||
|
|
@ -125,8 +139,10 @@ class StoriesController < ApplicationController
|
|||
@default_home_feed = true
|
||||
@featured_story, @stories = feed.default_home_feed(user_signed_in: user_signed_in?)
|
||||
end
|
||||
assign_hero_html
|
||||
assign_podcasts
|
||||
assign_classified_listings
|
||||
get_latest_campaign_articles if SiteConfig.campaign_sidebar_enabled?
|
||||
@article_index = true
|
||||
@featured_story = (@featured_story || Article.new)&.decorate
|
||||
@stories = ArticleDecorator.decorate_collection(@stories)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
class HtmlVariant < ApplicationRecord
|
||||
include CloudinaryHelper
|
||||
|
||||
GROUP_NAMES = %w[article_show_sidebar_cta article_show_below_article_cta badge_landing_page campaign].freeze
|
||||
|
||||
validates :html, presence: true
|
||||
validates :name, uniqueness: true
|
||||
validates :group, inclusion: { in: %w[article_show_sidebar_cta article_show_below_article_cta badge_landing_page] }
|
||||
validates :group, inclusion: { in: GROUP_NAMES }
|
||||
validates :success_rate, presence: true
|
||||
validate :no_edits
|
||||
|
||||
|
|
@ -13,6 +15,8 @@ class HtmlVariant < ApplicationRecord
|
|||
|
||||
before_save :prefix_all_images
|
||||
|
||||
scope :relevant, -> { where(approved: true, published: true) }
|
||||
|
||||
def calculate_success_rate!
|
||||
self.success_rate = html_variant_successes.size.to_f / (html_variant_trials.size * 10.0) # x10 because we only capture every 10th
|
||||
save!
|
||||
|
|
|
|||
|
|
@ -13,6 +13,13 @@ class SiteConfig < RailsSettings::Base
|
|||
field :default_site_email, type: :string, default: "yo@dev.to"
|
||||
field :social_networks_handle, type: :string, default: "thepracticaldev"
|
||||
|
||||
# campaign
|
||||
field :campaign_hero_html_variant_name, type: :string, default: ""
|
||||
field :campaign_background_color, type: :string, default: "FFFFFF"
|
||||
field :campaign_text_color, type: :string, default: "000000"
|
||||
field :campaign_featured_tags, type: :array, default: %w[]
|
||||
field :campaign_sidebar_enabled, type: :boolean, default: 0
|
||||
|
||||
# images
|
||||
field :main_social_image, type: :string, default: "https://thepracticaldev.s3.amazonaws.com/i/6hqmcjaxbgbon8ydw93z.png"
|
||||
field :favicon_url, type: :string, default: "favicon.ico"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render "articles/sidebar_campaign" if SiteConfig.campaign_sidebar_enabled? %>
|
||||
<% if params[:timeframe].blank? && @classified_listings.any? %>
|
||||
<div class="widget" id="sidebar-listings-widget">
|
||||
<header class="widget-header-listings">
|
||||
|
|
|
|||
16
app/views/articles/_sidebar_campaign.html.erb
Normal file
16
app/views/articles/_sidebar_campaign.html.erb
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<div class="widget">
|
||||
<header>
|
||||
<h4>
|
||||
<% SiteConfig.campaign_featured_tags.each do |t| %>
|
||||
<%= link_to("##{t}", "/t/#{t}") %>
|
||||
<% end %>
|
||||
</h4>
|
||||
</header>
|
||||
<div class="widget-body">
|
||||
<div class="widget-link-list">
|
||||
<% @latest_campaign_articles.each do |plucked_article| %>
|
||||
<%= render "articles/widget_list_item", plucked_article: plucked_article, show_comment_count: false %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
<%= f.label :published %>
|
||||
<%= f.check_box :published %>
|
||||
<%= f.label :group %>
|
||||
<%= f.select(:group, options_for_select(["article_show_sidebar_cta", "article_show_below_article_cta", "badge_landing_page"], @html_variant.group || "article_show_sidebar_cta")) %>
|
||||
<%= f.select(:group, options_for_select(HtmlVariant::GROUP_NAMES, @html_variant.group || "article_show_sidebar_cta")) %>
|
||||
</div>
|
||||
<%= f.submit %>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<a href="/html_variants?state=article_show_sidebar_cta" class="<%= "selected" if params[:state] == "article_show_sidebar_cta" %>">Show Page Sidebar</a>
|
||||
<a href="/html_variants?state=article_show_below_article_cta" class="<%= "selected" if params[:state] == "article_show_below_article_cta" %>">Show Page Below Article</a>
|
||||
<a href="/html_variants?state=badge_landing_page" class="<%= "selected" if params[:state] == "badge_landing_page" %>">Badge Landing Page</a>
|
||||
<a href="/html_variants?state=campaign" class="<%= "selected" if params[:state] == "campaign" %>">Campaign</a>
|
||||
</nav>
|
||||
<% if params[:state] == "mine" %>
|
||||
<h2>My Entries</h2>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,53 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Campaign</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<%= f.label :campaign_hero_html_variant_name %>
|
||||
<%= f.text_field :campaign_hero_html_variant_name,
|
||||
class: "form-control",
|
||||
value: SiteConfig.campaign_hero_html_variant_name,
|
||||
placeholder: "" %>
|
||||
<div class="alert alert-info">Hero HtmlVariant name</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :campaign_background_color %>
|
||||
<%= f.text_field :campaign_background_color,
|
||||
class: "form-control",
|
||||
value: SiteConfig.campaign_background_color,
|
||||
placeholder: "FFFFFF" %>
|
||||
<div class="alert alert-info">Campaign background color</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :campaign_text_color %>
|
||||
<%= f.text_field :campaign_text_color,
|
||||
class: "form-control",
|
||||
value: SiteConfig.campaign_text_color,
|
||||
placeholder: "FFFFFF" %>
|
||||
<div class="alert alert-info">Campaign text color</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :campaign_sidebar_enabled %>
|
||||
<%= f.check_box :campaign_sidebar_enabled, checked: SiteConfig.campaign_sidebar_enabled %>
|
||||
<div class="alert alert-info">Campaign sidebar enabled or not</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :campaign_featured_tags %>
|
||||
<%= f.text_field :campaign_featured_tags,
|
||||
class: "form-control",
|
||||
value: SiteConfig.campaign_featured_tags.join(","),
|
||||
placeholder: "List of campaign tags: comma separated, letters only e.g. shecoded,theycoded" %>
|
||||
<div class="alert alert-info">Posts with which tags will be featured in the campaign sidebar (comma separated, letters only)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Images</div>
|
||||
<div class="card-body">
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@
|
|||
</div>
|
||||
<% end %>
|
||||
<div id="page-content-inner">
|
||||
<% if @hero_html %>
|
||||
<%= @hero_html.html_safe %>
|
||||
<% end %>
|
||||
<%= yield %>
|
||||
</div>
|
||||
</div>
|
||||
<%= render "shell/bottom" %>
|
||||
<%= render "shell/bottom" %>
|
||||
|
|
|
|||
|
|
@ -68,6 +68,55 @@ RSpec.describe "StoriesIndex", type: :request do
|
|||
get "/"
|
||||
expect(response.body).to include(CGI.escapeHTML(listing.title))
|
||||
end
|
||||
|
||||
context "with campaign hero" do
|
||||
let!(:hero_html) { create(:html_variant, group: "campaign", name: "hero", html: Faker::Book.title, published: true, approved: true) }
|
||||
|
||||
it "displays hero html when it exists and is set in config" do
|
||||
SiteConfig.campaign_hero_html_variant_name = "hero"
|
||||
get "/"
|
||||
expect(response.body).to include(CGI.escapeHTML(hero_html.html))
|
||||
end
|
||||
|
||||
it "doesn't display when campaign_hero_html_variant_name is not set" do
|
||||
SiteConfig.campaign_hero_html_variant_name = ""
|
||||
get "/"
|
||||
expect(response.body).not_to include(CGI.escapeHTML(hero_html.html))
|
||||
end
|
||||
|
||||
it "doesn't display when hero html is not approved" do
|
||||
SiteConfig.campaign_hero_html_variant_name = "hero"
|
||||
hero_html.update_column(:approved, false)
|
||||
get "/"
|
||||
expect(response.body).not_to include(CGI.escapeHTML(hero_html.html))
|
||||
end
|
||||
end
|
||||
|
||||
context "with campaign_sidebar" do
|
||||
before do
|
||||
SiteConfig.campaign_featured_tags = "shecoded,theycoded"
|
||||
create(:article, approved: true, body_markdown: "---\ntitle: Super-sheep#{rand(1000)}\npublished: true\ntags: heyheyhey,shecoded\n---\n\nHello")
|
||||
create(:article, approved: false, body_markdown: "---\ntitle: Unapproved-post#{rand(1000)}\npublished: true\ntags: heyheyhey,shecoded\n---\n\nHello")
|
||||
end
|
||||
|
||||
it "doesn't display posts with the campaign tags when sidebar is disabled" do
|
||||
SiteConfig.campaign_sidebar_enabled = false
|
||||
get "/"
|
||||
expect(response.body).not_to include(CGI.escapeHTML("Super-sheep"))
|
||||
end
|
||||
|
||||
it "displays posts with the campaign tags when sidebar is enabled" do
|
||||
SiteConfig.campaign_sidebar_enabled = true
|
||||
get "/"
|
||||
expect(response.body).not_to include(CGI.escapeHTML("Unapproved-post"))
|
||||
end
|
||||
|
||||
it "displays only approved posts with the campaign tags" do
|
||||
SiteConfig.campaign_sidebar_enabled = false
|
||||
get "/"
|
||||
expect(response.body).not_to include(CGI.escapeHTML("Super-puper"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET query page" do
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue