Skip to content

Commit 1765af9

Browse files
Merge pull request #1024 from allmightyspiff/1019
#1019 - Ability to set ticket priority
2 parents cdaebcc + 45030b0 commit 1765af9

File tree

5 files changed

+144
-47
lines changed

5 files changed

+144
-47
lines changed

SoftLayer/CLI/ticket/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77

88
TEMPLATE_MSG = "***** SoftLayer Ticket Content ******"
99

10+
# https://softlayer.github.io/reference/services/SoftLayer_Ticket_Priority/getPriorities/
11+
PRIORITY_MAP = [
12+
'No Priority',
13+
'Severity 1 - Critical Impact / Service Down',
14+
'Severity 2 - Significant Business Impact',
15+
'Severity 3 - Minor Business Impact',
16+
'Severity 4 - Minimal Business Impact'
17+
]
18+
1019

1120
def get_ticket_results(mgr, ticket_id, update_count=1):
1221
"""Get output about a ticket.
@@ -24,6 +33,7 @@ def get_ticket_results(mgr, ticket_id, update_count=1):
2433

2534
table.add_row(['id', ticket['id']])
2635
table.add_row(['title', ticket['title']])
36+
table.add_row(['priority', PRIORITY_MAP[ticket.get('priority', 0)]])
2737
if ticket.get('assignedUser'):
2838
user = ticket['assignedUser']
2939
table.add_row([

SoftLayer/CLI/ticket/create.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,43 +11,38 @@
1111

1212
@click.command()
1313
@click.option('--title', required=True, help="The title of the ticket")
14-
@click.option('--subject-id',
15-
type=int,
16-
required=True,
14+
@click.option('--subject-id', type=int, required=True,
1715
help="""The subject id to use for the ticket,
1816
issue 'slcli ticket subjects' to get the list""")
1917
@click.option('--body', help="The ticket body")
20-
@click.option('--hardware',
21-
'hardware_identifier',
18+
@click.option('--hardware', 'hardware_identifier',
2219
help="The identifier for hardware to attach")
23-
@click.option('--virtual',
24-
'virtual_identifier',
20+
@click.option('--virtual', 'virtual_identifier',
2521
help="The identifier for a virtual server to attach")
22+
@click.option('--priority', 'priority', type=click.Choice(['1', '2', '3', '4']), default=None,
23+
help="""Ticket priority, from 1 (Critical) to 4 (Minimal Impact).
24+
Only settable with Advanced and Premium support. See https://www.ibm.com/cloud/support""")
2625
@environment.pass_env
27-
def cli(env, title, subject_id, body, hardware_identifier, virtual_identifier):
26+
def cli(env, title, subject_id, body, hardware_identifier, virtual_identifier, priority):
2827
"""Create a support ticket."""
2928
ticket_mgr = SoftLayer.TicketManager(env.client)
3029

3130
if body is None:
3231
body = click.edit('\n\n' + ticket.TEMPLATE_MSG)
33-
3432
created_ticket = ticket_mgr.create_ticket(
3533
title=title,
3634
body=body,
37-
subject=subject_id)
35+
subject=subject_id,
36+
priority=priority)
3837

3938
if hardware_identifier:
4039
hardware_mgr = SoftLayer.HardwareManager(env.client)
41-
hardware_id = helpers.resolve_id(hardware_mgr.resolve_ids,
42-
hardware_identifier,
43-
'hardware')
40+
hardware_id = helpers.resolve_id(hardware_mgr.resolve_ids, hardware_identifier, 'hardware')
4441
ticket_mgr.attach_hardware(created_ticket['id'], hardware_id)
4542

4643
if virtual_identifier:
4744
vs_mgr = SoftLayer.VSManager(env.client)
48-
vs_id = helpers.resolve_id(vs_mgr.resolve_ids,
49-
virtual_identifier,
50-
'VS')
45+
vs_id = helpers.resolve_id(vs_mgr.resolve_ids, virtual_identifier, 'VS')
5146
ticket_mgr.attach_virtual_server(created_ticket['id'], vs_id)
5247

5348
env.fout(ticket.get_ticket_results(ticket_mgr, created_ticket['id']))

SoftLayer/CLI/ticket/list.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,30 @@
99

1010

1111
@click.command()
12-
@click.option('--open / --closed', 'is_open',
13-
help="Display only open or closed tickets",
14-
default=True)
12+
@click.option('--open / --closed', 'is_open', default=True,
13+
help="Display only open or closed tickets")
1514
@environment.pass_env
1615
def cli(env, is_open):
1716
"""List tickets."""
1817
ticket_mgr = SoftLayer.TicketManager(env.client)
18+
table = formatting.Table([
19+
'id', 'assigned_user', 'title', 'last_edited', 'status', 'updates', 'priority'
20+
])
1921

