このコミットが含まれているのは:
@@ -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
|
||||
|
||||
|
||||
新しい課題から参照
ユーザをブロックする