diff --git a/app/controllers/api/lessons_controller.rb b/app/controllers/api/lessons_controller.rb index 305b2a632..a992d63f8 100644 --- a/app/controllers/api/lessons_controller.rb +++ b/app/controllers/api/lessons_controller.rb @@ -10,7 +10,10 @@ def index archive_scope = params[:include_archived] == 'true' ? Lesson : Lesson.unarchived scope = params[:school_class_id] ? archive_scope.where(school_class_id: params[:school_class_id]) : archive_scope ordered_scope = scope.order(created_at: :asc) - @lessons_with_users = ordered_scope.accessible_by(current_ability).with_users + accessible_lessons = ordered_scope.accessible_by(current_ability) + lessons_with_users = accessible_lessons.with_users + remixes = user_remixes(accessible_lessons) + @lessons_with_users_and_remixes = lessons_with_users.zip(remixes) render :index, formats: [:json], status: :ok end @@ -74,6 +77,22 @@ def verify_school_class_belongs_to_school raise ParameterError, 'school_class_id does not correspond to school_id' end + def user_remixes(lessons) + lessons.map do |lesson| + next nil unless lesson&.project&.remixes&.any? + + user_remix(lesson) + end + end + + def user_remix(lesson) + lesson.project&.remixes + &.where(user_id: current_user.id) + &.accessible_by(current_ability) + &.order(created_at: :asc) + &.first + end + def lesson_params base_params.merge(user_id: current_user.id) end diff --git a/app/controllers/api/projects/remixes_controller.rb b/app/controllers/api/projects/remixes_controller.rb index c1e784a89..222279f7e 100644 --- a/app/controllers/api/projects/remixes_controller.rb +++ b/app/controllers/api/projects/remixes_controller.rb @@ -5,7 +5,7 @@ module Projects class RemixesController < ApiController before_action :authorize_user load_and_authorize_resource :school, only: :index - before_action :load_and_authorize_remix, only: %i[show] + before_action :load_and_authorize_remix, only: %i[show show_identifier] def index projects = Project.where(remixed_from_id: project.id).accessible_by(current_ability) @@ -17,6 +17,10 @@ def show render '/api/projects/show', formats: [:json] end + def show_identifier + render json: { identifier: @project.identifier }, status: :ok + end + def create # Ensure we have a fallback value to prevent bad requests remix_origin = request.origin || request.referer diff --git a/app/views/api/lessons/index.json.jbuilder b/app/views/api/lessons/index.json.jbuilder index 74d8d0a43..3f43d4123 100644 --- a/app/views/api/lessons/index.json.jbuilder +++ b/app/views/api/lessons/index.json.jbuilder @@ -1,6 +1,7 @@ # frozen_string_literal: true -json.array!(@lessons_with_users) do |lesson, user| +json.array!(@lessons_with_users_and_remixes) do |lesson_with_user, remix| + lesson, user = lesson_with_user # Destructure the pair json.call( lesson, :id, @@ -26,4 +27,6 @@ json.array!(@lessons_with_users) do |lesson, user| end json.user_name(user&.name) + + json.remix_identifier(remix.identifier) if remix.present? end diff --git a/config/routes.rb b/config/routes.rb index d00374877..32d639474 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -43,7 +43,9 @@ post :submit, on: :member, to: 'school_projects#submit' post :return, on: :member, to: 'school_projects#return' post :complete, on: :member, to: 'school_projects#complete' - resource :remix, only: %i[show create], controller: 'projects/remixes' + resource :remix, only: %i[show create], controller: 'projects/remixes' do + get :identifier, on: :member, to: 'projects/remixes#show_identifier' + end resources :remixes, only: %i[index], controller: 'projects/remixes' resource :images, only: %i[show create], controller: 'projects/images' resources :feedback, only: %i[index create], controller: 'feedback' do diff --git a/spec/features/lesson/listing_lessons_spec.rb b/spec/features/lesson/listing_lessons_spec.rb index 8b5f6cb16..a15d47008 100644 --- a/spec/features/lesson/listing_lessons_spec.rb +++ b/spec/features/lesson/listing_lessons_spec.rb @@ -210,6 +210,17 @@ expect(data.size).to eq(1) end + it "includes the remix identifier when the user has remixed the lesson's project" do + student = create(:student, school:) + authenticated_in_hydra_as(student) + create(:class_student, school_class:, student_id: student.id) + student_project = create(:project, school:, lesson:, parent: lesson.project, user_id: student.id) + + get('/api/lessons', headers:) + data = JSON.parse(response.body, symbolize_names: true) + expect(data.first[:remix_identifier]).to eq(student_project.identifier) + end + it "does not include the lesson when the user is not a school-student within the lesson's class" do student = create(:student, school:) authenticated_in_hydra_as(student) diff --git a/spec/requests/projects/remix_spec.rb b/spec/requests/projects/remix_spec.rb index 6e9c9d676..1443deca5 100644 --- a/spec/requests/projects/remix_spec.rb +++ b/spec/requests/projects/remix_spec.rb @@ -70,6 +70,35 @@ end end + describe('#show_identifier') do + let!(:remixed_project) do + create(:project, remixed_from_id: original_project.id, user_id: authenticated_user.id) + end + + it 'returns success response' do + get("/api/projects/#{original_project.identifier}/remix/identifier", headers:) + expect(response).to have_http_status(:ok) + end + + it 'returns the project identifier' do + get("/api/projects/#{original_project.identifier}/remix/identifier", headers:) + expect(response.parsed_body['identifier']).to eq(remixed_project.identifier) + end + + it 'returns 404 response if invalid project' do + get('/api/projects/no-such-project/remix/identifier', headers:) + expect(response).to have_http_status(:not_found) + end + + it 'returns 404 if no remixed project for user' do + another_user = create(:owner, school:) + authenticated_in_hydra_as(another_user) + + get("/api/projects/#{original_project.identifier}/remix/identifier", headers:) + expect(response).to have_http_status(:not_found) + end + end + describe '#create' do it 'returns success response' do post("/api/projects/#{original_project.identifier}/remix", params: { project: project_params }, headers:) @@ -116,6 +145,13 @@ end end + describe '#show_identifier' do + it 'returns unauthorized' do + get "/api/projects/#{original_project.identifier}/remix/identifier" + expect(response).to have_http_status(:unauthorized) + end + end + describe '#create' do it 'returns unauthorized' do post "/api/projects/#{original_project.identifier}/remix"