このコミットが含まれているのは:
@@ -133,12 +133,14 @@ class MaterialsController < ApplicationController
|
||||
block = MaterialImportBlockMatcher.match_for_sha256(file_sha256)
|
||||
return render_material_import_block(block) if block
|
||||
|
||||
locale = resolve_locale!
|
||||
|
||||
uploaded_blob = build_uploaded_material_blob!(file, file_sha256)
|
||||
|
||||
begin
|
||||
Material.transaction do
|
||||
MaterialVersionRecorder.ensure_snapshot!(material, created_by_user: current_user)
|
||||
tag = resolve_material_tag!(tag_name_raw)
|
||||
tag = resolve_material_tag!(locale, tag_name_raw)
|
||||
material.assign_attributes(tag:, url:, updated_by_user: current_user)
|
||||
if uploaded_blob
|
||||
material.file.attach(uploaded_blob)
|
||||
|
||||
@@ -218,7 +218,7 @@ class PostsController < ApplicationController
|
||||
preflight = PostCreatePreflight.new(
|
||||
attributes: post_create_attributes,
|
||||
thumbnail: params[:thumbnail],
|
||||
host: request.base_url).run
|
||||
host: request.base_url).run(locale)
|
||||
return render json: dry_run_json(preflight) if bool?(:dry)
|
||||
if preflight[:existing_post_id].present?
|
||||
post = Post.new(url: preflight[:url])
|
||||
@@ -273,13 +273,18 @@ class PostsController < ApplicationController
|
||||
return head :forbidden unless current_user.gte_member?
|
||||
return head :unsupported_media_type unless request.content_mime_type == Mime[:multipart_form]
|
||||
return head :payload_too_large if request.content_length.to_i > MAX_BULK_REQUEST_BYTES
|
||||
|
||||
locale = resolve_locale!
|
||||
|
||||
posts = parse_bulk_posts_manifest
|
||||
thumbnails = parse_bulk_thumbnails(posts.length)
|
||||
|
||||
result = PostBulkCreator.new(
|
||||
actor: current_user,
|
||||
posts:,
|
||||
thumbnails:,
|
||||
host: request.base_url).run
|
||||
host: request.base_url).run(locale)
|
||||
|
||||
render json: result
|
||||
rescue JSON::ParserError
|
||||
render_bad_request 'posts manifest の JSON が不正です.'
|
||||
|
||||
@@ -406,10 +406,10 @@ class TagsController < ApplicationController
|
||||
return render_unprocessable_entity('カテゴリは必須です.', field: :category) if category.blank?
|
||||
return render_unprocessable_entity '廃止状態は必須です.', field: :deprecated unless params.key?(:deprecated)
|
||||
|
||||
return unless validate_tag_rename(tag, name)
|
||||
|
||||
locale = resolve_locale!
|
||||
|
||||
return unless validate_tag_rename(locale, tag, name)
|
||||
|
||||
alias_names = params[:aliases].to_s.split.uniq
|
||||
parent_names = params[:parent_tags].to_s.split.uniq
|
||||
deprecated = bool?(:deprecated)
|
||||
@@ -455,6 +455,8 @@ class TagsController < ApplicationController
|
||||
return head :unauthorized unless current_user
|
||||
return head :forbidden unless current_user.gte_member?
|
||||
|
||||
locale = resolve_locale!
|
||||
|
||||
name = params[:name].presence
|
||||
category = params[:category].presence
|
||||
deprecated_given = params.key?(:deprecated)
|
||||
@@ -462,7 +464,7 @@ class TagsController < ApplicationController
|
||||
|
||||
tag = Tag.find(params[:id])
|
||||
|
||||
return unless validate_tag_rename(tag, name)
|
||||
return unless validate_tag_rename(locale, tag, name)
|
||||
|
||||
if category.present? && category == 'nico'
|
||||
return render_unprocessable_entity 'ニコタグは変更できません.', field: :category
|
||||
@@ -684,7 +686,7 @@ class TagsController < ApplicationController
|
||||
created_by_user:)
|
||||
end
|
||||
|
||||
def validate_tag_rename tag, name
|
||||
def validate_tag_rename locale, tag, name
|
||||
return true if name.blank? || name == tag.name
|
||||
|
||||
if tag.in?([Tag.tagme, Tag.bot, Tag.no_deerjikist, Tag.video, Tag.niconico])
|
||||
@@ -692,9 +694,8 @@ class TagsController < ApplicationController
|
||||
return false
|
||||
end
|
||||
|
||||
target_tag_name = TagName.find_by(name:)
|
||||
return true if target_tag_name.nil?
|
||||
return true if target_tag_name.canonical_id?
|
||||
target_tag_name = TagName.find_by(language_code: locale.language_code, name:)
|
||||
return true unless target_tag_name&.primary_flg
|
||||
|
||||
render_unprocessable_entity 'その名前は既に使はれてゐます.', field: :name
|
||||
false
|
||||
|
||||
@@ -135,7 +135,7 @@ class Tag < ApplicationRecord
|
||||
raise SectionLiteralParseError.new(raw_name, raw_name)
|
||||
end
|
||||
|
||||
name = TagName.canonicalise(name).first
|
||||
name = TagName.canonicalise(locale, name).first
|
||||
|
||||
find_or_create_by_tag_name!(locale, name, category: (cat || :general)).tap do |tag|
|
||||
if deny_deprecated && tag.deprecated?
|
||||
@@ -235,10 +235,7 @@ class Tag < ApplicationRecord
|
||||
end
|
||||
|
||||
tag = tn.tag
|
||||
if tag
|
||||
tag.update!(tag_name_id: tn.id) if tag.tag_name_id != tn.id
|
||||
return tag
|
||||
end
|
||||
return tag if tag
|
||||
|
||||
tag = Tag.create!(tag_name: tn, category:)
|
||||
tn.update!(tag:)
|
||||
@@ -279,6 +276,8 @@ class Tag < ApplicationRecord
|
||||
end
|
||||
|
||||
TagVersioning.record!(source_tag, event_type: :discard, created_by_user:)
|
||||
source_tag.tag_names.update_all(tag_id: source_tag.id, primary_key: false,
|
||||
updated_at: Time.current)
|
||||
source_tag.destroy!
|
||||
|
||||
source_tag_name.update_columns(canonical_id: target_tag.tag_name_id,
|
||||
|
||||
@@ -1,24 +1,36 @@
|
||||
class TagName < ApplicationRecord
|
||||
belongs_to :language, foreign_key: :language_code, primary_key: :code
|
||||
belongs_to :tag, optional: true
|
||||
has_one :wiki_page
|
||||
|
||||
belongs_to :canonical, class_name: 'TagName', optional: true
|
||||
has_many :aliases, class_name: 'TagName', foreign_key: :canonical_id
|
||||
validates :name, presence: true,
|
||||
length: { maximum: 255 },
|
||||
uniqueness: { scope: :language_code }
|
||||
|
||||
validates :name, presence: true, length: { maximum: 255 }, uniqueness: true
|
||||
|
||||
validate :canonical_must_be_canonical
|
||||
validate :alias_name_must_not_have_prefix
|
||||
validate :canonical_must_not_be_present_with_tag_or_wiki_page
|
||||
validate :alias_must_not_have_wiki_page
|
||||
validate :name_must_be_sanitised
|
||||
|
||||
def self.canonicalise names
|
||||
def primary? = primary_flg
|
||||
|
||||
def canonical = TagName.find_by(language:, tag:, primary_flg: true)
|
||||
def aliases = TagName.where(language:, tag:, primary_flg: false)
|
||||
|
||||
def self.canonicalise locale, names
|
||||
names = Array(names).map { |n| n.to_s.strip }.reject(&:blank?)
|
||||
return [] if names.blank?
|
||||
|
||||
tns = TagName.includes(:canonical).where(name: names).index_by(&:name)
|
||||
tns = TagName.where(language_code: locale.language_code, name: names).index_by(&:name)
|
||||
|
||||
names.map { |name| tns[name]&.canonical&.name || name }.uniq
|
||||
names.map { |name|
|
||||
if tns[name].primary_flg
|
||||
name
|
||||
else
|
||||
TagName.find_by(language_code: locale.language_code,
|
||||
tag_id: tns[name].tag_id,
|
||||
primary_flg: true).name
|
||||
end
|
||||
}.uniq
|
||||
end
|
||||
|
||||
def self.generate_name locale, tag, name
|
||||
@@ -29,21 +41,15 @@ class TagName < ApplicationRecord
|
||||
|
||||
private
|
||||
|
||||
def canonical_must_be_canonical
|
||||
if canonical&.canonical_id?
|
||||
errors.add :canonical, 'canonical は実体を示す必要があります.'
|
||||
end
|
||||
end
|
||||
|
||||
def alias_name_must_not_have_prefix
|
||||
if canonical_id? && name.to_s.include?(':')
|
||||
if !(primary?) && name.to_s.include?(':')
|
||||
errors.add :name, 'エーリアス名にプレフィクスを含むことはできません.'
|
||||
end
|
||||
end
|
||||
|
||||
def canonical_must_not_be_present_with_tag_or_wiki_page
|
||||
if canonical_id? && (tag || wiki_page)
|
||||
errors.add :canonical, 'タグもしくは Wiki の参照がある名前はエーリアスになれません.'
|
||||
def alias_must_not_have_wiki_page
|
||||
if !(primary?) && wiki_page
|
||||
errors.add :primary_flg, 'Wiki 参照がある名前はエーリアスになれません.'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -15,31 +15,38 @@ class TagNameSanitisationRule < ApplicationRecord
|
||||
end
|
||||
|
||||
def apply!
|
||||
TagName.find_each do |tn|
|
||||
name = sanitise(tn.name)
|
||||
next if name == tn.name
|
||||
Language.find_each do |language|
|
||||
TagName.where(language:).find_each do |tn|
|
||||
name = sanitise(tn.name)
|
||||
next if name == tn.name
|
||||
|
||||
TagName.transaction do
|
||||
existing_tn = TagName.find_by(name:)
|
||||
if existing_tn
|
||||
existing_tn = existing_tn.canonical || existing_tn
|
||||
next if existing_tn.id == tn.id
|
||||
TagName.transaction do
|
||||
existing_tn = TagName.find_by(language:, name:)
|
||||
if existing_tn
|
||||
unless existing_tn.primary_flg
|
||||
existing_tn = TagName.find_by!(language:,
|
||||
tag_id: existing_tn.tag_id,
|
||||
primary_flg: true)
|
||||
end
|
||||
next if existing_tn.id == tn.id
|
||||
|
||||
existing_tag = Tag.find_by(tag_name_id: existing_tn.id)
|
||||
source_tag = Tag.find_by(tag_name_id: tn.id)
|
||||
existing_tag = existing_tn.tag
|
||||
source_tag = tn.tag
|
||||
|
||||
if existing_tag
|
||||
Tag.merge_tags!(existing_tag, source_tag) if tn.tag
|
||||
elsif source_tag
|
||||
source_tag.update_columns(tag_name_id: existing_tn.id, updated_at: Time.current)
|
||||
if existing_tag
|
||||
Tag.merge_tags!(existing_tag, source_tag) if tn.tag
|
||||
elsif source_tag
|
||||
source_tag.update_columns(tag_name_id: existing_tn.id, updated_at: Time.current)
|
||||
existing_tn.update_columns(tag_id: source_tag.id, updated_at: Time.current)
|
||||
end
|
||||
tn.destroy!
|
||||
|
||||
next
|
||||
end
|
||||
tn.destroy!
|
||||
|
||||
next
|
||||
# TagName 側の自動サニタイズを回避
|
||||
tn.update_columns(name:, updated_at: Time.current)
|
||||
end
|
||||
|
||||
# TagName 側の自動サニタイズを回避
|
||||
tn.update_columns(name:, updated_at: Time.current)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,13 +8,13 @@ class PostCreatePlan
|
||||
@existing_tags_by_name = nil
|
||||
end
|
||||
|
||||
def build!
|
||||
direct_tag_specs, tag_sections = parse_direct_tag_specs
|
||||
def build! locale
|
||||
direct_tag_specs, tag_sections = parse_direct_tag_specs(locale)
|
||||
default_tag_specs = build_default_tag_specs(direct_tag_specs)
|
||||
snapshot_tag_specs = merge_tag_specs(direct_tag_specs + default_tag_specs)
|
||||
preload_existing_tags_by_name!(snapshot_tag_specs.map { _1[:name] })
|
||||
validate_new_tag_specs!(snapshot_tag_specs)
|
||||
post_tag_specs = expand_parent_tag_specs(snapshot_tag_specs)
|
||||
post_tag_specs = expand_parent_tag_specs(locale, snapshot_tag_specs)
|
||||
video_ms = normalise_video_ms(snapshot_tag_specs)
|
||||
validate_video_sections!(video_ms, tag_sections)
|
||||
parent_post_ids = normalise_parent_post_ids
|
||||
@@ -42,13 +42,13 @@ class PostCreatePlan
|
||||
|
||||
def tag_names = @attributes[:tags].to_s.split
|
||||
|
||||
def parse_direct_tag_specs
|
||||
def parse_direct_tag_specs locale
|
||||
tag_sections = { }
|
||||
direct_tag_specs = []
|
||||
|
||||
tag_names.each do |raw_name|
|
||||
tag_name, category, sections = parse_raw_tag_name(raw_name)
|
||||
existing_tag = existing_tags_by_name[tag_name]
|
||||
tag_name, category, sections = parse_raw_tag_name(locale, raw_name)
|
||||
existing_tag = existing_tags_by_name(locale)[tag_name]
|
||||
raise Tag::DeprecatedTagNormalisationError, [existing_tag.name] if existing_tag&.deprecated?
|
||||
|
||||
direct_tag_specs << {
|
||||
@@ -65,7 +65,7 @@ class PostCreatePlan
|
||||
[merge_tag_specs(direct_tag_specs), tag_sections]
|
||||
end
|
||||
|
||||
def parse_raw_tag_name raw_name
|
||||
def parse_raw_tag_name locale, raw_name
|
||||
name = raw_name.to_s
|
||||
prefix, category =
|
||||
Tag::CATEGORY_PREFIXES.find {
|
||||
@@ -74,7 +74,7 @@ class PostCreatePlan
|
||||
name = name.sub(/\A#{ prefix }/i, '')
|
||||
|
||||
sections = []
|
||||
while (match = name.match(/\A(\S*?)\[([^\[\]\s]*)-([^\[\]\s]*)\](\S*)\z/))
|
||||
while match = name.match(/\A(\S*?)\[([^\[\]\s]*)-([^\[\]\s]*)\](\S*)\z/)
|
||||
name = "#{ match[1] }#{ match[4] }"
|
||||
next if match[2].empty? && match[3].empty?
|
||||
|
||||
@@ -87,17 +87,17 @@ class PostCreatePlan
|
||||
raise Tag::SectionLiteralParseError.new(raw_name, raw_name)
|
||||
end
|
||||
|
||||
[resolved_tag_name(name), category&.to_sym, sections]
|
||||
[resolved_tag_name(locale, name), category&.to_sym, sections]
|
||||
end
|
||||
|
||||
def build_default_tag_specs direct_tag_specs
|
||||
def build_default_tag_specs locale, direct_tag_specs
|
||||
default_tag_specs = []
|
||||
if direct_tag_specs.length < 10 && direct_tag_specs.none? { _1[:name] == TAGME_TAG_NAME }
|
||||
default_tag_specs << {
|
||||
name: TAGME_TAG_NAME,
|
||||
category: :meta }
|
||||
end
|
||||
if direct_tag_specs.none? { deerjikist_tag_spec?(_1) }
|
||||
if direct_tag_specs.none? { deerjikist_tag_spec?(locale, _1) }
|
||||
default_tag_specs << {
|
||||
name: NO_DEERJIKIST_TAG_NAME,
|
||||
category: :meta }
|
||||
@@ -131,8 +131,10 @@ class PostCreatePlan
|
||||
raise ActiveRecord::RecordInvalid, post
|
||||
end
|
||||
|
||||
def expand_parent_tag_specs snapshot_tag_specs
|
||||
existing_snapshot_tags = snapshot_tag_specs.filter_map { existing_tags_by_name[_1[:name]] }
|
||||
def expand_parent_tag_specs locale, snapshot_tag_specs
|
||||
existing_snapshot_tags = snapshot_tag_specs.filter_map do
|
||||
existing_tags_by_name(locale)[_1[:name]]
|
||||
end
|
||||
expanded_parent_specs =
|
||||
Tag.expand_parent_tags(existing_snapshot_tags)
|
||||
.reject(&:deprecated?)
|
||||
@@ -156,33 +158,33 @@ class PostCreatePlan
|
||||
}.values.sort_by { _1[:name] }
|
||||
end
|
||||
|
||||
def existing_tags_by_name
|
||||
def existing_tags_by_name locale
|
||||
@existing_tags_by_name ||= begin
|
||||
names = tag_names.map { canonical_tag_name_without_sections(_1) }.uniq
|
||||
names = tag_names.map { canonical_tag_name_without_sections(locale, _1) }.uniq
|
||||
Tag.joins(:tag_name).where(tag_names: { name: names }).index_by(&:name)
|
||||
end
|
||||
end
|
||||
|
||||
def preload_existing_tags_by_name! names
|
||||
def preload_existing_tags_by_name! locale, names
|
||||
wanted_names = Array(names).map { _1.to_s }.reject(&:blank?).uniq
|
||||
missing_names = wanted_names - existing_tags_by_name.keys
|
||||
missing_names = wanted_names - existing_tags_by_name(locale).keys
|
||||
return if missing_names.empty?
|
||||
|
||||
existing_tags_by_name.merge!(
|
||||
existing_tags_by_name(locale).merge!(
|
||||
Tag.joins(:tag_name)
|
||||
.where(tag_names: { name: missing_names })
|
||||
.index_by(&:name))
|
||||
end
|
||||
|
||||
def canonical_tag_name_without_sections raw_name
|
||||
name, = parse_raw_tag_name(raw_name)
|
||||
def canonical_tag_name_without_sections locale, raw_name
|
||||
name, = parse_raw_tag_name(locale, raw_name)
|
||||
name
|
||||
end
|
||||
|
||||
def deerjikist_tag_spec? spec
|
||||
def deerjikist_tag_spec? locale, spec
|
||||
return true if spec[:category] == :deerjikist
|
||||
|
||||
existing_tags_by_name[spec[:name]]&.deerjikist?
|
||||
existing_tags_by_name(locale)[spec[:name]]&.deerjikist?
|
||||
end
|
||||
|
||||
def normalise_parent_post_ids
|
||||
@@ -260,10 +262,13 @@ class PostCreatePlan
|
||||
end
|
||||
end
|
||||
|
||||
def resolved_tag_name name
|
||||
tag_name = TagName.includes(:canonical).find_by(name:)
|
||||
return name if tag_name.nil?
|
||||
|
||||
(tag_name.canonical || tag_name).name
|
||||
def resolved_tag_name locale, name
|
||||
tag_name = TagName.find_by!(language_code: locale.language_code, name:)
|
||||
unless tag_name.primary_flg
|
||||
tag_name = TagName.find_by!(language_code: locale.language_code,
|
||||
tag_id: tag_name.tag_id,
|
||||
primary_flg: true)
|
||||
end
|
||||
tag_name.name
|
||||
end
|
||||
end
|
||||
|
||||
@@ -21,14 +21,14 @@ class PostCreator
|
||||
ApplicationRecord.transaction do
|
||||
post.save!
|
||||
post.thumbnail.attach(thumbnail_attachment) if thumbnail_attachment.present?
|
||||
snapshot_tags = planned_snapshot_tags
|
||||
post_tags = planned_post_tags
|
||||
sections = planned_sections
|
||||
snapshot_tags = planned_snapshot_tags(locale)
|
||||
post_tags = planned_post_tags(locale)
|
||||
sections = planned_sections(locale)
|
||||
TagVersioning.record_tag_snapshots!(snapshot_tags, created_by_user: @actor)
|
||||
post.video_ms = planned_video_ms(locale)
|
||||
post.save!
|
||||
sync_post_tags!(post, post_tags, sections)
|
||||
sync_parent_posts!(post, planned_parent_post_ids)
|
||||
sync_parent_posts!(post, planned_parent_post_ids(locale))
|
||||
PostVersionRecorder.record!(post:, event_type: :create, created_by_user: @actor)
|
||||
end
|
||||
post
|
||||
@@ -45,13 +45,15 @@ class PostCreator
|
||||
thumbnail_base: @attributes[:thumbnail_base].presence)
|
||||
end
|
||||
|
||||
def planned_snapshot_tags = planned_create_attributes[:snapshot_tags]
|
||||
def planned_snapshot_tags(locale) = planned_create_attributes(locale)[:snapshot_tags]
|
||||
|
||||
def planned_post_tags = planned_create_attributes[:post_tags]
|
||||
def planned_post_tags(locale) = planned_create_attributes(locale)[:post_tags]
|
||||
|
||||
def planned_sections = planned_create_attributes[:tag_sections]
|
||||
def planned_sections(locale) = planned_create_attributes(locale)[:tag_sections]
|
||||
|
||||
def planned_parent_post_ids = planned_create_attributes[:normalised_parent_post_ids]
|
||||
def planned_parent_post_ids locale
|
||||
planned_create_attributes(locale)[:normalised_parent_post_ids]
|
||||
end
|
||||
|
||||
def planned_video_ms locale
|
||||
planned_create_attributes(locale)[:video_ms]
|
||||
|
||||
@@ -11,6 +11,7 @@ RSpec.describe 'discarded tag cleanup migrations' do
|
||||
end
|
||||
|
||||
context 'with legacy records' do
|
||||
# Reproduce the historical schema required by these pre-multilingual migrations.
|
||||
self.use_transactional_tests = false
|
||||
|
||||
before do
|
||||
|
||||
@@ -7,15 +7,6 @@ FactoryBot.define do
|
||||
|
||||
trait :alias do
|
||||
primary_flg { false }
|
||||
|
||||
after(:create) do |tag_name|
|
||||
owner = tag_name.canonical&.tag
|
||||
raise ArgumentError, 'alias requires a canonical tag' unless owner
|
||||
|
||||
# The alias validation still rejects tag_id; its contract is tested separately.
|
||||
tag_name.update_columns(tag_id: owner.id)
|
||||
tag_name.association(:tag).reset
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -27,10 +27,10 @@ RSpec.describe Locale, type: :model do
|
||||
expect(first.tag_names.find_by!(language_code: 'fr', primary_flg: true))
|
||||
.to have_attributes(name: 'name_from_generator', tag_id: first.id,
|
||||
language_code: 'fr', script_code: 'Latn',
|
||||
primary_flg: true, canonical_id: nil)
|
||||
primary_flg: true)
|
||||
expect(second.tag_names.find_by!(language_code: 'fr', primary_flg: true))
|
||||
.to have_attributes(tag_id: second.id, language_code: 'fr',
|
||||
script_code: 'Latn', primary_flg: true, canonical_id: nil)
|
||||
script_code: 'Latn', primary_flg: true)
|
||||
expect(TagName.where(language_code: 'fr', primary_flg: true,
|
||||
tag_id: [first.id, second.id]).count).to eq(2)
|
||||
end
|
||||
@@ -53,13 +53,13 @@ RSpec.describe Locale, type: :model do
|
||||
prepare_french_reference!
|
||||
tag = create(:tag, name: 'alias_only_tag')
|
||||
alias_name = create(:tag_name, :alias, name: 'alias_fr',
|
||||
canonical: tag.tag_name,
|
||||
tag:,
|
||||
language_code: 'fr', script_code: 'Latn')
|
||||
|
||||
create_french_locale!
|
||||
|
||||
expect(alias_name.reload).to have_attributes(
|
||||
canonical_id: tag.tag_name_id, tag_id: tag.id,
|
||||
tag_id: tag.id,
|
||||
language_code: 'fr', script_code: 'Latn', primary_flg: false)
|
||||
generated = TagName.find_by!(tag_id: tag.id, language_code: 'fr', primary_flg: true)
|
||||
expect(generated).to have_attributes(tag_id: tag.id, language_code: 'fr',
|
||||
|
||||
@@ -79,7 +79,7 @@ RSpec.describe TagNameSanitisationRule, type: :model do
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a conflicting canonical tag_name exists' do
|
||||
context 'when a conflicting primary tag name exists' do
|
||||
let!(:existing) { create(:tag_name, name: 'foobar') }
|
||||
let!(:source) do
|
||||
create(:tag_name, name: 'tmp').tap do |tn|
|
||||
@@ -105,8 +105,7 @@ RSpec.describe TagNameSanitisationRule, type: :model do
|
||||
|
||||
it 'moves the tag to the existing tag_name' do
|
||||
described_class.apply!
|
||||
expected_tag_name_id = existing.canonical_id || existing.id
|
||||
expect(source_tag.reload.tag_name_id).to eq(expected_tag_name_id)
|
||||
expect(source_tag.reload.tag_name_id).to eq(existing.id)
|
||||
expect(TagName.unscoped.exists?(source_tag_name_id)).to be(false)
|
||||
end
|
||||
end
|
||||
@@ -114,7 +113,7 @@ RSpec.describe TagNameSanitisationRule, type: :model do
|
||||
context 'when the sanitised name is an alias of an existing tag' do
|
||||
let!(:existing_tag) { create(:tag) }
|
||||
let!(:alias_name) do
|
||||
create(:tag_name, :alias, name: 'foobar', canonical: existing_tag.tag_name)
|
||||
create(:tag_name, :alias, name: 'foobar', tag: existing_tag)
|
||||
end
|
||||
let!(:source) do
|
||||
create(:tag_name, name: 'tmp').tap do |tn|
|
||||
@@ -122,11 +121,15 @@ RSpec.describe TagNameSanitisationRule, type: :model do
|
||||
end
|
||||
end
|
||||
|
||||
it 'deletes only the source and preserves the alias and its canonical tag' do
|
||||
it 'deletes only the source and preserves the alias and its owning tag' do
|
||||
described_class.apply!
|
||||
|
||||
expect(TagName.unscoped.exists?(source.id)).to be(false)
|
||||
expect(alias_name.reload.canonical).to eq(existing_tag.tag_name)
|
||||
expect(alias_name.reload).to have_attributes(
|
||||
tag_id: existing_tag.id, language_code: 'ja', primary_flg: false)
|
||||
expect(TagName.find_by!(tag_id: existing_tag.id,
|
||||
language_code: 'ja', primary_flg: true))
|
||||
.to eq(existing_tag.tag_name)
|
||||
expect(Tag.find(existing_tag.id)).to eq(existing_tag)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -32,37 +32,58 @@ RSpec.describe TagName, type: :model do
|
||||
|
||||
expect(tag.reload.tag_name.reload.tag_id).to eq(tag.id)
|
||||
expect(tag.tag_name.tag).to eq(tag)
|
||||
expect(described_class.find_by!(tag_id: tag.id, language_code: 'ja', primary_flg: true))
|
||||
.to eq(tag.tag_name)
|
||||
end
|
||||
|
||||
it 'accepts an alias owned by the canonical tag' do
|
||||
it 'persists an alias owned by the same tag as its primary name' do
|
||||
tag = create(:tag)
|
||||
alias_name = build(:tag_name, name: 'valid_alias', canonical: tag.tag_name,
|
||||
tag:, primary_flg: false)
|
||||
alias_name = create(:tag_name, :alias, name: 'valid_alias', tag:)
|
||||
|
||||
expect(alias_name).to have_attributes(
|
||||
canonical_id: tag.tag_name_id, tag_id: tag.id,
|
||||
expect(alias_name.reload).to have_attributes(
|
||||
tag_id: tag.id,
|
||||
primary_flg: false, language_code: 'ja')
|
||||
expect(alias_name).to be_valid
|
||||
primary = described_class.find_by!(tag_id: alias_name.tag_id,
|
||||
language_code: alias_name.language_code,
|
||||
primary_flg: true)
|
||||
expect(primary).to eq(tag.tag_name)
|
||||
end
|
||||
|
||||
describe '.canonicalise' do
|
||||
it 'resolves the primary name of the alias language on the same tag' do
|
||||
tag = create(:tag, name: '日本語正本')
|
||||
english_primary = create(:tag_name, tag:, name: 'english_primary',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english_alias = create(:tag_name, :alias, tag:, name: 'english_alias',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
representative_id = tag.tag_name_id
|
||||
|
||||
primary = described_class.find_by!(tag_id: english_alias.tag_id,
|
||||
language_code: english_alias.language_code,
|
||||
primary_flg: true)
|
||||
|
||||
expect(primary).to eq(english_primary)
|
||||
expect(described_class.canonicalise(locale, [english_alias.name]))
|
||||
.to eq([english_primary.name])
|
||||
expect(tag.reload.tag_name_id).to eq(representative_id)
|
||||
end
|
||||
|
||||
it 'resolves only aliases in the requested language' do
|
||||
japanese = create(:tag, name: 'japanese_canonical')
|
||||
english_name = create(:tag_name, name: 'english_canonical',
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english = create(:tag, tag_name: english_name)
|
||||
japanese_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
canonical: japanese.tag_name)
|
||||
english_alias = create(:tag_name, :alias, name: 'temporary_alias',
|
||||
canonical: english_name,
|
||||
tag: japanese)
|
||||
english_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
tag: english,
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english_alias.update_columns(name: 'shared_alias')
|
||||
|
||||
expect(japanese_alias.reload).to have_attributes(
|
||||
canonical_id: japanese.tag_name_id, tag_id: japanese.id,
|
||||
tag_id: japanese.id,
|
||||
primary_flg: false, language_code: 'ja')
|
||||
expect(english_alias.reload).to have_attributes(
|
||||
canonical_id: english_name.id, tag_id: english.id,
|
||||
tag_id: english.id,
|
||||
primary_flg: false, language_code: 'en')
|
||||
expect(described_class.canonicalise(locale, ['shared_alias']))
|
||||
.to eq(['english_canonical'])
|
||||
|
||||
@@ -37,17 +37,16 @@ RSpec.describe Tag, type: :model do
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english = create(:tag, tag_name: english_name)
|
||||
japanese_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
canonical: japanese.tag_name)
|
||||
english_alias = create(:tag_name, :alias, name: 'temporary_alias',
|
||||
canonical: english_name,
|
||||
tag: japanese)
|
||||
english_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
tag: english,
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english_alias.update_columns(name: 'shared_alias')
|
||||
|
||||
expect(japanese_alias.reload).to have_attributes(
|
||||
canonical_id: japanese.tag_name_id, tag_id: japanese.id,
|
||||
tag_id: japanese.id,
|
||||
primary_flg: false, language_code: 'ja')
|
||||
expect(english_alias.reload).to have_attributes(
|
||||
canonical_id: english_name.id, tag_id: english.id,
|
||||
tag_id: english.id,
|
||||
primary_flg: false, language_code: 'en')
|
||||
expect(described_class.normalise_tags!(
|
||||
english_locale, ['shared_alias'],
|
||||
@@ -270,12 +269,12 @@ RSpec.describe Tag, type: :model do
|
||||
expect(tag.category).to eq('character')
|
||||
end
|
||||
|
||||
it 'reuses the canonical tag for an alias without changing its category' do
|
||||
it 'reuses the owning tag for an alias without changing its category' do
|
||||
tag = create(:tag, category: :character)
|
||||
representative_id = tag.tag_name_id
|
||||
alias_name = create(:tag_name, :alias, name: 'lookup_alias', canonical: tag.tag_name)
|
||||
alias_name = create(:tag_name, :alias, name: 'lookup_alias', tag:)
|
||||
expect(alias_name.reload).to have_attributes(
|
||||
canonical_id: tag.tag_name_id, tag_id: tag.id,
|
||||
tag_id: tag.id,
|
||||
primary_flg: false, language_code: 'ja')
|
||||
found = nil
|
||||
|
||||
@@ -289,14 +288,14 @@ RSpec.describe Tag, type: :model do
|
||||
expect(tag.reload.tag_name_id).to eq(representative_id)
|
||||
end
|
||||
|
||||
it 'reuses the canonical tag through another alias' do
|
||||
it 'reuses the owning tag through another alias' do
|
||||
tag = create(:tag)
|
||||
canonical = tag.tag_name
|
||||
alias_name = create(:tag_name, :alias, name: 'lookup_alias', canonical:)
|
||||
other_alias = create(:tag_name, :alias, name: 'lookup_other_alias', canonical:)
|
||||
primary = tag.tag_name
|
||||
alias_name = create(:tag_name, :alias, name: 'lookup_alias', tag:)
|
||||
other_alias = create(:tag_name, :alias, name: 'lookup_other_alias', tag:)
|
||||
|
||||
expect([alias_name.reload, other_alias.reload]).to all(have_attributes(
|
||||
canonical_id: canonical.id, tag_id: tag.id,
|
||||
tag_id: tag.id,
|
||||
primary_flg: false, language_code: 'ja'))
|
||||
|
||||
expect {
|
||||
@@ -305,7 +304,7 @@ RSpec.describe Tag, type: :model do
|
||||
expect(found).to eq(tag)
|
||||
}.to change(Tag, :count).by(0).and change(TagName, :count).by(0)
|
||||
|
||||
expect(tag.tag_name).to eq(canonical)
|
||||
expect(tag.reload.tag_name).to eq(primary)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -329,7 +328,8 @@ RSpec.describe Tag, type: :model do
|
||||
expect(PostTag.exists?(post: post_record, tag: source_tag)).to be(false)
|
||||
expect(target_link).to be_present
|
||||
expect(Tag.unscoped.exists?(source_tag.id)).to be(false)
|
||||
expect(source_tag_name.reload.canonical_id).to eq(target_tag.tag_name_id)
|
||||
expect(source_tag_name.reload).to have_attributes(
|
||||
tag_id: target_tag.id, language_code: 'ja', primary_flg: false)
|
||||
expect(target_tag.reload.post_count).to eq(1)
|
||||
end
|
||||
end
|
||||
@@ -355,7 +355,8 @@ RSpec.describe Tag, type: :model do
|
||||
expect(target_post_tag.reload.sections).to contain_exactly(target_section)
|
||||
|
||||
expect(Tag.unscoped.exists?(source_tag.id)).to be(false)
|
||||
expect(source_tag_name.reload.canonical_id).to eq(target_tag.tag_name_id)
|
||||
expect(source_tag_name.reload).to have_attributes(
|
||||
tag_id: target_tag.id, language_code: 'ja', primary_flg: false)
|
||||
expect(target_tag.reload.post_count).to eq(1)
|
||||
end
|
||||
end
|
||||
@@ -363,7 +364,7 @@ RSpec.describe Tag, type: :model do
|
||||
it 'keeps source history and records the new target alias after deleting the source' do
|
||||
user = create_member_user!
|
||||
source_name = source_tag.name
|
||||
source_alias = create(:tag_name, :alias, name: 'merge_alias', canonical: source_tag_name)
|
||||
source_alias = create(:tag_name, :alias, name: 'merge_alias', tag: source_tag)
|
||||
TagVersioning.ensure_snapshot!(source_tag, created_by_user: user)
|
||||
original_version = source_tag.tag_versions.first
|
||||
|
||||
@@ -433,7 +434,8 @@ RSpec.describe Tag, type: :model do
|
||||
expect(Tag.unscoped.exists?(source_tag.id)).to be(false)
|
||||
expect(PostTag.exists?(post: post_record, tag: source_tag)).to be(false)
|
||||
expect(target_link).to be_present
|
||||
expect(source_tag_name.reload.canonical_id).to eq(target_tag.tag_name_id)
|
||||
expect(source_tag_name.reload).to have_attributes(
|
||||
tag_id: target_tag.id, language_code: 'ja', primary_flg: false)
|
||||
expect(target_tag.reload.post_count).to eq(1)
|
||||
end
|
||||
end
|
||||
@@ -464,7 +466,8 @@ RSpec.describe Tag, type: :model do
|
||||
expect(target_link).to be_present
|
||||
|
||||
expect(Tag.unscoped.exists?(source_tag.id)).to be(false)
|
||||
expect(source_tag_name.reload.canonical_id).to eq(target_tag.tag_name_id)
|
||||
expect(source_tag_name.reload).to have_attributes(
|
||||
tag_id: target_tag.id, language_code: 'ja', primary_flg: false)
|
||||
expect(target_tag.reload.post_count).to eq(1)
|
||||
end
|
||||
end
|
||||
@@ -493,7 +496,8 @@ RSpec.describe Tag, type: :model do
|
||||
}.to raise_error(ActiveRecord::RecordInvalid)
|
||||
|
||||
expect(Tag.unscoped.exists?(earlier_source.id)).to be(true)
|
||||
expect(earlier_name.reload.canonical_id).to be_nil
|
||||
expect(earlier_name.reload).to have_attributes(
|
||||
tag_id: earlier_source.id, language_code: 'ja', primary_flg: true)
|
||||
expect(TagVersion.where(tag_id: [earlier_source.id, source_tag.id, target_tag.id]))
|
||||
.to be_empty
|
||||
expect(Tag.unscoped.exists?(source_tag.id)).to be(true)
|
||||
@@ -502,7 +506,8 @@ RSpec.describe Tag, type: :model do
|
||||
expect(source_post_tag.sections).to contain_exactly(source_section)
|
||||
expect(PostTag.find_by(post: post_record, tag: target_tag)).to be_nil
|
||||
expect(source_tag.reload.post_count).to eq(1)
|
||||
expect(source_tag_name.reload.canonical_id).to be_nil
|
||||
expect(source_tag_name.reload).to have_attributes(
|
||||
tag_id: source_tag.id, language_code: 'ja', primary_flg: true)
|
||||
expect(target_tag.reload.post_count).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -202,17 +202,19 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
expect(response).to have_http_status(:ok), response.body
|
||||
expect(TagName.find_by!(language_code: 'en', name: 'english_alias'))
|
||||
.to have_attributes(
|
||||
script_code: 'Latn', canonical_id: english_name.id,
|
||||
script_code: 'Latn',
|
||||
tag_id: tag.id, primary_flg: false, language_code: 'en')
|
||||
expect(tag.reload.tag_name_id).to eq(english_name.id)
|
||||
primary = TagName.find_by!(tag_id: tag.id, language_code: 'en', primary_flg: true)
|
||||
expect(primary).to have_attributes(name: 'english_original', script_code: 'Latn')
|
||||
end
|
||||
|
||||
it 'does not take an alias from another language' do
|
||||
japanese = create(:tag, name: 'japanese_owner')
|
||||
japanese_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
canonical: japanese.tag_name)
|
||||
tag: japanese)
|
||||
expect(japanese_alias.reload).to have_attributes(
|
||||
canonical_id: japanese.tag_name_id, tag_id: japanese.id,
|
||||
tag_id: japanese.id,
|
||||
primary_flg: false, language_code: 'ja')
|
||||
|
||||
put "/tags/#{ tag.id }", params: {
|
||||
@@ -221,12 +223,14 @@ RSpec.describe 'Locale propagation on write paths', type: :request do
|
||||
|
||||
expect(response).to have_http_status(:ok), response.body
|
||||
expect(japanese_alias.reload).to have_attributes(
|
||||
canonical_id: japanese.tag_name_id, tag_id: japanese.id,
|
||||
tag_id: japanese.id,
|
||||
primary_flg: false, language_code: 'ja')
|
||||
expect(TagName.find_by!(language_code: 'en', name: 'shared_alias'))
|
||||
.to have_attributes(
|
||||
canonical_id: english_name.id, tag_id: tag.id,
|
||||
tag_id: tag.id, script_code: 'Latn',
|
||||
primary_flg: false, language_code: 'en')
|
||||
expect(TagName.where(name: 'shared_alias').pluck(:language_code, :tag_id))
|
||||
.to contain_exactly(['ja', japanese.id], ['en', tag.id])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -129,7 +129,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
let!(:tag) { create(:tag, tag_name:, category: :general) }
|
||||
let!(:tag_name2) { create(:tag_name, name: 'unko') }
|
||||
let!(:tag2) { create(:tag, tag_name: tag_name2, category: :deerjikist) }
|
||||
let!(:alias_tag_name) { create(:tag_name, :alias, name: 'manko', canonical: tag_name) }
|
||||
let!(:alias_tag_name) { create(:tag_name, :alias, name: 'manko', tag:) }
|
||||
|
||||
let!(:hit_post) do
|
||||
Post.create!(uploaded_user: user, title: 'hello spec world',
|
||||
@@ -351,7 +351,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
let!(:baz_tag) { create(:tag, tag_name: baz_tag_name, category: :general) }
|
||||
|
||||
let!(:foo_alias_tag_name) do
|
||||
create(:tag_name, :alias, name: 'not_spec_foo_alias', canonical: foo_tag_name)
|
||||
create(:tag_name, :alias, name: 'not_spec_foo_alias', tag: foo_tag)
|
||||
end
|
||||
|
||||
let!(:foo_only_post) do
|
||||
@@ -854,7 +854,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
15.times.map do |i|
|
||||
tag_name = create(:tag_name, name: "show_query_tag_#{ i }")
|
||||
tag = create(:tag, tag_name:, category: :general)
|
||||
create(:tag_name, :alias, name: "show_query_alias_#{ i }", canonical: tag_name)
|
||||
create(:tag_name, :alias, name: "show_query_alias_#{ i }", tag:)
|
||||
PostTag.create!(post: post_record, tag:)
|
||||
tag
|
||||
end
|
||||
@@ -999,7 +999,7 @@ RSpec.describe 'Posts API', type: :request do
|
||||
|
||||
describe 'POST /posts' do
|
||||
let(:member) { create(:user, :member) }
|
||||
let!(:alias_tag_name) { create(:tag_name, :alias, name: 'manko', canonical: tag_name) }
|
||||
let!(:alias_tag_name) { create(:tag_name, :alias, name: 'manko', tag:) }
|
||||
|
||||
it '401 when not logged in' do
|
||||
sign_out
|
||||
|
||||
@@ -4,7 +4,7 @@ require 'rails_helper'
|
||||
RSpec.describe 'Tags API', type: :request do
|
||||
let!(:tn) { create(:tag_name, name: 'spec_tag') }
|
||||
let!(:tag) { create(:tag, tag_name: tn, category: :general) }
|
||||
let!(:alias_tn) { create(:tag_name, :alias, name: 'unko', canonical: tn) }
|
||||
let!(:alias_tn) { create(:tag_name, :alias, name: 'unko', tag:) }
|
||||
let!(:post) { Post.create!(url: 'https://example.com/unkounkounko') }
|
||||
let!(:post_tag) { PostTag.create!(post:, tag:) }
|
||||
let!(:tn2) { create(:tag_name, name: 'unknown') }
|
||||
@@ -466,7 +466,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
it 'excludes external tags but preserves internal alias matches when nico is false' do
|
||||
internal = create(:tag, category: :general, name: 'switch_internal', post_count: 1)
|
||||
alias_target = create(:tag, category: :general, name: 'alias_target', post_count: 1)
|
||||
create(:tag_name, :alias, name: 'switch_alias', canonical: alias_target.tag_name)
|
||||
create(:tag_name, :alias, name: 'switch_alias', tag: alias_target)
|
||||
create(:external_tag, name: 'switch_external', post_count: 1)
|
||||
|
||||
get '/tags/autocomplete', params: { q: 'switch', nico: '0' }
|
||||
@@ -479,13 +479,13 @@ RSpec.describe 'Tags API', type: :request do
|
||||
end
|
||||
|
||||
['%', '_'].each do |wildcard|
|
||||
it "treats #{ wildcard } literally for canonical, alias, and external names" do
|
||||
it "treats #{ wildcard } literally for primary, alias, and external names" do
|
||||
literal = "literal#{ wildcard }match"
|
||||
create(:tag, category: :general, name: literal, post_count: 1)
|
||||
alias_target = create(
|
||||
:tag, category: :general, name: 'literal_alias_target', post_count: 1)
|
||||
create(:tag_name, :alias, name: "#{ literal }_alias",
|
||||
canonical: alias_target.tag_name)
|
||||
tag: alias_target)
|
||||
create(:external_tag, name: literal, post_count: 1)
|
||||
create(:tag, category: :general, name: 'literalXmatch', post_count: 2)
|
||||
create(:external_tag, name: 'literalXmatch', post_count: 2)
|
||||
@@ -509,7 +509,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
expect(t['matched_alias']).to be(nil)
|
||||
end
|
||||
|
||||
it 'returns matching canonical tags by q with aliases' do
|
||||
it 'returns matching primary tag names by q with aliases' do
|
||||
get '/tags/autocomplete', params: { q: 'unk' }
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
@@ -772,7 +772,8 @@ RSpec.describe 'Tags API', type: :request do
|
||||
}
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(TagName.find_by!(name: 'spec_tag').canonical).to eq(tag.reload.tag_name)
|
||||
expect(TagName.find_by!(language_code: 'ja', name: 'spec_tag'))
|
||||
.to have_attributes(tag_id: tag.id, primary_flg: false)
|
||||
|
||||
patch "/tags/#{ tag.id }", params: { name: 'spec_tag' }
|
||||
|
||||
@@ -781,8 +782,10 @@ RSpec.describe 'Tags API', type: :request do
|
||||
tag.reload
|
||||
|
||||
expect(tag.name).to eq('spec_tag')
|
||||
expect(tag.tag_name.canonical_id).to be_nil
|
||||
expect(TagName.find_by!(name: 'patch_roundtrip_target').canonical).to eq(tag.tag_name)
|
||||
expect(tag.tag_name).to have_attributes(
|
||||
tag_id: tag.id, language_code: 'ja', primary_flg: true)
|
||||
expect(TagName.find_by!(language_code: 'ja', name: 'patch_roundtrip_target'))
|
||||
.to have_attributes(tag_id: tag.id, primary_flg: false)
|
||||
end
|
||||
|
||||
it '別 tag の正規名には変更できない' do
|
||||
@@ -801,7 +804,8 @@ RSpec.describe 'Tags API', type: :request do
|
||||
)
|
||||
|
||||
expect(tag.reload.name).to eq('spec_tag')
|
||||
expect(tag.tag_name.aliases.map(&:name)).to contain_exactly('unko')
|
||||
expect(TagName.where(tag_id: tag.id, language_code: 'ja', primary_flg: false).pluck(:name))
|
||||
.to contain_exactly('unko')
|
||||
expect(wiki_page.reload.tag_name).to eq(tag.tag_name)
|
||||
end
|
||||
|
||||
@@ -1170,14 +1174,17 @@ RSpec.describe 'Tags API', type: :request do
|
||||
expect(tag.name).to eq('put_renamed_tag')
|
||||
expect(tag.category).to eq('meme')
|
||||
|
||||
expect(TagName.find_by(name: 'put_alias_a').canonical).to eq(tag.tag_name)
|
||||
expect(TagName.find_by(name: 'put_alias_b').canonical).to eq(tag.tag_name)
|
||||
expect(TagName.find_by!(language_code: 'ja', name: 'put_alias_a'))
|
||||
.to have_attributes(tag_id: tag.id, primary_flg: false)
|
||||
expect(TagName.find_by!(language_code: 'ja', name: 'put_alias_b'))
|
||||
.to have_attributes(tag_id: tag.id, primary_flg: false)
|
||||
|
||||
old_name_alias = TagName.find_by(name: 'spec_tag')
|
||||
expect(old_name_alias).to be_present
|
||||
expect(old_name_alias.canonical).to eq(tag.tag_name)
|
||||
expect(old_name_alias).to have_attributes(
|
||||
tag_id: tag.id, language_code: 'ja', primary_flg: false)
|
||||
|
||||
expect(alias_tn.reload.canonical).to be_nil
|
||||
expect(alias_tn.reload.tag_id).to be_nil
|
||||
|
||||
expect(tag.parents.map(&:name)).to contain_exactly(
|
||||
'put_kept_parent',
|
||||
@@ -1212,7 +1219,8 @@ RSpec.describe 'Tags API', type: :request do
|
||||
|
||||
tag.reload
|
||||
|
||||
expect(TagName.find_by(name: 'put_alias_self_test').canonical).to eq(tag.tag_name)
|
||||
expect(TagName.find_by!(language_code: 'ja', name: 'put_alias_self_test'))
|
||||
.to have_attributes(tag_id: tag.id, primary_flg: false)
|
||||
expect(json['aliases']).to include('put_alias_self_test')
|
||||
expect(json['aliases']).not_to include('spec_tag')
|
||||
end
|
||||
@@ -1283,10 +1291,14 @@ RSpec.describe 'Tags API', type: :request do
|
||||
tag.reload
|
||||
|
||||
expect(tag.name).to eq('spec_tag')
|
||||
expect(TagName.find_by!(name: 'put_roundtrip_b').canonical).to eq(tag.tag_name)
|
||||
expect(tag.tag_name.aliases.map(&:name)).to contain_exactly('put_roundtrip_b', 'unko')
|
||||
expect(tag.tag_name.aliases.map(&:name)).not_to include('spec_tag')
|
||||
expect(alias_tn.reload.canonical).to eq(tag.tag_name)
|
||||
expect(TagName.find_by!(language_code: 'ja', name: 'put_roundtrip_b'))
|
||||
.to have_attributes(tag_id: tag.id, primary_flg: false)
|
||||
expect(TagName.where(tag_id: tag.id, language_code: 'ja', primary_flg: false).pluck(:name))
|
||||
.to contain_exactly('put_roundtrip_b', 'unko')
|
||||
expect(TagName.where(tag_id: tag.id, language_code: 'ja', primary_flg: false).pluck(:name))
|
||||
.not_to include('spec_tag')
|
||||
expect(alias_tn.reload).to have_attributes(
|
||||
tag_id: tag.id, language_code: 'ja', primary_flg: false)
|
||||
|
||||
version = tag.tag_versions.order(:version_no).last
|
||||
|
||||
@@ -1395,7 +1407,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
)
|
||||
end
|
||||
|
||||
it 'wiki を持つ tag を旧 alias へ戻しても wiki を新 canonical へ移す' do
|
||||
it 'wiki を持つ tag を旧 alias へ戻しても wiki を新しい正本名へ移す' do
|
||||
wiki_page =
|
||||
Wiki::Commit.create_content!(
|
||||
tag_name: tag.tag_name,
|
||||
@@ -1429,7 +1441,8 @@ RSpec.describe 'Tags API', type: :request do
|
||||
|
||||
expect(wiki_page.reload.tag_name).to eq(tag.tag_name)
|
||||
expect(TagName.find_by!(name: 'put_wiki_roundtrip_b').wiki_page).to be_nil
|
||||
expect(TagName.find_by!(name: 'put_wiki_roundtrip_b').canonical).to eq(tag.tag_name)
|
||||
expect(TagName.find_by!(language_code: 'ja', name: 'put_wiki_roundtrip_b'))
|
||||
.to have_attributes(tag_id: tag.id, primary_flg: false)
|
||||
|
||||
versions = wiki_page.wiki_versions.order(:version_no).last(2)
|
||||
|
||||
@@ -1443,9 +1456,11 @@ RSpec.describe 'Tags API', type: :request do
|
||||
category: :general)
|
||||
stolen_alias = create(:tag_name, :alias,
|
||||
name: 'put_stolen_alias',
|
||||
canonical: old_owner.tag_name)
|
||||
tag: old_owner)
|
||||
|
||||
expect(old_owner.tag_name.aliases.map(&:name)).to include('put_stolen_alias')
|
||||
expect(TagName.where(tag_id: old_owner.id, language_code: 'ja',
|
||||
primary_flg: false).pluck(:name))
|
||||
.to include('put_stolen_alias')
|
||||
|
||||
expect {
|
||||
put "/tags/#{ tag.id }", params: {
|
||||
@@ -1461,8 +1476,11 @@ RSpec.describe 'Tags API', type: :request do
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
expect(stolen_alias.reload.canonical).to eq(tag.tag_name)
|
||||
expect(old_owner.reload.tag_name.aliases.map(&:name)).not_to include('put_stolen_alias')
|
||||
expect(stolen_alias.reload).to have_attributes(
|
||||
tag_id: tag.id, language_code: 'ja', primary_flg: false)
|
||||
expect(TagName.where(tag_id: old_owner.id, language_code: 'ja',
|
||||
primary_flg: false).pluck(:name))
|
||||
.not_to include('put_stolen_alias')
|
||||
|
||||
old_owner_versions = old_owner.tag_versions.order(:version_no)
|
||||
|
||||
@@ -1479,7 +1497,7 @@ RSpec.describe 'Tags API', type: :request do
|
||||
category: :general)
|
||||
stolen_alias = create(:tag_name, :alias,
|
||||
name: 'put_alias_collision_name',
|
||||
canonical: old_owner.tag_name)
|
||||
tag: old_owner)
|
||||
wiki_page =
|
||||
Wiki::Commit.create_content!(
|
||||
tag_name: tag.tag_name,
|
||||
@@ -1502,9 +1520,13 @@ RSpec.describe 'Tags API', type: :request do
|
||||
stolen_alias.reload
|
||||
|
||||
expect(tag.name).to eq('put_alias_collision_name')
|
||||
expect(stolen_alias.canonical_id).to be_nil
|
||||
expect(TagName.find_by!(name: 'spec_tag').canonical).to eq(tag.tag_name)
|
||||
expect(old_owner.tag_name.aliases.map(&:name)).not_to include('put_alias_collision_name')
|
||||
expect(stolen_alias).to have_attributes(
|
||||
tag_id: tag.id, language_code: 'ja', primary_flg: true)
|
||||
expect(TagName.find_by!(language_code: 'ja', name: 'spec_tag'))
|
||||
.to have_attributes(tag_id: tag.id, primary_flg: false)
|
||||
expect(TagName.where(tag_id: old_owner.id, language_code: 'ja',
|
||||
primary_flg: false).pluck(:name))
|
||||
.not_to include('put_alias_collision_name')
|
||||
|
||||
old_owner_versions = old_owner.tag_versions.order(:version_no)
|
||||
|
||||
|
||||
@@ -40,17 +40,16 @@ RSpec.describe PostCreatePlan do
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english = create(:tag, tag_name: english_name, category: :character)
|
||||
japanese_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
canonical: japanese.tag_name)
|
||||
english_alias = create(:tag_name, :alias, name: 'temporary_alias',
|
||||
canonical: english_name,
|
||||
tag: japanese)
|
||||
english_alias = create(:tag_name, :alias, name: 'shared_alias',
|
||||
tag: english,
|
||||
language_code: 'en', script_code: 'Latn')
|
||||
english_alias.update_columns(name: 'shared_alias')
|
||||
|
||||
expect(japanese_alias.reload).to have_attributes(
|
||||
canonical_id: japanese.tag_name_id, tag_id: japanese.id,
|
||||
tag_id: japanese.id,
|
||||
primary_flg: false, language_code: 'ja')
|
||||
expect(english_alias.reload).to have_attributes(
|
||||
canonical_id: english_name.id, tag_id: english.id,
|
||||
tag_id: english.id,
|
||||
primary_flg: false, language_code: 'en')
|
||||
|
||||
plan = described_class.new(attributes: { tags: 'shared_alias' }).build!(locale)
|
||||
@@ -79,9 +78,9 @@ RSpec.describe PostCreatePlan do
|
||||
expect([TagName.count, Tag.count]).to eq(counts)
|
||||
end
|
||||
|
||||
it 'resolves aliases and keeps tag sections separate from canonical names' do
|
||||
canonical = create_tag!('虹夏', :character)
|
||||
create(:tag_name, :alias, name: 'にじか', canonical: canonical.tag_name)
|
||||
it 'resolves aliases and keeps tag sections separate from primary names' do
|
||||
tag = create_tag!('虹夏', :character)
|
||||
create(:tag_name, :alias, name: 'にじか', tag:)
|
||||
create_tag!('動画', :meta)
|
||||
|
||||
plan = described_class.new(
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする