diff --git a/dynatademand/api.py b/dynatademand/api.py index da50910..939e90a 100644 --- a/dynatademand/api.py +++ b/dynatademand/api.py @@ -291,6 +291,44 @@ def get_project_detailed_report(self, project_id): ) return self._api_get('/projects/{}/detailedReport'.format(project_id)) + def get_user_info(self): + return self._api_get('/user') + + def get_company_users(self): + return self._api_get('/users') + + def get_company_teams(self): + return self._api_get('/teams') + + def get_roles(self, **kwargs): + self.validator.validate_request( + 'get_roles', + query_params=kwargs + ) + return self._api_get('/roles', kwargs) + + def get_project_permissions(self, project_id): + self.validator.validate_request( + 'get_project_permissions', + path_data={'extProjectId': '{}'.format(project_id)}, + ) + return self._api_get('/projects/{}/permissions'.format(project_id)) + + def upsert_project_permissions(self, project_id, upsert_permissions_data): + self.validator.validate_request( + 'upsert_project_permissions', + path_data={'extProjectId': '{}'.format(project_id)}, + request_body=upsert_permissions_data, + ) + response_data = self._api_post('/projects/{}/permissions'.format(project_id), upsert_permissions_data) + if response_data.get('status').get('message') != 'success': + raise DemandAPIError( + "Could not upsert project permissions. Demand API responded with: {}".format( + response_data + ) + ) + return response_data + def add_line_item(self, project_id, lineitem_data): ''' A line item is a project entity that exist for a specific market and @@ -524,7 +562,7 @@ def delete_template(self, id): self.validator.validate_request( 'delete_template', path_data={'id': '{}'.format(id)}, - ) + ) return self._api_delete('/templates/quotaplan/{}'.format(id)) def get_templates(self, country, lang, **kwargs): diff --git a/dynatademand/schemas/request/body/upsert_project_permissions.json b/dynatademand/schemas/request/body/upsert_project_permissions.json new file mode 100644 index 0000000..10416d2 --- /dev/null +++ b/dynatademand/schemas/request/body/upsert_project_permissions.json @@ -0,0 +1,30 @@ +{ + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "role": { + "type": "string" + } + } + } + }, + "teams": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + } + } + } + } + } +} diff --git a/dynatademand/schemas/request/path/get_project_permissions.json b/dynatademand/schemas/request/path/get_project_permissions.json new file mode 100644 index 0000000..42fe507 --- /dev/null +++ b/dynatademand/schemas/request/path/get_project_permissions.json @@ -0,0 +1,12 @@ +{ + "type": "object", + "properties": { + "extProjectId": { + "type": "string", + "required": true + } + }, + "required": [ + "extProjectId" + ] +} diff --git a/dynatademand/schemas/request/path/upsert_project_permissions.json b/dynatademand/schemas/request/path/upsert_project_permissions.json new file mode 100644 index 0000000..42fe507 --- /dev/null +++ b/dynatademand/schemas/request/path/upsert_project_permissions.json @@ -0,0 +1,12 @@ +{ + "type": "object", + "properties": { + "extProjectId": { + "type": "string", + "required": true + } + }, + "required": [ + "extProjectId" + ] +} diff --git a/dynatademand/schemas/request/query/get_roles.json b/dynatademand/schemas/request/query/get_roles.json new file mode 100644 index 0000000..363c981 --- /dev/null +++ b/dynatademand/schemas/request/query/get_roles.json @@ -0,0 +1,16 @@ +{ + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "This is the name of the role. eg: manager" + }, + "id": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [] +} diff --git a/dynatademand/validator.py b/dynatademand/validator.py index 7edddff..5070380 100644 --- a/dynatademand/validator.py +++ b/dynatademand/validator.py @@ -17,6 +17,11 @@ 'buy_project': ['path', 'body', ], 'get_project_detailed_report': ['path', ], 'reconcile_project': ['path', ], + 'get_project_permissions': ['path', ], + 'upsert_project_permissions': ['path', 'body', ], + + # Roles + 'get_roles': ['query', ], # Invoices 'get_invoice': ['path', ], diff --git a/pyproject.toml b/pyproject.toml index 81303fd..d02265e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,7 @@ pytest = "4.6.6" jsonschema = "3.2.0" pytest-runner = "5.2" flake8 = "^3.7.9" +pyrsistent = "0.14.11" [build-system] requires = ["poetry>=0.12"] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..87608f6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +responses>=0.10.0 +jsonschema>=2.5.0 diff --git a/tests/test_files/get_company_users.json b/tests/test_files/get_company_users.json new file mode 100644 index 0000000..f8fe240 --- /dev/null +++ b/tests/test_files/get_company_users.json @@ -0,0 +1,14 @@ +[ + { + "email": "samplifyweb@dynata.com", + "id": 71, + "name": "Bears Beets", + "userName": "battlestargalactica" + }, + { + "email": "samplify@dynata.com", + "id": 102, + "name": "Michael Scott", + "userName": "papercompany" + } +] diff --git a/tests/test_files/get_project_permissions.json b/tests/test_files/get_project_permissions.json new file mode 100644 index 0000000..e9a6d36 --- /dev/null +++ b/tests/test_files/get_project_permissions.json @@ -0,0 +1,21 @@ +{ + "currentUser": { + "roles": [ + "PROJECT_MANAGER" + ] + }, + "extProjectId": "1910a9fe-59de-4796-aac6-8b7356a7d340", + "teams": [ + { + "id": 139, + "name": "All Users" + } + ], + "users": [ + { + "id": 71, + "role": "PROJECT_MANAGER", + "username": "samplifyweb" + } + ] +} diff --git a/tests/test_files/get_roles.json b/tests/test_files/get_roles.json new file mode 100644 index 0000000..dd41fa9 --- /dev/null +++ b/tests/test_files/get_roles.json @@ -0,0 +1,22 @@ +[ + { + "allowedActions": [ + { + "action": "GET PROJECT", + "description": "Ability to view all the project details", + "id": "GET_PROJECT" + }, + { + "action": "LIST ALL PROJECTS", + "description": "Ability to view a list of projects on samplify", + "id": "LIST_ALL_PROJECTS" + } + ], + "assignableRoles": [ + "SURVEY_AUTHOR" + ], + "description": "", + "id": "SURVEY_AUTHOR", + "name": "Survey Author" + } +] diff --git a/tests/test_files/get_teams.json b/tests/test_files/get_teams.json new file mode 100644 index 0000000..5e3e868 --- /dev/null +++ b/tests/test_files/get_teams.json @@ -0,0 +1,11 @@ +[ + { + "createdAt": "2020/05/06 15:39:03", + "default": true, + "description": "", + "id": 139, + "name": "That's what she said", + "status": "ACTIVE", + "updatedAt": "2020/05/06 15:39:03" + } +] diff --git a/tests/test_files/get_user_info.json b/tests/test_files/get_user_info.json new file mode 100644 index 0000000..52e893f --- /dev/null +++ b/tests/test_files/get_user_info.json @@ -0,0 +1,23 @@ +{ + "companies": [ + { + "default": true, + "defaultRole": "PROJECT_MANAGER", + "id": 51, + "name": "Samplify Web", + "teams": [ + { + "default": true, + "id": 139, + "name": "All Users", + "role": "PROJECT_MANAGER", + "status": "ACTIVE" + } + ] + } + ], + "email": "samplifyweb@dynata.com", + "fullName": "Monica Faloola Gellar", + "id": 71, + "userName": "monicagellarrr" +} diff --git a/tests/test_files/upsert_project_permissions.json b/tests/test_files/upsert_project_permissions.json new file mode 100644 index 0000000..e9a6d36 --- /dev/null +++ b/tests/test_files/upsert_project_permissions.json @@ -0,0 +1,21 @@ +{ + "currentUser": { + "roles": [ + "PROJECT_MANAGER" + ] + }, + "extProjectId": "1910a9fe-59de-4796-aac6-8b7356a7d340", + "teams": [ + { + "id": 139, + "name": "All Users" + } + ], + "users": [ + { + "id": 71, + "role": "PROJECT_MANAGER", + "username": "samplifyweb" + } + ] +} diff --git a/tests/test_permissions.py b/tests/test_permissions.py new file mode 100644 index 0000000..60ff85f --- /dev/null +++ b/tests/test_permissions.py @@ -0,0 +1,59 @@ +# encoding: utf-8 +from __future__ import unicode_literals, print_function + +import json +import unittest +import responses + +from dynatademand.api import DemandAPIClient +from dynatademand.errors import DemandAPIError + +BASE_HOST = "http://test-url.example" + + +class TestProjectPermissionsEndpoints(unittest.TestCase): + def setUp(self): + self.api = DemandAPIClient(client_id='test', username='testuser', password='testpass', base_host=BASE_HOST) + self.api._access_token = 'Bearer testtoken' + + @responses.activate + def test_get_project_permissions(self): + with open('./tests/test_files/get_project_permissions.json', 'r') as get_permissions_file: + permissions_json = json.load(get_permissions_file) + responses.add( + responses.GET, + '{}/sample/v1/projects/1/permissions'.format(BASE_HOST), + json=permissions_json, + status=200 + ) + self.api.get_project_permissions(1) + self.assertEqual(len(responses.calls), 1) + self.assertEqual(responses.calls[0].response.json(), permissions_json) + + @responses.activate + def test_upsert_project_permissions(self): + # Tests updating a project. + with open('./tests/test_files/upsert_project_permissions.json', 'r') as upsert_project_file: + upsert_project_data = json.load(upsert_project_file) + + # Success response + responses.add( + responses.POST, + '{}/sample/v1/projects/1/permissions'.format(BASE_HOST), + json={'status': {'message': 'success'}}, + status=200) + # Error message included + responses.add( + responses.POST, + '{}/sample/v1/projects/1/permissions'.format(BASE_HOST), + json={'status': {'message': 'error'}}, + status=200) + + # Test successful response. + self.api.upsert_project_permissions(1, upsert_project_data) + self.assertEqual(len(responses.calls), 1) + + # Test response with error included. + with self.assertRaises(DemandAPIError): + self.api.upsert_project_permissions(1, upsert_project_data) + self.assertEqual(len(responses.calls), 2) diff --git a/tests/test_roles.py b/tests/test_roles.py new file mode 100644 index 0000000..5bfc717 --- /dev/null +++ b/tests/test_roles.py @@ -0,0 +1,26 @@ +# encoding: utf-8 +from __future__ import unicode_literals, print_function + +import json +import unittest +import responses + +from dynatademand.api import DemandAPIClient + +BASE_HOST = "http://test-url.example" + + +class TestRolesEndpoints(unittest.TestCase): + def setUp(self): + self.api = DemandAPIClient(client_id='test', username='testuser', password='testpass', base_host=BASE_HOST) + self.api._access_token = 'Bearer testtoken' + + @responses.activate + def test_get_roles(self): + # Tests getting all roles. + with open('./tests/test_files/get_roles.json', 'r') as roles: + roles_json = json.load(roles) + # Success response + responses.add(responses.GET, '{}/sample/v1/roles'.format(BASE_HOST), json=roles_json, status=200) + self.api.get_roles() + self.assertEqual(len(responses.calls), 1) diff --git a/tests/test_teams.py b/tests/test_teams.py new file mode 100644 index 0000000..47b987e --- /dev/null +++ b/tests/test_teams.py @@ -0,0 +1,26 @@ +# encoding: utf-8 +from __future__ import unicode_literals, print_function + +import json +import unittest +import responses + +from dynatademand.api import DemandAPIClient + +BASE_HOST = "http://test-url.example" + + +class TestTeamsEndpoints(unittest.TestCase): + def setUp(self): + self.api = DemandAPIClient(client_id='test', username='testuser', password='testpass', base_host=BASE_HOST) + self.api._access_token = 'Bearer testtoken' + + @responses.activate + def test_get_teams(self): + # Tests getting all teams. + with open('./tests/test_files/get_teams.json', 'r') as teams: + teams_json = json.load(teams) + # Success response + responses.add(responses.GET, '{}/sample/v1/teams'.format(BASE_HOST), json=teams_json, status=200) + self.api.get_company_teams() + self.assertEqual(len(responses.calls), 1) diff --git a/tests/test_users.py b/tests/test_users.py new file mode 100644 index 0000000..486ccd8 --- /dev/null +++ b/tests/test_users.py @@ -0,0 +1,36 @@ +# encoding: utf-8 +from __future__ import unicode_literals, print_function + +import json +import unittest +import responses + +from dynatademand.api import DemandAPIClient + +BASE_HOST = "http://test-url.example" + + +class TestUsersEndpoints(unittest.TestCase): + def setUp(self): + self.api = DemandAPIClient(client_id='test', username='testuser', password='testpass', base_host=BASE_HOST) + self.api._access_token = 'Bearer testtoken' + + @responses.activate + def test_get_user_info(self): + # Tests getting currently logged in user info. + with open('./tests/test_files/get_user_info.json', 'r') as user_info: + user_info_json = json.load(user_info) + # Success response + responses.add(responses.GET, '{}/sample/v1/user'.format(BASE_HOST), json=user_info_json, status=200) + self.api.get_user_info() + self.assertEqual(len(responses.calls), 1) + + @responses.activate + def test_get_company_users(self): + # Tests getting all company users. + with open('./tests/test_files/get_company_users.json', 'r') as company_users: + company_users_json = json.load(company_users) + # Success response + responses.add(responses.GET, '{}/sample/v1/users'.format(BASE_HOST), json=company_users_json, status=200) + self.api.get_company_users() + self.assertEqual(len(responses.calls), 1)