Skip to content

Commit

Permalink
Add Publish Grading Feature (#965)
Browse files Browse the repository at this point in the history
* Add migrations to create is_grading_published column for submissions

Current submissions will have the is_grading_published field populated
as `true` if all answers have been graded i.e. have a grader_id, while
the rest will default to `false`.

Future submissions will have the field with default value `false` upon
creation.

* Add and update endpoints for new publish grading feature

- Update existing endpoints and queries related to assessment retrieval
- Add new routes and endpoints to handle new publish grading feature
- Add notification for new feature

* Fix missing return tuple values in assessments.ex

* Fix notification and formatting

* Fix indentation and minor error

* Fix formatting

* fix formatting

* fix credo long line

* fix credo nesting alias

* Fix formatting and code quality

* Fix tests

* feat: Implement format helper function

Changing xp in the assessment_with_questions_and_answers is the wrong direction,
I feel that the function should not be tied to a specific format. Instead,
I will call a helper function in the controller to format the xp.

* feat: Add formatting function for getting all assessments

* fix: Fix bug of using virtual variable instead

* refactor: Remove default value for virtual variable is_grading_published

* feat: Implement tests for helper functions

* feat: Add isGradingPublished to response for fetching all assessments

* refactor: Format

* chore: Remove unused match

* feat: Implement tests for unpublish route

* feat: Implement tests for publish route

* refactor: Move repeated code into setup for publish test

* refactor: Move repeated code into setup for unpublish test

* refactor: Format code

* feat: Add a guard to prevent unsubmit when grade is still published

* feat: Implement filter by notPublished

* refactor: Format

* fix: Fix incorrect guard check for is_grading_published

* refactor: Edit tests to accommodate new guard

* feat: Implement test for new guard (check is_grading_published)

* feat: Update seed to include is_grading_published

* refactor: Update old tests to accommodate for is_grading_published

* refactor: Improve filter tests to be more flexible

Remove hard coded numbers and count expected number with students_with_assessment_info

* feat: Implement test for filter by not published

* chore: Format

* refactor: Make is_grading_published default to false in factory function

* feat: Add is_grading_auto_published column to assessment config

* feat: Add guard clause to ensure submission is fully graded before publishing

* feat: Implement publish_grading and is_fully_autograded?

- Adds another publish_grading function which bypasses all checks
- Adds a new function is_fully_autograded? which checks if all answers are successfully auto graded

* chore: Clean up code

* feat: Add is_grading_auto_published and is_manually_graded to seed

* feat: Implement tests for is_fully_autograded?/1

* feat: Implement publish_all_grades route

* feat: Add publish_all_grades in controller

* feat: Implement publish_all_graded function

* feat: Implement tests for publish_all_graded/2

* refactor: Rename param names and allow filter by true or false

* refactor: Add tests for change in param and refactor code

* refactor: Change response for publish all grades

* refactor: Use update_all instead of recursively updating individual submissions

* feat: Implement unpublish all grades route

* feat: Implement unpublish_all

* feat: Implement unpublish_all tests

* chore: Format

* feat: Implement auto publish for mcq/voting questions

* feat: Implement auto publish for auto graded programming questions

* chore: Fix consistency issue

* feat: Implement published and unpublished notifications and remove deprecated ones

* feat: Include isGradingAutoPublished in response for assessment configs

* fix: Include sending of notifications when publishing/unpublishing all

* docs: Add docs for functions implemented

* chore: Update wording for tests

* chore: Remove unused variables

* feat: Implement test for unpublish and publish all routes

* feat: Implement guard for publish/unpublish grades

This commit prevents admin/staff from individually publishing/unpublishing grades for students.

* refactor: Change notification types in swagger_schema

* chore: Add comment in seed

* refactor: remove redundant lines

* Redate migrations

Ensures total ordering of migration files are preserved.

* Revert unnecessary changes

* Revert more unnecessary changes

* refactor: Move duplicate code into helper function

* chore: Fix typo

* refactor: Change control flow structure

---------

Co-authored-by: YaleChen299 <[email protected]>
Co-authored-by: Richard Dominick <[email protected]>
Co-authored-by: GabrielCWT <[email protected]>
  • Loading branch information
4 people authored Apr 13, 2024
1 parent d94f60a commit 3cf8d7d
Show file tree
Hide file tree
Showing 33 changed files with 1,715 additions and 155 deletions.
10 changes: 5 additions & 5 deletions lib/cadet/accounts/notification_type.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import EctoEnum
defenum(Cadet.Accounts.NotificationType, :notification_type, [
# Notifications for new assessments
:new,
# Notifications for autograded assessments
:autograded,
# Notifications for manually graded assessments
:graded,
# Notifications for unsubmitted submissions
:unsubmitted,
# Notifications for submitted assessments
:submitted
:submitted,
# Notifications for published grades
:published_grading,
# Notifications for unpublished grades
:unpublished_grading
])
33 changes: 28 additions & 5 deletions lib/cadet/accounts/notifications.ex
Original file line number Diff line number Diff line change
Expand Up @@ -145,18 +145,41 @@ defmodule Cadet.Accounts.Notifications do
{:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
def handle_unsubmit_notifications(assessment_id, student = %CourseRegistration{})
when is_ecto_id(assessment_id) do
# Fetch and delete all notifications of :autograded and :graded
# Fetch and delete all notifications of :unpublished_grading
# Add new notification :unsubmitted

Notification
|> where(course_reg_id: ^student.id)
|> where(assessment_id: ^assessment_id)
|> where([n], n.type in ^[:autograded, :graded])
|> where([n], n.type in ^[:unpublished_grading])
|> Repo.delete_all()

write(%{
type: :unsubmitted,
role: student.role,
role: :student,
course_reg_id: student.id,
assessment_id: assessment_id
})
end

@doc """
Function that handles notifications when a submission grade is unpublished.
Deletes all :published notifications and adds a new :unpublished_grading notification.
"""
@spec handle_unpublish_grades_notifications(integer(), CourseRegistration.t()) ::
{:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
def handle_unpublish_grades_notifications(assessment_id, student = %CourseRegistration{})
when is_ecto_id(assessment_id) do
Notification
|> where(course_reg_id: ^student.id)
|> where(assessment_id: ^assessment_id)
|> where([n], n.type in ^[:published_grading])
|> Repo.delete_all()

write(%{
type: :unpublished_grading,
read: false,
role: :student,
course_reg_id: student.id,
assessment_id: assessment_id
})
Expand All @@ -166,9 +189,9 @@ defmodule Cadet.Accounts.Notifications do
Writes a notification that a student's submission has been
graded successfully. (for the student)
"""
@spec write_notification_when_graded(integer(), any()) ::
@spec write_notification_when_published(integer(), any()) ::
{:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
def write_notification_when_graded(submission_id, type) when type in [:graded, :autograded] do
def write_notification_when_published(submission_id, type) when type in [:published_grading] do
case Repo.get(Submission, submission_id) do
nil ->
{:error, %Ecto.Changeset{}}
Expand Down
1 change: 1 addition & 0 deletions lib/cadet/assessments/assessment.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ defmodule Cadet.Assessments.Assessment do
field(:grading_status, :string, virtual: true)
field(:question_count, :integer, virtual: true)
field(:graded_count, :integer, virtual: true)
field(:is_grading_published, :boolean, virtual: true)
field(:title, :string)
field(:is_published, :boolean, default: false)
field(:summary_short, :string)
Expand Down
Loading

0 comments on commit 3cf8d7d

Please sign in to comment.