**本番 DB のバックアップをかならずすること** Reviewed-on: #420 Co-authored-by: miteruzo <miteruzo@naver.com>
このコミットはプルリクエスト #420 でマージされました。
このコミットが含まれているのは:
@@ -15,6 +15,20 @@ RSpec.describe 'nico:sync' do
|
||||
NicoTagRelation.create!(nico_tag_id: nico_tag.id, tag_id: tag.id)
|
||||
end
|
||||
|
||||
def create_nico_sanitisation_rules!
|
||||
TagNameSanitisationRule.create!(priority: 20,
|
||||
source_pattern: '\\?',
|
||||
replacement: '_')
|
||||
|
||||
TagNameSanitisationRule.create!(priority: 40,
|
||||
source_pattern: '_$',
|
||||
replacement: '')
|
||||
|
||||
TagNameSanitisationRule.create!(priority: 45,
|
||||
source_pattern: '^([^:]+\\:)?_',
|
||||
replacement: '\\1')
|
||||
end
|
||||
|
||||
it '既存 post を見つけて、nico tag と linked tag を追加し、差分が出たら bot を付ける' do
|
||||
# 既存 post(正規表現で拾われるURL)
|
||||
post = Post.create!(
|
||||
@@ -29,7 +43,7 @@ RSpec.describe 'nico:sync' do
|
||||
|
||||
# 追加される linked tag を準備(nico tag に紐付く一般タグ)
|
||||
linked = create_tag!('spec_linked', category: 'general')
|
||||
nico = create_tag!('nico:AAA', category: 'nico')
|
||||
nico = create_external_tag!('AAA')
|
||||
link_nico_to_tag!(nico, linked)
|
||||
|
||||
# bot / tagme は task 内で使うので作っておく(Tag.bot/tagme がある前提)
|
||||
@@ -53,7 +67,7 @@ RSpec.describe 'nico:sync' do
|
||||
active_tag_names = post.tags.joins(:tag_name).pluck('tag_names.name')
|
||||
|
||||
expect(active_tag_names).to include('spec_kept')
|
||||
expect(active_tag_names).to include('nico:AAA')
|
||||
expect(post.external_tags).to contain_exactly(nico)
|
||||
expect(active_tag_names).to include('spec_linked')
|
||||
|
||||
expect(post.original_created_from).to eq(Time.iso8601('2026-01-01T03:34:00Z'))
|
||||
@@ -115,12 +129,12 @@ RSpec.describe 'nico:sync' do
|
||||
)
|
||||
|
||||
# 旧nicoタグ(今回の同期結果に含まれない)
|
||||
old_nico = create_tag!('nico:OLD', category: 'nico')
|
||||
PostTag.create!(post:, tag: old_nico)
|
||||
old_nico = create_external_tag!('OLD')
|
||||
PostExternalTag.create!(post:, external_tag: old_nico)
|
||||
create_post_version_for!(post)
|
||||
|
||||
# 今回は NEW のみ欲しい
|
||||
new_nico = create_tag!('nico:NEW', category: 'nico')
|
||||
new_nico = create_external_tag!('NEW')
|
||||
|
||||
# bot/tagme 念のため
|
||||
Tag.bot
|
||||
@@ -131,23 +145,21 @@ RSpec.describe 'nico:sync' do
|
||||
|
||||
run_rake_task('nico:sync')
|
||||
|
||||
expect(PostTag.exists?(post:, tag: old_nico)).to be(false)
|
||||
expect(PostExternalTag.exists?(post:, external_tag: old_nico)).to be(false)
|
||||
expect(old_nico.reload.post_count).to eq(0)
|
||||
expect(new_nico.reload.post_count).to eq(1)
|
||||
|
||||
versions = post.post_versions.order(:version_no)
|
||||
expect(versions.first.tags_json.map { |item| item.fetch('id') })
|
||||
expect(versions.first.tags_json.filter_map { |item| item['external_tag_id'] })
|
||||
.to include(old_nico.id)
|
||||
expect(versions.last.tags_json.map { |item| item.fetch('id') })
|
||||
expect(versions.last.tags_json.filter_map { |item| item['external_tag_id'] })
|
||||
.to include(new_nico.id)
|
||||
expect(versions.last.tags_json.map { |item| item.fetch('id') })
|
||||
expect(versions.last.tags_json.filter_map { |item| item['external_tag_id'] })
|
||||
.not_to include(old_nico.id)
|
||||
|
||||
# NEW は active にいる
|
||||
post.reload
|
||||
active_names = post.tags.joins(:tag_name).pluck('tag_names.name')
|
||||
expect(active_names).to include('nico:NEW')
|
||||
expect(active_names).not_to include('nico:OLD')
|
||||
expect(post.external_tags).to contain_exactly(new_nico)
|
||||
end
|
||||
|
||||
def snapshot_tags(post)
|
||||
@@ -213,7 +225,7 @@ RSpec.describe 'nico:sync' do
|
||||
create_post_version_for!(post)
|
||||
|
||||
linked = create_tag!('spec_linked', category: 'general')
|
||||
nico = create_tag!('nico:AAA', category: 'nico')
|
||||
nico = create_external_tag!('AAA')
|
||||
link_nico_to_tag!(nico, linked)
|
||||
|
||||
Tag.bot
|
||||
@@ -241,7 +253,7 @@ RSpec.describe 'nico:sync' do
|
||||
end
|
||||
|
||||
it '既存 post に差分が無いときは新しい version を作らない' do
|
||||
nico = create_tag!('nico:AAA', category: 'nico')
|
||||
nico = create_external_tag!('AAA')
|
||||
no_deerjikist = create_tag!('ニジラー情報不詳', category: 'meta')
|
||||
|
||||
post = Post.create!(
|
||||
@@ -252,7 +264,7 @@ RSpec.describe 'nico:sync' do
|
||||
original_created_before: Time.iso8601('2026-01-01T03:35:00Z')
|
||||
)
|
||||
|
||||
PostTag.create!(post: post, tag: nico)
|
||||
PostExternalTag.create!(post:, external_tag: nico)
|
||||
PostTag.create!(post: post, tag: no_deerjikist)
|
||||
create_post_version_for!(post)
|
||||
|
||||
@@ -295,7 +307,7 @@ RSpec.describe 'nico:sync' do
|
||||
run_rake_task('nico:sync')
|
||||
}.to change(NicoTagVersion, :count).by(1)
|
||||
|
||||
nico_tag = Tag.joins(:tag_name).find_by!(tag_names: { name: 'nico:AAA' })
|
||||
nico_tag = ExternalTag.find_by!(platform: :nico, name: 'AAA')
|
||||
version = nico_tag.nico_tag_versions.order(:version_no).last
|
||||
|
||||
expect(version.version_no).to eq(1)
|
||||
@@ -378,4 +390,203 @@ RSpec.describe 'nico:sync' do
|
||||
expect(versions.second.title).to eq('changed title')
|
||||
expect(versions.second.tags).to eq(snapshot_tags(post.reload))
|
||||
end
|
||||
|
||||
def create_external_tag!(name)
|
||||
ExternalTag.create!(platform: :nico, name:)
|
||||
end
|
||||
|
||||
def create_nico_sync_post!
|
||||
post = Post.create!(
|
||||
title: 't',
|
||||
url: 'https://www.nicovideo.jp/watch/sm9',
|
||||
uploaded_user: nil
|
||||
)
|
||||
|
||||
PostTag.create!(post:, tag: Tag.no_deerjikist)
|
||||
|
||||
post
|
||||
end
|
||||
|
||||
def run_nico_sync_with_tags! tags
|
||||
stub_python([{
|
||||
'code' => 'sm9',
|
||||
'title' => 't',
|
||||
'tags' => tags,
|
||||
'user' => nil
|
||||
}])
|
||||
|
||||
allow(URI).to receive(:open).and_return(StringIO.new('<html></html>'))
|
||||
|
||||
run_rake_task('nico:sync')
|
||||
end
|
||||
|
||||
it '外部タグだけの変更では bot を付けず,投稿履歴を記録する' do
|
||||
post = create_nico_sync_post!
|
||||
PostVersionRecorder.record!(post:, event_type: :create, created_by_user: nil)
|
||||
|
||||
expect {
|
||||
run_nico_sync_with_tags!(['raw tag[]', 'raw tag[]'])
|
||||
}.to change(PostVersion, :count).by(1)
|
||||
.and change(ExternalTag, :count).by(1)
|
||||
.and change(PostExternalTag, :count).by(1)
|
||||
.and change(NicoTagVersion, :count).by(1)
|
||||
.and change(TagName, :count).by(0)
|
||||
|
||||
external = post.external_tags.sole
|
||||
expect(external.name).to eq('raw tag[]')
|
||||
expect(post.tags.map(&:name)).not_to include('bot操作')
|
||||
expect(post.post_versions.order(:version_no).last.tags_json)
|
||||
.to include('external_tag_id' => external.id)
|
||||
|
||||
expect {
|
||||
run_nico_sync_with_tags!(['raw tag[]'])
|
||||
}.to change(PostVersion, :count).by(0).and change(NicoTagVersion, :count).by(0)
|
||||
|
||||
expect {
|
||||
run_nico_sync_with_tags!([])
|
||||
}.to change(PostVersion, :count).by(1)
|
||||
expect(post.reload.external_tags).to be_empty
|
||||
expect(post.tags.map(&:name)).not_to include('bot操作')
|
||||
end
|
||||
|
||||
it 'サニタイズ後の既存外部タグを再利用し、その連携タグを記載する' do
|
||||
post = create_nico_sync_post!
|
||||
|
||||
create_nico_sanitisation_rules!
|
||||
|
||||
external_tag = create_external_tag!('AAA')
|
||||
linked_tag = create_tag!('spec_linked', category: :general)
|
||||
link_nico_to_tag!(external_tag, linked_tag)
|
||||
|
||||
expect {
|
||||
run_nico_sync_with_tags!(['AAA?'])
|
||||
}.not_to change(ExternalTag, :count)
|
||||
|
||||
post.reload
|
||||
|
||||
expect(post.external_tags).to contain_exactly(external_tag)
|
||||
expect(post.tags).to include(linked_tag)
|
||||
expect(ExternalTag.exists?(platform: :nico, name: 'AAA?')).to be(false)
|
||||
end
|
||||
|
||||
it '外部タグに差分がない場合,内外マッピングが変はっても連携タグを再評価しない' do
|
||||
post = create_nico_sync_post!
|
||||
|
||||
external_tag = create_external_tag!('AAA')
|
||||
old_linked_tag = create_tag!('spec_old_linked', category: :general)
|
||||
new_linked_tag = create_tag!('spec_new_linked', category: :general)
|
||||
|
||||
relation = link_nico_to_tag!(external_tag, old_linked_tag)
|
||||
|
||||
run_nico_sync_with_tags!(['AAA'])
|
||||
|
||||
expect(post.reload.tags).to include(old_linked_tag)
|
||||
|
||||
# 人手で連携タグを消除する.
|
||||
PostTag.find_by!(post:, tag: old_linked_tag).destroy!
|
||||
|
||||
# 内外マッピングを変更する.
|
||||
relation.destroy!
|
||||
link_nico_to_tag!(external_tag, new_linked_tag)
|
||||
|
||||
# 外部タグ自体には差分が無い.
|
||||
run_nico_sync_with_tags!(['AAA'])
|
||||
|
||||
post.reload
|
||||
|
||||
expect(post.external_tags).to include(external_tag)
|
||||
expect(post.tags).not_to include(old_linked_tag)
|
||||
expect(post.tags).not_to include(new_linked_tag)
|
||||
end
|
||||
|
||||
it '外部タグの消除では連携タグを消除せず,再記載時にその時点の内外マッピングを適用する' do
|
||||
post = create_nico_sync_post!
|
||||
|
||||
external_tag = create_external_tag!('AAA')
|
||||
old_linked_tag = create_tag!('spec_old_linked', category: :general)
|
||||
new_linked_tag = create_tag!('spec_new_linked', category: :general)
|
||||
|
||||
relation = link_nico_to_tag!(external_tag, old_linked_tag)
|
||||
|
||||
# 外部タグを新規記載する.
|
||||
run_nico_sync_with_tags!(['AAA'])
|
||||
|
||||
post.reload
|
||||
expect(post.external_tags).to include(external_tag)
|
||||
expect(post.tags).to include(old_linked_tag)
|
||||
|
||||
# 外部タグを消除する.
|
||||
run_nico_sync_with_tags!([])
|
||||
|
||||
post.reload
|
||||
expect(post.external_tags).not_to include(external_tag)
|
||||
|
||||
# 外部タグの消除によって連携タグまでは消除されない.
|
||||
expect(post.tags).to include(old_linked_tag)
|
||||
|
||||
# 外部タグが記載されてゐない間に内外マッピングを変更する.
|
||||
relation.destroy!
|
||||
link_nico_to_tag!(external_tag, new_linked_tag)
|
||||
|
||||
# 同じ外部タグを再記載する.
|
||||
run_nico_sync_with_tags!(['AAA'])
|
||||
|
||||
post.reload
|
||||
|
||||
expect(post.external_tags).to include(external_tag)
|
||||
|
||||
# 旧連携タグは自動的には消除されない.
|
||||
expect(post.tags).to include(old_linked_tag)
|
||||
|
||||
# 再記載時点の内外マッピングが新たに適用される.
|
||||
expect(post.tags).to include(new_linked_tag)
|
||||
end
|
||||
|
||||
it '外部タグだけの変更では bot を付けず、投稿履歴を記録する' do
|
||||
post = create_nico_sync_post!
|
||||
PostVersionRecorder.record!(post:, event_type: :create, created_by_user: nil)
|
||||
|
||||
create_nico_sanitisation_rules!
|
||||
|
||||
expect {
|
||||
run_nico_sync_with_tags!(['AAA?', 'AAA?'])
|
||||
}.to change(PostVersion, :count).by(1)
|
||||
.and change(ExternalTag, :count).by(1)
|
||||
.and change(PostExternalTag, :count).by(1)
|
||||
.and change(NicoTagVersion, :count).by(1)
|
||||
.and change(TagName, :count).by(0)
|
||||
|
||||
external = post.reload.external_tags.sole
|
||||
|
||||
expect(external).to have_attributes(
|
||||
platform: 'nico',
|
||||
name: 'AAA')
|
||||
expect(ExternalTag.exists?(platform: :nico, name: 'AAA?')).to be(false)
|
||||
|
||||
expect(post.tags.map(&:name)).not_to include('bot操作')
|
||||
expect(post.post_versions.order(:version_no).last.tags_json)
|
||||
.to include('external_tag_id' => external.id)
|
||||
|
||||
expect {
|
||||
run_nico_sync_with_tags!(['AAA?'])
|
||||
}.to change(PostVersion, :count).by(0)
|
||||
.and change(NicoTagVersion, :count).by(0)
|
||||
|
||||
expect {
|
||||
run_nico_sync_with_tags!([])
|
||||
}.to change(PostVersion, :count).by(1)
|
||||
|
||||
expect(post.reload.external_tags).to be_empty
|
||||
expect(post.tags.map(&:name)).not_to include('bot操作')
|
||||
end
|
||||
|
||||
it 'nico: prefix を含む従来の規則で外部タグ名をサニタイズする' do
|
||||
post = create_nico_sync_post!
|
||||
create_nico_sanitisation_rules!
|
||||
|
||||
run_nico_sync_with_tags!(['foo:_bar'])
|
||||
|
||||
expect(post.reload.external_tags.sole)
|
||||
.to have_attributes(platform: 'nico', name: 'foo:_bar')
|
||||
end
|
||||
end
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする