diff --git a/SoftLayer/CLI/ticket/__init__.py b/SoftLayer/CLI/ticket/__init__.py index e5f711d92..11fe2a879 100644 --- a/SoftLayer/CLI/ticket/__init__.py +++ b/SoftLayer/CLI/ticket/__init__.py @@ -7,6 +7,15 @@ TEMPLATE_MSG = "***** SoftLayer Ticket Content ******" +# https://softlayer.github.io/reference/services/SoftLayer_Ticket_Priority/getPriorities/ +PRIORITY_MAP = [ + 'No Priority', + 'Severity 1 - Critical Impact / Service Down', + 'Severity 2 - Significant Business Impact', + 'Severity 3 - Minor Business Impact', + 'Severity 4 - Minimal Business Impact' +] + def get_ticket_results(mgr, ticket_id, update_count=1): """Get output about a ticket. @@ -24,6 +33,7 @@ def get_ticket_results(mgr, ticket_id, update_count=1): table.add_row(['id', ticket['id']]) table.add_row(['title', ticket['title']]) + table.add_row(['priority', PRIORITY_MAP[ticket.get('priority', 0)]]) if ticket.get('assignedUser'): user = ticket['assignedUser'] table.add_row([ diff --git a/SoftLayer/CLI/ticket/create.py b/SoftLayer/CLI/ticket/create.py index 71ebd26e5..75c34b799 100644 --- a/SoftLayer/CLI/ticket/create.py +++ b/SoftLayer/CLI/ticket/create.py @@ -11,43 +11,38 @@ @click.command() @click.option('--title', required=True, help="The title of the ticket") -@click.option('--subject-id', - type=int, - required=True, +@click.option('--subject-id', type=int, required=True, help="""The subject id to use for the ticket, issue 'slcli ticket subjects' to get the list""") @click.option('--body', help="The ticket body") -@click.option('--hardware', - 'hardware_identifier', +@click.option('--hardware', 'hardware_identifier', help="The identifier for hardware to attach") -@click.option('--virtual', - 'virtual_identifier', +@click.option('--virtual', 'virtual_identifier', help="The identifier for a virtual server to attach") +@click.option('--priority', 'priority', type=click.Choice(['1', '2', '3', '4']), default=None, + help="""Ticket priority, from 1 (Critical) to 4 (Minimal Impact). + Only settable with Advanced and Premium support. See https://www.ibm.com/cloud/support""") @environment.pass_env -def cli(env, title, subject_id, body, hardware_identifier, virtual_identifier): +def cli(env, title, subject_id, body, hardware_identifier, virtual_identifier, priority): """Create a support ticket.""" ticket_mgr = SoftLayer.TicketManager(env.client) if body is None: body = click.edit('\n\n' + ticket.TEMPLATE_MSG) - created_ticket = ticket_mgr.create_ticket( title=title, body=body, - subject=subject_id) + subject=subject_id, + priority=priority) if hardware_identifier: hardware_mgr = SoftLayer.HardwareManager(env.client) - hardware_id = helpers.resolve_id(hardware_mgr.resolve_ids, - hardware_identifier, - 'hardware') + hardware_id = helpers.resolve_id(hardware_mgr.resolve_ids, hardware_identifier, 'hardware') ticket_mgr.attach_hardware(created_ticket['id'], hardware_id) if virtual_identifier: vs_mgr = SoftLayer.VSManager(env.client) - vs_id = helpers.resolve_id(vs_mgr.resolve_ids, - virtual_identifier, - 'VS') + vs_id = helpers.resolve_id(vs_mgr.resolve_ids, virtual_identifier, 'VS') ticket_mgr.attach_virtual_server(created_ticket['id'], vs_id) env.fout(ticket.get_ticket_results(ticket_mgr, created_ticket['id'])) diff --git a/SoftLayer/CLI/ticket/list.py b/SoftLayer/CLI/ticket/list.py index d7c72794a..64c8b7dd6 100644 --- a/SoftLayer/CLI/ticket/list.py +++ b/SoftLayer/CLI/ticket/list.py @@ -9,25 +9,21 @@ @click.command() -@click.option('--open / --closed', 'is_open', - help="Display only open or closed tickets", - default=True) +@click.option('--open / --closed', 'is_open', default=True, + help="Display only open or closed tickets") @environment.pass_env def cli(env, is_open): """List tickets.""" ticket_mgr = SoftLayer.TicketManager(env.client) + table = formatting.Table([ + 'id', 'assigned_user', 'title', 'last_edited', 'status', 'updates', 'priority' + ]) - tickets = ticket_mgr.list_tickets(open_status=is_open, - closed_status=not is_open) - - table = formatting.Table(['id', 'assigned_user', 'title', - 'last_edited', 'status']) - + tickets = ticket_mgr.list_tickets(open_status=is_open, closed_status=not is_open) for ticket in tickets: user = formatting.blank() if ticket.get('assignedUser'): - user = "%s %s" % (ticket['assignedUser']['firstName'], - ticket['assignedUser']['lastName']) + user = "%s %s" % (ticket['assignedUser']['firstName'], ticket['assignedUser']['lastName']) table.add_row([ ticket['id'], @@ -35,6 +31,8 @@ def cli(env, is_open): click.wrap_text(ticket['title']), ticket['lastEditDate'], ticket['status']['name'], + ticket.get('updateCount', 0), + ticket.get('priority', 0) ]) env.fout(table) diff --git a/SoftLayer/managers/ticket.py b/SoftLayer/managers/ticket.py index 93b915097..0155f0d5f 100644 --- a/SoftLayer/managers/ticket.py +++ b/SoftLayer/managers/ticket.py @@ -28,8 +28,8 @@ def list_tickets(self, open_status=True, closed_status=True): :param boolean open_status: include open tickets :param boolean closed_status: include closed tickets """ - mask = ('id, title, assignedUser[firstName, lastName],' - 'createDate,lastEditDate,accountId,status') + mask = """mask[id, title, assignedUser[firstName, lastName], priority, + createDate, lastEditDate, accountId, status, updateCount]""" call = 'getTickets' if not all([open_status, closed_status]): @@ -53,18 +53,18 @@ def get_ticket(self, ticket_id): :returns: dict -- information about the specified ticket """ - mask = ('id, title, assignedUser[firstName, lastName],status,' - 'createDate,lastEditDate,updates[entry,editor],updateCount') + mask = """mask[id, title, assignedUser[firstName, lastName],status, + createDate,lastEditDate,updates[entry,editor],updateCount, priority]""" return self.ticket.getObject(id=ticket_id, mask=mask) - def create_ticket(self, title=None, body=None, subject=None): + def create_ticket(self, title=None, body=None, subject=None, priority=None): """Create a new ticket. :param string title: title for the new ticket :param string body: body for the new ticket :param integer subject: id of the subject to be assigned to the ticket + :param integer priority: Value from 1 (highest) to 4 (lowest) """ - current_user = self.account.getCurrentUser() new_ticket = { 'subjectId': subject, @@ -72,6 +72,9 @@ def create_ticket(self, title=None, body=None, subject=None): 'assignedUserId': current_user['id'], 'title': title, } + if priority is not None: + new_ticket['priority'] = int(priority) + created_ticket = self.ticket.createStandardTicket(new_ticket, body) return created_ticket @@ -83,18 +86,12 @@ def update_ticket(self, ticket_id=None, body=None): """ return self.ticket.addUpdate({'entry': body}, id=ticket_id) - def upload_attachment(self, ticket_id=None, file_path=None, - file_name=None): + def upload_attachment(self, ticket_id=None, file_path=None, file_name=None): """Upload an attachment to a ticket. - :param integer ticket_id: the id of the ticket to - upload the attachment to - :param string file_path: - The path of the attachment to be uploaded - :param string file_name: - The name of the attachment shown - in the ticket - + :param integer ticket_id: the id of the ticket to upload the attachment to + :param string file_path: The path of the attachment to be uploaded + :param string file_name: The name of the attachment shown in the ticket :returns: dict -- The uploaded attachment """ file_content = None diff --git a/tests/CLI/modules/ticket_tests.py b/tests/CLI/modules/ticket_tests.py index c9d27ba37..817b3e71f 100644 --- a/tests/CLI/modules/ticket_tests.py +++ b/tests/CLI/modules/ticket_tests.py @@ -8,6 +8,9 @@ import mock from SoftLayer.CLI import exceptions +from SoftLayer.CLI import formatting +from SoftLayer.CLI import ticket +from SoftLayer.managers import TicketManager from SoftLayer import testing @@ -20,10 +23,12 @@ def test_list(self): 'assigned_user': 'John Smith', 'id': 102, 'last_edited': '2013-08-01T14:16:47-07:00', + 'priority': 0, 'status': 'Open', - 'title': 'Cloud Instance Cancellation - 08/01/13'}] + 'title': 'Cloud Instance Cancellation - 08/01/13', + 'updates': 0}] self.assert_no_fail(result) - self.assertEqual(json.loads(result.output), expected) + self.assertEqual(expected, json.loads(result.output)) def test_detail(self): result = self.run_command(['ticket', 'detail', '1']) @@ -32,6 +37,7 @@ def test_detail(self): 'created': '2013-08-01T14:14:04-07:00', 'edited': '2013-08-01T14:16:47-07:00', 'id': 100, + 'priority': 'No Priority', 'status': 'Closed', 'title': 'Cloud Instance Cancellation - 08/01/13', 'update 1': 'a bot says something', @@ -53,8 +59,23 @@ def test_create(self): 'assignedUserId': 12345, 'title': 'Test'}, 'ticket body') - self.assert_called_with('SoftLayer_Ticket', 'createStandardTicket', - args=args) + self.assert_called_with('SoftLayer_Ticket', 'createStandardTicket', args=args) + + def test_create_with_priority(self): + result = self.run_command(['ticket', 'create', '--title=Test', + '--subject-id=1000', + '--body=ticket body', + '--priority=1']) + + self.assert_no_fail(result) + + args = ({'subjectId': 1000, + 'contents': 'ticket body', + 'assignedUserId': 12345, + 'title': 'Test', + 'priority': 1}, 'ticket body') + + self.assert_called_with('SoftLayer_Ticket', 'createStandardTicket', args=args) def test_create_and_attach(self): result = self.run_command(['ticket', 'create', '--title=Test', @@ -204,3 +225,79 @@ def test_ticket_upload(self): args=({"filename": "a_file_name", "data": b"ticket attached data"},), identifier=1) + + def test_init_ticket_results(self): + ticket_mgr = TicketManager(self.client) + ticket_table = ticket.get_ticket_results(ticket_mgr, 100) + self.assert_called_with('SoftLayer_Ticket', 'getObject', identifier=100) + self.assertIsInstance(ticket_table, formatting.KeyValueTable) + + ticket_object = ticket_table.to_python() + self.assertEqual('No Priority', ticket_object['priority']) + self.assertEqual(100, ticket_object['id']) + + def test_init_ticket_results_asigned_user(self): + mock = self.set_mock('SoftLayer_Ticket', 'getObject') + mock.return_value = { + "id": 100, + "title": "Simple Title", + "priority": 1, + "assignedUser": { + "firstName": "Test", + "lastName": "User" + }, + "status": { + "name": "Closed" + }, + "createDate": "2013-08-01T14:14:04-07:00", + "lastEditDate": "2013-08-01T14:16:47-07:00", + "updates": [{'entry': 'a bot says something'}] + } + + ticket_mgr = TicketManager(self.client) + ticket_table = ticket.get_ticket_results(ticket_mgr, 100) + self.assert_called_with('SoftLayer_Ticket', 'getObject', identifier=100) + self.assertIsInstance(ticket_table, formatting.KeyValueTable) + + ticket_object = ticket_table.to_python() + self.assertEqual('Severity 1 - Critical Impact / Service Down', ticket_object['priority']) + self.assertEqual('Test User', ticket_object['user']) + + def test_ticket_summary(self): + mock = self.set_mock('SoftLayer_Account', 'getObject') + mock.return_value = { + 'openTicketCount': 1, + 'closedTicketCount': 2, + 'openBillingTicketCount': 3, + 'openOtherTicketCount': 4, + 'openSalesTicketCount': 5, + 'openSupportTicketCount': 6, + 'openAccountingTicketCount': 7 + } + expected = [ + {'Status': 'Open', + 'count': [ + {'Type': 'Accounting', 'count': 7}, + {'Type': 'Billing', 'count': 3}, + {'Type': 'Sales', 'count': 5}, + {'Type': 'Support', 'count': 6}, + {'Type': 'Other', 'count': 4}, + {'Type': 'Total', 'count': 1}]}, + {'Status': 'Closed', 'count': 2} + ] + result = self.run_command(['ticket', 'summary']) + self.assert_no_fail(result) + self.assert_called_with('SoftLayer_Account', 'getObject') + self.assertEqual(expected, json.loads(result.output)) + + def test_ticket_update(self): + result = self.run_command(['ticket', 'update', '100', '--body=Testing']) + self.assert_no_fail(result) + self.assert_called_with('SoftLayer_Ticket', 'addUpdate', args=({'entry': 'Testing'},), identifier=100) + + @mock.patch('click.edit') + def test_ticket_update_no_body(self, edit_mock): + edit_mock.return_value = 'Testing1' + result = self.run_command(['ticket', 'update', '100']) + self.assert_no_fail(result) + self.assert_called_with('SoftLayer_Ticket', 'addUpdate', args=({'entry': 'Testing1'},), identifier=100)