Repository: ucfopen/canvasapi

Issue:
Create observer pairing code
**What resource needs additional coverage?**
User Observees

**What endpoints need to be covered?**
https://canvas.instructure.com/doc/api/user_observees.html#method.observer_pairing_codes_api.create

- [ ] `POST /api/v1/users/:user_id/observer_pairing_codes`

---

**Original Title**
Looking for the pairing code reference

**Original Text**

I can see that there are "observees" listed in the reference, but I am having trouble finding a way to use this library to create pairing codes for my students.

[Listed here on the API documentation](https://canvas.instructure.com/doc/api/user_observees.html) you can see at the very bottom a method for creating the pairing code, but I'm having trouble figuring out how to use that in conjunction with this Canvas library.

Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/34493005/badge)](https://coveralls.io/builds/34493005)

Coverage remained the same at 100.0% when pulling **84ed4bc22c34a6b06ce80f4ce025a157324e34b0 on bennettscience:issue/411-create-pairing-code** into **9175ff4b43d6bdfb0149fb63c320e41e72b69314 on ucfopen:develop**.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c52c9d1..8ababb2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@
 ### New Endpoint Coverage
 
 - Course TODO items (Thanks, [@onomou](https://github.com/onomou))
+- Create observer pairing code (Thanks, [@bennettscience](https://github.com/bennettscience))
 
 ## [2.0.0] - 2020-08-14
 
diff --git a/canvasapi/pairing_code.py b/canvasapi/pairing_code.py
new file mode 100644
index 0000000..1028540
--- /dev/null
+++ b/canvasapi/pairing_code.py
@@ -0,0 +1,6 @@
+from canvasapi.canvas_object import CanvasObject
+
+
+class PairingCode(CanvasObject):
+    def __str__(self):
+        return "{} - {}".format(self.user_id, self.code)
diff --git a/canvasapi/user.py b/canvasapi/user.py
index 4d15a15..401f150 100644
--- a/canvasapi/user.py
+++ b/canvasapi/user.py
@@ -4,6 +4,7 @@ from canvasapi.communication_channel import CommunicationChannel
 from canvasapi.feature import Feature, FeatureFlag
 from canvasapi.folder import Folder
 from canvasapi.paginated_list import PaginatedList
+from canvasapi.pairing_code import PairingCode
 from canvasapi.license import License
 from canvasapi.upload import Uploader
 from canvasapi.usage_rights import UsageRights
@@ -118,6 +119,24 @@ class User(CanvasObject):
         )
         return Folder(self._requester, response.json())
 
+    def create_pairing_code(self, **kwargs):
+        """
+        Create a pairing code for this user.
+
+        :calls: `POST /api/v1/users/:user_id/observer_pairing_codes \
+            <https://canvas.instructure.com/doc/api/user_observees.html#method.observer_pairing_codes_api.create>`_
+
+        :rtype: :class:`canvasapi.pairing_code.PairingCode`
+        """
+
+        response = self._requester.request(
+            "POST",
+            "users/{}/observer_pairing_codes".format(self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
+        return PairingCode(self._requester, response.json())
+
     def edit(self, **kwargs):
         """
         Modify this user's information.
diff --git a/docs/class-reference.rst b/docs/class-reference.rst
index 87a46b2..cb5e00d 100644
--- a/docs/class-reference.rst
+++ b/docs/class-reference.rst
@@ -40,6 +40,7 @@ Class Reference
     outcome-ref
     outcome-import-ref
     page-ref
+    pairing-code-ref
     planner-ref
     poll-ref
     poll-choice-ref
diff --git a/docs/pairing-code-ref.rst b/docs/pairing-code-ref.rst
new file mode 100644
index 0000000..a27b9c7
--- /dev/null
+++ b/docs/pairing-code-ref.rst
@@ -0,0 +1,6 @@
+===========
+PairingCode
+===========
+
+.. autoclass:: canvasapi.pairing_code.PairingCode
+    :members:


Test patch:
diff --git a/tests/fixtures/user.json b/tests/fixtures/user.json
index b180fc6..11b77b1 100644
--- a/tests/fixtures/user.json
+++ b/tests/fixtures/user.json
@@ -267,7 +267,18 @@
             "full_name": "Folder 1"
         },
         "status_code": 200
-    },
+	},
+	"observer_pairing_codes": {
+		"method": "POST",
+		"endpoint": "users/1/observer_pairing_codes",
+		"data": {
+			"user_id": 1,
+			"code": "abc123",
+			"expires_at": "2020-10-30T17:00:00Z",
+			"workflow_state": "active"
+		},
+		"status_code": 200
+	},
 	"get_user_assignments": {
 		"method": "GET",
 		"endpoint": "users/1/courses/1/assignments",
diff --git a/tests/test_pairing_code.py b/tests/test_pairing_code.py
new file mode 100644
index 0000000..13dcf66
--- /dev/null
+++ b/tests/test_pairing_code.py
@@ -0,0 +1,28 @@
+import unittest
+
+import requests_mock
+
+from canvasapi import Canvas
+from canvasapi.pairing_code import PairingCode
+from tests import settings
+from tests.util import register_uris
+
+
+@requests_mock.Mocker()
+class TestPairingCode(unittest.TestCase):
+    def setUp(self):
+        self.canvas = Canvas(settings.BASE_URL, settings.API_KEY)
+
+        with requests_mock.Mocker() as m:
+            requires = {"user": ["get_by_id"]}
+            register_uris(requires, m)
+
+            self.user = self.canvas.get_user(1)
+
+    # __str__()
+    def test__str__(self, m):
+        register_uris({"user": ["observer_pairing_codes"]}, m)
+
+        pairing_code = self.user.create_pairing_code()
+        self.assertIsInstance(pairing_code, PairingCode)
+        self.assertEqual("1 - abc123", pairing_code.__str__())
diff --git a/tests/test_user.py b/tests/test_user.py
index d46e26f..fec49ca 100644
--- a/tests/test_user.py
+++ b/tests/test_user.py
@@ -20,6 +20,7 @@ from canvasapi.login import Login
 from canvasapi.license import License
 from canvasapi.page_view import PageView
 from canvasapi.paginated_list import PaginatedList
+from canvasapi.pairing_code import PairingCode
 from canvasapi.user import User
 from canvasapi.usage_rights import UsageRights
 from tests import settings
@@ -565,6 +566,14 @@ class TestUser(unittest.TestCase):
         self.assertIsInstance(root_folder_list[0], Folder)
         self.assertEqual("my_files", root_folder_list[0].name)
 
+    # create_pairing_code()
+    def test_create_pairing_code(self, m):
+        register_uris({"user": ["observer_pairing_codes"]}, m)
+
+        pairing_code = self.user.create_pairing_code()
+        self.assertIsInstance(pairing_code, PairingCode)
+        self.assertEqual("abc123", pairing_code.code)
+
 
 @requests_mock.Mocker()
 class TestUserDisplay(unittest.TestCase):