Skip to content

Commit fb4832b

Browse files
committed
changing route structure to be one route per status
1 parent f4e2ed5 commit fb4832b

8 files changed

Lines changed: 403 additions & 23 deletions

File tree

app/controllers/api/school_projects_controller.rb

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,42 @@ def show_status
1010
render :show_status, formats: [:json], status: :ok
1111
end
1212

13-
def set_status
14-
authorize! :set_status, school_project
15-
result = SchoolProject::SetStatus.call(school_project:, status: params[:status], user_id: current_user.id)
13+
def unsubmit
14+
authorize! :unsubmit, school_project
15+
result = SchoolProject::SetStatus.call(school_project:, status: 'unsubmitted', user_id: current_user.id)
16+
if result.success?
17+
@school_project = result[:school_project]
18+
render :show_status, formats: [:json], status: :ok
19+
else
20+
render json: { error: result[:error] }, status: :unprocessable_entity
21+
end
22+
end
23+
24+
def submit
25+
authorize! :submit, school_project
26+
result = SchoolProject::SetStatus.call(school_project:, status: 'submitted', user_id: current_user.id)
27+
if result.success?
28+
@school_project = result[:school_project]
29+
render :show_status, formats: [:json], status: :ok
30+
else
31+
render json: { error: result[:error] }, status: :unprocessable_entity
32+
end
33+
end
34+
35+
def return
36+
authorize! :return, school_project
37+
result = SchoolProject::SetStatus.call(school_project:, status: 'returned', user_id: current_user.id)
38+
if result.success?
39+
@school_project = result[:school_project]
40+
render :show_status, formats: [:json], status: :ok
41+
else
42+
render json: { error: result[:error] }, status: :unprocessable_entity
43+
end
44+
end
45+
46+
def complete
47+
authorize! :complete, school_project
48+
result = SchoolProject::SetStatus.call(school_project:, status: 'complete', user_id: current_user.id)
1649
if result.success?
1750
@school_project = result[:school_project]
1851
render :show_status, formats: [:json], status: :ok

app/models/ability.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def define_school_teacher_abilities(user:, school:)
9696
)
9797
).pluck(:id)
9898
can(%i[read], Project, remixed_from_id: teacher_project_ids)
99-
can(%i[show_status set_status], SchoolProject, project: { remixed_from_id: teacher_project_ids })
99+
can(%i[show_status unsubmit return complete], SchoolProject, project: { remixed_from_id: teacher_project_ids })
100100
can(%i[read create], Feedback, school_project: { project: { remixed_from_id: teacher_project_ids } })
101101
end
102102

@@ -114,7 +114,7 @@ def define_school_student_abilities(user:, school:)
114114
can(%i[read create update], Project, school_id: school.id, user_id: user.id, lesson_id: nil, remixed_from_id: visible_lesson_project_ids)
115115
can(%i[read show_context], Project, lesson: { school_id: school.id, visibility: 'students', school_class: { students: { student_id: user.id } } })
116116
can(%i[read], Feedback, school_project: { project: { school_id: school.id, user_id: user.id, lesson_id: nil, remixed_from_id: visible_lesson_project_ids } })
117-
can(%i[show_finished set_finished show_status set_status], SchoolProject, project: { user_id: user.id, lesson_id: nil }, school_id: school.id)
117+
can(%i[show_finished set_finished show_status unsubmit submit], SchoolProject, project: { user_id: user.id, lesson_id: nil }, school_id: school.id)
118118
end
119119

120120
def define_experience_cs_admin_abilities(user)

