diff --git a/backend/app/controllers/tags_controller.rb b/backend/app/controllers/tags_controller.rb index e689891..dae8994 100644 --- a/backend/app/controllers/tags_controller.rb +++ b/backend/app/controllers/tags_controller.rb @@ -265,14 +265,17 @@ class TagsController < ApplicationController end def show - tag = Tag.joins(:tag_name) - .includes(:tag_name, :materials, tag_name: :wiki_page) - .find_by(id: params[:id]) - if tag - render json: TagRepr.base(tag) - else - head :not_found - end + tag = + Tag + .joins(:tag_name) + .includes(:tag_name, :materials, tag_name: :wiki_page) + .find_by(id: params[:id]) + return render json: TagRepr.base(tag) if tag + + external_tag = ExternalTag.find_by(id: params[:id]) + return render json: ExternalTagRepr.base(external_tag) if external_tag + + head :not_found end def show_by_name diff --git a/backend/lib/tasks/sync_nico.rake b/backend/lib/tasks/sync_nico.rake index d5a4bdb..db386a3 100644 --- a/backend/lib/tasks/sync_nico.rake +++ b/backend/lib/tasks/sync_nico.rake @@ -143,7 +143,7 @@ namespace :nico do desired_tag_ids = kept_tag_ids.to_a datum['tags'].each do |raw| - name = TagNameSanitisationRule.sanitise(raw) + name = TagNameSanitisationRule.sanitise("nico:#{ raw }").delete_prefix('nico:') tag = ExternalTag.find_or_create_by!(platform: :nico, name:) unless tag.nico_tag_versions.exists? diff --git a/backend/spec/requests/tags_spec.rb b/backend/spec/requests/tags_spec.rb index c9c36fe..b7232da 100644 --- a/backend/spec/requests/tags_spec.rb +++ b/backend/spec/requests/tags_spec.rb @@ -379,6 +379,37 @@ RSpec.describe 'Tags API', type: :request do expect(response).to have_http_status(:not_found) end end + + it 'falls back to ExternalTag when no internal Tag has the id' do + external = create( + :external_tag, + id: Tag.maximum(:id).to_i + 10_000, + name: 'legacy_id_lookup') + + get "/tags/#{ external.id }" + + expect(response).to have_http_status(:ok) + expect(json).to include( + 'id' => external.id, + 'name' => 'nico:legacy_id_lookup', + 'category' => 'nico') + end + + it 'prefers Tag when Tag and ExternalTag have the same id' do + internal = create(:tag, name: 'internal_collision') + create( + :external_tag, + id: internal.id, + name: 'external_collision') + + get "/tags/#{ internal.id }" + + expect(response).to have_http_status(:ok) + expect(json).to include( + 'id' => internal.id, + 'name' => 'internal_collision') + expect(json.fetch('category')).not_to eq('nico') + end end describe 'GET /tags/autocomplete' do diff --git a/backend/spec/tasks/nico_sync_spec.rb b/backend/spec/tasks/nico_sync_spec.rb index 3788917..b3c053f 100644 --- a/backend/spec/tasks/nico_sync_spec.rb +++ b/backend/spec/tasks/nico_sync_spec.rb @@ -16,8 +16,17 @@ RSpec.describe 'nico:sync' do end def create_nico_sanitisation_rules! - TagNameSanitisationRule.create!(priority: 20, source_pattern: '\\?', replacement: '_') - TagNameSanitisationRule.create!(priority: 40, source_pattern: '_$', replacement: '') + 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 @@ -573,6 +582,7 @@ RSpec.describe 'nico:sync' do it 'nico: prefix を含む従来の規則で外部タグ名をサニタイズする' do post = create_nico_sync_post! + create_nico_sanitisation_rules! run_nico_sync_with_tags!(['foo:_bar'])