このコミットが含まれているのは:
2026-06-26 01:20:30 +09:00
コミット d7b136c198
9個のファイルの変更407行の追加154行の削除
+76 -52
ファイルの表示
@@ -64,27 +64,36 @@ RSpec.describe 'Materials API', type: :request do
'name' => 'material_index_b',
'category' => 'material'
)
expect(row['created_by_user']).to include(
'id' => member_user.id,
'name' => member_user.name
)
expect(row['content_type']).to eq('image/png')
expect(row['media_kind']).to eq('image')
end
it 'filters materials by tag_id' do
get '/materials', params: { tag_id: material_a.tag_id }
it 'filters materials by q' do
get '/materials', params: { q: 'material_index_a' }
expect(response).to have_http_status(:ok)
expect(json['count']).to eq(1)
expect(response_materials.map { |m| m['id'] }).to eq([material_a.id])
end
it 'filters materials by parent_id' do
get '/materials', params: { parent_id: material_a.id }
it 'filters materials by tag_state' do
untagged =
build_material(tag: nil, user: member_user,
file: dummy_upload(filename: 'untagged.png'))
get '/materials', params: { tag_state: 'untagged' }
expect(response).to have_http_status(:ok)
expect(json['count']).to eq(1)
expect(response_materials.map { |m| m['id'] }).to eq([material_b.id])
expect(response_materials.map { |m| m['id'] }).to eq([untagged.id])
end
it 'filters materials by media_kind' do
get '/materials', params: { media_kind: 'image' }
expect(response).to have_http_status(:ok)
expect(json['count']).to eq(2)
expect(response_materials.map { |m| m['media_kind'] }).to all(eq('image'))
end
it 'paginates and keeps total count' do
@@ -528,9 +537,8 @@ RSpec.describe 'Materials API', type: :request do
expect(response.body.b).not_to include('素材/b.png'.b)
end
it 'does not include suppressed materials' do
material_b.update!(file_suppressed_at: Time.current,
file_suppression_reason: 'copyright_high_risk')
it 'does not include disabled export items' do
material_b.material_export_items.first.update!(enabled: false)
get '/materials/download.zip', params: { profile: 'legacy_drive' }
@@ -540,62 +548,78 @@ RSpec.describe 'Materials API', type: :request do
end
end
describe 'PATCH /materials/:id/suppress_file' do
describe 'GET /materials/versions' do
let!(:tag) do
Tag.create!(tag_name: TagName.create!(name: 'material_suppress'), category: :material)
Tag.create!(tag_name: TagName.create!(name: 'material_history'), category: :material)
end
let!(:material) do
build_material(tag:, user: member_user, file: dummy_upload(filename: 'suppress.png'))
build_material(tag:, user: member_user, file: dummy_upload(filename: 'history.png'))
end
it 'allows admin to suppress a file and records a suppress version' do
sign_in_as(admin_user)
it 'returns material versions in reverse chronological order' do
MaterialVersionRecorder.record!(material:, event_type: :create,
created_by_user: member_user)
material.update!(url: 'https://example.com/history')
MaterialVersionRecorder.record!(material:, event_type: :update,
created_by_user: admin_user)
get '/materials/versions', params: { material_id: material.id }
expect(response).to have_http_status(:ok)
expect(json['count']).to eq(2)
versions = json.fetch('versions')
expect(versions.map { |v| v['version_no'] }).to eq([2, 1])
expect(versions.first).to include(
'material_id' => material.id,
'event_type' => 'update',
'tag_name' => 'material_history',
'file_filename' => 'history.png',
'url' => 'https://example.com/history'
)
expect(versions.first['created_by_user']).to include('id' => admin_user.id)
end
it 'filters material versions by tag and event_type' do
MaterialVersionRecorder.record!(material:, event_type: :create,
created_by_user: member_user)
expect do
patch "/materials/#{ material.id }/suppress_file",
params: { reason: 'copyright_high_risk' }
end.to change(MaterialVersion, :count).by(1)
get '/materials/versions', params: {
tag: 'material_history',
event_type: 'create'
}
expect(response).to have_http_status(:ok)
expect(json.fetch('versions').map { |v| v['material_id'] }).to include(material.id)
expect(json.fetch('versions').map { |v| v['event_type'] }).to all(eq('create'))
end
end
material.reload
expect(material.file_suppressed_at).to be_present
expect(material.file_suppressed_by_user).to eq(admin_user)
expect(material.file_suppression_reason).to eq('copyright_high_risk')
expect(material.material_versions.order(:version_no).last.event_type).to eq('suppress')
expect(json['file']).to be_nil
expect(json['file_suppressed_at']).to be_present
describe 'material sync suppressions' do
it 'requires member permission for index' do
sign_out
get '/materials/suppressions'
expect(response).to have_http_status(:unauthorized)
end
it 'purges blob when purge=true is requested' do
sign_in_as(admin_user)
old_blob_id = material.file.blob.id
MaterialVersionRecorder.record!(material:, event_type: :create,
created_by_user: member_user)
expect do
patch "/materials/#{ material.id }/suppress_file",
params: { reason: 'copyright_takedown', purge: '1' }
end.to have_enqueued_job(ActiveStorage::PurgeJob)
expect(response).to have_http_status(:ok)
version = material.material_versions.order(:version_no).last
expect(version.event_type).to eq('suppress')
expect(version.file_blob_id).to eq(old_blob_id)
expect(version.file_filename).to eq('suppress.png')
expect(version.file_sha256).to be_present
end
it 'rejects member suppression' do
it 'creates source suppression as member' do
sign_in_as(member_user)
patch "/materials/#{ material.id }/suppress_file",
params: { reason: 'copyright_high_risk' }
expect do
post '/materials/suppressions', params: {
source_kind: 'google_drive_path_prefix',
drive_path: '伊地知ニジカ/危険素材',
reason: 'copyright_high_risk'
}
end.to change(MaterialSyncSuppression, :count).by(1)
expect(response).to have_http_status(:forbidden)
expect(response).to have_http_status(:created)
expect(json).to include(
'source_kind' => 'google_drive_path_prefix',
'drive_path' => '伊地知ニジカ/危険素材',
'normalized_source_key' => 'google_drive_path_prefix:伊地知ニジカ/危険素材'
)
end
end