diff --git a/app/controllers/playlists_controller.rb b/app/controllers/playlists_controller.rb index afa5bb0f5c..3ab05bac04 100644 --- a/app/controllers/playlists_controller.rb +++ b/app/controllers/playlists_controller.rb @@ -125,18 +125,15 @@ def create def duplicate old_playlist = Playlist.find(params['old_playlist_id']) unless can? :duplicate, old_playlist - render json: {errors: 'You do not have sufficient privileges to copy this item'}, status: 401 and return + render json: { errors: 'You do not have sufficient privileges to copy this item' }, status: 401 and return end @playlist = Playlist.new(playlist_params.merge(user: current_user)) if @playlist.save - #copy items + # copy items old_playlist.items.each do |item| next if item.clip.master_file.nil? - copy_item = item.duplicate! - copy_item.playlist_id = @playlist.id - copy_item.save! - copy_item.move_to_bottom + item.duplicate!(to_playlist: @playlist) end respond_to do |format| @@ -147,7 +144,7 @@ def duplicate else respond_to do |format| format.json do - render json: {errors: @playlist.errors} + render json: { errors: @playlist.errors } end end end @@ -187,12 +184,12 @@ def update_multiple playlist_items = PlaylistItem.where(id: params[:clip_ids]) playlist_items.each do |item| next if item.clip.master_file.nil? - if (params[:action_type] == 'copy_to_playlist') - item = item.duplicate! + if params[:action_type] == 'copy_to_playlist' + item.duplicate!(to_playlist: @new_playlist) + else + item.playlist_id = @new_playlist.id + item.save! end - item.playlist_id = @new_playlist.id - item.save! - item.move_to_bottom end @playlist.save! @new_playlist.save! @@ -307,31 +304,31 @@ def reorder_items(playlist) changed_playlist, new, changed_position, unchanged = playlist.items. sort_by(&:position). group_by do |item| - if item.playlist_id_was != item.playlist_id - :changed_playlist - elsif item.position_was.nil? - :new - elsif item.position_was != item.position - :changed_position - else - :unchanged - end + if item.playlist_id_was != item.playlist_id + :changed_playlist + elsif item.position_was.nil? + :new + elsif item.position_was != item.position + :changed_position + else + :unchanged + end end.values_at(:changed_playlist, :new, :changed_position, :unchanged).map(&:to_a) # items that will be in this playlist unmoved_items = unchanged # place items whose positions were specified - changed_position.map {|item| unmoved_items.insert(item.position - 1, item)} + changed_position.map { |item| unmoved_items.insert(item.position - 1, item) } # add new items at the end - unmoved_items = unmoved_items + new + unmoved_items += new # calculate positions unmoved_items.compact. - select {|item| item.playlist_id_was == item.playlist_id}. + select { |item| item.playlist_id_was == item.playlist_id }. each_with_index do |item, position| - item.position = position + 1 - end + item.position = position + 1 + end # items that have moved to another playlist - changed_playlist.select {|item| item.playlist_id_was != item.playlist_id}.each do |item| + changed_playlist.select { |item| item.playlist_id_was != item.playlist_id }.each do |item| item.position = nil end end diff --git a/app/models/playlist_item.rb b/app/models/playlist_item.rb index b8bcf162b5..04ebebd1ac 100644 --- a/app/models/playlist_item.rb +++ b/app/models/playlist_item.rb @@ -27,12 +27,12 @@ class PlaylistItem < ActiveRecord::Base clip.save end - def duplicate! + def duplicate!(to_playlist: nil) return nil if clip.master_file.nil? new_clip = clip.dup new_clip.save! - new_playlist_item = PlaylistItem.create(playlist: playlist, clip: new_clip) + new_playlist_item = PlaylistItem.create(playlist: to_playlist || playlist, clip: new_clip) marker.each do |old_marker| new_marker = old_marker.dup diff --git a/spec/controllers/playlists_controller_spec.rb b/spec/controllers/playlists_controller_spec.rb index bc0033f84e..7d349468cc 100644 --- a/spec/controllers/playlists_controller_spec.rb +++ b/spec/controllers/playlists_controller_spec.rb @@ -268,340 +268,360 @@ end context 'non-blank playlist' do - let(:media_object) { FactoryBot.create(:media_object, visibility: 'public') } let!(:video_master_file) { FactoryBot.create(:master_file, media_object: media_object, duration: "200000") } - let!(:clip) { AvalonClip.create(master_file: video_master_file, title: Faker::Lorem.word, - comment: Faker::Lorem.sentence, start_time: 1000, end_time: 2000) } + let!(:clip) { AvalonClip.create(master_file: video_master_file, title: Faker::Lorem.word, comment: Faker::Lorem.sentence, start_time: 1000, end_time: 2000) } let!(:playlist_item) { PlaylistItem.create!(playlist: playlist, clip: clip) } - let!(:bookmark) { AvalonMarker.create(playlist_item: playlist_item, master_file: video_master_file, start_time: "200000")} - - it 'duplicate playlist with items' do - post :duplicate, params: { format: 'json', old_playlist_id: playlist.id, playlist: { 'title' => playlist.title, 'comment' => playlist.comment, 'visibility' => playlist.visibility } } - expect(response.body).not_to be_empty - parsed_response = JSON.parse(response.body) + let!(:bookmark) { AvalonMarker.create(playlist_item: playlist_item, master_file: video_master_file, start_time: "200000") } - new_playlist = Playlist.find(parsed_response['playlist']['id']) - expect(new_playlist.items.count).to eq 1 - expect(new_playlist.clips.first.start_time).to eq clip.start_time - expect(new_playlist.clips.first.id).not_to eq clip.id - expect(new_playlist.items.first.id).not_to eq playlist_item.id - expect(new_playlist.items.first.marker.count).to eq 1 + it 'duplicate playlist with items' do + post :duplicate, params: { format: 'json', old_playlist_id: playlist.id, playlist: { 'title' => playlist.title, 'comment' => playlist.comment, 'visibility' => playlist.visibility } } + expect(response.body).not_to be_empty + parsed_response = JSON.parse(response.body) - end + new_playlist = Playlist.find(parsed_response['playlist']['id']) + expect(new_playlist.items.count).to eq 1 + expect(new_playlist.clips.first.start_time).to eq clip.start_time + expect(new_playlist.clips.first.id).not_to eq clip.id + expect(new_playlist.items.first.id).not_to eq playlist_item.id + expect(new_playlist.items.first.marker.count).to eq 1 end end - describe 'PUT #update' do - context 'with valid params' do - let(:new_attributes) do - { title: Faker::Lorem.word, visibility: Playlist::PUBLIC, comment: Faker::Lorem.sentence } - end + context 'playlist with multiple items' do + let(:media_object) { FactoryBot.create(:media_object, visibility: 'public') } + let!(:video_master_file) { FactoryBot.create(:master_file, media_object: media_object, duration: "200000") } + let!(:clip) { AvalonClip.create(master_file: video_master_file, title: Faker::Lorem.word, comment: Faker::Lorem.sentence, start_time: 1000, end_time: 2000) } + let!(:playlist_item) { PlaylistItem.create!(playlist: playlist, clip: clip) } + let!(:bookmark) { AvalonMarker.create(playlist_item: playlist_item, master_file: video_master_file, start_time: "200000") } + let!(:clip_2) { AvalonClip.create(master_file: video_master_file, title: Faker::Lorem.word, comment: Faker::Lorem.sentence, start_time: 1500, end_time: 1750) } + let!(:playlist_item_2) { PlaylistItem.create!(playlist: playlist, clip: clip_2) } + let!(:bookmark_2) { AvalonMarker.create(playlist_item: playlist_item_2, master_file: video_master_file, start_time: "200000") } + + it 'duplicates playlist with items in order' do + expect(playlist.clips.first.start_time).to eq clip.start_time + expect(playlist.clips.second.start_time).to eq clip_2.start_time + post :duplicate, params: { format: 'json', old_playlist_id: playlist.id, playlist: { 'title' => playlist.title, 'comment' => playlist.comment, 'visibility' => playlist.visibility } } + expect(response.body).not_to be_empty + parsed_response = JSON.parse(response.body) - it 'updates the requested playlist' do - playlist = Playlist.create! valid_attributes - put :update, params: { id: playlist.to_param, playlist: new_attributes }, session: valid_session - playlist.reload - expect(playlist.title).to eq new_attributes[:title] - expect(playlist.visibility).to eq new_attributes[:visibility] - expect(playlist.comment).to eq new_attributes[:comment] - end + new_playlist = Playlist.find(parsed_response['playlist']['id']) + expect(new_playlist.items.count).to eq 2 + expect(new_playlist.clips.first.start_time).to eq clip.start_time + expect(new_playlist.clips.second.start_time).to eq clip_2.start_time + end + end + end - it 'assigns the requested playlist as @playlist' do - playlist = Playlist.create! valid_attributes - put :update, params: { id: playlist.to_param, playlist: new_attributes }, session: valid_session - expect(assigns(:playlist)).to eq(playlist) - end + describe 'PUT #update' do + context 'with valid params' do + let(:new_attributes) do + { title: Faker::Lorem.word, visibility: Playlist::PUBLIC, comment: Faker::Lorem.sentence } + end - it 'redirects to edit playlist' do - playlist = Playlist.create! valid_attributes - put :update, params: { id: playlist.to_param, playlist: new_attributes }, session: valid_session - expect(response).to redirect_to(edit_playlist_path(playlist)) - end + it 'updates the requested playlist' do + playlist = Playlist.create! valid_attributes + put :update, params: { id: playlist.to_param, playlist: new_attributes }, session: valid_session + playlist.reload + expect(playlist.title).to eq new_attributes[:title] + expect(playlist.visibility).to eq new_attributes[:visibility] + expect(playlist.comment).to eq new_attributes[:comment] + end - it 'generates a token if visibility is private-with-token' do - playlist = Playlist.create! valid_attributes - put :update, params: { id: playlist.to_param, playlist: { visibility: Playlist::PRIVATE_WITH_TOKEN } }, session: valid_session - playlist.reload - expect(playlist.access_token).not_to be_blank - end + it 'assigns the requested playlist as @playlist' do + playlist = Playlist.create! valid_attributes + put :update, params: { id: playlist.to_param, playlist: new_attributes }, session: valid_session + expect(assigns(:playlist)).to eq(playlist) end - context 'with invalid params' do - it 'assigns the playlist as @playlist' do - playlist = Playlist.create! valid_attributes - put :update, params: { id: playlist.to_param, playlist: invalid_attributes }, session: valid_session - expect(assigns(:playlist)).to eq(playlist) - end + it 'redirects to edit playlist' do + playlist = Playlist.create! valid_attributes + put :update, params: { id: playlist.to_param, playlist: new_attributes }, session: valid_session + expect(response).to redirect_to(edit_playlist_path(playlist)) + end - it "re-renders the 'edit' template" do - playlist = Playlist.create! valid_attributes - put :update, params: { id: playlist.to_param, playlist: invalid_attributes }, session: valid_session - expect(response).to render_template('edit') - end + it 'generates a token if visibility is private-with-token' do + playlist = Playlist.create! valid_attributes + put :update, params: { id: playlist.to_param, playlist: { visibility: Playlist::PRIVATE_WITH_TOKEN } }, session: valid_session + playlist.reload + expect(playlist.access_token).not_to be_blank end end - describe 'PUT #update_multiple' do - before do - login_as :user + context 'with invalid params' do + it 'assigns the playlist as @playlist' do + playlist = Playlist.create! valid_attributes + put :update, params: { id: playlist.to_param, playlist: invalid_attributes }, session: valid_session + expect(assigns(:playlist)).to eq(playlist) end - let!(:playlist) { FactoryBot.create(:playlist, valid_attributes) } - let!(:new_playlist) { FactoryBot.create(:playlist, valid_attributes) } + it "re-renders the 'edit' template" do + playlist = Playlist.create! valid_attributes + put :update, params: { id: playlist.to_param, playlist: invalid_attributes }, session: valid_session + expect(response).to render_template('edit') + end + end + end - let(:media_object) { FactoryBot.create(:media_object, visibility: 'public') } - let!(:video_master_file) { FactoryBot.create(:master_file, media_object: media_object, duration: "200000") } - let!(:clip) { AvalonClip.create(master_file: video_master_file, title: Faker::Lorem.word, - comment: Faker::Lorem.sentence, start_time: 1000, end_time: 2000) } - let!(:playlist_item) { PlaylistItem.create!(playlist: playlist, clip: clip) } - let!(:bookmark) { AvalonMarker.create(playlist_item: playlist_item, master_file: video_master_file, start_time: "200000")} + describe 'PUT #update_multiple' do + before do + login_as :user + end - context 'delete' do + let!(:playlist) { FactoryBot.create(:playlist, valid_attributes) } + let!(:new_playlist) { FactoryBot.create(:playlist, valid_attributes) } - it 'redirects to edit playlist' do - put :update_multiple, params: { id: playlist.to_param, clip_ids: ["1"] }, session: valid_session - expect(response).to redirect_to(edit_playlist_path(playlist)) - end + let(:media_object) { FactoryBot.create(:media_object, visibility: 'public') } + let!(:video_master_file) { FactoryBot.create(:master_file, media_object: media_object, duration: "200000") } + let!(:clip) { AvalonClip.create(master_file: video_master_file, title: Faker::Lorem.word, + comment: Faker::Lorem.sentence, start_time: 1000, end_time: 2000) } + let!(:playlist_item) { PlaylistItem.create!(playlist: playlist, clip: clip) } + let!(:bookmark) { AvalonMarker.create(playlist_item: playlist_item, master_file: video_master_file, start_time: "200000")} - it 'deletes a playlist item' do - playlist.items << playlist_item - expect(playlist.items.count).to eq(1) - expect do - # maybe request headers, run delete to see what gets pushed through. - delete :update_multiple, params: { id: playlist.to_param, clip_ids:[ playlist_item.to_param ] }, session: valid_session - end.to change(playlist.items, :count).by(-1) - end + context 'delete' do + it 'redirects to edit playlist' do + put :update_multiple, params: { id: playlist.to_param, clip_ids: ["1"] }, session: valid_session + expect(response).to redirect_to(edit_playlist_path(playlist)) end - context 'copy_to' do - it 'copys an item from one playlist to another' do - playlist.items << playlist_item - expect(playlist.items.count).to eq(1) - expect do - put :update_multiple, params: { id: playlist.id, clip_ids:[ playlist_item.to_param ], new_playlist_id: new_playlist.id, action_type: 'copy_to_playlist' }, session: valid_session - end.to change(new_playlist.items, :count).by(+1) - expect(playlist.items.count).to eq(1) - end + it 'deletes a playlist item' do + playlist.items << playlist_item + expect(playlist.items.count).to eq(1) + expect do + # maybe request headers, run delete to see what gets pushed through. + delete :update_multiple, params: { id: playlist.to_param, clip_ids:[ playlist_item.to_param ] }, session: valid_session + end.to change(playlist.items, :count).by(-1) end + end - context 'move_to' do - it 'moves an item from one playlist to another' do - playlist.items << playlist_item - expect(playlist.items.count).to eq(1) - expect do - put :update_multiple, params: { id: playlist.id, clip_ids:[ playlist_item.to_param ], new_playlist_id: new_playlist.id, action_type: 'move_to_playlist' }, session: valid_session - end.to change(new_playlist.items, :count).by(+1) - expect(playlist.items.count).to eq(0) - end + context 'copy_to' do + it 'copys an item from one playlist to another' do + playlist.items << playlist_item + expect(playlist.items.count).to eq(1) + expect do + put :update_multiple, params: { id: playlist.id, clip_ids: [playlist_item.to_param], new_playlist_id: new_playlist.id, action_type: 'copy_to_playlist' }, session: valid_session + end.to change(new_playlist.items, :count).by(+1) + expect(playlist.items.count).to eq(1) end end - describe 'DELETE #destroy' do - it 'destroys the requested playlist' do - playlist = Playlist.create! valid_attributes + context 'move_to' do + it 'moves an item from one playlist to another' do + playlist.items << playlist_item + expect(playlist.items.count).to eq(1) expect do - delete :destroy, params: { id: playlist.to_param }, session: valid_session - end.to change(Playlist, :count).by(-1) + put :update_multiple, params: { id: playlist.id, clip_ids: [playlist_item.to_param], new_playlist_id: new_playlist.id, action_type: 'move_to_playlist' }, session: valid_session + end.to change(new_playlist.items, :count).by(+1) + expect(playlist.items.count).to eq(0) end + end + end - it 'redirects to the playlists list' do - playlist = Playlist.create! valid_attributes + describe 'DELETE #destroy' do + it 'destroys the requested playlist' do + playlist = Playlist.create! valid_attributes + expect do delete :destroy, params: { id: playlist.to_param }, session: valid_session - expect(response).to redirect_to(playlists_url) - end + end.to change(Playlist, :count).by(-1) end - describe 'GET #edit' do - it 'assigns the requested playlist as @playlist' do - playlist = Playlist.create! valid_attributes - get :edit, params: { id: playlist.to_param }, session: valid_session - expect(assigns(:playlist)).to eq(playlist) - end + it 'redirects to the playlists list' do + playlist = Playlist.create! valid_attributes + delete :destroy, params: { id: playlist.to_param }, session: valid_session + expect(response).to redirect_to(playlists_url) end + end - context "Conditional Share partials should be rendered" do - render_views - let(:playlist) { FactoryBot.create(:playlist, visibility: Playlist::PUBLIC) } - context "Normal login" do - it "administrators: should include lti and share" do - login_as(:administrator) - get :show, params: { id: playlist.id } - expect(response).to render_template(:_share_resource) - expect(response).to render_template(:_lti_url) - end - it "Playlist owner: should include lti and share" do - login_user playlist.user.user_key - get :show, params: { id: playlist.id } - expect(response).to render_template(:_share_resource) - expect(response).to render_template(:_lti_url) - end - it "others: should include share and NOT lti" do - login_as(:user) - get :show, params: { id: playlist.id } - expect(response).to render_template(:_share_resource) - expect(response).to_not render_template(:_lti_url) - end + describe 'GET #edit' do + it 'assigns the requested playlist as @playlist' do + playlist = Playlist.create! valid_attributes + get :edit, params: { id: playlist.to_param }, session: valid_session + expect(assigns(:playlist)).to eq(playlist) + end + end + + describe "Conditional Share partials should be rendered" do + render_views + let(:playlist) { FactoryBot.create(:playlist, visibility: Playlist::PUBLIC) } + context "Normal login" do + it "administrators: should include lti and share" do + login_as(:administrator) + get :show, params: { id: playlist.id } + expect(response).to render_template(:_share_resource) + expect(response).to render_template(:_lti_url) end - context "LTI login" do - it "administrators/managers/editors: should include lti and share" do - login_lti 'administrator' - lti_group = @controller.user_session[:virtual_groups].first - get :show, params: { id: playlist.id } - expect(response).to render_template(:_share_resource) - expect(response).to render_template(:_lti_url) - end - it "others: should include only lti" do - login_lti 'user' - lti_group = @controller.user_session[:virtual_groups].first - get :show, params: { id: playlist.id } - expect(response).to_not render_template(:_share_resource) - expect(response).to render_template(:_lti_url) - end + it "Playlist owner: should include lti and share" do + login_user playlist.user.user_key + get :show, params: { id: playlist.id } + expect(response).to render_template(:_share_resource) + expect(response).to render_template(:_lti_url) end - context "No share tabs rendered" do - before do - @original_conditional_partials = controller.class.conditional_partials.deep_dup - controller.class.conditional_partials[:share].each {|partial_name, conditions| conditions[:if] = false } - end - after do - controller.class.conditional_partials = @original_conditional_partials - end - it "should not render Share button" do - # allow(@controller).to receive(:evaluate_if_unless_configuration).and_return false - # allow(@controller).to receive(:is_editor_or_not_lti).and_return false - expect(response).to_not render_template(:_share) - end + it "others: should include share and NOT lti" do + login_as(:user) + get :show, params: { id: playlist.id } + expect(response).to render_template(:_share_resource) + expect(response).to_not render_template(:_lti_url) end - context "No LTI configuration" do - around do |example| - providers = Avalon::Authentication::Providers - Avalon::Authentication::Providers = Avalon::Authentication::Providers.reject{|p| p[:provider] == :lti} - example.run - Avalon::Authentication::Providers = providers - end - it "should not include lti" do - login_as(:administrator) - get :show, params: { id: playlist.id } - expect(response).to render_template(:_share_resource) - expect(response).to_not render_template(:_lti_url) - end + end + context "LTI login" do + it "administrators/managers/editors: should include lti and share" do + login_lti 'administrator' + lti_group = @controller.user_session[:virtual_groups].first + get :show, params: { id: playlist.id } + expect(response).to render_template(:_share_resource) + expect(response).to render_template(:_lti_url) + end + it "others: should include only lti" do + login_lti 'user' + lti_group = @controller.user_session[:virtual_groups].first + get :show, params: { id: playlist.id } + expect(response).to_not render_template(:_share_resource) + expect(response).to render_template(:_lti_url) end end - - describe "POST #paged_index" do + context "No share tabs rendered" do before do - login_as :user + @original_conditional_partials = controller.class.conditional_partials.deep_dup + controller.class.conditional_partials[:share].each {|partial_name, conditions| conditions[:if] = false } end - before :each do - FactoryBot.reload - FactoryBot.create(:playlist, title: "aardvark", user: user) - FactoryBot.create_list(:playlist, 9, title: 'bbbbb', user: user) - FactoryBot.create(:playlist, title: "zzzebra", user: user) + after do + controller.class.conditional_partials = @original_conditional_partials end - - it 'returns all results' do - post :paged_index, format: 'json', session: valid_session - parsed_response = JSON.parse(response.body) - expect(parsed_response['recordsTotal']).to eq(11) - expect(parsed_response['data'].count).to eq(11) + it "should not render Share button" do + # allow(@controller).to receive(:evaluate_if_unless_configuration).and_return false + # allow(@controller).to receive(:is_editor_or_not_lti).and_return false + expect(response).to_not render_template(:_share) end end + context "No LTI configuration" do + around do |example| + providers = Avalon::Authentication::Providers + Avalon::Authentication::Providers = Avalon::Authentication::Providers.reject{|p| p[:provider] == :lti} + example.run + Avalon::Authentication::Providers = providers + end + it "should not include lti" do + login_as(:administrator) + get :show, params: { id: playlist.id } + expect(response).to render_template(:_share_resource) + expect(response).to_not render_template(:_lti_url) + end + end + end + + describe "POST #paged_index" do + before do + login_as :user + end + before :each do + FactoryBot.reload + FactoryBot.create(:playlist, title: "aardvark", user: user) + FactoryBot.create_list(:playlist, 9, title: 'bbbbb', user: user) + FactoryBot.create(:playlist, title: "zzzebra", user: user) + end - describe "GET #manifest" do - let(:playlist) { FactoryBot.create(:playlist, items: [playlist_item, playlist_item_2], visibility: Playlist::PUBLIC) } - let(:playlist_item) { FactoryBot.create(:playlist_item, clip: clip) } - let(:playlist_item_2) { FactoryBot.create(:playlist_item, clip: clip) } - let(:clip) { FactoryBot.create(:avalon_clip, master_file: master_file) } - let(:master_file) { FactoryBot.create(:master_file, :with_derivative, media_object: media_object) } - let(:media_object) { FactoryBot.create(:published_media_object, visibility: 'public') } + it 'returns all results' do + post :paged_index, format: 'json', session: valid_session + parsed_response = JSON.parse(response.body) + expect(parsed_response['recordsTotal']).to eq(11) + expect(parsed_response['data'].count).to eq(11) + end + end - it "returns a IIIF manifest" do + describe "GET #manifest" do + let(:playlist) { FactoryBot.create(:playlist, items: [playlist_item, playlist_item_2], visibility: Playlist::PUBLIC) } + let(:playlist_item) { FactoryBot.create(:playlist_item, clip: clip) } + let(:playlist_item_2) { FactoryBot.create(:playlist_item, clip: clip) } + let(:clip) { FactoryBot.create(:avalon_clip, master_file: master_file) } + let(:master_file) { FactoryBot.create(:master_file, :with_derivative, media_object: media_object) } + let(:media_object) { FactoryBot.create(:published_media_object, visibility: 'public') } + + it "returns a IIIF manifest" do + get :manifest, format: 'json', params: { id: playlist.id }, session: valid_session + expect(response).to have_http_status(200) + parsed_response = JSON.parse(response.body) + expect(parsed_response['@context']).to include "http://iiif.io/api/presentation/3/context.json" + expect(parsed_response['type']).to eq 'Manifest' + expect(parsed_response['items']).not_to be_empty + end + + context "playlist item" do + it "contains metadata about the playlist item's parent media obejct" do get :manifest, format: 'json', params: { id: playlist.id }, session: valid_session - expect(response).to have_http_status(200) parsed_response = JSON.parse(response.body) - expect(parsed_response['@context']).to include "http://iiif.io/api/presentation/3/context.json" - expect(parsed_response['type']).to eq 'Manifest' - expect(parsed_response['items']).not_to be_empty + expect(parsed_response['items'][0]['metadata']).to be_present end - context "playlist item" do - it "contains metadata about the playlist item's parent media obejct" do - get :manifest, format: 'json', params: { id: playlist.id }, session: valid_session - parsed_response = JSON.parse(response.body) - expect(parsed_response['items'][0]['metadata']).to be_present - end - - it "contains a homepage with the playlist item's positional URL" do - get :manifest, format: 'json', params:{ id: playlist.id }, session: valid_session - parsed_response = JSON.parse(response.body) - expect(parsed_response['items'][0]['homepage']).to be_present - expect(parsed_response['items'][0]['homepage'][0]['id']).to eq "#{Rails.application.routes.url_helpers.playlist_url(playlist.id)}?position=1" - expect(parsed_response['items'][1]['homepage']).to be_present - expect(parsed_response['items'][1]['homepage'][0]['id']).to eq "#{Rails.application.routes.url_helpers.playlist_url(playlist.id)}?position=2" - end - - context "with deleted source" do - before do - master_file.delete - end - - it "returns a blank canvas" do - get :manifest, format: 'json', params: { id: playlist.id }, session: valid_session - parsed_response = JSON.parse(response.body) - expect(parsed_response['items'][0]['items'][0].keys).to include 'items' - expect(parsed_response['items'][0]['items'][0]['items']).to be_empty - end - end + it "contains a homepage with the playlist item's positional URL" do + get :manifest, format: 'json', params:{ id: playlist.id }, session: valid_session + parsed_response = JSON.parse(response.body) + expect(parsed_response['items'][0]['homepage']).to be_present + expect(parsed_response['items'][0]['homepage'][0]['id']).to eq "#{Rails.application.routes.url_helpers.playlist_url(playlist.id)}?position=1" + expect(parsed_response['items'][1]['homepage']).to be_present + expect(parsed_response['items'][1]['homepage'][0]['id']).to eq "#{Rails.application.routes.url_helpers.playlist_url(playlist.id)}?position=2" end - context "playlist item auth" do - let(:playlist_item_2) { FactoryBot.create(:playlist_item, clip: clip_2) } - let(:clip_2) { FactoryBot.create(:avalon_clip, master_file: master_file_2) } - let(:master_file_2) { FactoryBot.create(:master_file, :with_derivative, media_object: media_object_2) } - let(:media_object_2) { FactoryBot.create(:published_media_object, visibility: 'restricted') } + context "with deleted source" do + before do + master_file.delete + end - it "returns populated canvas for public item and blank canvas for restricted item" do + it "returns a blank canvas" do get :manifest, format: 'json', params: { id: playlist.id }, session: valid_session parsed_response = JSON.parse(response.body) - expect(parsed_response['items'].length).to eq 2 expect(parsed_response['items'][0]['items'][0].keys).to include 'items' - expect(parsed_response['items'][1]['items'][0].keys).to include 'items' - expect(parsed_response['items'][1]['items'][0]['items']).to be_empty + expect(parsed_response['items'][0]['items'][0]['items']).to be_empty end end + end - context "when playlist is empty" do - let(:playlist) { FactoryBot.create(:playlist, items: [], visibility: Playlist::PUBLIC) } + context "playlist item auth" do + let(:playlist_item_2) { FactoryBot.create(:playlist_item, clip: clip_2) } + let(:clip_2) { FactoryBot.create(:avalon_clip, master_file: master_file_2) } + let(:master_file_2) { FactoryBot.create(:master_file, :with_derivative, media_object: media_object_2) } + let(:media_object_2) { FactoryBot.create(:published_media_object, visibility: 'restricted') } - it "returns a IIIF manifest" do - get :manifest, format: 'json', params: { id: playlist.id }, session: valid_session - expect(response).to have_http_status(200) - parsed_response = JSON.parse(response.body) - expect(parsed_response['@context']).to include "http://iiif.io/api/presentation/3/context.json" - expect(parsed_response['type']).to eq 'Manifest' - expect(parsed_response['items']).to be_empty - end + it "returns populated canvas for public item and blank canvas for restricted item" do + get :manifest, format: 'json', params: { id: playlist.id }, session: valid_session + parsed_response = JSON.parse(response.body) + expect(parsed_response['items'].length).to eq 2 + expect(parsed_response['items'][0]['items'][0].keys).to include 'items' + expect(parsed_response['items'][1]['items'][0].keys).to include 'items' + expect(parsed_response['items'][1]['items'][0]['items']).to be_empty end + end - context "when playlist owner" do - before do - login_user playlist.user.user_key - end + context "when playlist is empty" do + let(:playlist) { FactoryBot.create(:playlist, items: [], visibility: Playlist::PUBLIC) } - it "includes the marker annotation service definition" do - get :manifest, format: 'json', params: { id: playlist.id }, session: valid_session - parsed_response = JSON.parse(response.body) - expect(parsed_response["service"]).to be_present - end + it "returns a IIIF manifest" do + get :manifest, format: 'json', params: { id: playlist.id }, session: valid_session + expect(response).to have_http_status(200) + parsed_response = JSON.parse(response.body) + expect(parsed_response['@context']).to include "http://iiif.io/api/presentation/3/context.json" + expect(parsed_response['type']).to eq 'Manifest' + expect(parsed_response['items']).to be_empty end + end - context "when not playlist owner" do - it "does not include the marker annotation service definition" do - get :manifest, format: 'json', params: { id: playlist.id }, session: valid_session - parsed_response = JSON.parse(response.body) - expect(parsed_response["service"]).not_to be_present - end + context "when playlist owner" do + before do + login_user playlist.user.user_key + end + + it "includes the marker annotation service definition" do + get :manifest, format: 'json', params: { id: playlist.id }, session: valid_session + parsed_response = JSON.parse(response.body) + expect(parsed_response["service"]).to be_present + end + end + + context "when not playlist owner" do + it "does not include the marker annotation service definition" do + get :manifest, format: 'json', params: { id: playlist.id }, session: valid_session + parsed_response = JSON.parse(response.body) + expect(parsed_response["service"]).not_to be_present end end end +end diff --git a/spec/models/playlist_item_spec.rb b/spec/models/playlist_item_spec.rb index 238d96db06..37a7186397 100644 --- a/spec/models/playlist_item_spec.rb +++ b/spec/models/playlist_item_spec.rb @@ -112,5 +112,18 @@ expect(new_item.clip_id).not_to eq playlist_item.clip_id expect(new_item.persisted?).to eq true end + + context 'copying to a new playlist' do + let(:new_playlist) { FactoryBot.create(:playlist, visibility: Playlist::PUBLIC) } + + it 'assigns the duplicated item to the proper playlist' do + new_item = playlist_item.duplicate!(to_playlist: new_playlist) + expect(new_item.id).not_to eq playlist_item.id + expect(new_item.playlist_id).not_to eq playlist_item.playlist_id + expect(new_item.playlist_id).to eq new_playlist.id + expect(new_item.clip_id).not_to eq playlist_item.clip_id + expect(new_item.persisted?).to eq true + end + end end end