Skip to content

Commit

Permalink
Merge 876d9e5 into c5f1426
Browse files Browse the repository at this point in the history
  • Loading branch information
fanglinfang committed Feb 25, 2022
2 parents c5f1426 + 876d9e5 commit e8f4736
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 11 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,12 @@
Installation:

pip install UW-RestClients-MyPlan

To use this client, you'll need these settings in your application or script:

# Specifies whether requests should use live or mocked resources,
# acceptable values are 'Live' or 'Mock' (default)
RESTCLIENTS_MYPLAN_DAO_CLASS='Live'
RESTCLIENTS_MYPLAN_AUTH_DAO_CLASS='Live'
RESTCLIENTS_MYPLAN_AUTH_SECRET=''
RESTCLIENTS_MYPLAN_AUTH_HOST=''
8 changes: 7 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Copyright 2022 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0

import os
from setuptools import setup

Expand All @@ -20,7 +23,10 @@
author="UW-IT AXDD",
author_email="aca-it@uw.edu",
include_package_data=True,
install_requires=['UW-RestClients-Core'],
install_requires=[
'UW-RestClients-Core',
'mock',
],
license='Apache License, Version 2.0',
description=('A library for connecting to the UW MyPlan API'),
long_description=README,
Expand Down
13 changes: 9 additions & 4 deletions uw_myplan/__init__.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
# Copyright 2021 UW-IT, University of Washington
# Copyright 2022 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0

"""
This is the interface for interacting with MyPlan.
https://wiki.cac.washington.edu/display/MyPlan/Plan+Resource+v1
"""

from uw_myplan.dao import MyPlan_DAO
import json
import logging
from restclients_core.exceptions import DataFailureException
from uw_myplan.dao import MyPlan_DAO
from uw_myplan.models import (
MyPlan, MyPlanTerm, MyPlanCourse, MyPlanCourseSection)
import json

logger = logging.getLogger(__name__)


def get_plan(regid, year, quarter, terms=4):
dao = MyPlan_DAO()
url = get_plan_url(regid, year, quarter, terms)

response = dao.getURL(url, {"Accept": "application/json"})
logger.debug(
{'url': url, 'status': response.status, 'data': response.data})
if response.status != 200:
raise DataFailureException(url, response.status, str(response.data))

Expand Down Expand Up @@ -57,5 +62,5 @@ def get_plan(regid, year, quarter, terms=4):


def get_plan_url(regid, year, quarter, terms=4):
return "/student/api/plan/v1/{year},{quarter},{terms},{uwregid}".format(
return "/plan/v1/{year},{quarter},{terms},{uwregid}".format(
year=year, quarter=quarter, terms=terms, uwregid=regid)
57 changes: 56 additions & 1 deletion uw_myplan/dao.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,70 @@
# Copyright 2021 UW-IT, University of Washington
# Copyright 2022 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0

import json
import logging
import os
from os.path import abspath, dirname
from restclients_core.dao import DAO
from restclients_core.exceptions import DataFailureException

logger = logging.getLogger(__name__)


class MyPlan_Auth_DAO(DAO):
def service_name(self):
return "myplan_auth"

def _is_cacheable(self, method, url, headers, body=None):
return True

def get_auth_token(self, secret):
url = "/oauth2/token"
headers = {"Authorization": "Basic {}".format(secret),
"Content-type": "application/x-www-form-urlencoded"}

response = self.postURL(url, headers, "grant_type=client_credentials")
logger.debug(
{'url': url,
'status': response.status,
'data': response.data})
if response.status != 200:
raise DataFailureException(url, response.status, response.data)

data = json.loads(response.data)
return data.get("access_token", "")

def service_mock_paths(self):
return [abspath(os.path.join(dirname(__file__), "resources"))]

def _edit_mock_response(self, method, url, headers, body, response):
if response.status == 404 and method != "GET":
alternative_url = "{0}.{1}".format(url, method)
backend = self.get_implementation()
new_resp = backend.load(method, alternative_url, headers, body)
response.status = new_resp.status
response.data = new_resp.data
logger.debug(
{'url': alternative_url,
'status': response.status,
'data': response.data})


class MyPlan_DAO(DAO):

def __init__(self):
self.auth_dao = MyPlan_Auth_DAO()
return super(MyPlan_DAO, self).__init__()

def service_name(self):
return 'myplan'

def service_mock_paths(self):
return [abspath(os.path.join(dirname(__file__), "resources"))]

def _custom_headers(self, method, url, headers, body):
headers = {}
secret = self.get_service_setting("AUTH_SECRET", "")
if secret:
headers["Authorization"] = self.auth_dao.get_auth_token(secret)
return headers
2 changes: 1 addition & 1 deletion uw_myplan/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2021 UW-IT, University of Washington
# Copyright 2022 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0

from restclients_core import models
Expand Down
5 changes: 5 additions & 0 deletions uw_myplan/resources/myplan_auth/file/oauth2/token.POST
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"access_token":"eyJraWQiOmYmEwwvOQ",
"expires_in":3600,
"token_type":"Bearer"
}
2 changes: 1 addition & 1 deletion uw_myplan/test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2021 UW-IT, University of Washington
# Copyright 2022 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0