config/routes.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@
3939
get :context, on: :member, to: 'projects#show_context'
4040
put :finished, on: :member, to: 'school_projects#set_finished'
4141
get :status, on: :member, to: 'school_projects#show_status'
42-
put :status, on: :member, to: 'school_projects#set_status'
42+
post :unsubmit, on: :member, to: 'school_projects#unsubmit'
43+
post :submit, on: :member, to: 'school_projects#submit'
44+
post :return, on: :member, to: 'school_projects#return'
45+
post :complete, on: :member, to: 'school_projects#complete'
4346
resource :remix, only: %i[show create], controller: 'projects/remixes'
4447
resources :remixes, only: %i[index], controller: 'projects/remixes'
4548
resource :images, only: %i[show create], controller: 'projects/images'
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
RSpec.describe 'School project complete requests', type: :request do
6+
let(:headers) { { Authorization: UserProfileMock::TOKEN } }
7+
let(:school) { create(:school) }
8+
let(:student) { create(:student, school:) }
9+
let(:teacher) { create(:teacher, school:) }
10+
let(:school_class) { create(:school_class, teacher_ids: [teacher.id], school:) }
11+
let(:class_student) { create(:class_student, school_class:, student_id: student.id) }
12+
let(:lesson) { create(:lesson, school:, school_class:, user_id: teacher.id) }
13+
let(:teacher_project) { create(:project, user_id: teacher.id, school:, lesson:) }
14+
let!(:student_project) { create(:project, school_id: school.id, lesson_id: nil, user_id: student.id, remixed_from_id: teacher_project.id, locale: nil, finished: false) }
15+
let(:school_project_json) do
16+
{
17+
id: student_project.school_project.id,
18+
school_id: student_project.school_project.school_id,
19+
project_id: student_project.school_project.project_id,
20+
status: student_project.school_project.status,
21+
identifier: student_project.identifier
22+
}.to_json
23+
end
24+
25+
context 'when logged in as student' do
26+
before do
27+
authenticated_in_hydra_as(student)
28+
post("/api/projects/#{student_project.identifier}/complete", headers:)
29+
end
30+
31+
it 'completes forbidden response' do
32+
expect(response).to have_http_status(:forbidden)
33+
end
34+
35+
it 'does not change the status' do
36+
expect(student_project.school_project).to be_unsubmitted
37+
end
38+
end
39+
40+
context 'when logged in as teacher' do
41+
before do
42+
authenticated_in_hydra_as(teacher)
43+
end
44+
45+
context('when transition is valid') do
46+
before do
47+
student_project.school_project.transition_status_to!(:submitted, student.id)
48+
post("/api/projects/#{student_project.identifier}/complete", headers:)
49+
end
50+
51+
it 'completes success response' do
52+
expect(response).to have_http_status(:ok)
53+
end
54+
55+
it 'completes the school project json' do
56+
expect(response.body).to eq(school_project_json)
57+
end
58+
59+
it 'sets the status to complete' do
60+
expect(student_project.school_project).to be_complete
61+
end
62+
end
63+
64+
context 'when attempting an invalid status transition' do
65+
before do
66+
student_project.school_project.transition_status_to!(:complete, student.id)
67+
post("/api/projects/#{student_project.identifier}/complete", headers:)
68+
end
69+
70+
it 'completes unauthorized response' do
71+
expect(response).to have_http_status(:unprocessable_entity)
72+
end
73+
74+
it 'completes error message' do
75+
expect(JSON.parse(response.body)['error']).to eq("Cannot transition from 'complete' to 'complete'")
76+
end
77+
end
78+
end
79+
80+
context 'when user does not own the project and is not the class teacher' do
81+
let(:another_teacher) { create(:teacher, school:) }
82+
83+
before do
84+
authenticated_in_hydra_as(another_teacher)
85+
post("/api/projects/#{student_project.identifier}/complete", headers:)
86+
end
87+
88+
it 'completes forbidden response' do
89+
expect(response).to have_http_status(:forbidden)
90+
end
91+
92+
it 'does not change the status' do
93+
expect(student_project.school_project).to be_unsubmitted
94+
end
95+
end
96+
97+
context 'when project does not exist' do
98+
before do
99+
authenticated_in_hydra_as(student)
100+
post('/api/projects/does-not-exist/complete', headers:)
101+
end
102+
103+
it 'completes not found response' do
104+
expect(response).to have_http_status(:not_found)
105+
end
106+
end
107+
end
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
RSpec.describe 'School project return requests', type: :request do
6+
let(:headers) { { Authorization: UserProfileMock::TOKEN } }
7+
let(:school) { create(:school) }
8+
let(:student) { create(:student, school:) }
9+
let(:teacher) { create(:teacher, school:) }
10+
let(:school_class) { create(:school_class, teacher_ids: [teacher.id], school:) }
11+
let(:class_student) { create(:class_student, school_class:, student_id: student.id) }
12+
let(:lesson) { create(:lesson, school:, school_class:, user_id: teacher.id) }
13+
let(:teacher_project) { create(:project, user_id: teacher.id, school:, lesson:) }
14+
let!(:student_project) { create(:project, school_id: school.id, lesson_id: nil, user_id: student.id, remixed_from_id: teacher_project.id, locale: nil, finished: false) }
15+
let(:school_project_json) do
16+
{
17+
id: student_project.school_project.id,
18+
school_id: student_project.school_project.school_id,
19+
project_id: student_project.school_project.project_id,
20+
status: student_project.school_project.status,
21+
identifier: student_project.identifier
22+
}.to_json
23+
end
24+
25+
context 'when logged in as student' do
26+
before do
27+
authenticated_in_hydra_as(student)
28+
post("/api/projects/#{student_project.identifier}/return", headers:)
29+
end
30+
31+
it 'returns forbidden response' do
32+
expect(response).to have_http_status(:forbidden)
33+
end
34+
35+
it 'does not change the status' do
36+
expect(student_project.school_project).to be_unsubmitted
37+
end
38+
end
39+
40+
context 'when logged in as teacher' do
41+
before do
42+
authenticated_in_hydra_as(teacher)
43+
end
44+
45+
context('when transition is valid') do
46+
before do
47+
student_project.school_project.transition_status_to!(:submitted, student.id)
48+
post("/api/projects/#{student_project.identifier}/return", headers:)
49+
end
50+
51+
it 'returns success response' do
52+
expect(response).to have_http_status(:ok)
53+
end
54+
55+
it 'returns the school project json' do
56+
expect(response.body).to eq(school_project_json)
57+
end
58+
59+
it 'sets the status to returned' do
60+
expect(student_project.school_project).to be_returned
61+
end
62+
end
63+
64+
context 'when attempting an invalid status transition' do
65+
before do
66+
post("/api/projects/#{student_project.identifier}/return", headers:)
67+
end
68+
69+
it 'returns unauthorized response' do
70+
expect(response).to have_http_status(:unprocessable_entity)
71+
end
72+
73+
it 'returns error message' do
74+
expect(JSON.parse(response.body)['error']).to eq("Cannot transition from 'unsubmitted' to 'returned'")
75+
end
76+
77+
it 'does not change the status' do
78+
expect(student_project.school_project).to be_unsubmitted
79+
end
80+
end
81+
end
82+
83+
context 'when user does not own the project and is not the class teacher' do
84+
let(:another_teacher) { create(:teacher, school:) }
85+
86+
before do
87+
authenticated_in_hydra_as(another_teacher)
88+
post("/api/projects/#{student_project.identifier}/return", headers:)
89+
end
90+
91+
it 'returns forbidden response' do
92+
expect(response).to have_http_status(:forbidden)
93+
end
94+
95+
it 'does not change the status' do
96+
expect(student_project.school_project).to be_unsubmitted
97+
end
98+
end
99+
100+
context 'when project does not exist' do
101+
before do
102+
authenticated_in_hydra_as(student)
103+
post('/api/projects/does-not-exist/return', headers:)
104+
end
105+
106+
it 'returns not found response' do
107+
expect(response).to have_http_status(:not_found)
108+
end
109+
end
110+
end

0 commit comments

Comments
 (0)