20-
tickets = ticket_mgr.list_tickets(open_status=is_open,
21-
closed_status=not is_open)
22-
23-
table = formatting.Table(['id', 'assigned_user', 'title',
24-
'last_edited', 'status'])
25-
22+
tickets = ticket_mgr.list_tickets(open_status=is_open, closed_status=not is_open)
2623
for ticket in tickets:
2724
user = formatting.blank()
2825
if ticket.get('assignedUser'):
29-
user = "%s %s" % (ticket['assignedUser']['firstName'],
30-
ticket['assignedUser']['lastName'])
26+
user = "%s %s" % (ticket['assignedUser']['firstName'], ticket['assignedUser']['lastName'])
3127

3228
table.add_row([
3329
ticket['id'],
3430
user,
3531
click.wrap_text(ticket['title']),
3632
ticket['lastEditDate'],
3733
ticket['status']['name'],
34+
ticket.get('updateCount', 0),
35+
ticket.get('priority', 0)
3836
])
3937

4038
env.fout(table)

SoftLayer/managers/ticket.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ def list_tickets(self, open_status=True, closed_status=True):
2828
:param boolean open_status: include open tickets
2929
:param boolean closed_status: include closed tickets
3030
"""
31-
mask = ('id, title, assignedUser[firstName, lastName],'
32-
'createDate,lastEditDate,accountId,status')
31+
mask = """mask[id, title, assignedUser[firstName, lastName], priority,
32+
createDate, lastEditDate, accountId, status, updateCount]"""
3333

3434
call = 'getTickets'
3535
if not all([open_status, closed_status]):
@@ -53,25 +53,28 @@ def get_ticket(self, ticket_id):
5353
:returns: dict -- information about the specified ticket
5454
5555
"""
56-
mask = ('id, title, assignedUser[firstName, lastName],status,'
57-
'createDate,lastEditDate,updates[entry,editor],updateCount')
56+
mask = """mask[id, title, assignedUser[firstName, lastName],status,
57+
createDate,lastEditDate,updates[entry,editor],updateCount, priority]"""
5858
return self.ticket.getObject(id=ticket_id, mask=mask)
5959

60-
def create_ticket(self, title=None, body=None, subject=None):
60+
def create_ticket(self, title=None, body=None, subject=None, priority=None):
6161
"""Create a new ticket.
6262
6363
:param string title: title for the new ticket
6464
:param string body: body for the new ticket
6565
:param integer subject: id of the subject to be assigned to the ticket
66+
:param integer priority: Value from 1 (highest) to 4 (lowest)
6667
"""
67-
6868
current_user = self.account.getCurrentUser()
6969
new_ticket = {
7070
'subjectId': subject,
7171
'contents': body,
7272
'assignedUserId': current_user['id'],
7373
'title': title,
7474
}
75+
if priority is not None:
76+
new_ticket['priority'] = int(priority)
77+
7578
created_ticket = self.ticket.createStandardTicket(new_ticket, body)
7679
return created_ticket
7780

