Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add comment to student grade #180

Merged
merged 6 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions __tests__/integration/grades_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/stretchr/testify/require"
)

func TestSetCriteriaToStudentSubmission(t *testing.T) {
func TestGradeStudentSubmission(t *testing.T) {
c := require.New(t)

// ## Test preparation
Expand Down Expand Up @@ -78,18 +78,26 @@ func TestSetCriteriaToStudentSubmission(t *testing.T) {
firstStudent := enrolledStudents[0].(map[string]interface{})
studentUUID := firstStudent["uuid"].(string)

// ## Test execution
// ## Test: Set criteria to student grade
// Select the criteria for the student grade
_, code := SetCriteriaToStudentGrade(&SetCriteriaToStudentGradeUtilsDTO{
LaboratoryUUID: laboratoryUUID,
RubricUUID: rubricUUID,
StudentUUID: studentUUID,
ObjectiveUUID: objectiveUUID,
CriteriaUUID: criteriaUUID,
}, cookie)
c.Equal(http.StatusNoContent, code)

// Get all the grades of students in the laboratory
// ## Test: Set comment to student grade
comment := "Set criteria to student grade test - comment"
_, code = SetCommentToStudentGrade(&SetCommentToStudentGradeUtilsDTO{
LaboratoryUUID: laboratoryUUID,
StudentUUID: studentUUID,
Comment: comment,
}, cookie)
c.Equal(http.StatusNoContent, code)

// ## Test: Get all the grades of students in the laboratory
studentGradeResponse, code := GetSummarizedGrades(laboratoryUUID, cookie)
c.Equal(http.StatusOK, code)

Expand All @@ -100,7 +108,7 @@ func TestSetCriteriaToStudentSubmission(t *testing.T) {
c.Equal(studentUUID, firstStudentGrade["student_uuid"].(string))
c.Equal(criteriaWeight, firstStudentGrade["grade"].(float64))

// Get the grade of the student in the laboratory
// ## Test: Get the grade of the student in the laboratory
studentGradeResponse, code = GetStudentGrade(&GetStudentGradeUtilsDTO{
LaboratoryUUID: laboratoryUUID,
RubricUUID: rubricUUID,
Expand All @@ -112,7 +120,7 @@ func TestSetCriteriaToStudentSubmission(t *testing.T) {
c.Equal(criteriaWeight, studentGrade)

gradeComment := studentGradeResponse["comment"].(string)
c.Equal("", gradeComment)
c.Equal(comment, gradeComment)

selectedCriteriaList := studentGradeResponse["selected_criteria"].([]interface{})
c.Equal(1, len(selectedCriteriaList))
Expand Down
25 changes: 23 additions & 2 deletions __tests__/integration/grades_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ func GetSummarizedGrades(laboratoryUUID string, cookie *http.Cookie) (response m

type SetCriteriaToStudentGradeUtilsDTO struct {
LaboratoryUUID string
RubricUUID string
StudentUUID string
ObjectiveUUID string
CriteriaUUID string
Expand All @@ -28,7 +27,6 @@ func SetCriteriaToStudentGrade(dto *SetCriteriaToStudentGradeUtilsDTO, cookie *h
w, r := PrepareRequest("PUT", endpoint, map[string]interface{}{
"objective_uuid": dto.ObjectiveUUID,
"criteria_uuid": dto.CriteriaUUID,
"rubric_uuid": dto.RubricUUID,
})
r.AddCookie(cookie)
router.ServeHTTP(w, r)
Expand Down Expand Up @@ -58,3 +56,26 @@ func GetStudentGrade(dto *GetStudentGradeUtilsDTO, cookie *http.Cookie) (respons
jsonResponse := ParseJsonResponse(w.Body)
return jsonResponse, w.Code
}

type SetCommentToStudentGradeUtilsDTO struct {
LaboratoryUUID string
StudentUUID string
Comment string
}

func SetCommentToStudentGrade(dto *SetCommentToStudentGradeUtilsDTO, cookie *http.Cookie) (response map[string]interface{}, statusCode int) {
endpoint := fmt.Sprintf(
"/api/v1/grades/laboratories/%s/students/%s/comment",
dto.LaboratoryUUID,
dto.StudentUUID,
)

w, r := PrepareRequest("PUT", endpoint, map[string]interface{}{
"comment": dto.Comment,
})
r.AddCookie(cookie)
router.ServeHTTP(w, r)

jsonResponse := ParseJsonResponse(w.Body)
return jsonResponse, w.Code
}
17 changes: 17 additions & 0 deletions docs/bruno/grades/set-comment-to-student-grade.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
meta {
name: set-comment-to-student-grade
type: http
seq: 4
}

put {
url: {{BASE_URL}}/grades/laboratories/d0ce7e95-59b4-4ac1-9238-461e9a47ce1d/students/3fd0671b-8673-4282-94f5-9bd6300d943f/comment
body: json
auth: none
}

body:json {
{
"comment": "Good job"
}
}
57 changes: 51 additions & 6 deletions docs/openapi/spec.openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2176,7 +2176,7 @@ paths:
schema:
$ref: "#/components/schemas/default_error_response"

/grades/laboratory/{laboratory_uuid}:
/grades/laboratories/{laboratory_uuid}:
get:
tags:
- Grades
Expand Down Expand Up @@ -2216,6 +2216,56 @@ paths:
schema:
$ref: "#/components/schemas/default_error_response"

/grades/laboratories/{laboratory_uuid}/students/{student_uuid}/comment:
put:
tags:
- Grades
security:
- cookieAuth: []
parameters:
- in: path
name: student_uuid
schema:
type: string
example: "b0c553b3-ddb2-4392-9d94-b31d8c9c4a84"
required: true
- in: path
name: laboratory_uuid
schema:
type: string
example: "a9be2f1e-e0e9-4b8d-9f72-6ed55ea5b1b8"
required: true
description: Add / update the comment given by the teacher to the given student in the given laboratory.
requestBody:
content:
application/json:
schema:
type: object
properties:
comment:
type: string
example: "This is a comment made by the teacher :D"
responses:
"204":
description: The comment was updated.
"400":
description: Required fields were missed or doesn't fulfill the required format.
content:
application/json:
schema:
$ref: "#/components/schemas/default_error_response"
"403":
description: The session token isn't valid or the user doesn't have enough permissions.
content:
application/json:
schema:
$ref: "#/components/schemas/default_error_response"
"500":
description: There was an unexpected error in the server side.
content:
application/json:
schema:
$ref: "#/components/schemas/default_error_response"

components:
securitySchemes:
Expand Down Expand Up @@ -2357,11 +2407,6 @@ components:
select_criteria_to_grade_req:
allOf:
- $ref: "#/components/schemas/selected_criteria_in_grade"
type: object
properties:
rubric_uuid:
type: string
example: "3fc29baf-9517-430c-9048-0f85599b61b7"

# Responses
default_error_response:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package implementations
import (
"context"
"database/sql"
"fmt"
"log"
"time"

Expand Down Expand Up @@ -480,7 +479,6 @@ func (repository *BlocksPostgresRepository) SwapBlocks(firstBlockUUID, secondBlo
}

// Run the query
fmt.Println("Swapping blocks", firstBlockUUID, secondBlockUUID)
_, err = tx.ExecContext(ctx, query, firstBlockUUID, secondBlockUUID)
if err != nil {
return err
Expand Down
40 changes: 36 additions & 4 deletions src/grades/application/use_cases.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,8 @@ func (useCases *GradesUseCases) SetCriteriaToGrade(dto *dtos.SetCriteriaToGradeD
return gradesErrors.LaboratoryDoesNotHaveRubricError{}
}

// Validate the rubric UUID
if *rubricUUID != dto.RubricUUID {
return gradesErrors.RubricDoesNotMatchLaboratoryError{}
}
// Set the rubric UUID
dto.RubricUUID = *rubricUUID

// Validate the objective belongs to the rubric
objectiveBelongsToRubric, err := useCases.RubricsRepository.DoesRubricHaveObjective(
Expand Down Expand Up @@ -134,3 +132,37 @@ func (useCases *GradesUseCases) GetStudentGradeInLaboratoryWithRubric(dto *dtos.
grade, err := useCases.GradesRepository.GetStudentGradeInLaboratoryWithRubric(dto)
return grade, err
}

// SetCommentToGrade sets a comment to an student's grade
func (useCases *GradesUseCases) SetCommentToGrade(dto *dtos.SetCommentToGradeDTO) error {
// Validate the teacher owns the laboratory
teacherOwnsLaboratory, err := useCases.LaboratoriesRepository.DoesTeacherOwnLaboratory(
dto.TeacherUUID,
dto.LaboratoryUUID,
)
if err != nil {
return err
}
if !teacherOwnsLaboratory {
return laboratoriesErrors.TeacherDoesNotOwnLaboratoryError{}
}

// Get the UUID of the current rubric of the laboratory
laboratoryUUID := dto.LaboratoryUUID
laboratoryInformation, err := useCases.LaboratoriesRepository.GetLaboratoryInformationByUUID(laboratoryUUID)
if err != nil {
return err
}

// Return an error if the laboratory does not have a rubric
rubricUUID := laboratoryInformation.RubricUUID
if rubricUUID == nil {
return gradesErrors.LaboratoryDoesNotHaveRubricError{}
}

// Set the rubric UUID
dto.RubricUUID = *rubricUUID

// Set the comment to the student's grade
return useCases.GradesRepository.SetCommentToGrade(dto)
}
1 change: 1 addition & 0 deletions src/grades/domain/definitions/grades_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type GradesRepository interface {
[]*dtos.SummarizedStudentGradeDTO, error,
)
SetCriteriaToGrade(dto *dtos.SetCriteriaToGradeDTO) error
SetCommentToGrade(dto *dtos.SetCommentToGradeDTO) error
GetStudentGradeInLaboratoryWithRubric(
dto *dtos.GetStudentGradeInLaboratoryWithRubricDTO,
) (
Expand Down
9 changes: 9 additions & 0 deletions src/grades/domain/dtos/grades_dtos.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,12 @@ type SelectedCriteriaInStudentGradeDTO struct {
ObjectiveUUID string `json:"objective_uuid"`
CriteriaUUID string `json:"criteria_uuid"`
}

// SetCommentToGradeDTO data transfer object to parse the request of the endpoint
type SetCommentToGradeDTO struct {
TeacherUUID string
LaboratoryUUID string
RubricUUID string
StudentUUID string
Comment string
}
56 changes: 54 additions & 2 deletions src/grades/infrastructure/http/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,11 @@ func (controller *GradesController) HandleSetCriteriaGrade(c *gin.Context) {
return
}

// Create DTO
// Create DTO, note that the rubric field will be populated in the use case
dto := &dtos.SetCriteriaToGradeDTO{
TeacherUUID: teacherUUID,
LaboratoryUUID: laboratoryUUID,
StudentUUID: studentUUID,
RubricUUID: request.RubricUUID,
ObjectiveUUID: request.ObjectiveUUID,
CriteriaUUID: request.CriteriaUUID,
}
Expand Down Expand Up @@ -137,3 +136,56 @@ func (controller *GradesController) HandleGetStudentGradeInLaboratoryWithRubric(

c.JSON(http.StatusOK, grade)
}

// HandleSetCommentToGrade controller to set a comment to a student's grade
func (controller *GradesController) HandleSetCommentToGrade(c *gin.Context) {
teacherUUID := c.GetString("session_uuid")
laboratoryUUID := c.Param("laboratoryUUID")
studentUUID := c.Param("studentUUID")

// Validate UUIDs
requestUUIDs := requests.SetCommentToGradeRequestUUIDs{
StudentUUID: studentUUID,
LaboratoryUUID: laboratoryUUID,
}
if err := sharedInfrastructure.GetValidator().Struct(requestUUIDs); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"message": "Please, make sure the provided UUIDs are valid",
})
return
}

// Parse the request body
var request requests.SetCommentToGradeRequest
if err := c.ShouldBindJSON(&request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"message": "Request body is not valid",
})
return
}

// Validate the request body
if err := sharedInfrastructure.GetValidator().Struct(request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"message": "Validation error",
"errors": err.Error(),
})
return
}

// Create DTO. Note that the rubric field will be populated in the use case
dto := &dtos.SetCommentToGradeDTO{
TeacherUUID: teacherUUID,
LaboratoryUUID: laboratoryUUID,
StudentUUID: studentUUID,
Comment: request.Comment,
}

err := controller.UseCases.SetCommentToGrade(dto)
if err != nil {
c.Error(err)
return
}

c.Status(http.StatusNoContent)
}
7 changes: 7 additions & 0 deletions src/grades/infrastructure/http/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,11 @@ func StartGradesRoutes(g *gin.RouterGroup) {
sharedInfrastructure.WithAuthorizationMiddleware([]string{"teacher"}),
controller.HandleSetCriteriaGrade,
)

gradesGroup.PUT(
"/laboratories/:laboratoryUUID/students/:studentUUID/comment",
sharedInfrastructure.WithAuthenticationMiddleware(),
sharedInfrastructure.WithAuthorizationMiddleware([]string{"teacher"}),
controller.HandleSetCommentToGrade,
)
}
Loading