Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions cterasdk/core/admins.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from .base_command import BaseCommand
from ..exceptions import CTERAException, ObjectNotFoundException
from ..exceptions.transport import HTTPError
from ..common import Object, DateTimeUtils
from ..common import union
from . import query
Expand Down Expand Up @@ -126,8 +127,19 @@ def modify(self, current_username, new_username=None, email=None, first_name=Non
logger.info("User modified. %s", {'username': user.name})
return response
except CTERAException as error:
logger.error('Could not modify user: %s', ref)
raise CTERAException(f'Could not modify user: {ref}') from error
failure_message = Administrators._modify_failure_message(ref, error)
logger.error('%s', failure_message)
raise CTERAException(failure_message) from error

@staticmethod
def _modify_failure_message(ref, error):
message = f'Could not modify user: {ref}'
if not isinstance(error, HTTPError):
return message
err_detail = error.error.response.error
if hasattr(err_detail, 'msg') and err_detail.msg:
return f'{message}. {err_detail.msg}'
return message

def delete(self, name):
"""
Expand Down
12 changes: 12 additions & 0 deletions docs/source/UserGuides/Miscellaneous/Changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
Changelog
=========

2.20.48
-------

Bug Fixes
^^^^^^^^^

* Restore portal validation details in ``admins.modify`` failure messages when the API returns an
HTTP error with a portal ``msg`` attribute (for example, when the new password matches the current
password).

Related issue: `SDK-369 <https://cteranet.atlassian.net/browse/SDK-369>`_

2.20.47
-------

Expand Down
81 changes: 81 additions & 0 deletions tests/ut/core/admin/test_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,87 @@ def test_modify_admin_user(self):
actual_param = self._global_admin.api.put.call_args[0][1]
self._assert_equal_objects(actual_param, new_user_object)

@mock.patch('cterasdk.core.admins.logger')
def test_modify_admin_user_same_password_includes_portal_msg(self, logger_mock):
current_user_object = self._get_admin_object(
name=self._username,
email=self._email,
firstName=self._first_name,
lastName=self._last_name,
password=self._password,
role=self._role,
company=None,
comment=None
)
portal_msg = 'Object validation failed (field: password error: Old and new passwords cannot be the same)'
password_value = 'Str0ngP@ssword!1'
portal_error = Object()
portal_error.msg = portal_msg
field = Object()
field.name = 'password'
field.desc = 'Old and new passwords cannot be the same'
field.val = password_value
portal_error.fields = [field]
http_error = Object()
http_error.request = Object(url='/administrators/' + self._username)
http_error.response = Object(status=500, error=portal_error)
self._init_global_admin(get_response=current_user_object)
self._global_admin.api.put = mock.MagicMock(side_effect=exceptions.transport.InternalServerError(http_error))
with self.assertRaises(exceptions.CTERAException) as error:
admins.Administrators(self._global_admin).modify(self._username, password=self._password)
ref = f'/administrators/{self._username}'
self._global_admin.api.get.assert_called_once_with(ref)
self._global_admin.api.put.assert_called_once_with(ref, mock.ANY)
exception_text = str(error.exception)
self.assertIn(f'Could not modify user: {ref}', exception_text)
self.assertIn('Old and new passwords cannot be the same', exception_text)
self.assertNotIn(password_value, exception_text)
logger_mock.error.assert_called_once_with('%s', exception_text)

def test_modify_admin_user_http_error_without_portal_msg_uses_generic_message(self):
current_user_object = self._get_admin_object(
name=self._username,
email=self._email,
firstName=self._first_name,
lastName=self._last_name,
password=self._password,
role=self._role,
company=None,
comment=None
)
portal_error = Object()
http_error = Object()
http_error.request = Object(url='/administrators/' + self._username)
http_error.response = Object(status=500, error=portal_error)
self._init_global_admin(get_response=current_user_object)
self._global_admin.api.put = mock.MagicMock(side_effect=exceptions.transport.InternalServerError(http_error))
ref = f'/administrators/{self._username}'
expected_message = f'Could not modify user: {ref}'
with self.assertRaises(exceptions.CTERAException) as error:
admins.Administrators(self._global_admin).modify(self._username, password=self._password)
self.assertEqual(expected_message, str(error.exception))

def test_modify_admin_user_non_http_error_uses_generic_message(self):
current_user_object = self._get_admin_object(
name=self._username,
email=self._email,
firstName=self._first_name,
lastName=self._last_name,
password=self._password,
role=self._role,
company=None,
comment=None
)
self._init_global_admin(get_response=current_user_object)
self._global_admin.api.put = mock.MagicMock(
side_effect=exceptions.ObjectNotFoundException('Object not found')
)
ref = f'/administrators/{self._username}'
expected_message = f'Could not modify user: {ref}'
with self.assertRaises(exceptions.CTERAException) as error:
admins.Administrators(self._global_admin).modify(self._username, password=self._password)
self.assertEqual(expected_message, str(error.exception))

def test_delete_admin_user(self):
execute_response = 'Success'
self._init_global_admin(execute_response=execute_response)
Expand Down
Loading