def test_get_project_permissions(self): mock_requests = MagicMock() page1 = { "results": [ { "project": { "id": "8593ab3c-9999-11e8-9eb6-529269fb1459", }, "user": { "id": "8593aeac-9999-11e8-9eb6-529269fb1459", }, "auth_role": { "id": "project_admin", } } ] } mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value=page1, num_pages=1), ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1", http=mock_requests) response = api.get_project_permissions(project_id='123') args, kwargs = mock_requests.get.call_args self.assertEqual(args[0], 'something.com/v1/projects/123/permissions/') results = response.json()['results'] self.assertEqual(len(results), 1) self.assertEqual(results[0]['project']['id'], '8593ab3c-9999-11e8-9eb6-529269fb1459') self.assertEqual(results[0]['user']['id'], '8593aeac-9999-11e8-9eb6-529269fb1459') self.assertEqual(results[0]['auth_role']['id'], 'project_admin')
def test_check_err_with_404_with_flag(self): resp = Mock(headers={}, status_code=404) resp.json.return_value = {"code": "resource_not_consistent"} url_suffix = "" data = None with self.assertRaises(DSResourceNotConsistentError): DataServiceApi._check_err(resp, url_suffix, data, allow_pagination=False)
def test_get_collection_one_page(self): mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value={"results": [1, 2, 3]}, num_pages=1) ] api = DataServiceApi(auth=None, url="something.com/v1/", http=mock_requests) response = api._get_collection(url_suffix="users", data={}, content_type=ContentType.json) self.assertEqual([1, 2, 3], response.json()["results"]) call_args_list = mock_requests.get.call_args_list self.assertEqual(1, len(call_args_list)) # Check first request call_args = call_args_list[0] first_param = call_args[0][0] self.assertEqual('something.com/v1/users', first_param) dict_param = call_args[1] self.assertEqual('application/json', dict_param['headers']['Content-Type']) self.assertIn("DukeDSClient/", dict_param['headers']['User-Agent']) self.assertIn('"per_page": 100', dict_param['params'])
def test_get_collection_two_pages(self): mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value={"results": [1, 2, 3]}, num_pages=2), fake_response_with_pages(status_code=200, json_return_value={"results": [4, 5]}, num_pages=2) ] api = DataServiceApi(self.create_mock_auth(config_page_size=100), url="something.com/v1/", http=mock_requests) response = api._get_collection(url_suffix="projects", data={}) self.assertEqual([1, 2, 3, 4, 5], response.json()["results"]) call_args_list = mock_requests.get.call_args_list self.assertEqual(2, len(call_args_list)) # Check first request call_args = call_args_list[0] first_param = call_args[0][0] self.assertEqual('something.com/v1/projects', first_param) dict_param = call_args[1] self.assertEqual('application/x-www-form-urlencoded', dict_param['headers']['Content-Type']) self.assertIn("DukeDSClient/", dict_param['headers']['User-Agent']) self.assertEqual(100, dict_param['params']['per_page']) self.assertEqual(1, dict_param['params']['page']) # Check second request call_args = call_args_list[1] first_param = call_args[0][0] self.assertEqual('something.com/v1/projects', first_param) dict_param = call_args[1] self.assertEqual('application/x-www-form-urlencoded', dict_param['headers']['Content-Type']) self.assertIn("DukeDSClient/", dict_param['headers']['User-Agent']) self.assertEqual(100, dict_param['params']['per_page']) self.assertEqual(2, dict_param['params']['page'])
def test_get_projects(self): page1 = { "results": [ { "id": "1234" } ] } page2 = { "results": [ { "id": "1235" } ] } mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value=page1, num_pages=2), fake_response_with_pages(status_code=200, json_return_value=page2, num_pages=2), ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1", http=mock_requests) resp = api.get_projects() self.assertEqual(2, len(resp.json()['results'])) self.assertEqual("1234", resp.json()['results'][0]['id']) self.assertEqual("1235", resp.json()['results'][1]['id']) self.assertEqual(2, mock_requests.get.call_count) first_call_second_arg = mock_requests.get.call_args_list[0][1] self.assertEqual('application/x-www-form-urlencoded', first_call_second_arg['headers']['Content-Type']) self.assertEqual(100, first_call_second_arg['params']['per_page']) self.assertEqual(1, first_call_second_arg['params']['page']) second_call_second_arg = mock_requests.get.call_args_list[0][1] self.assertEqual(100, second_call_second_arg['params']['per_page']) self.assertEqual(1, second_call_second_arg['params']['page'])
def test_get_collection_two_pages(self): mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value={"results": [1, 2, 3]}, num_pages=2), fake_response_with_pages(status_code=200, json_return_value={"results": [4, 5]}, num_pages=2) ] api = DataServiceApi(auth=None, url="something.com/v1/", http=mock_requests) response = api._get_collection(url_suffix="projects", data={}, content_type=ContentType.json) self.assertEqual([1, 2, 3, 4, 5], response.json()["results"]) call_args_list = mock_requests.get.call_args_list self.assertEqual(2, len(call_args_list)) # Check first request call_args = call_args_list[0] first_param = call_args[0][0] self.assertEqual('something.com/v1/projects', first_param) dict_param = call_args[1] self.assertEqual({'Content-Type': 'application/json'}, dict_param['headers']) self.assertIn('"per_page": 100', dict_param['params']) # Check second request call_args = call_args_list[1] first_param = call_args[0][0] self.assertEqual('something.com/v1/projects', first_param) dict_param = call_args[1] self.assertEqual({'Content-Type': 'application/json'}, dict_param['headers']) self.assertIn('"per_page": 100', dict_param['params']) self.assertIn('"page": 2', dict_param['params'])
def test_check_err_with_404(self): resp = Mock(headers={}, status_code=404) resp.json.return_value = {"code": "not_found"} url_suffix = "" data = None with self.assertRaises(DataServiceError): DataServiceApi._check_err(resp, url_suffix, data, allow_pagination=False)
def test_put_create_upload_url_invalid_number(self): mock_requests = MagicMock() api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1", http=mock_requests) with self.assertRaises(ValueError) as raised_exception: api.create_upload_url(upload_id='someId', number=0, size=200, hash_value='somehash', hash_alg='md5') self.assertEqual(str(raised_exception.exception), "Chunk number must be > 0")
def test_get_single_page_works_on_paging_response(self): mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value={"ok": True}, num_pages=3) ] api = DataServiceApi(auth=None, url="something.com/v1/", http=mock_requests) resp = api._get_single_page(url_suffix='stuff', data={}, content_type=ContentType.json, page_num=1) self.assertEqual(True, resp.json()['ok'])
def __init__(self, config): """ Setup to allow fetching project tree. :param config: ddsc.config.Config settings to use for connecting to the dataservice. """ self.config = config auth = DataServiceAuth(self.config) self.data_service = DataServiceApi(auth, self.config.url)
def test_get_single_page_works_on_paging_response(self): mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value={"ok": True}, num_pages=3) ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1/", http=mock_requests) resp = api._get_single_page(url_suffix='stuff', data={}, page_num=1) self.assertEqual(True, resp.json()['ok'])
def test_get_single_item_raises_error_on_paging_response(self): mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value={}, num_pages=3) ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1/", http=mock_requests) with self.assertRaises(UnexpectedPagingReceivedError): api._get_single_item(url_suffix='stuff', data={})
def test_get_single_item_raises_error_on_paging_response(self): mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value={}, num_pages=3) ] api = DataServiceApi(auth=None, url="something.com/v1/", http=mock_requests) with self.assertRaises(ValueError) as er: resp = api._get_single_item(url_suffix='stuff', data={}) self.assertEqual(UNEXPECTED_PAGING_DATA_RECEIVED, str(er.exception))
def test_get_folder(self): mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response(status_code=200, json_return_value={}) ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="base/v1", http=mock_requests) api.get_folder(folder_id='1023aef') mock_requests.get.assert_called() args, kw = mock_requests.get.call_args self.assertEqual(args[0], 'base/v1/folders/1023aef')
def test_get_auth_provider_affiliates_username(self): mock_requests, json_results = self.make_mock_requests_for_auth_provider_affiliates() api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1", http=mock_requests) result = api.get_auth_provider_affiliates('provider_id_123', username='******') self.assertEqual(200, result.status_code) self.assertEqual(json_results, result.json()) mock_requests.get.assert_called_with('something.com/v1/auth_providers/provider_id_123/affiliates/', headers=ANY, params={'username': '******', 'page': 1, 'per_page': 100})
def test_delete_file(self): mock_requests = MagicMock() mock_requests.delete.side_effect = [ fake_response(status_code=200, json_return_value={}) ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="base/v1", http=mock_requests) api.delete_file(file_id='1023cde') mock_requests.delete.assert_called() args, kw = mock_requests.delete.call_args self.assertEqual(args[0], 'base/v1/files/1023cde')
def test_get_auth_provider(self): mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response(status_code=200, json_return_value={"ok": True}) ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1", http=mock_requests) result = api.get_auth_provider('provider_id_123') self.assertEqual(200, result.status_code) mock_requests.get.assert_called_with('something.com/v1/auth_providers/provider_id_123/', headers=ANY, params=ANY)
def test_put_create_upload_url(self): mock_requests = MagicMock() api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1", http=mock_requests) mock_response = { "id": "8593aeac-9999-11e8-9eb6-529269fb1459" } mock_requests.put.side_effect = [ fake_response(status_code=200, json_return_value=mock_response), ] resp = api.create_upload_url(upload_id='someId', number=1, size=200, hash_value='somehash', hash_alg='md5') self.assertEqual(resp.json(), mock_response)
def test_get_project_transfers(self): return_value = {"results": [{"id": "1234"}]} mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value=return_value, num_pages=1) ] api = DataServiceApi(auth=None, url="something.com/v1/", http=mock_requests) resp = api.get_project_transfers(project_id='4521') self.assertEqual(1, len(resp.json()['results'])) self.assertEqual("1234", resp.json()['results'][0]['id'])
def test_auth_provider_add_user(self): user = { "id": "abc4e9-9987-47eb-bb4e-19f0203efbf6", "username": "******", } mock_requests = MagicMock() mock_requests.post.side_effect = [ fake_response(status_code=200, json_return_value=user) ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1", http=mock_requests) result = api.auth_provider_add_user('123', "joe") self.assertEqual(200, result.status_code) self.assertEqual(user, result.json()) expected_url = 'something.com/v1/auth_providers/123/affiliates/joe/dds_user/' self.assertEqual(expected_url, mock_requests.post.call_args_list[0][0][0])
def test_get_all_project_transfers(self): return_value = { "results": [ {"id": "abcd"}, {"id": "efgh"} ] } mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value=return_value, num_pages=1) ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1/", http=mock_requests) resp = api.get_all_project_transfers() self.assertEqual(2, len(resp.json()['results'])) self.assertEqual("abcd", resp.json()['results'][0]['id']) self.assertEqual("efgh", resp.json()['results'][1]['id'])
def test_auth_provider_add_user(self): user = { "id": "abc4e9-9987-47eb-bb4e-19f0203efbf6", "username": "******", } mock_requests = MagicMock() mock_requests.post.side_effect = [ fake_response(status_code=200, json_return_value=user) ] api = DataServiceApi(auth=None, url="something.com/v1", http=mock_requests) result = api.auth_provider_add_user('123', "joe") self.assertEqual(200, result.status_code) self.assertEqual(user, result.json()) expected_url = 'something.com/v1/auth_providers/123/affiliates/joe/dds_user/' self.assertEqual(expected_url, mock_requests.post.call_args_list[0][0][0])
def test_list_auth_roles(self): return_value = { "results": [ { "id": "project_admin", "name": "Project Admin", } ] } mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value=return_value, num_pages=1) ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1/", http=mock_requests) resp = api.get_auth_roles(context='') self.assertEqual(1, len(resp.json()['results'])) self.assertEqual("Project Admin", resp.json()['results'][0]['name'])
def test_get_project_files(self): mock_requests = MagicMock() page1 = { "results": [ { "id": "1234" } ] } mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value=page1, num_pages=1), ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1", http=mock_requests) api.get_project_files(project_id='123') args, kwargs = mock_requests.get.call_args self.assertEqual(args[0], 'something.com/v1/projects/123/files')
def test_list_auth_roles(self): return_value = { "results": [{ "id": "project_admin", "name": "Project Admin", }] } mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value=return_value, num_pages=1) ] api = DataServiceApi(auth=None, url="something.com/v1/", http=mock_requests) resp = api.get_auth_roles(context='') self.assertEqual(1, len(resp.json()['results'])) self.assertEqual("Project Admin", resp.json()['results'][0]['name'])
def test_get_project_children(self): mock_requests = MagicMock() page1 = { "results": [ { "id": "1234" } ] } mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value=page1, num_pages=1), ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1", http=mock_requests) api.get_project_children(project_id='123', name_contains='test', exclude_response_fields=['this', 'that']) args, kwargs = mock_requests.get.call_args params = kwargs['params'] self.assertEqual('test', params['name_contains']) self.assertEqual('this that', params['exclude_response_fields'])
def rebuild_data_service(config, data_service_auth_data): """ Deserialize value into DataServiceApi object. :param config: :param data_service_auth_data: :return: """ auth = DataServiceAuth(config) auth.set_auth_data(data_service_auth_data) return DataServiceApi(auth, config.url)
def authenticate(self, token): """ Authenticate a user with a DukeDS API token. Returns None if no user could be authenticated, and sets the errors list with the reasons :param token: A JWT token :return: an authenticated, populated user if found, or None if not. """ self.failure_reason = None # 1. check if token is valid for this purpose try: check_jwt_token(token) except InvalidTokenError as e: self.failure_reason = e # Token may be expired or may not be valid for this service, so return None return None # Token is a JWT and not expired # 2. Check if token exists in database user = get_local_user(token) if user: # token matched a user, return it return user # 3. Token appears valid but we have not seen it before. # Fetch user details from DukeDS config = make_auth_config(token) auth = DataServiceAuth(config) api = DataServiceApi(auth, config.url) try: response = api.get_current_user() response.raise_for_status() user_dict = response.json() except HTTPError as e: self.failure_reason = e return None # DukeDS shouldn't stomp over existing user details user = self.save_user(user_dict, False) # 4. Have a user, save their token save_dukeds_token(user, token) self.handle_new_user(user, user_dict) return user
def test_get_users_no_filtering(self): mock_requests = MagicMock() page1 = { "results": [ { "id": "8593aeac-9999-11e8-9eb6-529269fb1459" } ] } mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value=page1, num_pages=1), ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1", http=mock_requests) response = api.get_users() mock_requests.get.assert_called_with('something.com/v1/users', headers=ANY, params={'page': 1, 'per_page': 100}) results = response.json()['results'] self.assertEqual(len(results), 1) self.assertEqual(results[0]['id'], '8593aeac-9999-11e8-9eb6-529269fb1459')
def test_create_upload(self): mock_requests = MagicMock() api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1", http=mock_requests) mock_requests.post.return_value = fake_response(status_code=201, json_return_value={}) api.create_upload(project_id='123', filename='data.txt', content_type='sometype', size=10, hash_value='somehash', hash_alg='md5', storage_provider_id='abc456') expected_data = json.dumps({ "name": "data.txt", "content_type": "sometype", "size": 10, "hash": { "value": "somehash", "algorithm": "md5" }, "chunked": True, "storage_provider": {"id": "abc456"} }) mock_requests.post.assert_called_with('something.com/v1/projects/123/uploads', expected_data, headers=ANY)
def test_get_auth_providers(self): provider = { "id": "aca35ba3-a44a-47c2-8b3b-afe43a88360d", "service_id": "cfde039d-f550-47e7-833c-9ebc4e257847", "name": "Duke Authentication Service", "is_deprecated": True, "is_default": True, "login_initiation_url": "https://someurl" } json_results = {"results": [provider]} mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value=json_results, num_pages=1) ] api = DataServiceApi(auth=None, url="something.com/v1", http=mock_requests) result = api.get_auth_providers() self.assertEqual(200, result.status_code) self.assertEqual(json_results, result.json()) self.assertEqual('something.com/v1/auth_providers', mock_requests.get.call_args_list[0][0][0])
def test_get_auth_providers(self): provider = { "id": "aca35ba3-a44a-47c2-8b3b-afe43a88360d", "service_id": "cfde039d-f550-47e7-833c-9ebc4e257847", "name": "Duke Authentication Service", "is_deprecated": True, "is_default": True, "login_initiation_url": "https://someurl" } json_results = { "results": [ provider ] } mock_requests = MagicMock() mock_requests.get.side_effect = [ fake_response_with_pages(status_code=200, json_return_value=json_results, num_pages=1) ] api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="something.com/v1", http=mock_requests) result = api.get_auth_providers() self.assertEqual(200, result.status_code) self.assertEqual(json_results, result.json()) self.assertEqual('something.com/v1/auth_providers', mock_requests.get.call_args_list[0][0][0])
def upload_async(data_service_auth_data, config, upload_id, filename, index, num_chunks_to_send, progress_queue): """ Method run in another process called from ParallelChunkProcessor.make_and_start_process. :param data_service_auth_data: tuple of auth data for rebuilding DataServiceAuth :param config: dds.Config configuration settings to use during upload :param upload_id: uuid unique id of the 'upload' we are uploading chunks into :param filename: str path to file who's contents we will be uploading :param index: int offset into filename where we will start sending bytes from (must multiply by upload_bytes_per_chunk) :param num_chunks_to_send: int number of chunks of config.upload_bytes_per_chunk size to send. :param progress_queue: ProgressQueue queue to send notifications of progress or errors """ auth = DataServiceAuth(config) auth.set_auth_data(data_service_auth_data) data_service = DataServiceApi(auth, config.url) sender = ChunkSender(data_service, upload_id, filename, config.upload_bytes_per_chunk, index, num_chunks_to_send, progress_queue) return sender.send()
class RemoteStore(object): """ Fetches project tree data from remote store. """ def __init__(self, config): """ Setup to allow fetching project tree. :param config: ddsc.config.Config settings to use for connecting to the dataservice. """ self.config = config auth = DataServiceAuth(self.config) self.data_service = DataServiceApi(auth, self.config.url) def fetch_remote_project(self, project_name, must_exist=False, include_children=True): """ Retrieve the project via project_name. :param project_name: str name of the project to try and download :param must_exist: should we error if the project doesn't exist :param include_children: should we read children(folders/files) :return: RemoteProject project requested or None if not found(and must_exist=False) """ project = self._get_my_project(project_name) if project: if include_children: self._add_project_children(project) else: if must_exist: raise NotFoundError( u'There is no project with the name {}'.format( project_name).encode('utf-8')) return project def fetch_remote_project_by_id(self, id): """ Retrieves project from via id :param id: str id of project from data service :return: RemoteProject we downloaded """ response = self.data_service.get_project_by_id(id).json() return RemoteProject(response) def _get_my_project(self, project_name): """ Return project tree root for project_name. :param project_name: str name of the project to download :return: RemoteProject project we found or None """ response = self.data_service.get_projects().json() for project in response['results']: if project['name'] == project_name: return RemoteProject(project) return None def _add_project_children(self, project): """ Add the rest of the project tree from the remote store to the project object. :param project: RemoteProject root of the project tree to add children too """ response = self.data_service.get_project_children(project.id, '').json() project_children = RemoteProjectChildren(project.id, response['results']) for child in project_children.get_tree(): project.add_child(child) def lookup_or_register_user_by_email_or_username(self, email, username): """ Lookup user by email or username. Only fill in one field. For username it will try to register if not found. :param email: str: email address of the user :param username: netid of the user to find :return: RemoteUser """ if username: return self.get_or_register_user_by_username(username) else: # API doesn't support registering user by email address yet return self.lookup_user_by_email(email) def lookup_user_by_name(self, full_name): """ Query remote store for a single user with the name full_name or raise error. :param full_name: str Users full name separated by a space. :return: RemoteUser user info for single user with full_name """ res = self.data_service.get_users_by_full_name(full_name) json_data = res.json() results = json_data['results'] found_cnt = len(results) if found_cnt == 0: raise NotFoundError("User not found:" + full_name) elif found_cnt > 1: raise ValueError("Multiple users with name:" + full_name) user = RemoteUser(results[0]) if user.full_name.lower() != full_name.lower(): raise NotFoundError("User not found:" + full_name) return user def lookup_user_by_username(self, username): """ Finds the single user who has this username or raises ValueError. :param username: str username we are looking for :return: RemoteUser: user we found """ matches = [ user for user in self.fetch_all_users() if user.username == username ] if not matches: raise NotFoundError('Username not found: {}.'.format(username)) if len(matches) > 1: raise ValueError( 'Multiple users with same username found: {}.'.format( username)) return matches[0] def get_or_register_user_by_username(self, username): """ Try to lookup user by username. If not found try registering the user. :param username: str: username to lookup :return: RemoteUser: user we found """ try: return self.lookup_user_by_username(username) except NotFoundError: return self.register_user_by_username(username) def register_user_by_username(self, username): """ Tries to register user with the first non-deprecated auth provider. Raises ValueError if the data service doesn't have any non-deprecated providers. :param username: str: netid of the user we are trying to register :return: RemoteUser: user that was created for our netid """ current_providers = [ prov.id for prov in self.get_auth_providers() if not prov.is_deprecated ] if not current_providers: raise ValueError( "Unable to register user: no non-deprecated providers found!") auth_provider_id = current_providers[0] return self._register_user_by_username(auth_provider_id, username) def _register_user_by_username(self, auth_provider_id, username): """ Tries to register a user who has a valid netid but isn't registered with DukeDS yet under auth_provider_id. :param auth_provider_id: str: id from RemoteAuthProvider to use for registering :param username: str: netid of the user we are trying to register :return: RemoteUser: user that was created for our netid """ user_json = self.data_service.auth_provider_add_user( auth_provider_id, username).json() return RemoteUser(user_json) def get_auth_providers(self): """ Return the list of authorization providers. :return: [RemoteAuthProvider]: list of remote auth providers """ providers = [] response = self.data_service.get_auth_providers().json() for data in response['results']: providers.append(RemoteAuthProvider(data)) return providers def lookup_user_by_email(self, email): """ Finds the single user who has this email or raises ValueError. :param email: str email we are looking for :return: RemoteUser user we found """ matches = [ user for user in self.fetch_all_users() if user.email == email ] if not matches: raise ValueError('Email not found: {}.'.format(email)) if len(matches) > 1: raise ValueError( 'Multiple users with same email found: {}.'.format(email)) return matches[0] def get_current_user(self): """ Fetch info about the current user :return: RemoteUser user who we are logged in as(auth determines this). """ response = self.data_service.get_current_user().json() return RemoteUser(response) def fetch_all_users(self): """ Retrieves all users from data service. :return: [RemoteUser] list of all users we downloaded """ users = [] result = self.data_service.get_all_users() user_list_json = result.json() for user_json in user_list_json['results']: users.append(RemoteUser(user_json)) return users def fetch_user(self, id): """ Retrieves user from data service having a specific id :param id: str id of user from data service :return: RemoteUser user we downloaded """ response = self.data_service.get_user_by_id(id).json() return RemoteUser(response) def set_user_project_permission(self, project, user, auth_role): """ Update remote store for user giving auth_role permissions on project. :param project: RemoteProject project to give permissions to :param user: RemoteUser user who we are giving permissions to :param auth_role: str type of authorization to give user(project_admin) """ self.data_service.set_user_project_permission(project.id, user.id, auth_role) def revoke_user_project_permission(self, project, user): """ Update remote store for user removing auth_role permissions on project. :param project: RemoteProject project to remove permissions from :param user: RemoteUser user who we are removing permissions from """ # Server errors out with 500 if a user isn't found. try: self.data_service.get_user_project_permission(project.id, user.id) self.data_service.revoke_user_project_permission( project.id, user.id) except DataServiceError as e: if e.status_code != 404: raise def download_file(self, remote_file, path, watcher): """ Download a remote file associated with the remote uuid(file_id) into local path. :param remote_file: RemoteFile file to retrieve :param path: str file system path to save the contents to. :param watcher: object implementing send_item(item, increment_amt) that updates UI """ url_json = self.data_service.get_file_url(remote_file.id).json() http_verb = url_json['http_verb'] host = url_json['host'] url = url_json['url'] http_headers = url_json['http_headers'] response = self.data_service.receive_external(http_verb, host, url, http_headers) with open(path, 'wb') as f: for chunk in response.iter_content( chunk_size=DOWNLOAD_FILE_CHUNK_SIZE): if chunk: # filter out keep-alive new chunks f.write(chunk) watcher.transferring_item(remote_file, increment_amt=len(chunk)) def get_project_names(self): """ Return a list of names of the remote projects owned by this user. :return: [str]: the list of project names """ names = [] response = self.data_service.get_projects().json() for project in response['results']: names.append(project['name']) return names def delete_project_by_name(self, project_name): """ Find the project named project_name and delete it raise error if not found. :param project_name: str: Name of the project we want to be deleted """ project = self._get_my_project(project_name) if project: self.data_service.delete_project(project.id) else: raise ValueError( "No project named '{}' found.\n".format(project_name)) def get_active_auth_roles(self, context): """ Retrieve non-deprecated authorization roles based on a context. Context should be RemoteAuthRole.PROJECT_CONTEXT or RemoteAuthRole.SYSTEM_CONTEXT. :param context: str: context for which auth roles to retrieve :return: [RemoteAuthRole]: list of active auth_role objects """ response = self.data_service.get_auth_roles(context).json() return self.get_active_auth_roles_from_json(response) @staticmethod def get_active_auth_roles_from_json(json_data): """ Given a json blob response containing a list of authorization roles return the active ones in an array of RemoteAuthRole objects. :param json_data: list of dictionaries - data from dds in auth_role format :return: [RemoteAuthRole] list of active auth_role objects """ result = [] for auth_role_properties in json_data['results']: auth_role = RemoteAuthRole(auth_role_properties) if not auth_role.is_deprecated: result.append(auth_role) return result
def test_relations_methods(self): api = DataServiceApi(auth=None, url="base/v1/", http=MagicMock()) api._get_collection = MagicMock() api._get_single_item = MagicMock() api._post = MagicMock() api._delete = MagicMock() # This endpoint is a little strange with using object_kind and relation types as magic values api.get_relations('dds-file', '123') api._get_collection.assert_called_with('/relations/dds-file/123', {}) api.get_relation('124') api._get_single_item.assert_called_with('/relations/124/', {}) api.create_used_relation('125', 'dds-file', '456') payload = { 'entity': { 'kind': 'dds-file', 'id': '456' }, 'activity': { 'id': '125' } } api._post.assert_called_with('/relations/used', payload) api.create_was_generated_by_relation('126', 'dds-file', '457') payload = { 'entity': { 'kind': 'dds-file', 'id': '457' }, 'activity': { 'id': '126' } } api._post.assert_called_with('/relations/was_generated_by', payload) api.create_was_generated_by_relation('126', 'dds-file', '457') payload = { 'entity': { 'kind': 'dds-file', 'id': '457' }, 'activity': { 'id': '126' } } api._post.assert_called_with('/relations/was_generated_by', payload) api.create_was_invalidated_by_relation('127', 'dds-file', '458') payload = { 'entity': { 'kind': 'dds-file', 'id': '458' }, 'activity': { 'id': '127' } } api._post.assert_called_with('/relations/was_invalidated_by', payload) api.create_was_derived_from_relation('128', 'dds-file', '129', 'dds-file') payload = { 'generated_entity': { 'kind': 'dds-file', 'id': '129' }, 'used_entity': { 'kind': 'dds-file', 'id': '128' } } api._post.assert_called_with('/relations/was_derived_from', payload) api.delete_relation('130') api._delete.assert_called_with('/relations/130/', {})
def test_constructor_creates_session_when_passed_none(self): api = DataServiceApi(auth=None, url="something.com/v1/", http=None) self.assertIsNotNone(api.http) self.assertEqual(type(api.http), requests.sessions.Session)
def test_relations_methods(self): api = DataServiceApi(auth=self.create_mock_auth(config_page_size=100), url="base/v1/", http=MagicMock()) api._get_collection = MagicMock() api._get_single_item = MagicMock() api._post = MagicMock() api._delete = MagicMock() # This endpoint is a little strange with using object_kind and relation types as magic values api.get_relations('dds-file', '123') api._get_collection.assert_called_with('/relations/dds-file/123', {}) api.get_relation('124') api._get_single_item.assert_called_with('/relations/124/', {}) api.create_used_relation('125', 'dds-file', '456') payload = { 'entity': { 'kind': 'dds-file', 'id': '456' }, 'activity': { 'id': '125' } } api._post.assert_called_with('/relations/used', payload) api.create_was_generated_by_relation('126', 'dds-file', '457') payload = { 'entity': { 'kind': 'dds-file', 'id': '457' }, 'activity': { 'id': '126' } } api._post.assert_called_with('/relations/was_generated_by', payload) api.create_was_generated_by_relation('126', 'dds-file', '457') payload = { 'entity': { 'kind': 'dds-file', 'id': '457' }, 'activity': { 'id': '126' } } api._post.assert_called_with('/relations/was_generated_by', payload) api.create_was_invalidated_by_relation('127', 'dds-file', '458') payload = { 'entity': { 'kind': 'dds-file', 'id': '458' }, 'activity': { 'id': '127' } } api._post.assert_called_with('/relations/was_invalidated_by', payload) api.create_was_derived_from_relation('128', 'dds-file', '129', 'dds-file') payload = { 'generated_entity': { 'kind': 'dds-file', 'id': '129' }, 'used_entity': { 'kind': 'dds-file', 'id': '128' } } api._post.assert_called_with('/relations/was_derived_from', payload) api.delete_relation('130') api._delete.assert_called_with('/relations/130/', {})
def test_check_err_with_good_response(self): resp = Mock(headers={}, status_code=202) url_suffix = "" data = None DataServiceApi._check_err(resp, url_suffix, data, allow_pagination=False)
def test_check_err_with_400(self): resp = Mock(headers={}, status_code=400) url_suffix = "" data = None with self.assertRaises(DataServiceError): DataServiceApi._check_err(resp, url_suffix, data, allow_pagination=False)