# -*- coding: utf-8 -*-
"""
:Module: freshpy.tickets
:Synopsis: Functions for interacting with Freshservice tickets
:Created By: Jeff Shurtliff
:Last Modified: Jeff Shurtliff
:Modified Date: 04 Jan 2022
"""
from . import api, errors
from .utils import core_utils, log_utils
# Initialize logging
logger = log_utils.initialize_logging(__name__)
# Define constants
VALID_PREDEFINED_FILTERS = ['new_and_my_open', 'watching', 'spam', 'deleted']
SUPPORTED_FILTER_FIELDS = ['agent_id', 'group_id', 'priority', 'status', 'impact', 'urgency', 'tag', 'due_by',
'fr_due_by', 'created_at']
FILTER_LOGIC_OPERATORS = ['AND', 'OR']
[docs]def get_ticket(freshpy_object, ticket_number, include=None, verify_ssl=True):
"""This function returns the data for a specific ticket.
.. versionchanged:: 1.1.0
Added the ability to disable SSL verification on API calls.
.. versionadded:: 1.0.0
:param freshpy_object: The core :py:class:`freshpy.FreshPy` object
:type freshpy_object: class[freshpy.FreshPy]
:param ticket_number: The ticket number for which to return data
:type ticket_number: str, int
:param include: A string or iterable of `embedding <https://api.freshservice.com/#view_a_ticket>`_ options
:type include: str, tuple, list, set, None
:param verify_ssl: Determines if SSL verification should occur (``True`` by default)
:type verify_ssl: bool
:returns: JSON data for the given ticket
:raises: :py:exc:`freshpy.errors.exceptions.APIConnectionError`
"""
uri = f'tickets/{ticket_number}'
uri += _parse_constraints(_include=include)
return api.get_request_with_retries(freshpy_object, uri, verify_ssl=verify_ssl)
[docs]def get_tickets(freshpy_object, include=None, predefined_filter=None, filters=None, filter_logic='AND',
requester_id=None, requester_email=None, ticket_type=None, updated_since=None, ascending=None,
descending=None, per_page=None, page=None, verify_ssl=True):
"""This function returns a sequence of tickets with optional filters.
.. versionchanged:: 1.1.0
Added the ability to disable SSL verification on API calls.
.. versionadded:: 1.0.0
:param freshpy_object: The core :py:class:`freshpy.FreshPy` object
:type freshpy_object: class[freshpy.FreshPy]
:param include: A string or iterable of `embedding <https://api.freshservice.com/#view_a_ticket>`_ options
:type include: str, tuple, list, set, None
:param predefined_filter: One of the predefined filters ('new_and_my_open', 'watching', 'spam', 'deleted')
:type predefined_filter: str, None
:param filters: Query filter(s) in the form of a structured query string or a dictionary of values
:type filters: str, dict, None
:param filter_logic: Defines the logic to use as necessary in a filter query string (default is ``AND``)
:param requester_id: The numeric ID of a requester
:type requester_id: str, int, None
:param requester_email: The email address of a requester
:type requester_email: str, None
:param ticket_type: The type of ticket (e.g. ``Incident``, ``Service Request``, etc.)
:type ticket_type: str, None
:param updated_since: A date or timestamp (in UTC format) to be a threshold for when the ticket was last updated
:type updated_since: str, None
:param ascending: Determines if the tickets should be sorted in *ascending* order
:type ascending: bool, None
:param descending: Determines if the tickets should be sorted in *descending* order (default)
:type descending: bool, None
:param per_page: Displays a certain number of results per query
:type per_page: str, int, None
:param page: Returns a specific page number (used for paginated results)
:type page: str, int, None
:param verify_ssl: Determines if SSL verification should occur (``True`` by default)
:type verify_ssl: bool
:returns: A list of JSON objects for tickets
:raises: :py:exc:`freshpy.errors.exceptions.InvalidPredefinedFilterError`,
:py:exc:`freshpy.errors.exceptions.APIConnectionError`
"""
uri = 'tickets'
if filters:
uri += _parse_filters(filters, filter_logic)
else:
uri += _parse_constraints(_include=include, _predefined_filter=predefined_filter, _requester_id=requester_id,
_requester_email=requester_email, _ticket_type=ticket_type,
_updated_since=updated_since, _ascending=ascending, _descending=descending,
_per_page=per_page, _page=page)
return api.get_request_with_retries(freshpy_object, uri, verify_ssl=verify_ssl)
def _parse_filters(_filters=None, _logic='AND'):
_filters = {} if not _filters else _filters
if _logic.upper() not in FILTER_LOGIC_OPERATORS:
raise errors.exceptions.InvalidFilterLogicError(value=_logic)
if isinstance(_filters, str):
_filters = core_utils.url_encode(_filters)
_uri_segment = f'/filter?query="{_filters}"'
else:
_uri_segment = f'/filter?query='
_filter = ''
for _idx, (_field, _value) in enumerate(_filters.items()):
_filter += f'{_field}:{_value}'
if _idx < (len(_filters) - 1):
_filter += f' {_logic.upper()} '
_filter = core_utils.url_encode(_filter)
_uri_segment += f'"{_filter}"'
return _uri_segment
def _parse_constraints(_include=None, _predefined_filter=None, _requester_id=None, _requester_email=None,
_ticket_type=None, _updated_since=None, _ascending=None, _descending=None, _per_page=None,
_page=None):
"""This function parses any constraints into a properly constructed query string.
.. versionadded:: 1.0.0
:param _include: A string or iterable of `embedding <https://api.freshservice.com/#view_a_ticket>`_ options
:type _include: str, tuple, list, set, None
:param _predefined_filter: One of the predefined filters ('new_and_my_open', 'watching', 'spam', 'deleted')
:type _predefined_filter: str, None
:param _requester_id: The numeric ID of a requester
:type _requester_id: str, int, None
:param _requester_email: The email address of a requester
:type _requester_email: str, None
:param _ticket_type: The type of ticket (e.g. ``Incident``, ``Service Request``, etc.)
:type _ticket_type: str, None
:param _updated_since: A date or timestamp (in UTC format) to be a threshold for when the ticket was last updated
:type _updated_since: str, None
:param _ascending: Determines if the tickets should be sorted in *ascending* order
:type _ascending: bool, None
:param _descending: Determines if the tickets should be sorted in *descending* order (default)
:type _descending: bool, None
:param _per_page: Displays a certain number of results per query
:type _per_page: str, int, None
:param _page: Returns a specific page number (used for paginated results)
:type _page: str, int, None
:returns: The fully constructed query string
:raises: :py:exc:`freshpy.errors.exceptions.InvalidPredefinedFilterError`
"""
_constraints = ''
if _include:
# TODO: Perform a check to verify support for the provided include value(s)
if not isinstance(_include, str):
_include = ','.join(_include)
_constraints = core_utils.construct_query_string(_constraints, f'include={_include}')
if _predefined_filter:
if _predefined_filter not in VALID_PREDEFINED_FILTERS:
if isinstance(_predefined_filter, str):
raise errors.exceptions.InvalidPredefinedFilterError(value=_predefined_filter)
raise errors.exceptions.InvalidPredefinedFilterError()
_constraints = core_utils.construct_query_string(_constraints, f'filter={_predefined_filter}')
if _requester_id:
_constraints = core_utils.construct_query_string(_constraints, f'requester_id={_requester_id}')
if _requester_email:
_requester_email = core_utils.url_encode(_requester_email)
_constraints = core_utils.construct_query_string(_constraints, f'requester_email={_requester_email}')
if _ticket_type:
_ticket_type = _ticket_type.replace(' ', '+')
_constraints = core_utils.construct_query_string(_constraints, f'type={_ticket_type}')
if _updated_since:
_constraints = core_utils.construct_query_string(_constraints, f'updated_since={_updated_since}')
if _ascending:
_constraints = core_utils.construct_query_string(_constraints, 'order_type=asc')
if _descending:
_constraints = core_utils.construct_query_string(_constraints, 'order_type=desc')
if _per_page:
_constraints = core_utils.construct_query_string(_constraints, f'per_page={_per_page}')
if _page:
_constraints = core_utils.construct_query_string(_constraints, f'page={_page}')
return _constraints