Repository: ucfopen/canvasapi

Issue:
Moderated Grading - Moderation Set
**What resource needs additional coverage?**
Moderated Grading

**What endpoints need to be covered?**
- [ ] [List students selected for moderation](https://canvas.instructure.com/doc/api/moderated_grading.html#method.moderation_set.index)
- [ ] [Select students for moderation](https://canvas.instructure.com/doc/api/moderated_grading.html#method.moderation_set.create)


Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/ucfopen/canvasapi/pull/569?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ucfopen) Report
> Merging [#569](https://codecov.io/gh/ucfopen/canvasapi/pull/569?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ucfopen) (9b317d7) into [develop](https://codecov.io/gh/ucfopen/canvasapi/commit/76b234f8e9128485809d6ca3ae5366cddc854ebd?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ucfopen) (76b234f) will **not change** coverage.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff            @@
##           develop      #569   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           67        67           
  Lines         3565      3568    +3     
=========================================
+ Hits          3565      3568    +3     
```


| [Impacted Files](https://codecov.io/gh/ucfopen/canvasapi/pull/569?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ucfopen) | Coverage Δ | |
|---|---|---|
| [canvasapi/assignment.py](https://codecov.io/gh/ucfopen/canvasapi/pull/569/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ucfopen#diff-Y2FudmFzYXBpL2Fzc2lnbm1lbnQucHk=) | `100.00% <100.00%> (ø)` | |
| [canvasapi/upload.py](https://codecov.io/gh/ucfopen/canvasapi/pull/569/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ucfopen#diff-Y2FudmFzYXBpL3VwbG9hZC5weQ==) | `100.00% <0.00%> (ø)` | |

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ucfopen)


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 33a8df4..2de3e73 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,9 @@
     - Update a calendar's visibility
     - Update many calendars' visibility
     - List all account calendars
+- Moderation Grading (Moderation Set)
+    - List students selected for moderation
+    - Select students for moderation
 
 ### General
 
diff --git a/canvasapi/assignment.py b/canvasapi/assignment.py
index 325be72..34e6455 100644
--- a/canvasapi/assignment.py
+++ b/canvasapi/assignment.py
@@ -207,6 +207,26 @@ class Assignment(CanvasObject):
 
         return request_json.get("needs_provisional_grade")
 
+    def get_students_selected_for_moderation(self, **kwargs):
+        """
+        Get a list of students selected for moderation.
+
+        :calls: `GET /api/v1/courses/:course_id/assignments/:assignment_id/moderated_students \
+        <https://canvas.instructure.com/doc/api/moderated_grading.html#method.moderation_set.index>`_
+
+        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
+            :class:`canvasapi.user.User`
+        """
+        return PaginatedList(
+            User,
+            self._requester,
+            "GET",
+            "courses/{}/assignments/{}/moderated_students".format(
+                self.course_id, self.id
+            ),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
     def get_submission(self, user, **kwargs):
         """
         Get a single submission, based on user id.
@@ -277,6 +297,27 @@ class Assignment(CanvasObject):
         )
         return response.json()
 
+    def select_students_for_moderation(self, **kwargs):
+        """
+        Select student(s) for moderation.
+
+        :calls: `POST /api/v1/courses/:course_id/assignments/:assignment_id/moderated_students \
+        <https://canvas.instructure.com/doc/api/moderated_grading.html#method.moderation_set.create>`_
+
+        :returns: The list of users that were selected
+        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
+            :class:`canvasapi.user.User`
+        """
+        return PaginatedList(
+            User,
+            self._requester,
+            "POST",
+            "courses/{}/assignments/{}/moderated_students".format(
+                self.course_id, self.id
+            ),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
     def selected_provisional_grade(self, provisional_grade_id, **kwargs):
         """
         Choose which provisional grade the student should receive for a submission.


Test patch:
diff --git a/tests/fixtures/assignment.json b/tests/fixtures/assignment.json
index 95d8cc3..cfcbd2f 100644
--- a/tests/fixtures/assignment.json
+++ b/tests/fixtures/assignment.json
@@ -490,5 +490,33 @@
 		"data": {
 			"message": "OK"
 		}
+	},
+	"get_students_selected_moderation": {
+		"method": "GET",
+		"endpoint": "courses/1/assignments/1/moderated_students",
+		"data": [
+			{
+				"id": 1,
+				"name": "John Doe"
+			},
+			{
+				"id": 2,
+				"name": "John Smith"
+			}
+		]
+	},
+	"select_students_for_moderation": {
+		"method": "POST",
+		"endpoint": "courses/1/assignments/1/moderated_students",
+		"data": [
+			{
+				"id": 11,
+				"name": "Joyce Smith"
+			},
+			{
+				"id": 12,
+				"name": "Jane Doe"
+			}
+		]
 	}
 }
diff --git a/tests/test_assignment.py b/tests/test_assignment.py
index 28f36de..8f59ac8 100644
--- a/tests/test_assignment.py
+++ b/tests/test_assignment.py
@@ -17,7 +17,7 @@ from canvasapi.paginated_list import PaginatedList
 from canvasapi.peer_review import PeerReview
 from canvasapi.progress import Progress
 from canvasapi.submission import Submission
-from canvasapi.user import UserDisplay
+from canvasapi.user import User, UserDisplay
 from tests import settings
 from tests.util import cleanup_file, register_uris
 
@@ -137,6 +137,16 @@ class TestAssignment(unittest.TestCase):
         self.assertEqual(len(peer_review_list), 2)
         self.assertIsInstance(peer_review_list[0], PeerReview)
 
+    # get_students_selected_for_moderation()
+    def test_get_students_selected_for_moderation(self, m):
+        register_uris({"assignment": ["get_students_selected_moderation"]}, m)
+
+        selected_students = self.assignment.get_students_selected_for_moderation()
+        selected_student_list = list(selected_students)
+
+        self.assertEqual(len(selected_student_list), 2)
+        self.assertIsInstance(selected_student_list[0], User)
+
     # get_submission()
     def test_get_submission(self, m):
         register_uris({"submission": ["get_by_id_course"], "user": ["get_by_id"]}, m)
@@ -333,6 +343,18 @@ class TestAssignment(unittest.TestCase):
         self.assertIsInstance(status, bool)
         self.assertFalse(status)
 
+    # select_students_for_moderation()
+    def test_select_students_for_moderation(self, m):
+        register_uris({"assignment": ["select_students_for_moderation"]}, m)
+
+        selected_students = self.assignment.select_students_for_moderation(
+            student_ids=[11, 12]
+        )
+        selected_student_list = list(selected_students)
+
+        self.assertEqual(len(selected_student_list), 2)
+        self.assertIsInstance(selected_student_list[0], User)
+
     # selected_provisional_grade
     def test_selected_provisional_grade(self, m):
         register_uris({"assignment": ["selected_provisional_grade"]}, m)