diff --git a/SoftLayer/CLI/routes.py b/SoftLayer/CLI/routes.py index 48b0af834..049b43c3b 100644 --- a/SoftLayer/CLI/routes.py +++ b/SoftLayer/CLI/routes.py @@ -316,6 +316,8 @@ ('user:detail', 'SoftLayer.CLI.user.detail:cli'), ('user:permissions', 'SoftLayer.CLI.user.permissions:cli'), ('user:edit-permissions', 'SoftLayer.CLI.user.edit_permissions:cli'), + ('user:notifications', 'SoftLayer.CLI.user.notifications:cli'), + ('user:edit-notifications', 'SoftLayer.CLI.user.edit_notifications:cli'), ('user:edit-details', 'SoftLayer.CLI.user.edit_details:cli'), ('user:create', 'SoftLayer.CLI.user.create:cli'), ('user:delete', 'SoftLayer.CLI.user.delete:cli'), diff --git a/SoftLayer/CLI/user/edit_notifications.py b/SoftLayer/CLI/user/edit_notifications.py new file mode 100644 index 000000000..1be7527c2 --- /dev/null +++ b/SoftLayer/CLI/user/edit_notifications.py @@ -0,0 +1,35 @@ +"""Enable or Disable specific noticication for the current user""" +# :license: MIT, see LICENSE for more details. + +import click + +import SoftLayer +from SoftLayer.CLI import environment + + +@click.command() +@click.option('--enable/--disable', default=True, + help="Enable (DEFAULT) or Disable selected notification") +@click.argument('notification', nargs=-1, required=True) +@environment.pass_env +def cli(env, enable, notification): + """Enable or Disable specific notifications for the active user. + + Notification names should be enclosed in quotation marks. + Example:: + + slcli user edit-notifications --enable 'Order Approved' 'Reload Complete' + + """ + + mgr = SoftLayer.UserManager(env.client) + + if enable: + result = mgr.enable_notifications(notification) + else: + result = mgr.disable_notifications(notification) + + if result: + click.secho("Notifications updated successfully: %s" % ", ".join(notification), fg='green') + else: + click.secho("Failed to update notifications: %s" % ", ".join(notification), fg='red') diff --git a/SoftLayer/CLI/user/notifications.py b/SoftLayer/CLI/user/notifications.py new file mode 100644 index 000000000..deffd951e --- /dev/null +++ b/SoftLayer/CLI/user/notifications.py @@ -0,0 +1,34 @@ +"""List user notifications""" +import click + +import SoftLayer +from SoftLayer.CLI import environment +from SoftLayer.CLI import formatting + + +@click.command() +@environment.pass_env +def cli(env): + """My Notifications.""" + + mgr = SoftLayer.UserManager(env.client) + + all_notifications = mgr.get_all_notifications() + + env.fout(notification_table(all_notifications)) + + +def notification_table(all_notifications): + """Creates a table of available notifications""" + + table = formatting.Table(['Id', 'Name', 'Description', 'Enabled']) + table.align['Id'] = 'l' + table.align['Name'] = 'l' + table.align['Description'] = 'l' + table.align['Enabled'] = 'l' + for notification in all_notifications: + table.add_row([notification['id'], + notification['name'], + notification['description'], + notification['enabled']]) + return table diff --git a/SoftLayer/fixtures/SoftLayer_Email_Subscription.py b/SoftLayer/fixtures/SoftLayer_Email_Subscription.py new file mode 100644 index 000000000..bc3104b16 --- /dev/null +++ b/SoftLayer/fixtures/SoftLayer_Email_Subscription.py @@ -0,0 +1,22 @@ +getAllObjects = [ + {'description': 'Email about your order.', + 'enabled': True, + 'id': 1, + 'name': 'Order Being Reviewed' + }, + {'description': 'Maintenances that will or are likely to cause service ' + 'outages and disruptions', + 'enabled': True, + 'id': 8, + 'name': 'High Impact' + }, + {'description': 'Testing description.', + 'enabled': True, + 'id': 111, + 'name': 'Test notification' + } +] + +enable = True + +disable = True diff --git a/SoftLayer/managers/user.py b/SoftLayer/managers/user.py index 5875d76a8..0948df8b3 100644 --- a/SoftLayer/managers/user.py +++ b/SoftLayer/managers/user.py @@ -36,6 +36,7 @@ def __init__(self, client): self.user_service = self.client['SoftLayer_User_Customer'] self.override_service = self.client['Network_Service_Vpn_Overrides'] self.account_service = self.client['SoftLayer_Account'] + self.subscription_service = self.client['SoftLayer_Email_Subscription'] self.resolvers = [self._get_id_from_username] self.all_permissions = None @@ -85,6 +86,52 @@ def get_all_permissions(self): self.all_permissions = sorted(permissions, key=itemgetter('keyName')) return self.all_permissions + def get_all_notifications(self): + """Calls SoftLayer_Email_Subscription::getAllObjects + + Stores the result in self.all_permissions + :returns: A list of dictionaries that contains all valid permissions + """ + return self.subscription_service.getAllObjects(mask='mask[enabled]') + + def enable_notifications(self, notifications_names): + """Enables a list of notifications for the current a user profile. + + :param list notifications_names: List of notifications names to enable + :returns: True on success + + Example:: + enable_notifications(['Order Approved','Reload Complete']) + """ + + result = False + notifications = self.gather_notifications(notifications_names) + for notification in notifications: + notification_id = notification.get('id') + result = self.subscription_service.enable(id=notification_id) + if not result: + return False + return result + + def disable_notifications(self, notifications_names): + """Disable a list of notifications for the current a user profile. + + :param list notifications_names: List of notifications names to disable + :returns: True on success + + Example:: + disable_notifications(['Order Approved','Reload Complete']) + """ + + result = False + notifications = self.gather_notifications(notifications_names) + for notification in notifications: + notification_id = notification.get('id') + result = self.subscription_service.disable(id=notification_id) + if not result: + return False + return result + def add_permissions(self, user_id, permissions): """Enables a list of permissions for a user @@ -237,6 +284,23 @@ def format_permission_object(self, permissions): raise exceptions.SoftLayerError("'%s' is not a valid permission" % permission) return pretty_permissions + def gather_notifications(self, notifications_names): + """Gets a list of notifications. + + :param list notifications_names: A list of notifications names. + :returns: list of notifications. + """ + notifications = [] + available_notifications = self.get_all_notifications() + for notification in notifications_names: + result = next((item for item in available_notifications + if item.get('name') == notification), None) + if result: + notifications.append(result) + else: + raise exceptions.SoftLayerError("{} is not a valid notification name".format(notification)) + return notifications + def create_user(self, user_object, password): """Blindly sends user_object to SoftLayer_User_Customer::createObject diff --git a/docs/cli/users.rst b/docs/cli/users.rst index feb94e352..5195a7788 100644 --- a/docs/cli/users.rst +++ b/docs/cli/users.rst @@ -12,10 +12,18 @@ Version 5.6.0 introduces the ability to interact with user accounts from the cli :prog: user detail :show-nested: +.. click:: SoftLayer.CLI.user.notifications:cli + :prog: user notifications + :show-nested: + .. click:: SoftLayer.CLI.user.permissions:cli :prog: user permissions :show-nested: +.. click:: SoftLayer.CLI.user.edit_notifications:cli + :prog: user edit-notifications + :show-nested: + .. click:: SoftLayer.CLI.user.edit_permissions:cli :prog: user edit-permissions :show-nested: diff --git a/tests/CLI/modules/user_tests.py b/tests/CLI/modules/user_tests.py index 6f58c14a0..f16ef1843 100644 --- a/tests/CLI/modules/user_tests.py +++ b/tests/CLI/modules/user_tests.py @@ -305,3 +305,35 @@ def test_vpn_subnet_remove(self, click): result = self.run_command(['user', 'vpn-subnet', '12345', '--remove', '1234']) click.secho.assert_called_with('12345 updated successfully', fg='green') self.assert_no_fail(result) + + """User notification tests""" + + def test_notificacions_list(self): + result = self.run_command(['user', 'notifications']) + self.assert_no_fail(result) + self.assert_called_with('SoftLayer_Email_Subscription', 'getAllObjects', mask='mask[enabled]') + + """User edit-notification tests""" + + def test_edit_notification_on(self): + result = self.run_command(['user', 'edit-notifications', '--enable', 'Test notification']) + self.assert_no_fail(result) + self.assert_called_with('SoftLayer_Email_Subscription', 'enable', identifier=111) + + def test_edit_notification_on_bad(self): + result = self.run_command(['user', 'edit-notifications', '--enable', 'Test not exist']) + self.assertEqual(result.exit_code, 1) + + def test_edit_notifications_off(self): + result = self.run_command(['user', 'edit-notifications', '--disable', 'Test notification']) + self.assert_no_fail(result) + self.assert_called_with('SoftLayer_Email_Subscription', 'disable', identifier=111) + + @mock.patch('SoftLayer.CLI.user.edit_notifications.click') + def test_edit_notification_off_failure(self, click): + notification = self.set_mock('SoftLayer_Email_Subscription', 'disable') + notification.return_value = False + result = self.run_command(['user', 'edit-notifications', '--disable', 'Test notification']) + click.secho.assert_called_with('Failed to update notifications: Test notification', fg='red') + self.assert_no_fail(result) + self.assert_called_with('SoftLayer_Email_Subscription', 'disable', identifier=111) diff --git a/tests/managers/user_tests.py b/tests/managers/user_tests.py index b0ab015f9..61f5b4d0a 100644 --- a/tests/managers/user_tests.py +++ b/tests/managers/user_tests.py @@ -4,7 +4,9 @@ """ import datetime + import mock + import SoftLayer from SoftLayer import exceptions from SoftLayer import testing @@ -246,3 +248,49 @@ def test_vpn_subnet_remove(self): self.manager.vpn_subnet_remove(user_id, [subnet_id]) self.assert_called_with('SoftLayer_Network_Service_Vpn_Overrides', 'deleteObjects', args=expected_args) self.assert_called_with('SoftLayer_User_Customer', 'updateVpnUser', identifier=user_id) + + def test_get_all_notifications(self): + self.manager.get_all_notifications() + self.assert_called_with('SoftLayer_Email_Subscription', 'getAllObjects') + + def test_enable_notifications(self): + self.manager.enable_notifications(['Test notification']) + self.assert_called_with('SoftLayer_Email_Subscription', 'enable', identifier=111) + + def test_disable_notifications(self): + self.manager.disable_notifications(['Test notification']) + self.assert_called_with('SoftLayer_Email_Subscription', 'disable', identifier=111) + + def test_enable_notifications_fail(self): + notification = self.set_mock('SoftLayer_Email_Subscription', 'enable') + notification.return_value = False + result = self.manager.enable_notifications(['Test notification']) + self.assert_called_with('SoftLayer_Email_Subscription', 'enable', identifier=111) + self.assertFalse(result) + + def test_disable_notifications_fail(self): + notification = self.set_mock('SoftLayer_Email_Subscription', 'disable') + notification.return_value = False + result = self.manager.disable_notifications(['Test notification']) + self.assert_called_with('SoftLayer_Email_Subscription', 'disable', identifier=111) + self.assertFalse(result) + + def test_gather_notifications(self): + expected_result = [ + {'description': 'Testing description.', + 'enabled': True, + 'id': 111, + 'name': 'Test notification' + } + ] + result = self.manager.gather_notifications(['Test notification']) + self.assert_called_with('SoftLayer_Email_Subscription', + 'getAllObjects', + mask='mask[enabled]') + self.assertEqual(result, expected_result) + + def test_gather_notifications_fail(self): + ex = self.assertRaises(SoftLayer.SoftLayerError, + self.manager.gather_notifications, + ['Test not exit']) + self.assertEqual("Test not exit is not a valid notification name", str(ex))