[deploy] Streamline Tag parsing for both editors (#8175)

This commit is contained in:
Mac Siri 2020-06-05 08:46:24 -04:00 committed by GitHub
parent 4966783e18
commit 1b839d9328
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 83 additions and 17 deletions

View file

@ -383,12 +383,24 @@ class Article < ApplicationRecord
parsed_markdown = MarkdownParser.new(parsed.content)
self.reading_time = parsed_markdown.calculate_reading_time
self.processed_html = parsed_markdown.finalize
evaluate_front_matter(parsed.front_matter)
if parsed.front_matter.any?
evaluate_front_matter(parsed.front_matter)
elsif tag_list.any?
set_tag_list(tag_list)
end
self.description = processed_description if description.blank?
rescue StandardError => e
errors[:base] << ErrorMessageCleaner.new(e.message).clean
end
def set_tag_list(tags)
self.tag_list = [] # overwrite any existing tag with those from the front matter
tag_list.add(tags, parse: true)
self.tag_list = tag_list.map { |tag| Tag.find_preferred_alias_for(tag) }
end
def update_main_image_background_hex
return if main_image.blank? || main_image_background_hex_color != "#dddddd"
@ -446,12 +458,7 @@ class Article < ApplicationRecord
def evaluate_front_matter(front_matter)
self.title = front_matter["title"] if front_matter["title"].present?
if front_matter["tags"].present?
self.tag_list = [] # overwrite any existing tag with those from the front matter
tag_list.add(front_matter["tags"], parser: ActsAsTaggableOn::TagParser)
remove_tag_adjustments_from_tag_list
add_tag_adjustments_to_tag_list
end
set_tag_list(front_matter["tags"]) if front_matter["tags"].present?
self.published = front_matter["published"] if %w[true false].include?(front_matter["published"].to_s)
self.published_at = parse_date(front_matter["date"]) if published
self.main_image = determine_image(front_matter)
@ -497,12 +504,15 @@ class Article < ApplicationRecord
def remove_tag_adjustments_from_tag_list
tags_to_remove = TagAdjustment.where(article_id: id, adjustment_type: "removal", status: "committed").pluck(:tag_name)
tag_list.remove(tags_to_remove, parser: ActsAsTaggableOn::TagParser) if tags_to_remove.present?
tag_list.remove(tags_to_remove, parse: true) if tags_to_remove.present?
end
def add_tag_adjustments_to_tag_list
tags_to_add = TagAdjustment.where(article_id: id, adjustment_type: "addition", status: "committed").pluck(:tag_name)
tag_list.add(tags_to_add, parser: ActsAsTaggableOn::TagParser) if tags_to_add.present?
return if tags_to_add.blank?
tag_list.add(tags_to_add, parse: true)
self.tag_list = tag_list.map { |tag| Tag.find_preferred_alias_for(tag) }
end
def validate_video

View file

@ -73,7 +73,9 @@ class Listing < ApplicationRecord
end
def modify_inputs
ActsAsTaggableOn.default_parser = ActsAsTaggableOn::TagParser
temp_tags = tag_list
self.tag_list = [] # overwrite any existing tag with those from the front matter
tag_list.add(temp_tags, parser: ActsAsTaggableOn::TagParser)
self.body_markdown = body_markdown.to_s.gsub(/\r\n/, "\n")
end

View file

@ -76,6 +76,10 @@ class Tag < ActsAsTaggableOn::Tag
tag.alias_for.presence || tag.name
end
def self.find_preferred_alias_for(word)
find_by(name: word.downcase)&.alias_for.presence || word.downcase
end
def validate_name
errors.add(:name, "is too long (maximum is 30 characters)") if name.length > 30
errors.add(:name, "contains non-alphanumeric characters") unless name.match?(/\A[[:alnum:]]+\z/)

View file

@ -32,7 +32,9 @@ class RssReader
private
def get_tags
@categories.first(4).map { |tag| tag.lstrip[0..19] }.join(",")
@categories.first(4).map do |tag|
tag.delete(" ").gsub(/[^[:alnum:]]/i, "")[0..19]
end.join(",")
end
def assemble_body_markdown

View file

@ -0,0 +1 @@
ActsAsTaggableOn.force_lowercase = true

View file

@ -6,7 +6,7 @@ FactoryBot.define do
title { Faker::Food.dish }
published { true }
date { "01/01/2015" }
tags { Faker::Hipster.words(number: 4).join(", ") }
tags { "javascript, html, css" }
canonical_url { Faker::Internet.url }
with_canonical_url { false }
with_main_image { true }

View file

@ -3,7 +3,7 @@ require "rails_helper"
RSpec.describe LinkTag, type: :liquid_tag do
let(:user) { create(:user, username: "username45", name: "Chase Danger", profile_image: nil) }
let(:article) do
create(:article, user_id: user.id, title: "test this please", tags: "tag1 tag2 tag3")
create(:article, user_id: user.id, title: "test this please", tags: "html, rss, css")
end
let(:org) { build_stubbed(:organization) }
let(:org_user) do
@ -12,7 +12,7 @@ RSpec.describe LinkTag, type: :liquid_tag do
user
end
let(:org_article) do
create(:article, user_id: org_user.id, title: "test this please", tags: "tag1 tag2 tag3",
create(:article, user_id: org_user.id, title: "test this please", tags: "html, ruby, js",
organization_id: org.id)
end
let(:escaped_article) do
@ -30,7 +30,7 @@ RSpec.describe LinkTag, type: :liquid_tag do
end
def correct_link_html(article)
tags = article.tag_list.map { |t| "<span class='ltag__link__tag'>##{t}</span>" }.reverse.join
tags = article.tag_list.map { |t| "<span class='ltag__link__tag'>##{t}</span>" }.join("\n" + "\s" * 8)
<<~HTML
<div class='ltag__link'>
<a href='#{article.user.path}' class='ltag__link__link'>

View file

@ -242,6 +242,16 @@ RSpec.describe Article, type: :model do
expect(build(:article, tags: tags).valid?).to be(false)
end
it "rejects tag with non-alphanumerics" do
expect { build(:article, tags: "c++").validate! }.to raise_error(ActiveRecord::RecordInvalid)
end
it "always downcase tags" do
tags = "UPPERCASE, CAPITALIZE"
article = create(:article, tags: tags)
expect(article.tag_list).to eq(tags.downcase.split(", "))
end
it "parses tags when description is empty" do
body_markdown = "---\ntitle: Title\npublished: false\ndescription:\ntags: one\n---\n\n"
expect(build_and_validate_article(body_markdown: body_markdown).tag_list).to eq(["one"])

View file

@ -73,8 +73,7 @@ RSpec.describe TagAdjustment, type: :model do
describe "validates article tag_list" do
it "does not allow addition on articles with 4 tags" do
article_tags_maxed = create(:article)
allow(article_tags_maxed).to receive(:tag_list).and_return([1, 2, 3, 4])
article_tags_maxed = create(:article, tags: "ruby, javascript, html, css")
tag_adjustment = build(:tag_adjustment, user_id: admin_user.id, article_id: article_tags_maxed.id, tag_id: tag.id, tag_name: tag.name)
expect(tag_adjustment).to be_invalid
end

View file

@ -123,6 +123,35 @@ RSpec.describe Tag, type: :model do
end
end
describe "::aliased_name" do
it "returns the preferred alias tag" do
preferred_tag = create(:tag, name: "rails")
bad_tag = create(:tag, name: "ror", alias_for: "rails")
expect(described_class.aliased_name(bad_tag.name)).to eq(preferred_tag.name)
end
it "returns self if there's no preferred alias" do
tag = create(:tag, name: "ror")
expect(described_class.aliased_name(tag.name)).to eq(tag.name)
end
it "returns nil for non-existing tag" do
expect(described_class.aliased_name("faketag")).to be_nil
end
end
describe "::find_preferred_alias_for" do
it "returns preferred tag" do
preferred_tag = create(:tag, name: "rails")
tag = create(:tag, name: "ror", alias_for: "rails")
expect(described_class.find_preferred_alias_for(tag.name)).to eq(preferred_tag.name)
end
it "returns self if there's no preferred tag" do
expect(described_class.find_preferred_alias_for("something")).to eq("something")
end
end
def collect_keywords(record)
record.elasticsearch_doc.dig("_source", "tags").flat_map { |t| t["keywords_for_search"] }
end

View file

@ -16,6 +16,14 @@ RSpec.describe "ArticlesCreate", type: :request do
expect(Article.last.user_id).to eq(user.id)
end
it "properly downcase tags" do
new_title = "NEW TITLE #{rand(100)}"
post "/articles", params: {
article: { title: new_title, body_markdown: "Yo ho ho#{rand(100)}", tag_list: "What" }
}
expect(Article.last.tags.map(&:name)).to eq(["what"])
end
it "creates article with front matter params" do
post "/articles", params: {
article: {

View file

@ -95,6 +95,7 @@ RSpec.describe "Using the editor", type: :system do
fill_in "article_body_markdown", with: "Hello"
find("button", text: /\APublish\z/).click
expect(page).to have_text("Hello")
expect(page).to have_link("#what", href: "/t/what")
end
end
end