@@ -83,18 +86,12 @@ def update_ticket(self, ticket_id=None, body=None):
8386
"""
8487
return self.ticket.addUpdate({'entry': body}, id=ticket_id)
8588

86-
def upload_attachment(self, ticket_id=None, file_path=None,
87-
file_name=None):
89+
def upload_attachment(self, ticket_id=None, file_path=None, file_name=None):
8890
"""Upload an attachment to a ticket.
8991
90-
:param integer ticket_id: the id of the ticket to
91-
upload the attachment to
92-
:param string file_path:
93-
The path of the attachment to be uploaded
94-
:param string file_name:
95-
The name of the attachment shown
96-
in the ticket
97-
92+
:param integer ticket_id: the id of the ticket to upload the attachment to
93+
:param string file_path: The path of the attachment to be uploaded
94+
:param string file_name: The name of the attachment shown in the ticket
9895
:returns: dict -- The uploaded attachment
9996
"""
10097
file_content = None

tests/CLI/modules/ticket_tests.py

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
import mock
99

1010
from SoftLayer.CLI import exceptions
11+
from SoftLayer.CLI import formatting
12+
from SoftLayer.CLI import ticket
13+
from SoftLayer.managers import TicketManager
1114
from SoftLayer import testing
1215

1316

@@ -20,10 +23,12 @@ def test_list(self):
2023
'assigned_user': 'John Smith',
2124
'id': 102,
2225
'last_edited': '2013-08-01T14:16:47-07:00',
26+
'priority': 0,
2327
'status': 'Open',
24-
'title': 'Cloud Instance Cancellation - 08/01/13'}]
28+
'title': 'Cloud Instance Cancellation - 08/01/13',
29+
'updates': 0}]
2530
self.assert_no_fail(result)
26-
self.assertEqual(json.loads(result.output), expected)
31+
self.assertEqual(expected, json.loads(result.output))
2732

2833
def test_detail(self):
2934
result = self.run_command(['ticket', 'detail', '1'])
@@ -32,6 +37,7 @@ def test_detail(self):
3237
'created': '2013-08-01T14:14:04-07:00',
3338
'edited': '2013-08-01T14:16:47-07:00',
3439
'id': 100,
40+
'priority': 'No Priority',
3541
'status': 'Closed',
3642
'title': 'Cloud Instance Cancellation - 08/01/13',
3743
'update 1': 'a bot says something',
@@ -53,8 +59,23 @@ def test_create(self):
5359
'assignedUserId': 12345,
5460
'title': 'Test'}, 'ticket body')
5561

56-
self.assert_called_with('SoftLayer_Ticket', 'createStandardTicket',
57-
args=args)
62+
self.assert_called_with('SoftLayer_Ticket', 'createStandardTicket', args=args)
63+
64+
def test_create_with_priority(self):
65+
result = self.run_command(['ticket', 'create', '--title=Test',
66+
'--subject-id=1000',
67+
'--body=ticket body',
68+
'--priority=1'])
69+
70+
self.assert_no_fail(result)
71+
72+
args = ({'subjectId': 1000,
73+
'contents': 'ticket body',
74+
'assignedUserId': 12345,
75+
'title': 'Test',
76+
'priority': 1}, 'ticket body')
77+
78+
self.assert_called_with('SoftLayer_Ticket', 'createStandardTicket', args=args)
5879

5980
def test_create_and_attach(self):
6081
result = self.run_command(['ticket', 'create', '--title=Test',
@@ -204,3 +225,79 @@ def test_ticket_upload(self):
204225
args=({"filename": "a_file_name",
205226
"data": b"ticket attached data"},),
206227
identifier=1)
228+
229+
def test_init_ticket_results(self):
230+
ticket_mgr = TicketManager(self.client)
231+
ticket_table = ticket.get_ticket_results(ticket_mgr, 100)
232+
self.assert_called_with('SoftLayer_Ticket', 'getObject', identifier=100)
233+
self.assertIsInstance(ticket_table, formatting.KeyValueTable)
234+
235+
ticket_object = ticket_table.to_python()
236+
self.assertEqual('No Priority', ticket_object['priority'])
237+
self.assertEqual(100, ticket_object['id'])
238+
239+
def test_init_ticket_results_asigned_user(self):
240+
mock = self.set_mock('SoftLayer_Ticket', 'getObject')
241+
mock.return_value = {
242+
"id": 100,
243+
"title": "Simple Title",
244+
"priority": 1,
245+
"assignedUser": {
246+
"firstName": "Test",
247+
"lastName": "User"
248+
},
249+
"status": {
250+
"name": "Closed"
251+
},
252+
"createDate": "2013-08-01T14:14:04-07:00",
253+
"lastEditDate": "2013-08-01T14:16:47-07:00",
254+
"updates": [{'entry': 'a bot says something'}]
255+
}
256+
257+
ticket_mgr = TicketManager(self.client)
258+
ticket_table = ticket.get_ticket_results(ticket_mgr, 100)
259+
self.assert_called_with('SoftLayer_Ticket', 'getObject', identifier=100)
260+
self.assertIsInstance(ticket_table, formatting.KeyValueTable)
261+
262+
ticket_object = ticket_table.to_python()
263+
self.assertEqual('Severity 1 - Critical Impact / Service Down', ticket_object['priority'])
264+
self.assertEqual('Test User', ticket_object['user'])
265+
266+
def test_ticket_summary(self):
267+
mock = self.set_mock('SoftLayer_Account', 'getObject')
268+
mock.return_value = {
269+
'openTicketCount': 1,
270+
'closedTicketCount': 2,
271+
'openBillingTicketCount': 3,
272+
'openOtherTicketCount': 4,
273+
'openSalesTicketCount': 5,
274+
'openSupportTicketCount': 6,
275+
'openAccountingTicketCount': 7
276+
}
277+
expected = [
278+
{'Status': 'Open',
279+
'count': [
280+
{'Type': 'Accounting', 'count': 7},
281+
{'Type': 'Billing', 'count': 3},
282+
{'Type': 'Sales', 'count': 5},
283+
{'Type': 'Support', 'count': 6},
284+
{'Type': 'Other', 'count': 4},
285+
{'Type': 'Total', 'count': 1}]},
286+
{'Status': 'Closed', 'count': 2}
287+
]
288+
result = self.run_command(['ticket', 'summary'])
289+
self.assert_no_fail(result)
290+
self.assert_called_with('SoftLayer_Account', 'getObject')
291+
self.assertEqual(expected, json.loads(result.output))
292+
293+
def test_ticket_update(self):
294+
result = self.run_command(['ticket', 'update', '100', '--body=Testing'])
295+
self.assert_no_fail(result)
296+
self.assert_called_with('SoftLayer_Ticket', 'addUpdate', args=({'entry': 'Testing'},), identifier=100)
297+
298+
@mock.patch('click.edit')
299+
def test_ticket_update_no_body(self, edit_mock):
300+
edit_mock.return_value = 'Testing1'
301+
result = self.run_command(['ticket', 'update', '100'])
302+
self.assert_no_fail(result)
303+
self.assert_called_with('SoftLayer_Ticket', 'addUpdate', args=({'entry': 'Testing1'},), identifier=100)

0 commit comments

Comments
 (0)