# This is just a test runner for coverage
Expand Down
35 changes: 35 additions & 0 deletions uw_myplan/tests/test_dao.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright 2022 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0

from unittest import TestCase
import mock
from commonconf import override_settings
from restclients_core.exceptions import DataFailureException
from uw_myplan.dao import MyPlan_Auth_DAO, MyPlan_DAO
from uw_myplan.utils import (
fdao_myplan_override, fdao_myplan_auth_override)


@fdao_myplan_auth_override
@fdao_myplan_override
class TestMyPlanAuth(TestCase):

def test_is_cacheable(self):
auth = MyPlan_Auth_DAO()
self.assertTrue(auth._is_cacheable("POST", "/", {}, ""))

def test_get_auth_token(self):
self.assertIsNotNone(
MyPlan_Auth_DAO().get_auth_token("test1"))

def test_no_auth_header(self):
headers = MyPlan_DAO()._custom_headers("GET", "/", {}, "")
self.assertFalse("Authorization" in headers)

@override_settings(RESTCLIENTS_MYPLAN_AUTH_SECRET="test1")
@mock.patch.object(MyPlan_Auth_DAO, "get_auth_token")
def test_auth_header(self, mock_get_auth_token):
mock_get_auth_token.return_value = "abcdef"
headers = MyPlan_DAO()._custom_headers("GET", "/", {}, "")
self.assertTrue("Authorization" in headers)
self.assertEqual(headers["Authorization"], "abcdef")
6 changes: 3 additions & 3 deletions uw_myplan/tests/test_myplan.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2021 UW-IT, University of Washington
# Copyright 2022 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0

from unittest import TestCase
Expand All @@ -10,13 +10,13 @@ def test_plan_url(self):
self.assertEquals(
get_plan_url(
"9136CCB8F66711D5BE060004AC494FFE", 2013, "spring", 2), (
"/student/api/plan/v1/2013,spring,2,"
"/plan/v1/2013,spring,2,"
"9136CCB8F66711D5BE060004AC494FFE"))

self.assertEquals(
get_plan_url(
"9136CCB8F66711D5BE060004AC494FFE", 2012, "summer"), (
"/student/api/plan/v1/2012,summer,4,"
"/plan/v1/2012,summer,4,"
"9136CCB8F66711D5BE060004AC494FFE"))

def test_javerage(self):
Expand Down
9 changes: 9 additions & 0 deletions uw_myplan/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright 2022 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0

from commonconf import override_settings

fdao_myplan_override = override_settings(
RESTCLIENTS_MYPLAN_DAO_CLASS='Mock')
fdao_myplan_auth_override = override_settings(
RESTCLIENTS_MYPLAN_AUTH_DAO_CLASS='Mock')

0 comments on commit e8f4736

Please sign in to comment.