From 2c823ee27dd0b5a88d362bdd50756a44756af0c1 Mon Sep 17 00:00:00 2001 From: Wissam Date: Wed, 12 Feb 2014 11:28:02 -0600 Subject: [PATCH 01/13] Add initial support for ticketing --- SoftLayer/CLI/modules/ticket.py | 279 ++++++++++++++++++++++++++++++++ SoftLayer/managers/__init__.py | 3 +- SoftLayer/managers/ticket.py | 113 +++++++++++++ 3 files changed, 394 insertions(+), 1 deletion(-) create mode 100644 SoftLayer/CLI/modules/ticket.py create mode 100644 SoftLayer/managers/ticket.py diff --git a/SoftLayer/CLI/modules/ticket.py b/SoftLayer/CLI/modules/ticket.py new file mode 100644 index 000000000..0cc6e559d --- /dev/null +++ b/SoftLayer/CLI/modules/ticket.py @@ -0,0 +1,279 @@ +""" +usage: sl ticket [] [...] [options] + +Manage account tickets + +The available commands are: + create Create a new ticket + detail Output details about an ticket + list List tickets + update Update an existing ticket + subjects List the subject IDs that can be used for ticket creation + summary Gives summary info about tickets +""" +# :license: MIT, see LICENSE for more details. + +import textwrap + +from SoftLayer import TicketManager +from SoftLayer.CLI import CLIRunnable, formatting, Table, resolve_id, NestedDict, KeyValueTable + +""" Global variables for the status of the ticket - either open or closed """ +OPEN = 'open' +CLOSED ='closed' + +class ListTickets(CLIRunnable): + """ +usage: sl ticket list [--status=open,closed] + +List tickets + +Options: + --status=open or closed Display only opened or closed tickets, otherwise display both + +""" + action = 'list' + + def execute(self, args): + ticket_mgr = TicketManager(self.client) + + mask = 'id,accountId,title,createDate,lastEditDate,assignedUser[firstName, lastName]' + + """Determine what needs to be returned, either open tickets, closed tickets, or both""" + neither = True + if ( args.get('--status') == OPEN) or (args.get('--status') == CLOSED) : + neither = False + + tickets = [] + if ( args.get('--status') == OPEN) or neither: + for ticket in ticket_mgr.list_tickets(status=OPEN, mask=mask): + tickets.append(ticket) + + if (args.get('--status') == CLOSED) or neither: + for ticket in ticket_mgr.list_tickets(status=CLOSED,mask=mask): + tickets.append(ticket) + + t = Table(['id', 'assigned user', 'title', 'creation date', 'last edit date']) + + for ticket in tickets: + if ticket['assignedUser']: + t.add_row([ + ticket['id'], + ticket['assignedUser']['firstName'] + " " + ticket['assignedUser']['lastName'], + TicketUtils.wrap_string(ticket['title']), + ticket['createDate'], + ticket['lastEditDate'] + ]) + else: + t.add_row([ + ticket['id'], + 'N/A', + TicketUtils.wrap_string(ticket['title']), + ticket['createDate'], + ticket['lastEditDate'] + ]) + + return t + +class ListSubjectsTickets(CLIRunnable): + """ +usage: sl ticket subjects + +List Subject Ids for ticket creation + +""" + action = 'subjects' + + def execute(self, args): + ticket_mgr = TicketManager(self.client) + + t = Table(['id', 'subject']) + for subject in ticket_mgr.list_subjects(): + t.add_row([ + subject['id'], + subject['name'] + ]) + return t + +class UpdateTicket(CLIRunnable): + """ +usage: sl ticket update [options] + +Updates a certain ticket + +Options: + --body=BODY The entry that will be appended to the ticket + +""" + action = 'update' + options = ['--body'] + + def execute(self, args): + mgr = TicketManager(self.client) + + ticket_id = resolve_id( + mgr.resolve_ids, args.get(''), 'ticket') + + body = args.get('--body') + if (body is None): + body = TicketUtils.open_editor(beg_msg = "***** Softlayer Ticket Content ******") + + ticket = mgr.update_ticket(t_id=ticket_id, body=body) + return "Ticket Updated!" + +class TicketsSummary(CLIRunnable): + """ +usage: sl ticket summary + +Give summary info about tickets + +""" + action = 'summary' + + def execute(self, args): + account = self.client['Account'] + accountObject = account.getObject(mask='mask[openTicketCount, closedTicketCount, openBillingTicketCount,openOtherTicketCount,openSalesTicketCount,openSupportTicketCount,openAccountingTicketCount]') + t = Table(['Status', 'count']) + + nested = Table(['Type', 'count']) + nested.add_row(['Accounting', accountObject['openAccountingTicketCount']]) + nested.add_row(['Billing', accountObject['openBillingTicketCount']]) + nested.add_row(['Sales', accountObject['openSalesTicketCount']]) + nested.add_row(['Support', accountObject['openSupportTicketCount']]) + nested.add_row(['Other', accountObject['openOtherTicketCount']]) + nested.add_row(['Total', accountObject['openTicketCount']]) + t.add_row(['Open', nested]) + t.add_row(['Closed', accountObject['closedTicketCount']]) + + return t + + +class TicketUtils: + """ + TicketUtils class that is a helper for common methods within the Ticket module. + + """ + + @staticmethod + def get_ticket_results(mgr, ticket_id, update_count=1, **kwargs): + """ Get output about a ticket + + :param integer id: the ticket ID + :param integer update_count: the number of entries to retrieve from the ticket + :returns: a KeyValue table containing the details of the ticket + + """ + result = mgr.get_ticket(ticket_id) + result = NestedDict(result) + + t = KeyValueTable(['Name', 'Value']) + t.align['Name'] = 'r' + t.align['Value'] = 'l' + + t.add_row(['id', result['id']]) + t.add_row(['title', result['title']]) + if (result['assignedUser']): + t.add_row(['assignedUser', result['assignedUser']['firstName'] + " " + result['assignedUser']['lastName']] ) + t.add_row(['createDate', result['createDate']]) + t.add_row(['lastEditDate', result['lastEditDate']]) + + + totalUpdates = len(result['updates']) + count = min(totalUpdates, update_count) + for index in range(0,count): + t.add_row(['Update %s' %(totalUpdates-index), TicketUtils.wrap_string(result['updates'][totalUpdates-1-index]['entry'])]) + + return t + + @staticmethod + def open_editor(beg_msg, ending_msg=None): + """ + + :param beg_msg: generic msg to be appended at the end of the file + :param ending_msg: placeholder msg to be appended at the end of the file, like filesystem info, etc, not being used now + :returns: the content the user has entered + + """ + import tempfile,os + from subprocess import call + + #Let's get the default EDITOR of the environment, use nano if none is specified + editor = os.environ.get('EDITOR','nano') + + with tempfile.NamedTemporaryFile(suffix=".tmp") as tempfile: + #populate the file with the baked messages + tempfile.write("\n") + tempfile.write(beg_msg) + if (ending_msg): + tempfile.write("\n") + tempfile.write(ending_msg) + #flush the file and open it for editing + tempfile.flush() + call([editor, tempfile.name]) + tempfile.seek(0) + data=tempfile.read() + return data + + return + + @staticmethod + def wrap_string(input_str): + #utility method to wrap the content of the ticket, as it can make the output messy + return textwrap.wrap(input_str, 80) + +class TicketDetails(CLIRunnable): + """ +usage: sl ticket detail [options] + +Get details for a ticket + +Options: + --updateCount=X Show X count of updates, default is 1 +""" + action = 'detail' + + def execute(self, args): + mgr = TicketManager(self.client) + + ticket_id = resolve_id( + mgr.resolve_ids, args.get(''), 'ticket') + + count = args.get('--updateCount') + if not count: + count = 1 + return TicketUtils.get_ticket_results(mgr, ticket_id, int(count)) + + +class CreateTicket(CLIRunnable): + """ +usage: sl ticket create --subject=xxx [options] + +Create a support ticket. + +Required: + --title=TITLE The title of the ticket + --subject=xxx The id of the subject to use for the ticket, issue 'sl ticket subjects' to get the list + + +Optional: + --body the body text to attach to the ticket +""" + action = 'create' + required_params = ['--title, --subject'] + + def execute(self, args): + mgr = TicketManager(self.client) + if (args.get('--title') is None): + return 'Please provide a valid title' + body=args.get('--body') + if (body is None): + body = TicketUtils.open_editor(beg_msg = "***** Softlayer Ticket Content ******") + + createdTicket = mgr.create_ticket( + title=(args.get('--title')), + body=body, + hardware=args.get('--hardware'), #not being used now + rootPassword=args.get('--rootPassword'), #not being used now + subject=args.get('--subject')) + return TicketUtils.get_ticket_results(mgr, createdTicket['id'], 1) + diff --git a/SoftLayer/managers/__init__.py b/SoftLayer/managers/__init__.py index aed60a290..9db06a1d3 100644 --- a/SoftLayer/managers/__init__.py +++ b/SoftLayer/managers/__init__.py @@ -17,7 +17,8 @@ from SoftLayer.managers.network import NetworkManager from SoftLayer.managers.sshkey import SshKeyManager from SoftLayer.managers.ssl import SSLManager +from SoftLayer.managers.ticket import TicketManager __all__ = ['CCIManager', 'DNSManager', 'FirewallManager', 'HardwareManager', 'ImageManager', 'MessagingManager', 'MetadataManager', - 'NetworkManager', 'SshKeyManager', 'SSLManager'] + 'NetworkManager', 'SshKeyManager', 'SSLManager', 'TicketManager'] diff --git a/SoftLayer/managers/ticket.py b/SoftLayer/managers/ticket.py new file mode 100644 index 000000000..6fe26a178 --- /dev/null +++ b/SoftLayer/managers/ticket.py @@ -0,0 +1,113 @@ +""" + SoftLayer.ticket + ~~~~~~~~~~~~~~~ + Ticket Manager/helpers + + :license: MIT, see LICENSE for more details. +""" + +from SoftLayer.utils import query_filter, IdentifierMixin, NestedDict + + +class TicketManager(IdentifierMixin, object): + """ + Manages account Tickets + + :param SoftLayer.API.Client client: an API client instance + """ + + def __init__(self, client): + self.client = client + self.account = self.client['Account'] + self.ticket = self.client['Ticket'] + + def list_tickets(self, status='open', title=None, userId=None,**kwargs): + """ List all tickets + + :param string status: status of tickets to retrieve, Open by default + :param string title: filter based on title + :param dict \*\*kwargs: response-level arguments (limit, offset, etc.) + """ + TICKET_MASK = ('id','accountId','title','createDate','lastEditDate','assignedUser[firstName, lastName]') + if 'mask' not in kwargs: + kwargs['mask'] = TICKET_MASK + + _filter = NestedDict(kwargs.get('filter') or {}) + if title: + _filter['ticket']['title'] = \ + query_filter(title) + + kwargs['filter'] = _filter.to_dict() + + if (status == 'open'): + return self.account.getOpenTickets(**kwargs) + else: + return self.account.getClosedTickets(**kwargs) + + def list_subjects(self, **kwargs): + """ List all tickets + + :param dict \*\*kwargs: response-level arguments (limit, offset, etc.) + """ + return self.client['Ticket_Subject'].getAllObjects(**kwargs) + + + def get_ticket(self, ticket_id, **kwargs): + """ Get details about a ticket + + :param integer id: the ticket ID + :returns: A dictionary containing a large amount of information about + the specified ticket. + + """ + if 'mask' not in kwargs: + items = set([ + 'id', + 'title', + 'assignedUser[firstName, lastName]', + 'createDate', + 'lastEditDate', + 'updates[entry]', + 'updateCount', + ]) + kwargs['mask'] = "mask[%s]" % ','.join(items) + + return self.ticket.getObject(id=ticket_id, **kwargs) + + + def create_ticket(self, title=None, body=None, hardware=None, rootPassword=None, subject=None, **kwargs): + """ Create a new ticket + + :param string title: title for the new ticket + :param string body: body for the new ticket + :param string hardware: id of the hardware to be assigned to the ticket + :param dict \*\*kwargs: response-level arguments (limit, offset, etc.) + """ + + currentUser = self.account.getCurrentUser() + + new_ticket = { + 'subjectId' : subject, + 'contents': body, + 'assignedUserId': currentUser['id'], + 'title': title, + } + if (hardware is None): + created_ticket = self.ticket.createStandardTicket(new_ticket, body, **kwargs) + else: + created_ticket = self.ticket.createStandardTicket(new_ticket, body, hardware, rootPassword, **kwargs) + + return created_ticket + + def update_ticket(self, t_id=None, body=None, **kwargs): + """ Update a ticket + + :param string id: the id of the ticket to update + :param string body: entry to update in the ticket + """ + + + ticket = self.ticket.getObject(id=t_id, **kwargs) + self.ticket.edit(ticket, body, id=t_id) + + return \ No newline at end of file From 4fa084df795a0a9b0a5a84f4e3c1ad05aab42619 Mon Sep 17 00:00:00 2001 From: Wissam Date: Wed, 19 Feb 2014 19:34:11 -0600 Subject: [PATCH 02/13] Fixes formatting issues attempt --- SoftLayer/CLI/modules/ticket.py | 129 ++++++++++++++++---------------- SoftLayer/managers/ticket.py | 25 +++---- 2 files changed, 74 insertions(+), 80 deletions(-) diff --git a/SoftLayer/CLI/modules/ticket.py b/SoftLayer/CLI/modules/ticket.py index 0cc6e559d..cb5996954 100644 --- a/SoftLayer/CLI/modules/ticket.py +++ b/SoftLayer/CLI/modules/ticket.py @@ -16,22 +16,23 @@ import textwrap from SoftLayer import TicketManager -from SoftLayer.CLI import CLIRunnable, formatting, Table, resolve_id, NestedDict, KeyValueTable +from SoftLayer.CLI import CLIRunnable, Table, resolve_id, NestedDict, KeyValueTable """ Global variables for the status of the ticket - either open or closed """ OPEN = 'open' -CLOSED ='closed' +CLOSED = 'closed' + class ListTickets(CLIRunnable): """ -usage: sl ticket list [--status=open,closed] + usage: sl ticket list [--status=open,closed] -List tickets + List tickets -Options: - --status=open or closed Display only opened or closed tickets, otherwise display both - -""" + Options: + --status=open or closed Display only opened or closed tickets, otherwise display both + + """ action = 'list' def execute(self, args): @@ -72,16 +73,17 @@ def execute(self, args): ticket['createDate'], ticket['lastEditDate'] ]) - + return t - + + class ListSubjectsTickets(CLIRunnable): """ -usage: sl ticket subjects + usage: sl ticket subjects -List Subject Ids for ticket creation + List Subject Ids for ticket creation -""" + """ action = 'subjects' def execute(self, args): @@ -94,17 +96,18 @@ def execute(self, args): subject['name'] ]) return t + class UpdateTicket(CLIRunnable): """ -usage: sl ticket update [options] + usage: sl ticket update [options] -Updates a certain ticket + Updates a certain ticket -Options: - --body=BODY The entry that will be appended to the ticket + Options: + --body=BODY The entry that will be appended to the ticket -""" + """ action = 'update' options = ['--body'] @@ -113,21 +116,22 @@ def execute(self, args): ticket_id = resolve_id( mgr.resolve_ids, args.get(''), 'ticket') - + body = args.get('--body') if (body is None): body = TicketUtils.open_editor(beg_msg = "***** Softlayer Ticket Content ******") - + ticket = mgr.update_ticket(t_id=ticket_id, body=body) return "Ticket Updated!" - + + class TicketsSummary(CLIRunnable): """ -usage: sl ticket summary + usage: sl ticket summary -Give summary info about tickets + Give summary info about tickets -""" + """ action = 'summary' def execute(self, args): @@ -144,59 +148,57 @@ def execute(self, args): nested.add_row(['Total', accountObject['openTicketCount']]) t.add_row(['Open', nested]) t.add_row(['Closed', accountObject['closedTicketCount']]) - + return t class TicketUtils: """ TicketUtils class that is a helper for common methods within the Ticket module. - """ - + @staticmethod def get_ticket_results(mgr, ticket_id, update_count=1, **kwargs): """ Get output about a ticket - + :param integer id: the ticket ID :param integer update_count: the number of entries to retrieve from the ticket :returns: a KeyValue table containing the details of the ticket - + """ result = mgr.get_ticket(ticket_id) result = NestedDict(result) - + t = KeyValueTable(['Name', 'Value']) t.align['Name'] = 'r' t.align['Value'] = 'l' - + t.add_row(['id', result['id']]) t.add_row(['title', result['title']]) if (result['assignedUser']): t.add_row(['assignedUser', result['assignedUser']['firstName'] + " " + result['assignedUser']['lastName']] ) t.add_row(['createDate', result['createDate']]) t.add_row(['lastEditDate', result['lastEditDate']]) - - + totalUpdates = len(result['updates']) count = min(totalUpdates, update_count) for index in range(0,count): t.add_row(['Update %s' %(totalUpdates-index), TicketUtils.wrap_string(result['updates'][totalUpdates-1-index]['entry'])]) - + return t - + @staticmethod def open_editor(beg_msg, ending_msg=None): """ - + :param beg_msg: generic msg to be appended at the end of the file :param ending_msg: placeholder msg to be appended at the end of the file, like filesystem info, etc, not being used now :returns: the content the user has entered - + """ import tempfile,os from subprocess import call - + #Let's get the default EDITOR of the environment, use nano if none is specified editor = os.environ.get('EDITOR','nano') @@ -215,21 +217,22 @@ def open_editor(beg_msg, ending_msg=None): return data return - + @staticmethod def wrap_string(input_str): #utility method to wrap the content of the ticket, as it can make the output messy return textwrap.wrap(input_str, 80) - + + class TicketDetails(CLIRunnable): """ -usage: sl ticket detail [options] + usage: sl ticket detail [options] -Get details for a ticket + Get details for a ticket -Options: - --updateCount=X Show X count of updates, default is 1 -""" + Options: + --updateCount=X Show X count of updates, default is 1 + """ action = 'detail' def execute(self, args): @@ -237,27 +240,26 @@ def execute(self, args): ticket_id = resolve_id( mgr.resolve_ids, args.get(''), 'ticket') - + count = args.get('--updateCount') if not count: count = 1 return TicketUtils.get_ticket_results(mgr, ticket_id, int(count)) - + class CreateTicket(CLIRunnable): """ -usage: sl ticket create --subject=xxx [options] + usage: sl ticket create --subject=xxx [options] -Create a support ticket. + Create a support ticket. -Required: - --title=TITLE The title of the ticket - --subject=xxx The id of the subject to use for the ticket, issue 'sl ticket subjects' to get the list - + Required: + --title=TITLE The title of the ticket + --subject=xxx The id of the subject to use for the ticket, issue 'sl ticket subjects' to get the list -Optional: - --body the body text to attach to the ticket -""" + Optional: + --body the body text to attach to the ticket + """ action = 'create' required_params = ['--title, --subject'] @@ -267,13 +269,12 @@ def execute(self, args): return 'Please provide a valid title' body=args.get('--body') if (body is None): - body = TicketUtils.open_editor(beg_msg = "***** Softlayer Ticket Content ******") - + body = TicketUtils.open_editor(beg_msg="***** Softlayer Ticket Content ******") + createdTicket = mgr.create_ticket( - title=(args.get('--title')), - body=body, - hardware=args.get('--hardware'), #not being used now - rootPassword=args.get('--rootPassword'), #not being used now - subject=args.get('--subject')) + title=(args.get('--title')), + body=body, + hardware=args.get('--hardware'),# not being used now + rootPassword=args.get('--rootPassword'),# not being used now + subject=args.get('--subject')) return TicketUtils.get_ticket_results(mgr, createdTicket['id'], 1) - diff --git a/SoftLayer/managers/ticket.py b/SoftLayer/managers/ticket.py index 6fe26a178..676cf6a04 100644 --- a/SoftLayer/managers/ticket.py +++ b/SoftLayer/managers/ticket.py @@ -21,14 +21,14 @@ def __init__(self, client): self.account = self.client['Account'] self.ticket = self.client['Ticket'] - def list_tickets(self, status='open', title=None, userId=None,**kwargs): + def list_tickets(self, status='open', title=None, userId=None, **kwargs): """ List all tickets :param string status: status of tickets to retrieve, Open by default :param string title: filter based on title :param dict \*\*kwargs: response-level arguments (limit, offset, etc.) """ - TICKET_MASK = ('id','accountId','title','createDate','lastEditDate','assignedUser[firstName, lastName]') + TICKET_MASK = ('id', 'accountId', 'title', 'createDate', 'lastEditDate', 'assignedUser[firstName, lastName]') if 'mask' not in kwargs: kwargs['mask'] = TICKET_MASK @@ -43,22 +43,21 @@ def list_tickets(self, status='open', title=None, userId=None,**kwargs): return self.account.getOpenTickets(**kwargs) else: return self.account.getClosedTickets(**kwargs) - + def list_subjects(self, **kwargs): """ List all tickets :param dict \*\*kwargs: response-level arguments (limit, offset, etc.) """ return self.client['Ticket_Subject'].getAllObjects(**kwargs) - def get_ticket(self, ticket_id, **kwargs): """ Get details about a ticket - + :param integer id: the ticket ID :returns: A dictionary containing a large amount of information about the specified ticket. - + """ if 'mask' not in kwargs: items = set([ @@ -71,10 +70,8 @@ def get_ticket(self, ticket_id, **kwargs): 'updateCount', ]) kwargs['mask'] = "mask[%s]" % ','.join(items) - return self.ticket.getObject(id=ticket_id, **kwargs) - - + def create_ticket(self, title=None, body=None, hardware=None, rootPassword=None, subject=None, **kwargs): """ Create a new ticket @@ -85,9 +82,8 @@ def create_ticket(self, title=None, body=None, hardware=None, rootPassword=None, """ currentUser = self.account.getCurrentUser() - new_ticket = { - 'subjectId' : subject, + 'subjectId': subject, 'contents': body, 'assignedUserId': currentUser['id'], 'title': title, @@ -96,9 +92,8 @@ def create_ticket(self, title=None, body=None, hardware=None, rootPassword=None, created_ticket = self.ticket.createStandardTicket(new_ticket, body, **kwargs) else: created_ticket = self.ticket.createStandardTicket(new_ticket, body, hardware, rootPassword, **kwargs) - return created_ticket - + def update_ticket(self, t_id=None, body=None, **kwargs): """ Update a ticket @@ -106,8 +101,6 @@ def update_ticket(self, t_id=None, body=None, **kwargs): :param string body: entry to update in the ticket """ - ticket = self.ticket.getObject(id=t_id, **kwargs) self.ticket.edit(ticket, body, id=t_id) - - return \ No newline at end of file + return From a6e6f58494a8f532bbfe79d6b7fb745c20797824 Mon Sep 17 00:00:00 2001 From: Wissam Date: Wed, 19 Feb 2014 23:54:51 -0600 Subject: [PATCH 03/13] Fix Travis formatting issues. --- SoftLayer/CLI/modules/ticket.py | 63 +++++++++++++++++---------------- SoftLayer/managers/ticket.py | 4 +-- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/SoftLayer/CLI/modules/ticket.py b/SoftLayer/CLI/modules/ticket.py index cb5996954..ce6e792fa 100644 --- a/SoftLayer/CLI/modules/ticket.py +++ b/SoftLayer/CLI/modules/ticket.py @@ -39,25 +39,25 @@ def execute(self, args): ticket_mgr = TicketManager(self.client) mask = 'id,accountId,title,createDate,lastEditDate,assignedUser[firstName, lastName]' - + """Determine what needs to be returned, either open tickets, closed tickets, or both""" neither = True - if ( args.get('--status') == OPEN) or (args.get('--status') == CLOSED) : + if (args.get('--status') == OPEN) or (args.get('--status') == CLOSED): neither = False tickets = [] - if ( args.get('--status') == OPEN) or neither: + if (args.get('--status') == OPEN) or neither: for ticket in ticket_mgr.list_tickets(status=OPEN, mask=mask): tickets.append(ticket) if (args.get('--status') == CLOSED) or neither: - for ticket in ticket_mgr.list_tickets(status=CLOSED,mask=mask): + for ticket in ticket_mgr.list_tickets(status=CLOSED, mask=mask): tickets.append(ticket) t = Table(['id', 'assigned user', 'title', 'creation date', 'last edit date']) for ticket in tickets: - if ticket['assignedUser']: + if ticket['assignedUser']: t.add_row([ ticket['id'], ticket['assignedUser']['firstName'] + " " + ticket['assignedUser']['lastName'], @@ -79,7 +79,7 @@ def execute(self, args): class ListSubjectsTickets(CLIRunnable): """ - usage: sl ticket subjects + usage: sl ticket subjects List Subject Ids for ticket creation @@ -88,16 +88,16 @@ class ListSubjectsTickets(CLIRunnable): def execute(self, args): ticket_mgr = TicketManager(self.client) - + t = Table(['id', 'subject']) for subject in ticket_mgr.list_subjects(): t.add_row([ subject['id'], subject['name'] ]) - return t + return t + - class UpdateTicket(CLIRunnable): """ usage: sl ticket update [options] @@ -119,15 +119,15 @@ def execute(self, args): body = args.get('--body') if (body is None): - body = TicketUtils.open_editor(beg_msg = "***** Softlayer Ticket Content ******") + body = TicketUtils.open_editor(beg_msg="***** Softlayer Ticket Content ******") - ticket = mgr.update_ticket(t_id=ticket_id, body=body) - return "Ticket Updated!" + mgr.update_ticket(t_id=ticket_id, body=body) + return "Ticket Updated!" class TicketsSummary(CLIRunnable): """ - usage: sl ticket summary + usage: sl ticket summary Give summary info about tickets @@ -149,7 +149,7 @@ def execute(self, args): t.add_row(['Open', nested]) t.add_row(['Closed', accountObject['closedTicketCount']]) - return t + return t class TicketUtils: @@ -167,7 +167,7 @@ def get_ticket_results(mgr, ticket_id, update_count=1, **kwargs): """ result = mgr.get_ticket(ticket_id) - result = NestedDict(result) + result = NestedDict(result) t = KeyValueTable(['Name', 'Value']) t.align['Name'] = 'r' @@ -176,31 +176,32 @@ def get_ticket_results(mgr, ticket_id, update_count=1, **kwargs): t.add_row(['id', result['id']]) t.add_row(['title', result['title']]) if (result['assignedUser']): - t.add_row(['assignedUser', result['assignedUser']['firstName'] + " " + result['assignedUser']['lastName']] ) + t.add_row(['assignedUser', result['assignedUser']['firstName'] + " " + result['assignedUser']['lastName']]) t.add_row(['createDate', result['createDate']]) t.add_row(['lastEditDate', result['lastEditDate']]) totalUpdates = len(result['updates']) count = min(totalUpdates, update_count) - for index in range(0,count): - t.add_row(['Update %s' %(totalUpdates-index), TicketUtils.wrap_string(result['updates'][totalUpdates-1-index]['entry'])]) + for index in range(0, count): + t.add_row(['Update %s' %(totalUpdates-index), TicketUtils.wrap_string(result['updates'][totalUpdates - 1 - index]['entry'])]) return t @staticmethod def open_editor(beg_msg, ending_msg=None): - """ + """ :param beg_msg: generic msg to be appended at the end of the file :param ending_msg: placeholder msg to be appended at the end of the file, like filesystem info, etc, not being used now :returns: the content the user has entered """ - import tempfile,os + import tempfile + import os from subprocess import call #Let's get the default EDITOR of the environment, use nano if none is specified - editor = os.environ.get('EDITOR','nano') + editor = os.environ.get('EDITOR', 'nano') with tempfile.NamedTemporaryFile(suffix=".tmp") as tempfile: #populate the file with the baked messages @@ -209,11 +210,11 @@ def open_editor(beg_msg, ending_msg=None): if (ending_msg): tempfile.write("\n") tempfile.write(ending_msg) - #flush the file and open it for editing + #flush the file and open it for editing tempfile.flush() call([editor, tempfile.name]) tempfile.seek(0) - data=tempfile.read() + data = tempfile.read() return data return @@ -231,7 +232,7 @@ class TicketDetails(CLIRunnable): Get details for a ticket Options: - --updateCount=X Show X count of updates, default is 1 + --updateCount=X Show X count of updates, default is 1 """ action = 'detail' @@ -241,7 +242,7 @@ def execute(self, args): ticket_id = resolve_id( mgr.resolve_ids, args.get(''), 'ticket') - count = args.get('--updateCount') + count = args.get('--updateCount') if not count: count = 1 return TicketUtils.get_ticket_results(mgr, ticket_id, int(count)) @@ -255,10 +256,10 @@ class CreateTicket(CLIRunnable): Required: --title=TITLE The title of the ticket - --subject=xxx The id of the subject to use for the ticket, issue 'sl ticket subjects' to get the list + --subject=xxx The id of the subject to use for the ticket, issue 'sl ticket subjects' to get the list Optional: - --body the body text to attach to the ticket + --body the body text to attach to the ticket """ action = 'create' required_params = ['--title, --subject'] @@ -267,14 +268,14 @@ def execute(self, args): mgr = TicketManager(self.client) if (args.get('--title') is None): return 'Please provide a valid title' - body=args.get('--body') + body = args.get('--body') if (body is None): body = TicketUtils.open_editor(beg_msg="***** Softlayer Ticket Content ******") createdTicket = mgr.create_ticket( - title=(args.get('--title')), + title=(args.get('--title')), body=body, - hardware=args.get('--hardware'),# not being used now - rootPassword=args.get('--rootPassword'),# not being used now + hardware=args.get('--hardware'), # not being used now + rootPassword=args.get('--rootPassword'), # not being used now subject=args.get('--subject')) return TicketUtils.get_ticket_results(mgr, createdTicket['id'], 1) diff --git a/SoftLayer/managers/ticket.py b/SoftLayer/managers/ticket.py index 676cf6a04..486be4703 100644 --- a/SoftLayer/managers/ticket.py +++ b/SoftLayer/managers/ticket.py @@ -88,11 +88,11 @@ def create_ticket(self, title=None, body=None, hardware=None, rootPassword=None, 'assignedUserId': currentUser['id'], 'title': title, } - if (hardware is None): + if (hardware is None): created_ticket = self.ticket.createStandardTicket(new_ticket, body, **kwargs) else: created_ticket = self.ticket.createStandardTicket(new_ticket, body, hardware, rootPassword, **kwargs) - return created_ticket + return created_ticket def update_ticket(self, t_id=None, body=None, **kwargs): """ Update a ticket From 56cd51c82c63b48d8d49fcdf989a1c1b8c21f48b Mon Sep 17 00:00:00 2001 From: Wissam Date: Thu, 20 Feb 2014 00:10:15 -0600 Subject: [PATCH 04/13] Additional formatting fixes, just installed pep8 to resolved the issues --- SoftLayer/CLI/modules/ticket.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SoftLayer/CLI/modules/ticket.py b/SoftLayer/CLI/modules/ticket.py index ce6e792fa..2e847520e 100644 --- a/SoftLayer/CLI/modules/ticket.py +++ b/SoftLayer/CLI/modules/ticket.py @@ -183,7 +183,7 @@ def get_ticket_results(mgr, ticket_id, update_count=1, **kwargs): totalUpdates = len(result['updates']) count = min(totalUpdates, update_count) for index in range(0, count): - t.add_row(['Update %s' %(totalUpdates-index), TicketUtils.wrap_string(result['updates'][totalUpdates - 1 - index]['entry'])]) + t.add_row(['Update %s' % (totalUpdates - index), TicketUtils.wrap_string(result['updates'][totalUpdates - 1 - index]['entry'])]) return t @@ -252,7 +252,7 @@ class CreateTicket(CLIRunnable): """ usage: sl ticket create --subject=xxx [options] - Create a support ticket. + Create a support ticket. Required: --title=TITLE The title of the ticket @@ -275,7 +275,7 @@ def execute(self, args): createdTicket = mgr.create_ticket( title=(args.get('--title')), body=body, - hardware=args.get('--hardware'), # not being used now - rootPassword=args.get('--rootPassword'), # not being used now + hardware=args.get('--hardware'), # not being used now + rootPassword=args.get('--rootPassword'), # not being used now subject=args.get('--subject')) return TicketUtils.get_ticket_results(mgr, createdTicket['id'], 1) From 48ec441d60444ccfb37941fa39c83322cb3e86fd Mon Sep 17 00:00:00 2001 From: Wissam Date: Thu, 6 Mar 2014 01:23:58 -0600 Subject: [PATCH 05/13] Added Testcases and fixed comments from Nathan --- SoftLayer/CLI/modules/ticket.py | 98 ++++++++++++---------- SoftLayer/managers/ticket.py | 75 +++++++++-------- SoftLayer/tests/fixtures/Account.py | 54 ++++++++++++ SoftLayer/tests/fixtures/Ticket.py | 24 ++++++ SoftLayer/tests/fixtures/Ticket_Subject.py | 22 +++++ SoftLayer/tests/managers/ticket_tests.py | 94 +++++++++++++++++++++ 6 files changed, 288 insertions(+), 79 deletions(-) create mode 100644 SoftLayer/tests/fixtures/Ticket_Subject.py create mode 100644 SoftLayer/tests/managers/ticket_tests.py diff --git a/SoftLayer/CLI/modules/ticket.py b/SoftLayer/CLI/modules/ticket.py index 2e847520e..d750bd935 100644 --- a/SoftLayer/CLI/modules/ticket.py +++ b/SoftLayer/CLI/modules/ticket.py @@ -1,7 +1,7 @@ """ usage: sl ticket [] [...] [options] -Manage account tickets +Manages account tickets The available commands are: create Create a new ticket @@ -9,28 +9,28 @@ list List tickets update Update an existing ticket subjects List the subject IDs that can be used for ticket creation - summary Gives summary info about tickets + summary Give summary info about tickets """ # :license: MIT, see LICENSE for more details. import textwrap from SoftLayer import TicketManager -from SoftLayer.CLI import CLIRunnable, Table, resolve_id, NestedDict, KeyValueTable +from SoftLayer.CLI import CLIRunnable, Table, \ + resolve_id, NestedDict, KeyValueTable -""" Global variables for the status of the ticket - either open or closed """ -OPEN = 'open' -CLOSED = 'closed' +TEMPLATE_MSG = "***** SoftLayer Ticket Content ******" class ListTickets(CLIRunnable): """ - usage: sl ticket list [--status=open,closed] + usage: sl ticket list [--open|--closed] List tickets Options: - --status=open or closed Display only opened or closed tickets, otherwise display both + --open display only open tickets + --closed display only closed tickets display all if none specified """ action = 'list' @@ -38,29 +38,23 @@ class ListTickets(CLIRunnable): def execute(self, args): ticket_mgr = TicketManager(self.client) - mask = 'id,accountId,title,createDate,lastEditDate,assignedUser[firstName, lastName]' + mask = 'id,accountId,title,createDate,lastEditDate,'\ + 'assignedUser[firstName, lastName]' - """Determine what needs to be returned, either open tickets, closed tickets, or both""" - neither = True - if (args.get('--status') == OPEN) or (args.get('--status') == CLOSED): - neither = False + tickets = ticket_mgr.list_tickets( + open=args.get('--open'), + closed=args.get('--closed'), + mask=mask) - tickets = [] - if (args.get('--status') == OPEN) or neither: - for ticket in ticket_mgr.list_tickets(status=OPEN, mask=mask): - tickets.append(ticket) - - if (args.get('--status') == CLOSED) or neither: - for ticket in ticket_mgr.list_tickets(status=CLOSED, mask=mask): - tickets.append(ticket) - - t = Table(['id', 'assigned user', 'title', 'creation date', 'last edit date']) + t = Table(['id', 'assigned user', 'title', + 'creation date', 'last edit date']) for ticket in tickets: if ticket['assignedUser']: t.add_row([ ticket['id'], - ticket['assignedUser']['firstName'] + " " + ticket['assignedUser']['lastName'], + ticket['assignedUser']['firstName'] + + " " + ticket['assignedUser']['lastName'], TicketUtils.wrap_string(ticket['title']), ticket['createDate'], ticket['lastEditDate'] @@ -119,7 +113,7 @@ def execute(self, args): body = args.get('--body') if (body is None): - body = TicketUtils.open_editor(beg_msg="***** Softlayer Ticket Content ******") + body = TicketUtils.open_editor(beg_msg=TEMPLATE_MSG) mgr.update_ticket(t_id=ticket_id, body=body) return "Ticket Updated!" @@ -136,11 +130,16 @@ class TicketsSummary(CLIRunnable): def execute(self, args): account = self.client['Account'] - accountObject = account.getObject(mask='mask[openTicketCount, closedTicketCount, openBillingTicketCount,openOtherTicketCount,openSalesTicketCount,openSupportTicketCount,openAccountingTicketCount]') + mask = 'mask[openTicketCount, closedTicketCount, '\ + 'openBillingTicketCount, openOtherTicketCount, '\ + 'openSalesTicketCount, openSupportTicketCount, '\ + 'openAccountingTicketCount]' + accountObject = account.getObject(mask=mask) t = Table(['Status', 'count']) nested = Table(['Type', 'count']) - nested.add_row(['Accounting', accountObject['openAccountingTicketCount']]) + nested.add_row(['Accounting', + accountObject['openAccountingTicketCount']]) nested.add_row(['Billing', accountObject['openBillingTicketCount']]) nested.add_row(['Sales', accountObject['openSalesTicketCount']]) nested.add_row(['Support', accountObject['openSupportTicketCount']]) @@ -154,15 +153,15 @@ def execute(self, args): class TicketUtils: """ - TicketUtils class that is a helper for common methods within the Ticket module. + TicketUtils class that is a helper for common methods. """ @staticmethod - def get_ticket_results(mgr, ticket_id, update_count=1, **kwargs): + def get_ticket_results(mgr, ticket_id, update_count=1): """ Get output about a ticket :param integer id: the ticket ID - :param integer update_count: the number of entries to retrieve from the ticket + :param integer update_count: number of entries to retrieve from ticket :returns: a KeyValue table containing the details of the ticket """ @@ -176,14 +175,18 @@ def get_ticket_results(mgr, ticket_id, update_count=1, **kwargs): t.add_row(['id', result['id']]) t.add_row(['title', result['title']]) if (result['assignedUser']): - t.add_row(['assignedUser', result['assignedUser']['firstName'] + " " + result['assignedUser']['lastName']]) + t.add_row(['assignedUser', + result['assignedUser']['firstName'] + " " + + result['assignedUser']['lastName']]) t.add_row(['createDate', result['createDate']]) t.add_row(['lastEditDate', result['lastEditDate']]) totalUpdates = len(result['updates']) count = min(totalUpdates, update_count) for index in range(0, count): - t.add_row(['Update %s' % (totalUpdates - index), TicketUtils.wrap_string(result['updates'][totalUpdates - 1 - index]['entry'])]) + t.add_row(['Update %s' % (totalUpdates - index), + TicketUtils.wrap_string( + result['updates'][totalUpdates - 1 - index]['entry'])]) return t @@ -192,7 +195,8 @@ def open_editor(beg_msg, ending_msg=None): """ :param beg_msg: generic msg to be appended at the end of the file - :param ending_msg: placeholder msg to be appended at the end of the file, like filesystem info, etc, not being used now + :param ending_msg: placeholder msg to append at the end of the file, + like filesystem info, etc, not being used now :returns: the content the user has entered """ @@ -200,17 +204,18 @@ def open_editor(beg_msg, ending_msg=None): import os from subprocess import call - #Let's get the default EDITOR of the environment, use nano if none is specified + # Let's get the default EDITOR of the environment, + # use nano if none is specified editor = os.environ.get('EDITOR', 'nano') with tempfile.NamedTemporaryFile(suffix=".tmp") as tempfile: - #populate the file with the baked messages + # populate the file with the baked messages tempfile.write("\n") tempfile.write(beg_msg) if (ending_msg): tempfile.write("\n") tempfile.write(ending_msg) - #flush the file and open it for editing + # flush the file and open it for editing tempfile.flush() call([editor, tempfile.name]) tempfile.seek(0) @@ -221,7 +226,8 @@ def open_editor(beg_msg, ending_msg=None): @staticmethod def wrap_string(input_str): - #utility method to wrap the content of the ticket, as it can make the output messy + # utility method to wrap the content of the ticket, + # as it can make the output messy return textwrap.wrap(input_str, 80) @@ -232,7 +238,7 @@ class TicketDetails(CLIRunnable): Get details for a ticket Options: - --updateCount=X Show X count of updates, default is 1 + --updateCount=X Show X count of updates [default: 1] """ action = 'detail' @@ -243,37 +249,37 @@ def execute(self, args): mgr.resolve_ids, args.get(''), 'ticket') count = args.get('--updateCount') - if not count: - count = 1 return TicketUtils.get_ticket_results(mgr, ticket_id, int(count)) class CreateTicket(CLIRunnable): """ - usage: sl ticket create --subject=xxx [options] + usage: sl ticket create --title=TITLE --subject= [options] Create a support ticket. Required: --title=TITLE The title of the ticket - --subject=xxx The id of the subject to use for the ticket, issue 'sl ticket subjects' to get the list + --subject=xxx The id of the subject to use for the ticket, + issue 'sl ticket subjects' to get the list Optional: - --body the body text to attach to the ticket + --body=BODY the body text to attach to the ticket, + an editor will be opened if body is not provided """ action = 'create' required_params = ['--title, --subject'] def execute(self, args): mgr = TicketManager(self.client) - if (args.get('--title') is None): + if args.get('--title') is "": return 'Please provide a valid title' body = args.get('--body') if (body is None): - body = TicketUtils.open_editor(beg_msg="***** Softlayer Ticket Content ******") + body = TicketUtils.open_editor(beg_msg=TEMPLATE_MSG) createdTicket = mgr.create_ticket( - title=(args.get('--title')), + title=args.get('--title'), body=body, hardware=args.get('--hardware'), # not being used now rootPassword=args.get('--rootPassword'), # not being used now diff --git a/SoftLayer/managers/ticket.py b/SoftLayer/managers/ticket.py index 486be4703..2a1f1f526 100644 --- a/SoftLayer/managers/ticket.py +++ b/SoftLayer/managers/ticket.py @@ -21,28 +21,44 @@ def __init__(self, client): self.account = self.client['Account'] self.ticket = self.client['Ticket'] - def list_tickets(self, status='open', title=None, userId=None, **kwargs): + def list_tickets(self, open=True, closed=True, title=None, + userId=None, **kwargs): """ List all tickets - :param string status: status of tickets to retrieve, Open by default + :param boolean open: include open tickets + :param boolean closed: include closed tickets :param string title: filter based on title :param dict \*\*kwargs: response-level arguments (limit, offset, etc.) """ - TICKET_MASK = ('id', 'accountId', 'title', 'createDate', 'lastEditDate', 'assignedUser[firstName, lastName]') + TICKET_MASK = ('id', + 'accountId', + 'title', + 'createDate', + 'lastEditDate', + 'assignedUser[firstName, lastName]') + + + if 'mask' not in kwargs: kwargs['mask'] = TICKET_MASK _filter = NestedDict(kwargs.get('filter') or {}) if title: - _filter['ticket']['title'] = \ - query_filter(title) + _filter['ticket']['title'] = query_filter(title) kwargs['filter'] = _filter.to_dict() - if (status == 'open'): - return self.account.getOpenTickets(**kwargs) - else: - return self.account.getClosedTickets(**kwargs) + call = 'getTickets' + if not all([open, closed]): + if open: + print 'Open' + call = 'getOpenTickets' + elif closed: + print 'Closed' + call = 'getClosedTickets' + + func = getattr(self.account, call) + return func(**kwargs) def list_subjects(self, **kwargs): """ List all tickets @@ -51,7 +67,7 @@ def list_subjects(self, **kwargs): """ return self.client['Ticket_Subject'].getAllObjects(**kwargs) - def get_ticket(self, ticket_id, **kwargs): + def get_ticket(self, ticket_id): """ Get details about a ticket :param integer id: the ticket ID @@ -59,26 +75,17 @@ def get_ticket(self, ticket_id, **kwargs): the specified ticket. """ - if 'mask' not in kwargs: - items = set([ - 'id', - 'title', - 'assignedUser[firstName, lastName]', - 'createDate', - 'lastEditDate', - 'updates[entry]', - 'updateCount', - ]) - kwargs['mask'] = "mask[%s]" % ','.join(items) - return self.ticket.getObject(id=ticket_id, **kwargs) - - def create_ticket(self, title=None, body=None, hardware=None, rootPassword=None, subject=None, **kwargs): + mask = 'mask[id, title, assignedUser[firstName, lastName],'\ + 'createDate,lastEditDate,updates[entry],updateCount]' + return self.ticket.getObject(id=ticket_id, mask=mask) + + def create_ticket(self, title=None, body=None, + hardware=None, rootPassword=None, subject=None): """ Create a new ticket :param string title: title for the new ticket :param string body: body for the new ticket :param string hardware: id of the hardware to be assigned to the ticket - :param dict \*\*kwargs: response-level arguments (limit, offset, etc.) """ currentUser = self.account.getCurrentUser() @@ -88,19 +95,21 @@ def create_ticket(self, title=None, body=None, hardware=None, rootPassword=None, 'assignedUserId': currentUser['id'], 'title': title, } - if (hardware is None): - created_ticket = self.ticket.createStandardTicket(new_ticket, body, **kwargs) - else: - created_ticket = self.ticket.createStandardTicket(new_ticket, body, hardware, rootPassword, **kwargs) + # if (hardware is None): + created_ticket = self.ticket.createStandardTicket(new_ticket, body) + # else: + # created_ticket = \ + # self.ticket.createStandardTicket(new_ticket, + # body, hardware, rootPassword) return created_ticket - def update_ticket(self, t_id=None, body=None, **kwargs): + def update_ticket(self, t_id=None, body=None): """ Update a ticket :param string id: the id of the ticket to update :param string body: entry to update in the ticket """ - ticket = self.ticket.getObject(id=t_id, **kwargs) - self.ticket.edit(ticket, body, id=t_id) - return + ticket = self.ticket.getObject(id=t_id) + return self.ticket.edit(ticket, body, id=t_id) + diff --git a/SoftLayer/tests/fixtures/Account.py b/SoftLayer/tests/fixtures/Account.py index 499949a8d..6823218c2 100644 --- a/SoftLayer/tests/fixtures/Account.py +++ b/SoftLayer/tests/fixtures/Account.py @@ -201,3 +201,57 @@ 'id': 1234}] getExpiredSecurityCertificates = getSecurityCertificates getValidSecurityCertificates = getSecurityCertificates + +getTickets = [ + { + "accountId": 1234, + "assignedUserId": 12345, + "createDate": "2013-08-01T14:14:04-07:00", + "id": 100, + "lastEditDate": "2013-08-01T14:16:47-07:00", + "lastEditType": "AUTO", + "modifyDate": "2013-08-01T14:16:47-07:00", + "status": { + "id": 1002, + "name": "Closed" + }, + "statusId": 1002, + "title": "Cloud Instance Cancellation - 08/01/13" + }, + { + "accountId": 1234, + "assignedUserId": 12345, + "createDate": "2013-08-01T14:14:04-07:00", + "id": 101, + "lastEditDate": "2013-08-01T14:16:47-07:00", + "lastEditType": "AUTO", + "modifyDate": "2013-08-01T14:16:47-07:00", + "status": { + "id": 1002, + "name": "Closed" + }, + "statusId": 1002, + "title": "Cloud Instance Cancellation - 08/01/13" + }, + { + "accountId": 1234, + "assignedUserId": 12345, + "createDate": "2014-03-03T09:44:01-08:00", + "id": 102, + "lastEditDate": "2013-08-01T14:16:47-07:00", + "lastEditType": "AUTO", + "modifyDate": "2014-03-03T09:44:03-08:00", + "status": { + "id": 1001, + "name": "Open" + }, + "statusId": 1001, + "title": "Cloud Instance Cancellation - 08/01/13" + }] + +getOpenTickets = [ticket for ticket in getTickets + if ticket['statusId'] == 1001] +getClosedTickets = [ticket for ticket in getTickets + if ticket['statusId'] == 1002] + +getCurrentUser = {"id": 12345} diff --git a/SoftLayer/tests/fixtures/Ticket.py b/SoftLayer/tests/fixtures/Ticket.py index cd79a3397..e8a8ed336 100644 --- a/SoftLayer/tests/fixtures/Ticket.py +++ b/SoftLayer/tests/fixtures/Ticket.py @@ -1 +1,25 @@ createCancelServerTicket = {'id': 1234, 'title': 'Server Cancellation Request'} +getObject = { + "accountId": 1234, + "assignedUserId": 12345, + "createDate": "2013-08-01T14:14:04-07:00", + "id": 100, + "lastEditDate": "2013-08-01T14:16:47-07:00", + "lastEditType": "AUTO", + "modifyDate": "2013-08-01T14:16:47-07:00", + "status": { + "id": 1002, + "name": "Closed" + }, + "statusId": 1002, + "title": "Cloud Instance Cancellation - 08/01/13" + } + +createStandardTicket = { + "assignedUserId": 12345, + "id": 100, + "contents": "body", + "subjectId": 1004, + "title": "Cloud Instance Cancellation - 08/01/13" + } +edit = True diff --git a/SoftLayer/tests/fixtures/Ticket_Subject.py b/SoftLayer/tests/fixtures/Ticket_Subject.py new file mode 100644 index 000000000..e8ede3168 --- /dev/null +++ b/SoftLayer/tests/fixtures/Ticket_Subject.py @@ -0,0 +1,22 @@ +getAllObjects = [ + { + "id": 1001, + "name": "Accounting Request" + }, + { + "id": 1002, + "name": "Sales Request" + }, + { + "id": 1003, + "name": "Reboots and Console Access" + }, + { + "id": 1004, + "name": "DNS Request" + }, + { + "id": 1005, + "name": "Hardware Issue" + } +] diff --git a/SoftLayer/tests/managers/ticket_tests.py b/SoftLayer/tests/managers/ticket_tests.py new file mode 100644 index 000000000..0969ce870 --- /dev/null +++ b/SoftLayer/tests/managers/ticket_tests.py @@ -0,0 +1,94 @@ +""" + SoftLayer.tests.managers.ticket_tests + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + :license: MIT, see LICENSE for more details. +""" +from SoftLayer import TicketManager +from SoftLayer.tests import unittest, FixtureClient +from SoftLayer.tests.fixtures import Ticket, Account +from mock import MagicMock, ANY, call, patch + + +class TicketTests(unittest.TestCase): + + def setUp(self): + self.client = FixtureClient() + self.ticket = TicketManager(self.client) + + def test_list_tickets(self): + mcall = call(mask=ANY, filter={}) + service = self.client['Account'] + + list_expected_ids = [100, 101, 102] + open_expected_ids = [102] + closed_expected_ids = [100, 101] + + results = self.ticket.list_tickets() + service.getTickets.assert_has_calls(mcall) + for result in results: + self.assertIn(result['id'], list_expected_ids) + + results = self.ticket.list_tickets(open=True, closed=True) + service.getTickets.assert_has_calls(mcall) + for result in results: + self.assertIn(result['id'], list_expected_ids) + + results = self.ticket.list_tickets(open=True, closed=False) + for result in results: + self.assertIn(result['id'], open_expected_ids) + + results = self.ticket.list_tickets(open=False, closed=True) + for result in results: + self.assertIn(result['id'], closed_expected_ids) + + def test_list_subjects(self): + mcall = call(mask=ANY, filter={}) + service = self.client['Ticket_Subject'] + list_expected_ids = [1001, 1002, 1003, 1004, 1005] + + results = self.ticket.list_subjects() + for result in results: + self.assertIn(result['id'], list_expected_ids) + + def test_get_instance(self): + result = self.ticket.get_ticket(100) + self.client['Ticket'].getObject.assert_called_once_with( + id=100, mask=ANY) + self.assertEqual(Ticket.getObject, result) + + def test_create_ticket(self): + self.ticket.create_ticket( + title="Cloud Instance Cancellation - 08/01/13", + body="body", + subject=1004) + self.client['Ticket'].createStandardTicket.assert_called_once_with( + {"assignedUserId": 12345, + "contents": "body", + "subjectId": 1004, + "title": "Cloud Instance Cancellation - 08/01/13"}, "body") + + def test_update_ticket(self): + # Test editing user data + service = self.client['Ticket'] + + # test a full update + self.ticket.update_ticket(100, body='Update1') + service.edit.assert_called_once_with( + { + "accountId": 1234, + "assignedUserId": 12345, + "createDate": "2013-08-01T14:14:04-07:00", + "id": 100, + "lastEditDate": "2013-08-01T14:16:47-07:00", + "lastEditType": "AUTO", + "modifyDate": "2013-08-01T14:16:47-07:00", + "status": { + "id": 1002, + "name": "Closed" + }, + "statusId": 1002, + "title": "Cloud Instance Cancellation - 08/01/13" + }, + 'Update1', + id=100) From 25d647085d9c497858cbc5d2c8327eee9040ac97 Mon Sep 17 00:00:00 2001 From: Wissam Date: Thu, 6 Mar 2014 01:33:47 -0600 Subject: [PATCH 06/13] Fix pep8 issues --- SoftLayer/managers/ticket.py | 3 -- SoftLayer/tests/fixtures/Ticket.py | 40 ++++++++++++------------ SoftLayer/tests/managers/ticket_tests.py | 6 ++-- 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/SoftLayer/managers/ticket.py b/SoftLayer/managers/ticket.py index 2a1f1f526..d7e80a07e 100644 --- a/SoftLayer/managers/ticket.py +++ b/SoftLayer/managers/ticket.py @@ -37,8 +37,6 @@ def list_tickets(self, open=True, closed=True, title=None, 'lastEditDate', 'assignedUser[firstName, lastName]') - - if 'mask' not in kwargs: kwargs['mask'] = TICKET_MASK @@ -112,4 +110,3 @@ def update_ticket(self, t_id=None, body=None): ticket = self.ticket.getObject(id=t_id) return self.ticket.edit(ticket, body, id=t_id) - diff --git a/SoftLayer/tests/fixtures/Ticket.py b/SoftLayer/tests/fixtures/Ticket.py index e8a8ed336..b6a6bee0b 100644 --- a/SoftLayer/tests/fixtures/Ticket.py +++ b/SoftLayer/tests/fixtures/Ticket.py @@ -1,25 +1,25 @@ createCancelServerTicket = {'id': 1234, 'title': 'Server Cancellation Request'} getObject = { - "accountId": 1234, - "assignedUserId": 12345, - "createDate": "2013-08-01T14:14:04-07:00", - "id": 100, - "lastEditDate": "2013-08-01T14:16:47-07:00", - "lastEditType": "AUTO", - "modifyDate": "2013-08-01T14:16:47-07:00", - "status": { - "id": 1002, - "name": "Closed" - }, - "statusId": 1002, - "title": "Cloud Instance Cancellation - 08/01/13" - } + "accountId": 1234, + "assignedUserId": 12345, + "createDate": "2013-08-01T14:14:04-07:00", + "id": 100, + "lastEditDate": "2013-08-01T14:16:47-07:00", + "lastEditType": "AUTO", + "modifyDate": "2013-08-01T14:16:47-07:00", + "status": { + "id": 1002, + "name": "Closed" + }, + "statusId": 1002, + "title": "Cloud Instance Cancellation - 08/01/13" + } createStandardTicket = { - "assignedUserId": 12345, - "id": 100, - "contents": "body", - "subjectId": 1004, - "title": "Cloud Instance Cancellation - 08/01/13" - } + "assignedUserId": 12345, + "id": 100, + "contents": "body", + "subjectId": 1004, + "title": "Cloud Instance Cancellation - 08/01/13" + } edit = True diff --git a/SoftLayer/tests/managers/ticket_tests.py b/SoftLayer/tests/managers/ticket_tests.py index 0969ce870..affff8129 100644 --- a/SoftLayer/tests/managers/ticket_tests.py +++ b/SoftLayer/tests/managers/ticket_tests.py @@ -6,8 +6,8 @@ """ from SoftLayer import TicketManager from SoftLayer.tests import unittest, FixtureClient -from SoftLayer.tests.fixtures import Ticket, Account -from mock import MagicMock, ANY, call, patch +from SoftLayer.tests.fixtures import Ticket +from mock import ANY, call class TicketTests(unittest.TestCase): @@ -43,8 +43,6 @@ def test_list_tickets(self): self.assertIn(result['id'], closed_expected_ids) def test_list_subjects(self): - mcall = call(mask=ANY, filter={}) - service = self.client['Ticket_Subject'] list_expected_ids = [1001, 1002, 1003, 1004, 1005] results = self.ticket.list_subjects() From 1abdfcd182b686c6e0a1257a238424606f50cefc Mon Sep 17 00:00:00 2001 From: Wissam Date: Thu, 6 Mar 2014 01:53:53 -0600 Subject: [PATCH 07/13] Add 100% test coverage --- SoftLayer/CLI/modules/ticket.py | 7 +++--- SoftLayer/managers/ticket.py | 30 +++++------------------- SoftLayer/tests/managers/ticket_tests.py | 2 +- 3 files changed, 10 insertions(+), 29 deletions(-) diff --git a/SoftLayer/CLI/modules/ticket.py b/SoftLayer/CLI/modules/ticket.py index d750bd935..65e52fd91 100644 --- a/SoftLayer/CLI/modules/ticket.py +++ b/SoftLayer/CLI/modules/ticket.py @@ -38,13 +38,12 @@ class ListTickets(CLIRunnable): def execute(self, args): ticket_mgr = TicketManager(self.client) - mask = 'id,accountId,title,createDate,lastEditDate,'\ - 'assignedUser[firstName, lastName]' + # mask = 'id,accountId,title,createDate,lastEditDate,'\ + # 'assignedUser[firstName, lastName]' tickets = ticket_mgr.list_tickets( open=args.get('--open'), - closed=args.get('--closed'), - mask=mask) + closed=args.get('--closed')) t = Table(['id', 'assigned user', 'title', 'creation date', 'last edit date']) diff --git a/SoftLayer/managers/ticket.py b/SoftLayer/managers/ticket.py index d7e80a07e..043f9119c 100644 --- a/SoftLayer/managers/ticket.py +++ b/SoftLayer/managers/ticket.py @@ -21,49 +21,31 @@ def __init__(self, client): self.account = self.client['Account'] self.ticket = self.client['Ticket'] - def list_tickets(self, open=True, closed=True, title=None, - userId=None, **kwargs): + def list_tickets(self, open=True, closed=True, userId=None): """ List all tickets :param boolean open: include open tickets :param boolean closed: include closed tickets :param string title: filter based on title - :param dict \*\*kwargs: response-level arguments (limit, offset, etc.) """ - TICKET_MASK = ('id', - 'accountId', - 'title', - 'createDate', - 'lastEditDate', - 'assignedUser[firstName, lastName]') - - if 'mask' not in kwargs: - kwargs['mask'] = TICKET_MASK - - _filter = NestedDict(kwargs.get('filter') or {}) - if title: - _filter['ticket']['title'] = query_filter(title) - - kwargs['filter'] = _filter.to_dict() + mask = 'mask[id, title, assignedUser[firstName, lastName],'\ + 'createDate,lastEditDate,accountId]' call = 'getTickets' if not all([open, closed]): if open: - print 'Open' call = 'getOpenTickets' elif closed: - print 'Closed' call = 'getClosedTickets' func = getattr(self.account, call) - return func(**kwargs) + return func(mask=mask) - def list_subjects(self, **kwargs): + def list_subjects(self): """ List all tickets - :param dict \*\*kwargs: response-level arguments (limit, offset, etc.) """ - return self.client['Ticket_Subject'].getAllObjects(**kwargs) + return self.client['Ticket_Subject'].getAllObjects() def get_ticket(self, ticket_id): """ Get details about a ticket diff --git a/SoftLayer/tests/managers/ticket_tests.py b/SoftLayer/tests/managers/ticket_tests.py index affff8129..b9e20b211 100644 --- a/SoftLayer/tests/managers/ticket_tests.py +++ b/SoftLayer/tests/managers/ticket_tests.py @@ -17,7 +17,7 @@ def setUp(self): self.ticket = TicketManager(self.client) def test_list_tickets(self): - mcall = call(mask=ANY, filter={}) + mcall = call(mask=ANY) service = self.client['Account'] list_expected_ids = [100, 101, 102] From 778e633fadfcdf4315d16840e77943dd77d18aaa Mon Sep 17 00:00:00 2001 From: Wissam Date: Thu, 6 Mar 2014 01:58:12 -0600 Subject: [PATCH 08/13] Clean up Code --- SoftLayer/managers/ticket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SoftLayer/managers/ticket.py b/SoftLayer/managers/ticket.py index 043f9119c..b3819a9c8 100644 --- a/SoftLayer/managers/ticket.py +++ b/SoftLayer/managers/ticket.py @@ -6,7 +6,7 @@ :license: MIT, see LICENSE for more details. """ -from SoftLayer.utils import query_filter, IdentifierMixin, NestedDict +from SoftLayer.utils import IdentifierMixin class TicketManager(IdentifierMixin, object): From 80f27330313ffbd18dc1ac30aaf00166f2137c55 Mon Sep 17 00:00:00 2001 From: Wissam Date: Thu, 6 Mar 2014 09:43:14 -0600 Subject: [PATCH 09/13] Fix pep8 issues again --- SoftLayer/tests/fixtures/Account.py | 4 +-- SoftLayer/tests/fixtures/Ticket.py | 40 ++++++++++++++--------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/SoftLayer/tests/fixtures/Account.py b/SoftLayer/tests/fixtures/Account.py index 6823218c2..a9cc0f3f9 100644 --- a/SoftLayer/tests/fixtures/Account.py +++ b/SoftLayer/tests/fixtures/Account.py @@ -250,8 +250,8 @@ }] getOpenTickets = [ticket for ticket in getTickets - if ticket['statusId'] == 1001] + if ticket['statusId'] == 1001] getClosedTickets = [ticket for ticket in getTickets - if ticket['statusId'] == 1002] + if ticket['statusId'] == 1002] getCurrentUser = {"id": 12345} diff --git a/SoftLayer/tests/fixtures/Ticket.py b/SoftLayer/tests/fixtures/Ticket.py index b6a6bee0b..d34154579 100644 --- a/SoftLayer/tests/fixtures/Ticket.py +++ b/SoftLayer/tests/fixtures/Ticket.py @@ -1,25 +1,25 @@ createCancelServerTicket = {'id': 1234, 'title': 'Server Cancellation Request'} getObject = { - "accountId": 1234, - "assignedUserId": 12345, - "createDate": "2013-08-01T14:14:04-07:00", - "id": 100, - "lastEditDate": "2013-08-01T14:16:47-07:00", - "lastEditType": "AUTO", - "modifyDate": "2013-08-01T14:16:47-07:00", - "status": { - "id": 1002, - "name": "Closed" - }, - "statusId": 1002, - "title": "Cloud Instance Cancellation - 08/01/13" - } + "accountId": 1234, + "assignedUserId": 12345, + "createDate": "2013-08-01T14:14:04-07:00", + "id": 100, + "lastEditDate": "2013-08-01T14:16:47-07:00", + "lastEditType": "AUTO", + "modifyDate": "2013-08-01T14:16:47-07:00", + "status": { + "id": 1002, + "name": "Closed" + }, + "statusId": 1002, + "title": "Cloud Instance Cancellation - 08/01/13" +} createStandardTicket = { - "assignedUserId": 12345, - "id": 100, - "contents": "body", - "subjectId": 1004, - "title": "Cloud Instance Cancellation - 08/01/13" - } + "assignedUserId": 12345, + "id": 100, + "contents": "body", + "subjectId": 1004, + "title": "Cloud Instance Cancellation - 08/01/13" +} edit = True From 9132ce4be41490d33fc307b520fe4e7d4f48b61d Mon Sep 17 00:00:00 2001 From: Wissam Date: Thu, 6 Mar 2014 09:53:34 -0600 Subject: [PATCH 10/13] More Pep8 issues --- SoftLayer/CLI/modules/ticket.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SoftLayer/CLI/modules/ticket.py b/SoftLayer/CLI/modules/ticket.py index 65e52fd91..61985d5e7 100644 --- a/SoftLayer/CLI/modules/ticket.py +++ b/SoftLayer/CLI/modules/ticket.py @@ -184,8 +184,8 @@ def get_ticket_results(mgr, ticket_id, update_count=1): count = min(totalUpdates, update_count) for index in range(0, count): t.add_row(['Update %s' % (totalUpdates - index), - TicketUtils.wrap_string( - result['updates'][totalUpdates - 1 - index]['entry'])]) + TicketUtils.wrap_string( + result['updates'][totalUpdates - 1 - index]['entry'])]) return t From fefad10ba1b261ec9970f581645faf0a11a867bd Mon Sep 17 00:00:00 2001 From: Wissam Date: Thu, 6 Mar 2014 11:13:39 -0600 Subject: [PATCH 11/13] Fix pep8 issue --- SoftLayer/CLI/modules/ticket.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SoftLayer/CLI/modules/ticket.py b/SoftLayer/CLI/modules/ticket.py index 61985d5e7..97726de35 100644 --- a/SoftLayer/CLI/modules/ticket.py +++ b/SoftLayer/CLI/modules/ticket.py @@ -183,9 +183,9 @@ def get_ticket_results(mgr, ticket_id, update_count=1): totalUpdates = len(result['updates']) count = min(totalUpdates, update_count) for index in range(0, count): - t.add_row(['Update %s' % (totalUpdates - index), - TicketUtils.wrap_string( - result['updates'][totalUpdates - 1 - index]['entry'])]) + i = totalUpdates - index + update = TicketUtils.wrap_string(result['updates'][i - 1]['entry']) + t.add_row(['Update %s' % (i), update]) return t From a549f2fbda60aae3010ca120f70d0c0f04471171 Mon Sep 17 00:00:00 2001 From: Wissam Date: Thu, 6 Mar 2014 13:27:16 -0600 Subject: [PATCH 12/13] Integrated changes asked by sudorandom --- SoftLayer/CLI/modules/ticket.py | 267 +++++++++++------------ SoftLayer/managers/ticket.py | 24 +- SoftLayer/tests/managers/ticket_tests.py | 6 +- 3 files changed, 140 insertions(+), 157 deletions(-) diff --git a/SoftLayer/CLI/modules/ticket.py b/SoftLayer/CLI/modules/ticket.py index 97726de35..0bc035eff 100644 --- a/SoftLayer/CLI/modules/ticket.py +++ b/SoftLayer/CLI/modules/ticket.py @@ -4,16 +4,19 @@ Manages account tickets The available commands are: - create Create a new ticket - detail Output details about an ticket - list List tickets - update Update an existing ticket - subjects List the subject IDs that can be used for ticket creation - summary Give summary info about tickets + create Create a new ticket + detail Output details about an ticket + list List tickets + update Update an existing ticket + subjects List the subject IDs that can be used for ticket creation + summary Give summary info about tickets """ # :license: MIT, see LICENSE for more details. import textwrap +import tempfile +import os +from subprocess import call from SoftLayer import TicketManager from SoftLayer.CLI import CLIRunnable, Table, \ @@ -22,28 +25,96 @@ TEMPLATE_MSG = "***** SoftLayer Ticket Content ******" -class ListTickets(CLIRunnable): +def wrap_string(input_str): + # utility method to wrap the content of the ticket, + # as it can make the output messy + return textwrap.wrap(input_str, 80) + + +def get_ticket_results(mgr, ticket_id, update_count=1): + """ Get output about a ticket + + :param integer id: the ticket ID + :param integer update_count: number of entries to retrieve from ticket + :returns: a KeyValue table containing the details of the ticket + """ - usage: sl ticket list [--open|--closed] + result = mgr.get_ticket(ticket_id) + result = NestedDict(result) + + t = KeyValueTable(['Name', 'Value']) + t.align['Name'] = 'r' + t.align['Value'] = 'l' - List tickets + t.add_row(['id', result['id']]) + t.add_row(['title', result['title']]) + if result['assignedUser']: + t.add_row(['assignedUser', + "%s %s" % (result['assignedUser']['firstName'], + result['assignedUser']['lastName'])]) + t.add_row(['createDate', result['createDate']]) + t.add_row(['lastEditDate', result['lastEditDate']]) + + totalUpdates = len(result['updates']) + count = min(totalUpdates, update_count) + for index in range(0, count): + i = totalUpdates - index + update = wrap_string(result['updates'][i - 1]['entry']) + t.add_row(['Update %s' % (i), update]) + + return t + + +def open_editor(beg_msg, ending_msg=None): + """ - Options: - --open display only open tickets - --closed display only closed tickets display all if none specified + :param beg_msg: generic msg to be appended at the end of the file + :param ending_msg: placeholder msg to append at the end of the file, + like filesystem info, etc, not being used now + :returns: the content the user has entered """ + + # Let's get the default EDITOR of the environment, + # use nano if none is specified + editor = os.environ.get('EDITOR', 'nano') + + with tempfile.NamedTemporaryFile(suffix=".tmp") as tfile: + # populate the file with the baked messages + tfile.write("\n") + tfile.write(beg_msg) + if ending_msg: + tfile.write("\n") + tfile.write(ending_msg) + # flush the file and open it for editing + tfile.flush() + call([editor, tfile.name]) + tfile.seek(0) + data = tfile.read() + return data + + return + + +class ListTickets(CLIRunnable): + """ +usage: sl ticket list [--open | --closed] + +List tickets + +Options: + --open display only open tickets + --closed display only closed tickets display all if none specified + +""" action = 'list' def execute(self, args): ticket_mgr = TicketManager(self.client) - # mask = 'id,accountId,title,createDate,lastEditDate,'\ - # 'assignedUser[firstName, lastName]' - tickets = ticket_mgr.list_tickets( - open=args.get('--open'), - closed=args.get('--closed')) + openStatus=args.get('--open'), + closedStatus=args.get('--closed')) t = Table(['id', 'assigned user', 'title', 'creation date', 'last edit date']) @@ -52,9 +123,9 @@ def execute(self, args): if ticket['assignedUser']: t.add_row([ ticket['id'], - ticket['assignedUser']['firstName'] + - " " + ticket['assignedUser']['lastName'], - TicketUtils.wrap_string(ticket['title']), + "%s %s" % (ticket['assignedUser']['firstName'], + ticket['assignedUser']['lastName']), + wrap_string(ticket['title']), ticket['createDate'], ticket['lastEditDate'] ]) @@ -62,7 +133,7 @@ def execute(self, args): t.add_row([ ticket['id'], 'N/A', - TicketUtils.wrap_string(ticket['title']), + wrap_string(ticket['title']), ticket['createDate'], ticket['lastEditDate'] ]) @@ -72,11 +143,11 @@ def execute(self, args): class ListSubjectsTickets(CLIRunnable): """ - usage: sl ticket subjects +usage: sl ticket subjects - List Subject Ids for ticket creation +List Subject IDs for ticket creation - """ +""" action = 'subjects' def execute(self, args): @@ -93,14 +164,14 @@ def execute(self, args): class UpdateTicket(CLIRunnable): """ - usage: sl ticket update [options] +usage: sl ticket update [options] - Updates a certain ticket +Updates a certain ticket - Options: - --body=BODY The entry that will be appended to the ticket +Options: + --body=BODY The entry that will be appended to the ticket - """ +""" action = 'update' options = ['--body'] @@ -111,8 +182,8 @@ def execute(self, args): mgr.resolve_ids, args.get(''), 'ticket') body = args.get('--body') - if (body is None): - body = TicketUtils.open_editor(beg_msg=TEMPLATE_MSG) + if body is None: + body = open_editor(beg_msg=TEMPLATE_MSG) mgr.update_ticket(t_id=ticket_id, body=body) return "Ticket Updated!" @@ -120,19 +191,19 @@ def execute(self, args): class TicketsSummary(CLIRunnable): """ - usage: sl ticket summary +usage: sl ticket summary - Give summary info about tickets +Give summary info about tickets - """ +""" action = 'summary' def execute(self, args): account = self.client['Account'] - mask = 'mask[openTicketCount, closedTicketCount, '\ - 'openBillingTicketCount, openOtherTicketCount, '\ - 'openSalesTicketCount, openSupportTicketCount, '\ - 'openAccountingTicketCount]' + mask = ('mask[openTicketCount, closedTicketCount, ' + 'openBillingTicketCount, openOtherTicketCount, ' + 'openSalesTicketCount, openSupportTicketCount, ' + 'openAccountingTicketCount]') accountObject = account.getObject(mask=mask) t = Table(['Status', 'count']) @@ -150,95 +221,15 @@ def execute(self, args): return t -class TicketUtils: - """ - TicketUtils class that is a helper for common methods. - """ - - @staticmethod - def get_ticket_results(mgr, ticket_id, update_count=1): - """ Get output about a ticket - - :param integer id: the ticket ID - :param integer update_count: number of entries to retrieve from ticket - :returns: a KeyValue table containing the details of the ticket - - """ - result = mgr.get_ticket(ticket_id) - result = NestedDict(result) - - t = KeyValueTable(['Name', 'Value']) - t.align['Name'] = 'r' - t.align['Value'] = 'l' - - t.add_row(['id', result['id']]) - t.add_row(['title', result['title']]) - if (result['assignedUser']): - t.add_row(['assignedUser', - result['assignedUser']['firstName'] + " " + - result['assignedUser']['lastName']]) - t.add_row(['createDate', result['createDate']]) - t.add_row(['lastEditDate', result['lastEditDate']]) - - totalUpdates = len(result['updates']) - count = min(totalUpdates, update_count) - for index in range(0, count): - i = totalUpdates - index - update = TicketUtils.wrap_string(result['updates'][i - 1]['entry']) - t.add_row(['Update %s' % (i), update]) - - return t - - @staticmethod - def open_editor(beg_msg, ending_msg=None): - """ - - :param beg_msg: generic msg to be appended at the end of the file - :param ending_msg: placeholder msg to append at the end of the file, - like filesystem info, etc, not being used now - :returns: the content the user has entered - - """ - import tempfile - import os - from subprocess import call - - # Let's get the default EDITOR of the environment, - # use nano if none is specified - editor = os.environ.get('EDITOR', 'nano') - - with tempfile.NamedTemporaryFile(suffix=".tmp") as tempfile: - # populate the file with the baked messages - tempfile.write("\n") - tempfile.write(beg_msg) - if (ending_msg): - tempfile.write("\n") - tempfile.write(ending_msg) - # flush the file and open it for editing - tempfile.flush() - call([editor, tempfile.name]) - tempfile.seek(0) - data = tempfile.read() - return data - - return - - @staticmethod - def wrap_string(input_str): - # utility method to wrap the content of the ticket, - # as it can make the output messy - return textwrap.wrap(input_str, 80) - - class TicketDetails(CLIRunnable): """ - usage: sl ticket detail [options] +usage: sl ticket detail [options] - Get details for a ticket +Get details for a ticket - Options: - --updateCount=X Show X count of updates [default: 1] - """ +Options: + --updateCount=X Show X count of updates [default: 1] +""" action = 'detail' def execute(self, args): @@ -248,24 +239,24 @@ def execute(self, args): mgr.resolve_ids, args.get(''), 'ticket') count = args.get('--updateCount') - return TicketUtils.get_ticket_results(mgr, ticket_id, int(count)) + return get_ticket_results(mgr, ticket_id, int(count)) class CreateTicket(CLIRunnable): """ - usage: sl ticket create --title=TITLE --subject= [options] +usage: sl ticket create --title=TITLE --subject= [options] - Create a support ticket. +Create a support ticket. - Required: - --title=TITLE The title of the ticket - --subject=xxx The id of the subject to use for the ticket, - issue 'sl ticket subjects' to get the list +Required: + --title=TITLE The title of the ticket + --subject=xxx The id of the subject to use for the ticket, + issue 'sl ticket subjects' to get the list - Optional: - --body=BODY the body text to attach to the ticket, - an editor will be opened if body is not provided - """ +Optional: + --body=BODY the body text to attach to the ticket, + an editor will be opened if body is not provided +""" action = 'create' required_params = ['--title, --subject'] @@ -274,13 +265,11 @@ def execute(self, args): if args.get('--title') is "": return 'Please provide a valid title' body = args.get('--body') - if (body is None): - body = TicketUtils.open_editor(beg_msg=TEMPLATE_MSG) + if body is None: + body = open_editor(beg_msg=TEMPLATE_MSG) createdTicket = mgr.create_ticket( title=args.get('--title'), body=body, - hardware=args.get('--hardware'), # not being used now - rootPassword=args.get('--rootPassword'), # not being used now subject=args.get('--subject')) - return TicketUtils.get_ticket_results(mgr, createdTicket['id'], 1) + return get_ticket_results(mgr, createdTicket['id'], 1) diff --git a/SoftLayer/managers/ticket.py b/SoftLayer/managers/ticket.py index b3819a9c8..46bc14666 100644 --- a/SoftLayer/managers/ticket.py +++ b/SoftLayer/managers/ticket.py @@ -21,21 +21,21 @@ def __init__(self, client): self.account = self.client['Account'] self.ticket = self.client['Ticket'] - def list_tickets(self, open=True, closed=True, userId=None): + def list_tickets(self, openStatus=True, closedStatus=True, userId=None): """ List all tickets :param boolean open: include open tickets :param boolean closed: include closed tickets :param string title: filter based on title """ - mask = 'mask[id, title, assignedUser[firstName, lastName],'\ - 'createDate,lastEditDate,accountId]' + mask = ('mask[id, title, assignedUser[firstName, lastName],' + 'createDate,lastEditDate,accountId]') call = 'getTickets' - if not all([open, closed]): - if open: + if not all([openStatus, closedStatus]): + if openStatus: call = 'getOpenTickets' - elif closed: + elif closedStatus: call = 'getClosedTickets' func = getattr(self.account, call) @@ -55,12 +55,11 @@ def get_ticket(self, ticket_id): the specified ticket. """ - mask = 'mask[id, title, assignedUser[firstName, lastName],'\ - 'createDate,lastEditDate,updates[entry],updateCount]' + mask = ('mask[id, title, assignedUser[firstName, lastName],' + 'createDate,lastEditDate,updates[entry],updateCount]') return self.ticket.getObject(id=ticket_id, mask=mask) - def create_ticket(self, title=None, body=None, - hardware=None, rootPassword=None, subject=None): + def create_ticket(self, title=None, body=None, subject=None): """ Create a new ticket :param string title: title for the new ticket @@ -75,12 +74,7 @@ def create_ticket(self, title=None, body=None, 'assignedUserId': currentUser['id'], 'title': title, } - # if (hardware is None): created_ticket = self.ticket.createStandardTicket(new_ticket, body) - # else: - # created_ticket = \ - # self.ticket.createStandardTicket(new_ticket, - # body, hardware, rootPassword) return created_ticket def update_ticket(self, t_id=None, body=None): diff --git a/SoftLayer/tests/managers/ticket_tests.py b/SoftLayer/tests/managers/ticket_tests.py index b9e20b211..9a35cea3b 100644 --- a/SoftLayer/tests/managers/ticket_tests.py +++ b/SoftLayer/tests/managers/ticket_tests.py @@ -29,16 +29,16 @@ def test_list_tickets(self): for result in results: self.assertIn(result['id'], list_expected_ids) - results = self.ticket.list_tickets(open=True, closed=True) + results = self.ticket.list_tickets(openStatus=True, closedStatus=True) service.getTickets.assert_has_calls(mcall) for result in results: self.assertIn(result['id'], list_expected_ids) - results = self.ticket.list_tickets(open=True, closed=False) + results = self.ticket.list_tickets(openStatus=True, closedStatus=False) for result in results: self.assertIn(result['id'], open_expected_ids) - results = self.ticket.list_tickets(open=False, closed=True) + results = self.ticket.list_tickets(openStatus=False, closedStatus=True) for result in results: self.assertIn(result['id'], closed_expected_ids) From 11538ad1b22a377ecf5408c0106c67fdb3729eb7 Mon Sep 17 00:00:00 2001 From: Wissam Date: Thu, 6 Mar 2014 14:46:05 -0600 Subject: [PATCH 13/13] Fixed additional issues as requested --- SoftLayer/CLI/modules/ticket.py | 14 ++++++------ SoftLayer/managers/ticket.py | 27 +++++++++++------------- SoftLayer/tests/managers/ticket_tests.py | 6 +++--- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/SoftLayer/CLI/modules/ticket.py b/SoftLayer/CLI/modules/ticket.py index 0bc035eff..010bef861 100644 --- a/SoftLayer/CLI/modules/ticket.py +++ b/SoftLayer/CLI/modules/ticket.py @@ -19,8 +19,8 @@ from subprocess import call from SoftLayer import TicketManager -from SoftLayer.CLI import CLIRunnable, Table, \ - resolve_id, NestedDict, KeyValueTable +from SoftLayer.CLI import (CLIRunnable, Table, resolve_id, NestedDict, + KeyValueTable) TEMPLATE_MSG = "***** SoftLayer Ticket Content ******" @@ -113,8 +113,8 @@ def execute(self, args): ticket_mgr = TicketManager(self.client) tickets = ticket_mgr.list_tickets( - openStatus=args.get('--open'), - closedStatus=args.get('--closed')) + open_status=args.get('--open'), + closed_status=args.get('--closed')) t = Table(['id', 'assigned user', 'title', 'creation date', 'last edit date']) @@ -185,7 +185,7 @@ def execute(self, args): if body is None: body = open_editor(beg_msg=TEMPLATE_MSG) - mgr.update_ticket(t_id=ticket_id, body=body) + mgr.update_ticket(ticket_id=ticket_id, body=body) return "Ticket Updated!" @@ -244,13 +244,13 @@ def execute(self, args): class CreateTicket(CLIRunnable): """ -usage: sl ticket create --title=TITLE --subject= [options] +usage: sl ticket create --title=TITLE --subject=ID [options] Create a support ticket. Required: --title=TITLE The title of the ticket - --subject=xxx The id of the subject to use for the ticket, + --subject=ID The id of the subject to use for the ticket, issue 'sl ticket subjects' to get the list Optional: diff --git a/SoftLayer/managers/ticket.py b/SoftLayer/managers/ticket.py index 46bc14666..e1b00f6ea 100644 --- a/SoftLayer/managers/ticket.py +++ b/SoftLayer/managers/ticket.py @@ -21,30 +21,27 @@ def __init__(self, client): self.account = self.client['Account'] self.ticket = self.client['Ticket'] - def list_tickets(self, openStatus=True, closedStatus=True, userId=None): + def list_tickets(self, open_status=True, closed_status=True): """ List all tickets - :param boolean open: include open tickets - :param boolean closed: include closed tickets - :param string title: filter based on title + :param boolean open_status: include open tickets + :param boolean closed_status: include closed tickets """ mask = ('mask[id, title, assignedUser[firstName, lastName],' 'createDate,lastEditDate,accountId]') call = 'getTickets' - if not all([openStatus, closedStatus]): - if openStatus: + if not all([open_status, closed_status]): + if open_status: call = 'getOpenTickets' - elif closedStatus: + elif closed_status: call = 'getClosedTickets' func = getattr(self.account, call) return func(mask=mask) def list_subjects(self): - """ List all tickets - - """ + """ List all tickets""" return self.client['Ticket_Subject'].getAllObjects() def get_ticket(self, ticket_id): @@ -64,7 +61,7 @@ def create_ticket(self, title=None, body=None, subject=None): :param string title: title for the new ticket :param string body: body for the new ticket - :param string hardware: id of the hardware to be assigned to the ticket + :param integer subject: id of the subject to be assigned to the ticket """ currentUser = self.account.getCurrentUser() @@ -77,12 +74,12 @@ def create_ticket(self, title=None, body=None, subject=None): created_ticket = self.ticket.createStandardTicket(new_ticket, body) return created_ticket - def update_ticket(self, t_id=None, body=None): + def update_ticket(self, ticket_id=None, body=None): """ Update a ticket - :param string id: the id of the ticket to update + :param integer ticket_id: the id of the ticket to update :param string body: entry to update in the ticket """ - ticket = self.ticket.getObject(id=t_id) - return self.ticket.edit(ticket, body, id=t_id) + ticket = self.ticket.getObject(id=ticket_id) + return self.ticket.edit(ticket, body, id=ticket_id) diff --git a/SoftLayer/tests/managers/ticket_tests.py b/SoftLayer/tests/managers/ticket_tests.py index 9a35cea3b..543786c02 100644 --- a/SoftLayer/tests/managers/ticket_tests.py +++ b/SoftLayer/tests/managers/ticket_tests.py @@ -29,16 +29,16 @@ def test_list_tickets(self): for result in results: self.assertIn(result['id'], list_expected_ids) - results = self.ticket.list_tickets(openStatus=True, closedStatus=True) + results = self.ticket.list_tickets(open_status=True, closed_status=True) service.getTickets.assert_has_calls(mcall) for result in results: self.assertIn(result['id'], list_expected_ids) - results = self.ticket.list_tickets(openStatus=True, closedStatus=False) + results = self.ticket.list_tickets(open_status=True, closed_status=False) for result in results: self.assertIn(result['id'], open_expected_ids) - results = self.ticket.list_tickets(openStatus=False, closedStatus=True) + results = self.ticket.list_tickets(open_status=False, closed_status=True) for result in results: self.assertIn(result['id'], closed_expected_ids)