require 'rails_helper' RSpec.describe 'Sitemap entries API', type: :request do include_context 'Ainu locale' let(:user) { create(:user, :member) } it 'serves public resource counts with the default locale and page size' do create(:post) create(:tag, primary_name: 'sitemap_count_tag') get '/sitemap_entries' expect(response).to have_http_status(:ok) expect(json.fetch('page_size')).to eq(1_000) counts = json.fetch('resources').to_h { |entry| [entry.fetch('resource'), entry.fetch('count')] } expect(counts).to eq( 'posts' => Post.count, 'tags' => Tag.count, 'deerjikists' => 0, 'materials' => 0, 'descriptions' => 0, 'tag_groups' => 0, 'theatres' => 0) end it 'paginates public post IDs in ascending order without exposing post contents' do stub_const('SitemapEntriesController::PAGE_SIZE', 2) posts = create_list(:post, 3) get '/sitemap_entries/posts' expect(response).to have_http_status(:ok) expect(json).to eq('ids' => posts.first(2).map(&:id)) get '/sitemap_entries/posts', params: { page: 2 } expect(response).to have_http_status(:ok) expect(json).to eq('ids' => [posts.last.id]) get '/sitemap_entries/posts', params: { page: 3 } expect(response).to have_http_status(:not_found) end ['0', '-1', 'invalid', '1.5'].each do |page| it "rejects invalid sitemap page #{ page.inspect }" do get '/sitemap_entries/posts', params: { page: } expect(response).to have_http_status(:bad_request) end end it 'rejects unsupported resource names' do get '/sitemap_entries/users' expect(response).to have_http_status(:not_found) end it 'returns an empty first page for a resource without entries' do get '/sitemap_entries/posts' expect(response).to have_http_status(:ok) expect(json).to eq('ids' => []) end it 'rejects unregistered, deprecated and unsupported locales' do get '/sitemap_entries', params: { locale: 'ain-Kana' } expect(response).to have_http_status(:not_found) locale.update!(deprecated_at: Time.current) ['/sitemap_entries', '/sitemap_entries/posts'].each do |path| get path, params: { locale: 'ain-Kana' } expect(response).to have_http_status(:not_found) get path, params: { locale: 'en' } expect(response).to have_http_status(:not_found) end end it 'only lists live materials and theatres' do material = Material.create!(url: 'https://example.com/sitemap-material') discarded_material = Material.create!(url: 'https://example.com/sitemap-discarded') discarded_material.discard! theatre = create(:theatre) create(:theatre).discard! get '/sitemap_entries/materials' expect(response).to have_http_status(:ok) expect(json).to eq('ids' => [material.id]) get '/sitemap_entries/theatres' expect(response).to have_http_status(:ok) expect(json).to eq('ids' => [theatre.id]) end context 'with an active Ainu locale' do before { locale } it 'uses tag IDs and only includes deerjikists with linked accounts' do tagged = create(:tag, primary_name: 'sitemap_deer', category: :deerjikist) unlinked = create(:tag, primary_name: 'sitemap_unlinked', category: :deerjikist) Deerjikist.create!(tag: tagged, platform: 'youtube', code: 'sitemap-channel') Deerjikist.create!(tag: tagged, platform: 'nico', code: 'sitemap-nico') get '/sitemap_entries/tags', params: { locale: 'ain-Kana' } expect(response).to have_http_status(:ok) expect(json.fetch('ids')).to contain_exactly(tagged.id, unlinked.id) get '/sitemap_entries/deerjikists', params: { locale: 'ain-Kana' } expect(response).to have_http_status(:ok) expect(json).to eq('ids' => [tagged.id]) end it 'lists description IDs for the requested language with a nonempty current version' do tag = create(:tag, primary_name: 'sitemap_description') japanese = TagDescriptionOperation.create!( Locale.nipponese, tag:, body: 'Japanese sitemap body', created_by_user: user) ainu = TagDescriptionOperation.create!( locale, tag:, body: 'Ainu sitemap body', created_by_user: user) unversioned_tag = create(:tag, primary_name: 'sitemap_unversioned') TagDescription.create!(tag: unversioned_tag, language_code: 'ain', body: 'No revision', version_no: 1) empty_tag = create(:tag, primary_name: 'sitemap_empty') # Legacy empty bodies can exist even though the write service rejects them. empty = TagDescription.create!(tag: empty_tag, language_code: 'ain', body: '', version_no: 1) TagDescriptionVersion.create!(tag_id: empty_tag.id, language_code: 'ain', body: '', version_no: 1, event_type: 'create', created_by_user_id: user.id, created_at: Time.current) get '/sitemap_entries/descriptions', params: { locale: 'ain-Kana' } expect(response).to have_http_status(:ok) expect(json).to eq('ids' => [ainu.id]) expect(json.fetch('ids')).not_to include(japanese.id, empty.id) get '/sitemap_entries/descriptions', params: { locale: 'ja' } expect(response).to have_http_status(:ok) expect(json).to eq('ids' => [japanese.id]) get '/sitemap_entries', params: { locale: 'ain-Kana' } expect(response).to have_http_status(:ok) descriptions = json.fetch('resources').find { |entry| entry.fetch('resource') == 'descriptions' } expect(descriptions.fetch('count')).to eq(1) end it 'excludes groups without a revision matching the current version' do group = TagGroupOperation.create!( Locale.nipponese, name: 'Sitemap group', description: 'Group description', members: [], placements: [], actor: user) TagGroup.create!(name: 'Unversioned sitemap group', version_no: 1) get '/sitemap_entries/tag_groups', params: { locale: 'ain-Kana' } expect(response).to have_http_status(:ok) expect(json).to eq('ids' => [group.id]) end end end