-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
396 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# frozen_string_literal: true | ||
|
||
class Api::V1::GradesController < Api::V1::BaseController | ||
include ActionView::Helpers::SanitizeHelper | ||
|
||
before_action :authenticate_user! | ||
before_action :load_create_resources, only: %i[create] | ||
before_action :set_grade, only: %i[update destroy] | ||
before_action :check_access | ||
|
||
def create | ||
@grade.user_id = @current_user.id | ||
@grade.grade = grade_params[:grade] | ||
@grade.remarks = sanitize grade_params[:remarks] | ||
|
||
if @grade.save | ||
render json: Api::V1::GradeSerializer.new(@grade), status: :created | ||
else | ||
api_error(status: 422, errors: @grade.errors) | ||
end | ||
end | ||
|
||
def update | ||
@grade.update!(grade_params) | ||
render json: Api::V1::GradeSerializer.new(@grade), status: :accepted | ||
end | ||
|
||
def destroy | ||
@grade.destroy! | ||
render json: {}, status: :no_content | ||
end | ||
|
||
private | ||
|
||
def load_create_resources | ||
@grade = Grade.new( | ||
assignment_id: params[:assignment_id], project_id: params[:project_id] | ||
) | ||
end | ||
|
||
def set_grade | ||
@grade = Grade.find(params[:id]) | ||
end | ||
|
||
def check_access | ||
authorize @grade, :mentor? | ||
end | ||
|
||
def grade_params | ||
params.require(:grade).permit(:grade, :remarks) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# frozen_string_literal: true | ||
|
||
class Api::V1::GradeSerializer | ||
include FastJsonapi::ObjectSerializer | ||
|
||
attributes :grade, :remarks, :created_at, :updated_at | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# frozen_string_literal: true | ||
|
||
class AddUniqueGradeValidation < ActiveRecord::Migration[6.0] | ||
def change | ||
add_index :grades, %i[project_id assignment_id], unique: true | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
# frozen_string_literal: true | ||
|
||
require "rails_helper" | ||
|
||
RSpec.describe Api::V1::GradesController, "#create", type: :request do | ||
describe "create a grade" do | ||
let!(:mentor) { FactoryBot.create(:user) } | ||
let!(:group) { FactoryBot.create(:group, mentor: mentor) } | ||
let!(:assignment) { FactoryBot.create(:assignment, group: group, grading_scale: :letter) } | ||
let!(:project) { FactoryBot.create(:project, assignment: assignment) } | ||
|
||
context "when not authenticated" do | ||
before do | ||
post "/api/v1/assignments/#{assignment.id}/projects/#{project.id}/grades", as: :json | ||
end | ||
|
||
it "returns status unauthenticated" do | ||
expect(response).to have_http_status(401) | ||
expect(response.parsed_body).to have_jsonapi_errors | ||
end | ||
end | ||
|
||
context "when not authorized to grade assignment" do | ||
before do | ||
token = get_auth_token(FactoryBot.create(:user)) | ||
post "/api/v1/assignments/#{assignment.id}/projects/#{project.id}/grades", | ||
headers: { "Authorization": "Token #{token}" }, | ||
params: create_params, as: :json | ||
end | ||
|
||
it "returns status unauthorized" do | ||
expect(response).to have_http_status(403) | ||
expect(response.parsed_body).to have_jsonapi_errors | ||
end | ||
end | ||
|
||
context "when authorized but tries to create grade with invalid params" do | ||
before do | ||
token = get_auth_token(mentor) | ||
post "/api/v1/assignments/#{assignment.id}/projects/#{project.id}/grades", | ||
headers: { "Authorization": "Token #{token}" }, | ||
params: { "invalid": "invalid" }, as: :json | ||
end | ||
|
||
it "returns status bad_request" do | ||
expect(response).to have_http_status(400) | ||
expect(response.parsed_body).to have_jsonapi_errors | ||
end | ||
end | ||
|
||
context "when authorized but tries to create duplicate grade" do | ||
before do | ||
FactoryBot.create( | ||
:grade, project: project, assignment: assignment, \ | ||
user_id: mentor.id, grade: "A", remarks: "Good" | ||
) | ||
token = get_auth_token(mentor) | ||
post "/api/v1/assignments/#{assignment.id}/projects/#{project.id}/grades", | ||
headers: { "Authorization": "Token #{token}" }, | ||
params: create_params, as: :json | ||
end | ||
|
||
it "returns status unprocessable_identity" do | ||
expect(response).to have_http_status(422) | ||
expect(response.parsed_body).to have_jsonapi_errors | ||
end | ||
end | ||
|
||
context "when authorized but tries to create grade with different grading scale" do | ||
before do | ||
token = get_auth_token(mentor) | ||
post "/api/v1/assignments/#{assignment.id}/projects/#{project.id}/grades", | ||
headers: { "Authorization": "Token #{token}" }, | ||
params: invalid_grading_scale_params, as: :json | ||
end | ||
|
||
it "returns status unprocessable_identity" do | ||
expect(response).to have_http_status(422) | ||
expect(response.parsed_body).to have_jsonapi_errors | ||
end | ||
end | ||
|
||
context "when authorized to grade an assignment" do | ||
before do | ||
token = get_auth_token(mentor) | ||
post "/api/v1/assignments/#{assignment.id}/projects/#{project.id}/grades", | ||
headers: { "Authorization": "Token #{token}" }, | ||
params: create_params, as: :json | ||
end | ||
|
||
it "returns status created & grade details" do | ||
expect(response).to have_http_status(201) | ||
expect(response).to match_response_schema("grade") | ||
expect(response.parsed_body["data"]["attributes"]["grade"]).to eq("A") | ||
end | ||
end | ||
|
||
def create_params | ||
{ | ||
"grade": { | ||
"grade": "A", | ||
"remarks": "Nice Work" | ||
} | ||
} | ||
end | ||
|
||
def invalid_grading_scale_params | ||
{ | ||
"grade": { | ||
"grade": 100, | ||
"remarks": "Nice Work" | ||
} | ||
} | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# frozen_string_literal: true | ||
|
||
require "rails_helper" | ||
|
||
RSpec.describe Api::V1::GradesController, "#destroy", type: :request do | ||
describe "delete specific grade" do | ||
let!(:mentor) { FactoryBot.create(:user) } | ||
let!(:group) { FactoryBot.create(:group, mentor: mentor) } | ||
let!(:assignment) { FactoryBot.create(:assignment, group: group, grading_scale: :letter) } | ||
let!(:project) { FactoryBot.create(:project, assignment: assignment) } | ||
let!(:grade) do | ||
FactoryBot.create( | ||
:grade, project: project, assignment: assignment, \ | ||
user_id: mentor.id, grade: "A", remarks: "Good" | ||
) | ||
end | ||
|
||
context "when not authenticated" do | ||
before do | ||
delete "/api/v1/grades/#{grade.id}", as: :json | ||
end | ||
|
||
it "returns status unauthenticated" do | ||
expect(response).to have_http_status(401) | ||
expect(response.parsed_body).to have_jsonapi_errors | ||
end | ||
end | ||
|
||
context "when authenticated as random user and don't have delete access" do | ||
before do | ||
token = get_auth_token(FactoryBot.create(:user)) | ||
delete "/api/v1/grades/#{grade.id}", | ||
headers: { "Authorization": "Token #{token}" }, as: :json | ||
end | ||
|
||
it "returns status unauthorized" do | ||
expect(response).to have_http_status(403) | ||
expect(response.parsed_body).to have_jsonapi_errors | ||
end | ||
end | ||
|
||
context "when authorized but tries to delete non existent grade" do | ||
before do | ||
token = get_auth_token(mentor) | ||
delete "/api/v1/grades/0", | ||
headers: { "Authorization": "Token #{token}" }, as: :json | ||
end | ||
|
||
it "returns status not_found" do | ||
expect(response).to have_http_status(404) | ||
expect(response.parsed_body).to have_jsonapi_errors | ||
end | ||
end | ||
|
||
context "when authorized to delete grade" do | ||
before do | ||
token = get_auth_token(mentor) | ||
delete "/api/v1/grades/#{grade.id}", | ||
headers: { "Authorization": "Token #{token}" }, as: :json | ||
end | ||
|
||
it "delete group & return status no_content" do | ||
expect { Grade.find(grade.id) }.to raise_exception( | ||
ActiveRecord::RecordNotFound | ||
) | ||
expect(response).to have_http_status(204) | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.