Exemplo n.º 1
3
class ZendeskAction(Action):
    def __init__(self, config):
        super(ZendeskAction, self).__init__(config=config)
        self.email = self.config['email']
        self.token = self.config['api_token']
        self.subdomain = self.config['subdomain']

        self.credentials = {
            'email': self.email,
            'token': self.token,
            'subdomain': self.subdomain
        }

        self.api = Zenpy(**self.credentials)

    def clean_response(self, text):
        return text.replace('\n', ' ').replace('  ', ' ').strip()

    def url_for_ticket(self, ticket):
        return 'https://{}.zendesk.com/agent/tickets/{}'.format(self.subdomain, ticket)

    def api_search(self, query, search_type):
        return self.api.search(query, type=search_type, sort_by='created_at', sort_order='desc')

    def create_ticket(self, subject, description):
        ticket = Ticket(subject=subject, description=description)

        try:
            created_ticket_audit = self.api.tickets.create(ticket)
            return {
                'ticket_id': created_ticket_audit.ticket.id,
                'ticket_url': self.url_for_ticket(created_ticket_audit.ticket.id),
                'subject': self.clean_response(subject),
                'description': self.clean_response(description)
            }
        except APIException:
            return {'error': 'Could not create ticket with provided parameters'}
        except Exception as e:
            self.logger.error(e)
            return {'error': 'Could not make API request'}

    def search_tickets(self, query, search_type='ticket', limit=10):
        try:
            query_results = self.api_search(query, search_type)
            results_clean = map(lambda t: {
                'ticket_id': t.id,
                'ticket_url': self.url_for_ticket(t.id),
                'ticket_status': t.status,
                'subject': self.clean_response(t.subject),
                'description': self.clean_response(t.description)},
                list(query_results)[:limit]
            )
            return {'search_results': results_clean}
        except APIException:
            return {'error': 'Could not execute search for query: {}'.format(query)}
        except Exception as e:
            self.logger.error(e)
            return {'error': 'There was an error executing your search'}

    def update_ticket(self, ticket_id, comment_text, public):
        try:
            ticket = self.api.tickets(id=ticket_id)
            ticket.comment = Comment(body=comment_text, public=public)
            self.api.tickets.update(ticket)
            return {
                'ticket_id': ticket_id,
                'ticket_url': self.url_for_ticket(ticket_id),
                'body': self.clean_response(comment_text),
                'public': public
            }
        except RecordNotFoundException:
            return {'error': 'Could not find ticket #{}'.format(ticket_id)}
        except Exception as e:
            self.logger.error(e)
            return {'error': 'Could not update ticket'}

    def update_ticket_status(self, ticket_id, status):
        valid_statuses = ['new', 'open', 'pending', 'solved', 'closed']
        if status in valid_statuses:
            try:
                ticket = self.api.tickets(id=ticket_id)
                ticket.status = status
                self.api.tickets.update(ticket)
                return {
                    'ticket_id': ticket_id,
                    'ticket_url': self.url_for_ticket(ticket_id),
                    'status': status
                }
            except RecordNotFoundException:
                return {'error': 'Could not find ticket #{}'.format(ticket_id)}
            except Exception as e:
                self.logger.error(e)
                return {'error': 'Could not update ticket status'}
        else:
            return {'error': 'Invalid status given for ticket'}
class ZendeskConnection:
    def __init__(self):
        self._creds = {
            'email': os.environ.get('ZENDESK_USER', None),
            'token': os.environ.get('ZENDESK_TOKEN', None),
            'subdomain': "pagarme"
        }
        self._zenpy_client = Zenpy(**self._creds)
        self._sl = SlackConnection.SlackConnection()
        self._mc = MongoConnection.MongoConnection()


    def _generate_comment(self, ticket):
        ticket_comments = ""
        for comment in self._zenpy_client.tickets.comments(ticket_id=ticket.id):
            ticket_comments += " " + str(comment)

        return self._remove_special_characters(ticket_comments)


    def _remove_special_characters(self, phrase):
        phrase = phrase.lower()
        return unidecode(phrase)

    def _word_in_text(self, word, text):
        if re.search(r'\b' + word + r'\b', text):
            return True
        return False


    def _tag_ticket(self, ticket):
        try:
            TAGS = tags.TAGS
            new_tags = []
            subject = self._remove_special_characters(ticket.subject)
            ticket_comments = self._generate_comment(ticket)
            description = self._remove_special_characters(ticket.description)
            content = subject + " " + ticket_comments + " " + description + " "
            for tag in TAGS:
                for word in TAGS[tag]:
                    if (self._word_in_text(word, content)) and (tag not in new_tags):
                        new_tags.append(tag)
            ticket.tags.extend(new_tags)
            self._zenpy_client.tickets.update(ticket)
        except Exception as e:
            print(e.args)


    def _get_supporters(self):
        supporter_list = []

        for supporter in self._zenpy_client.search(type='user', group_id=21164867):
            for email in self._mc.get_active_supporters():
                if supporter.email in email['email']:
                    try:
                        supporter_list.append(supporter)
                    except Exception as e:
                        print(e.args)
        return supporter_list


    def _get_not_assigned_tickets(self):
        not_assigned_tickets = list()

        for tickets in self._zenpy_client.search(type='ticket', group_id=21164867,
                                                 assignee_id=None, status=['new', 'open', 'pending']):
            not_assigned_tickets.append(tickets)

        return not_assigned_tickets

    def _get_assignees_tickets(self, assignees, statuses):
        assigned_tickets = list()

        for ticket in self._zenpy_client.search(
            type='ticket', group_id=21164867, assignee_id=assignees,
            status=statuses
        ):
            assigned_tickets.append(ticket)

        return assigned_tickets

    def _get_pending_interaction_tickets(self, tickets, inactiveHours):
        pending = list()

        for ticket in tickets:
            comments = list(self._zenpy_client.tickets.comments(ticket.id))
            latest_comment = comments[len(comments)-1]

            now = datetime.now()
            latest_comment_date = datetime.strptime(str(latest_comment.created), "%Y-%m-%d %H:%M:%S+00:00")

            diff_in_hours = utilities.get_dates_diff_in_hours(now, latest_comment_date)

            if diff_in_hours >= inactiveHours:
                pending.append(ticket)

        return pending

    def _typing_tickets(self):
        not_assigned_tickets_with_type = list()
        fl = open("ticket_log.txt", "r+")
        read_file_string = fl.read()

        for ticket in self._get_not_assigned_tickets():
            if ticket.type in ['problem', 'incident', 'question', 'task']:
                not_assigned_tickets_with_type.append(ticket)
            else:
                if str(ticket.id) not in read_file_string:
                    self._sl.send_message(ticket)
                    fl.write("  " + str(ticket.id))

        fl.close()
        return not_assigned_tickets_with_type


    def _get_yesterday_tickets(self):
        yesterday = datetime.now() - timedelta(days=2)
        yesterday_tickets = self._zenpy_client.search(type='ticket', created_after=yesterday.date(), group_id=21164867)
        support_tickets = [];
        for ticket in yesterday_tickets:
            support_tickets.append(ticket)

        return support_tickets


    def _get_ticket_count_supporter(self):
        sups = self._get_supporters()
        ticket_count = []

        for sup in sups:
            tickets = self._zenpy_client.search(type='ticket', group_id=21164867,
                                                status=['open', 'pending'], assignee_id=sup.id)
            count = len(tickets)

            ticket_count.append({'nome': sup.name, 'count': count, 'id': sup.id})

        print('Active supporters: \n' + str(ticket_count))

        return ticket_count


    def tag_yesterday_tickets(self):
        yesterday_tickets = self._get_yesterday_tickets()
        tagged_tickets = [];
        for ticket in yesterday_tickets:
            self._tag_ticket(ticket)
            tagged_tickets.append(ticket.id)
        print('Tagged tickets: ' + ''.join( str(tagged_tickets) ) )


    def assign_tickets(self):
        sups = self._get_ticket_count_supporter()
        # Send ticket type message through slack
        tickets = self._typing_tickets()
        if sups:
            if len(tickets) > 0:
                for ticket in tickets:
                    #  Get lowest ticket count supporter
                    lowest_ticket_count_sup = None
                    for count in sups:
                        if not lowest_ticket_count_sup:
                            lowest_ticket_count_sup = count
                        elif count['count'] < lowest_ticket_count_sup['count']:
                            lowest_ticket_count_sup = count

                    sup = self._mc.get_supporter_by_zendesk_id(lowest_ticket_count_sup['id'])
                    try:
                        # Assign the ticket
                        ticket.assignee_id = sup['zendesk_id']
                        slack_id = sup['slack_id']
                        name = sup['name']
                        print(slack_id + " | " + name)
                        self._zenpy_client.tickets.update(ticket)

                        # Notify the supporter on slack
                        self._sl.notify_supporter(slack_id, name, ticket)

                        # Increase the ticket count for the agent who got it
                        for agent in sups:
                            if agent['id'] == lowest_ticket_count_sup['id']:
                                agent['count'] += 1

                    except Exception as e:
                        print(e.args)
            elif len(tickets) <= 0:
                print("No tickets to assign.")
        elif not sups:
            print("No active agents to assign tickets.")

    def notify_pending_interaction_tickets(self):
        supporters = list(self._mc.find_supporters())

        supportersIds = map(lambda supporter: supporter["zendesk_id"], supporters)
        supportersTickets = self._get_assignees_tickets(supportersIds, ["open", "pending", "hold"])

        minInactiveHours = 24
        pendingInteractionTickets = self._get_pending_interaction_tickets(supportersTickets, minInactiveHours)

        if len(pendingInteractionTickets) == 0:
            print("No pending tickets to notify")
            return

        for supporter in supporters:
            supporterTickets = [ticket for ticket in pendingInteractionTickets if str(ticket.assignee_id) == supporter["zendesk_id"]]

            self._sl.notify_pending_interaction_tickets(supporter, supporterTickets, minInactiveHours)
Exemplo n.º 3
0
def delete_all_tickets():
    zenpy_client = Zenpy(**settings.ZENDESK)

    for ticket in zenpy_client.search(status="new"):
        zenpy_client.tickets.delete(ticket)

    for ticket in zenpy_client.search(status="open"):
        zenpy_client.tickets.delete(ticket)
Exemplo n.º 4
0
    def validate_zendesk_credentials(subdomain: str, user_name: str,
                                     api_token: str):
        from zenpy import Zenpy
        from zenpy.lib.exception import APIException

        try:
            zendesk_client = Zenpy(subdomain=subdomain,
                                   email=user_name,
                                   token=api_token)
            list(zendesk_client.search(assignee='test'))
        except APIException as e:
            raise ActionFailure(e)
Exemplo n.º 5
0
 def check_zendesk_ticket(foia):
     """Check if an open zendesk ticket exists for this FOIA"""
     client = Zenpy(
         email=settings.ZENDESK_EMAIL,
         subdomain=settings.ZENDESK_SUBDOMAIN,
         token=settings.ZENDESK_TOKEN,
     )
     response = client.search(
         "{}-{}".format(foia.slug, foia.pk),
         type="ticket",
         via="api",
         subject="FOIAOnline",
         status="open",
     )
     return len(list(response)) > 0
Exemplo n.º 6
0
class ZendeskConnection:
    def __init__(self):
        self._creds = {
            'email': os.environ.get('ZENDESK_USER', None),
            'token': os.environ.get('ZENDESK_TOKEN', None),
            'subdomain': "pagarme"
        }
        self._zenpy_client = Zenpy(**self._creds)
        self._sl = SlackConnection.SlackConnection()
        self._mc = MongoConnection.MongoConnection()

    def _generate_comment(self, ticket):
        ticket_comments = ""
        for comment in self._zenpy_client.tickets.comments(
                ticket_id=ticket.id):
            ticket_comments += " " + str(comment)

        return self._remove_special_characters(ticket_comments)

    def _remove_special_characters(self, phrase):
        phrase = phrase.lower()
        return unidecode(phrase)

    def _word_in_text(self, word, text):
        if re.search(r'\b' + word + r'\b', text):
            return True
        return False

    def _tag_ticket(self, ticket):
        try:
            TAGS = tags.TAGS
            new_tags = []
            subject = self._remove_special_characters(ticket.subject)
            ticket_comments = self._generate_comment(ticket)
            description = self._remove_special_characters(ticket.description)
            content = subject + " " + ticket_comments + " " + description + " "
            for tag in TAGS:
                for word in TAGS[tag]:
                    if (self._word_in_text(word,
                                           content)) and (tag not in new_tags):
                        new_tags.append(tag)
            ticket.tags.extend(new_tags)
            self._zenpy_client.tickets.update(ticket)
        except Exception as e:
            print(e.args)

    def _get_supporters(self):
        supporter_list = []

        for supporter in self._zenpy_client.search(type='user',
                                                   group_id=21164867):
            for email in self._mc.get_active_supporters():
                if supporter.email in email['email']:
                    try:
                        supporter_list.append(supporter)
                    except Exception as e:
                        print(e.args)
        return supporter_list

    def _get_not_assigned_tickets(self):
        not_assigned_tickets = list()

        for tickets in self._zenpy_client.search(
                type='ticket',
                group_id=21164867,
                assignee_id=None,
                status=['new', 'open', 'pending']):
            not_assigned_tickets.append(tickets)

        return not_assigned_tickets

    def _get_assignees_tickets(self, assignees, statuses):
        assigned_tickets = list()

        for ticket in self._zenpy_client.search(type='ticket',
                                                group_id=21164867,
                                                assignee_id=assignees,
                                                status=statuses):
            assigned_tickets.append(ticket)

        return assigned_tickets

    def _get_pending_interaction_tickets(self, tickets, inactiveHours):
        pending = list()

        for ticket in tickets:
            comments = list(self._zenpy_client.tickets.comments(ticket.id))
            latest_comment = comments[len(comments) - 1]

            now = datetime.now()
            latest_comment_date = datetime.strptime(
                str(latest_comment.created), "%Y-%m-%d %H:%M:%S+00:00")

            diff_in_hours = utilities.get_dates_diff_in_hours(
                now, latest_comment_date)

            if diff_in_hours >= inactiveHours:
                pending.append(ticket)

        return pending

    def _typing_tickets(self):
        not_assigned_tickets_with_type = list()
        fl = open("ticket_log.txt", "r+")
        read_file_string = fl.read()

        for ticket in self._get_not_assigned_tickets():
            if ticket.type in ['problem', 'incident', 'question', 'task']:
                not_assigned_tickets_with_type.append(ticket)
            else:
                if str(ticket.id) not in read_file_string:
                    self._sl.send_message(ticket)
                    fl.write("  " + str(ticket.id))

        fl.close()
        return not_assigned_tickets_with_type

    def _get_yesterday_tickets(self):
        yesterday = datetime.now() - timedelta(days=2)
        yesterday_tickets = self._zenpy_client.search(
            type='ticket', created_after=yesterday.date(), group_id=21164867)
        support_tickets = []
        for ticket in yesterday_tickets:
            support_tickets.append(ticket)

        return support_tickets

    def _get_ticket_count_supporter(self):
        sups = self._get_supporters()
        ticket_count = []

        for sup in sups:
            tickets = self._zenpy_client.search(type='ticket',
                                                group_id=21164867,
                                                status=['open', 'pending'],
                                                assignee_id=sup.id)
            count = len(tickets)

            ticket_count.append({
                'nome': sup.name,
                'count': count,
                'id': sup.id
            })

        print('Active supporters: \n' + str(ticket_count))

        return ticket_count

    def tag_yesterday_tickets(self):
        yesterday_tickets = self._get_yesterday_tickets()
        tagged_tickets = []
        for ticket in yesterday_tickets:
            self._tag_ticket(ticket)
            tagged_tickets.append(ticket.id)
        print('Tagged tickets: ' + ''.join(str(tagged_tickets)))

    def assign_tickets(self):
        sups = self._get_ticket_count_supporter()
        # Send ticket type message through slack
        tickets = self._typing_tickets()
        if sups:
            if len(tickets) > 0:
                for ticket in tickets:
                    #  Get lowest ticket count supporter
                    lowest_ticket_count_sup = None
                    for count in sups:
                        if not lowest_ticket_count_sup:
                            lowest_ticket_count_sup = count
                        elif count['count'] < lowest_ticket_count_sup['count']:
                            lowest_ticket_count_sup = count

                    sup = self._mc.get_supporter_by_zendesk_id(
                        lowest_ticket_count_sup['id'])
                    try:
                        # Assign the ticket
                        ticket.assignee_id = sup['zendesk_id']
                        slack_id = sup['slack_id']
                        name = sup['name']
                        print(slack_id + " | " + name)
                        self._zenpy_client.tickets.update(ticket)

                        # Notify the supporter on slack
                        self._sl.notify_supporter(slack_id, name, ticket)

                        # Increase the ticket count for the agent who got it
                        for agent in sups:
                            if agent['id'] == lowest_ticket_count_sup['id']:
                                agent['count'] += 1

                    except Exception as e:
                        print(e.args)
            elif len(tickets) <= 0:
                print("No tickets to assign.")
        elif not sups:
            print("No active agents to assign tickets.")

    def notify_pending_interaction_tickets(self):
        supporters = list(self._mc.find_supporters())

        supportersIds = map(lambda supporter: supporter["zendesk_id"],
                            supporters)
        supportersTickets = self._get_assignees_tickets(
            supportersIds, ["open", "pending", "hold"])

        minInactiveHours = 24
        pendingInteractionTickets = self._get_pending_interaction_tickets(
            supportersTickets, minInactiveHours)

        if len(pendingInteractionTickets) == 0:
            print("No pending tickets to notify")
            return

        for supporter in supporters:
            supporterTickets = [
                ticket for ticket in pendingInteractionTickets
                if str(ticket.assignee_id) == supporter["zendesk_id"]
            ]

            self._sl.notify_pending_interaction_tickets(
                supporter, supporterTickets, minInactiveHours)
Exemplo n.º 7
0
class ZendeskConnection:
    def __init__(self):
        self._creds = {
            'email': os.environ.get('ZENDESK_USER', None),
            'token': os.environ.get('ZENDESK_TOKEN', None),
            'subdomain': "pagarme"
        }
        self._zenpy_client = Zenpy(**self._creds)
        self._sl = SlackConnection.SlackConnection()
        self._mc = MongoConnection.MongoConnection()

    def _generate_comment(self, ticket):
        ticket_comments = ""
        for comment in self._zenpy_client.tickets.comments(
                ticket_id=ticket.id):
            ticket_comments += " " + str(comment)

        return self._remove_special_characters(ticket_comments)

    def _remove_special_characters(self, phrase):
        phrase = phrase.lower()
        return unidecode(phrase)

    def _tag_ticket(self, ticket):
        try:
            TAGS = tags.TAGS
            new_tags = []
            subject = self._remove_special_characters(ticket.subject)
            ticket_comments = self._generate_comment(ticket)
            description = self._remove_special_characters(ticket.description)
            for tag in TAGS:
                for word in TAGS[tag]:
                    if (((word in subject) or (word in description) or
                         (word in ticket_comments)) and (tag not in new_tags)):
                        new_tags.append(tag)
            ticket.tags.extend(new_tags)
            self._zenpy_client.tickets.update(ticket)
        except Exception as e:
            print(e.args)

    def _get_supporters(self):
        supporter_list = []

        for supporter in self._zenpy_client.search(type='user',
                                                   group_id=21164867):
            for email in self._mc.get_active_supporters():
                if supporter.email in email['email']:
                    try:
                        supporter_list.append(supporter)
                    except Exception as e:
                        print(e.args)
        return supporter_list

    def _get_not_assigned_tickets(self):
        not_assigned_tickets = list()

        for tickets in self._zenpy_client.search(
                type='ticket',
                group_id=21164867,
                assignee_id=None,
                status=['new', 'open', 'pending']):
            not_assigned_tickets.append(tickets)

        return not_assigned_tickets

    def _typing_tickets(self):
        not_assigned_tickets_with_type = list()
        fl = open("ticket_log.txt", "r+")
        read_file_string = fl.read()

        for ticket in self._get_not_assigned_tickets():
            if ticket.type in ['problem', 'incident', 'question', 'task']:
                not_assigned_tickets_with_type.append(ticket)
            else:
                if str(ticket.id) not in read_file_string:
                    self._sl.send_message(ticket)
                    fl.write("  " + str(ticket.id))

        fl.close()
        return not_assigned_tickets_with_type

    def _get_yesterday_tickets(self):
        yesterday = datetime.now() - timedelta(days=2)
        yesterday_tickets = self._zenpy_client.search(
            type='ticket', created_after=yesterday.date(), group_id=21164867)
        support_tickets = []
        for ticket in yesterday_tickets:
            support_tickets.append(ticket)

        return support_tickets

    def _get_ticket_count_supporter(self):
        sups = self._get_supporters()
        ticket_count = []

        for sup in sups:
            tickets = self._zenpy_client.search(type='ticket',
                                                group_id=21164867,
                                                status=['open', 'pending'],
                                                assignee_id=sup.id)
            count = len(tickets)

            ticket_count.append({
                'nome': sup.name,
                'count': count,
                'id': sup.id
            })

        print('Active supporters: \n' + str(ticket_count))

        return ticket_count

    def tag_yesterday_tickets(self):
        yesterday_tickets = self._get_yesterday_tickets()
        tagged_tickets = []
        for ticket in yesterday_tickets:
            self._tag_ticket(ticket)
            tagged_tickets.append(ticket.id)
        print('Tagged tickets: ' + ''.join(str(tagged_tickets)))

    def assign_tickets(self):
        sups = self._get_ticket_count_supporter()
        # Send ticket type message through slack
        tickets = self._typing_tickets()
        if sups:
            if len(tickets) > 0:
                for ticket in tickets:
                    #  Get lowest ticket count supporter
                    lowest_ticket_count_sup = None
                    for count in sups:
                        if not lowest_ticket_count_sup:
                            lowest_ticket_count_sup = count
                        elif count['count'] < lowest_ticket_count_sup['count']:
                            lowest_ticket_count_sup = count

                    sup = self._mc.get_supporters_by_zendesk_id(
                        lowest_ticket_count_sup['id'])
                    try:
                        # Assign the ticket
                        ticket.assignee_id = sup['zendesk_id']
                        slack_id = sup['slack_id']
                        name = sup['name']
                        print(slack_id + " | " + name)
                        self._zenpy_client.tickets.update(ticket)

                        # Notify the supporter on slack
                        self._sl.notify_supporter(slack_id, name, ticket)

                        # Increase the ticket count for the agent who got it
                        for agent in sups:
                            if agent['id'] == lowest_ticket_count_sup['id']:
                                agent['count'] += 1

                    except Exception as e:
                        print(e.args)
            elif len(tickets) <= 0:
                print("No tickets to assign.")
        elif not sups:
            print("No active agents to assign tickets.")
Exemplo n.º 8
0
from zenpy import Zenpy
import datetime


creds = {
    'email' : '*****@*****.**',
    'token' : 'zgXYhMmdxGTT0gMPVOaFfRf5xUNue4UPNsE4MaGs',
    'subdomain': 'https://envusa.zendesk.com'}

zenpy_client = Zenpy(**creds)

yesterday = datetime.datetime.now() - datetime.timedelta(days=1)
today = datetime.datetime.now()
for ticket in zenpy_client.search("zenpy", created_between=[yesterday, today], type='ticket', minus='negated'):
    print(ticket)
Exemplo n.º 9
0
args = parser.parse_args()

try:
    with open('./creds.json', 'r') as f:
        creds = json.load(f)
except FileNotFoundError:
    raise FileNotFoundError("No creds.json found in current directory. Please make sure one exists before running this"
                            " script.")

ticketNums, rmDirs = [], []
count = 0
caseDir = args.directory
zenpy_client = Zenpy(**creds)

print("Getting list of open Zendesk tickets...")
for ticket in zenpy_client.search("type:ticket status:open status:new status:hold status:pending assignee:"
                                  + creds.get("email")):
    ticketNums.append(str(ticket.id))

# next(os.walk())[1] gets a list of all top-level directories in the path specified, and will avoid any literal files
# and/or subdirectories
for directory in next(os.walk(caseDir))[1]:
    if directory not in ticketNums:
        rmDirs.append(directory)

rmDirs.sort()

if not args.force:
    for item in rmDirs:
        valid = False

        while not valid:
Exemplo n.º 10
0
email = input('Email (default "{0}"): '.format(default_email)) or default_email
token = input('Token: ')
subdomain = input('Subdomain (default "{0}"): '.format(
    default_subdomain)) or default_subdomain

# Zendesk client
client = Zenpy(**{
    'email': email,
    'token': token,
    'subdomain': subdomain,
})

# Query for tickets
start_date = datetime(year=2017, month=12, day=3, tzinfo=timezone.utc)
end_date = datetime(year=2017, month=12, day=5, tzinfo=timezone.utc)
tickets = client.search(type='ticket', created_between=(start_date, end_date))

# Write tickets as tsv
with open('result.tsv', 'w') as outfile:
    writer = csv.writer(outfile, delimiter='\t')  # tab delimiter

    # Write headers
    writer.writerow([
        'Ticket ID',
        'Date',
        'Username',
        'Email',
        'Brand',
        'Tags',
        'Style',
        'Product',
Exemplo n.º 11
0
def main():
    # Fetch tickets from ZD (as a list of dictionaries)
    # load from disk if possible; if not call Zendesk API and save to disk
    logger.info("Fetching ZD tickets")
    zd_tickets = []
    zenpy_client = Zenpy(**zd_creds)
    begin_datetime = datetime.datetime(2019, 1, 1, 0, 0, 0, 0)
    end_datetime = datetime.datetime(2019, 1, 31, 0, 0, 0, 0)
    zd_tickets_filepath = "zd_tickets.json"
    if os.path.exists(zd_tickets_filepath):
        with open(zd_tickets_filepath) as f:
            zd_tickets = json.load(f)
    else:
        for ticket in zenpy_client.search(
                "Open Access enquiry has been received",
                created_between=[begin_datetime, end_datetime],
                type='ticket'):
            zd_tickets.append(ticket.to_dict())
        with open(zd_tickets_filepath, "w") as f:
            json.dump(zd_tickets, f)

    # Keep only tickets with zd_field_DspaceID not null
    # extract useful info from those tickets
    logger.info("Keeping only tickets with zd_field_DspaceID not null")
    _ = []
    for t in zd_tickets:
        include_ticket = False
        for c in t['custom_fields']:
            if (c['id'] == ZdFields.internal_item_id_apollo) and c['value']:
                t[DSPACE_ID_TAG] = c['value']
                include_ticket = True
                for k, v in FIELDS_OF_INTEREST.items():
                    if c['id'] == k:
                        t[v] = c['value']
        if include_ticket:
            t['original_files'] = parse_zd_ticket_description(t['description'])
            _.append(t)
    zd_tickets = _

    # Obtain the data and files we need from Apollo
    # Load from disk if possible; otherwise use API
    test_cases_filepath = "test_cases.json"
    if os.path.exists(test_cases_filepath):
        logger.info(
            "Loading test cases from disk (delete {} "
            "to collect from server instead)".format(test_cases_filepath))
        with open(test_cases_filepath) as f:
            test_cases = json.load(f)
    else:
        # Create a DSpace API client instance and login
        logger.info("Logging in to DSpace API")
        client = Dspace5Client()
        client.login()

        # Keep only tickets that:
        # 1-) have been archived in DSpace staging;
        # (i.e. we know what file version was made available/approved)
        logger.info("Collecting test cases")
        test_cases = []
        for t in zd_tickets:
            item = client.get_item(t[DSPACE_ID_TAG])
            if item['archived'] == 'true':
                bitstreams = client.get_item_bitstreams(t[DSPACE_ID_TAG])
                tc = TestCase()
                tc.zd_ticket = t
                tc.dspace_id = t[DSPACE_ID_TAG]
                tc.dspace_item = item
                tc.dspace_bitstreams = bitstreams
                test_cases.append(tc)
                # TODO: ged rid of this break when ready to test many cases
                if len(test_cases) > 10:
                    break
        with open(test_cases_filepath, "w") as f:
            json.dump(test_cases, f)

    # Changing wd to download folder
    os.chdir(downloads_folder)

    logger.info("Working on test cases")
    with open(OUTPUT_CSV, "w") as f:
        header = ["bitstream", "Apollo version", "outcome", "version/details"]
        csv_writer = csv.DictWriter(f,
                                    fieldnames=header,
                                    extrasaction='ignore')
        csv_writer.writeheader()
        for tc in test_cases[:19]:
            for bs in tc.dspace_bitstreams:
                if (bs['bundleName']
                        == 'ORIGINAL') and (bs['description'].lower()
                                            not in ['supporting information']):
                    if bs['name'] not in os.listdir(downloads_folder):
                        client.download_bitstream(bs['id'], downloads_folder)
                    vd = VersionDetector(
                        os.path.join(downloads_folder, bs['name']),
                        dec_ms_title=tc.dspace_item['name'],
                        dec_version=bs['description'],
                        dec_authors=extract_list_of_authors_from_ds_metadata(
                            client.get_item_metadata(tc.dspace_id)),
                        # **{'doi': 'foo'}
                    )

                    # if vd.check_extension() == 'docx':  # restrict tests to docx for now
                    result = vd.detect()
                    logger.info(result)
                    row = {
                        "bitstream": bs['name'],
                        "Apollo version": bs['description'],
                        "outcome": result[0],
                        "version/details": result[1]
                    }
                    csv_writer.writerow(row)
Exemplo n.º 12
0
class ZengoService(object):
    """Encapsulate behaviour allowing easy customisation."""

    def __init__(self, *args, **kwargs):
        creds = {
            "email": settings.ZENDESK_EMAIL,
            "token": settings.ZENDESK_TOKEN,
            "subdomain": settings.ZENDESK_SUBDOMAIN,
        }
        self.client = Zenpy(**creds)

    # extraction of data from local users for injection into Zendesk

    def get_local_user_name(self, local_user):
        return local_user.first_name

    def get_local_user_external_id(self, local_user):
        return local_user.id

    def get_local_user_profile_image(self, local_user):
        return None

    def get_local_user_for_external_id(self, external_id):
        return get_user_model().objects.filter(id=external_id).first()

    def get_remote_zd_user_for_local_user(self, local_user):
        """
        Attempt to resolve the provided user to an extant Zendesk User.

        Returns a Zendesk API User instance, and a boolean that indicates how
        definite the resolution is, based on how they've been found.
        """
        result = self.client.search(
            type="user", external_id=self.get_local_user_external_id(local_user)
        )
        if result.count:
            # strong match by external_id
            return result.next(), True

        # else check by associated emails, if allauth is installed and being used
        if "allauth.account" in settings.INSTALLED_APPS:
            emails = local_user.emailaddress_set.all()
            for e in emails:
                result = self.client.search(type="user", email=e.email)
                if result.count:
                    # match strength based on email verification state
                    return result.next(), e.verified

        # check for a weak match match using the email field on user instance
        if local_user.email:
            result = self.client.search(type="user", email=local_user.email)
            if result.count:
                return result.next(), False

        # no match at all, buh-bow
        return None, False

    def create_remote_zd_user_for_local_user(self, local_user):
        """Create a remote zendesk user based on the given local user's details."""
        try:
            remote_zd_user = self.client.users.create(
                RemoteZendeskUser(
                    name=self.get_local_user_name(local_user),
                    external_id=self.get_local_user_external_id(local_user),
                    email=local_user.email,
                    remote_photo_url=self.get_local_user_profile_image(local_user),
                )
            )
        except APIException as a:
            # if this is a duplicate error try one last time to get the user
            print(a.response.json())
            details = a.response.json()["details"]
            if any([d[0]["error"] == "DuplicateValue" for d in details.values()]):
                (
                    remote_zd_user,
                    is_definite_match,
                ) = self.get_remote_zd_user_for_local_user(local_user)
            else:
                raise
        return remote_zd_user

    def get_or_create_remote_zd_user_for_local_user(self, local_user):
        user, is_definite_match = self.get_remote_zd_user_for_local_user(local_user)
        if user:
            return user, is_definite_match
        # we create a remote user in Zendesk for this local user
        return self.create_remote_zd_user_for_local_user(local_user), True

    def get_special_zendesk_user(self):
        """
        Return a ZendeskUser instance representing the special Zendesk user that
        automations can add use to add comments.
        """
        instance, created = models.ZendeskUser.objects.get_or_create(
            zendesk_id=-1,
            defaults=dict(
                name="Zendesk",
                active=True,
                role=models.ZendeskUser.roles.admin,
                created_at=timezone.now(),
            ),
        )
        return instance

    def update_remote_zd_user_for_local_user(self, local_user, remote_zd_user):
        """
        Compare the User and ZendeskUser instances and determine whether we
        need to update the data in Zendesk.

        This method is suitable to be called when a local user changes their
        email address or other user data.
        """
        changed = False
        email_changed = False

        if self.get_local_user_name(local_user) != remote_zd_user.name:
            remote_zd_user.name = self.get_local_user_name(local_user)
            changed = True

        if self.get_local_user_external_id(local_user) != remote_zd_user.external_id:
            remote_zd_user.external_id = self.get_local_user_external_id(local_user)
            changed = True

        if local_user.email and local_user.email != remote_zd_user.email:
            remote_zd_user.email = local_user.email
            changed = True
            email_changed = True

        if changed:
            remote_zd_user = self.client.users.update(remote_zd_user)

        if email_changed:
            # then in addition to the above, we have to mark the newly
            # created identity as verified and promote it to be primary
            results = self.client.users.identities(id=remote_zd_user.id)
            for identity in results:
                if identity.value == local_user.email:
                    self.client.users.identities.make_primary(
                        user=remote_zd_user, identity=identity
                    )
                    break

    def update_or_create_remote_zd_user(self, local_user):
        remote_zd_user, is_definite_match = self.get_remote_zd_user_for_local_user(
            local_user
        )
        if remote_zd_user and is_definite_match:
            # check if we need to do any updates
            self.update_remote_zd_user_for_local_user(local_user, remote_zd_user)
        else:
            remote_zd_user = self.create_remote_zd_user_for_local_user(local_user)
        return remote_zd_user

    def sync_user(self, remote_zd_user):
        """
        Given a RemoteZendeskUser instance, persist it as a local ZendeskUser instance.
        """
        instance, created = models.ZendeskUser.objects.update_or_create(
            zendesk_id=remote_zd_user.id,
            defaults=dict(
                # attempt to resolve the local user if possible
                user=self.get_local_user_for_external_id(remote_zd_user.external_id),
                alias=remote_zd_user.alias,
                email=remote_zd_user.email,
                created_at=remote_zd_user.created_at,
                name=remote_zd_user.name,
                active=remote_zd_user.active,
                role=remote_zd_user.role,
                # store their latest photo JSON data
                photos_json=json.dumps(remote_zd_user.photo),
            ),
        )
        return instance

    def sync_ticket_id(self, ticket_id):
        return self.sync_ticket(self.client.tickets(id=ticket_id))

    def sync_ticket(self, remote_zd_ticket):
        """
        Create or update local representations of a Zendesk ticket, its comments
        and all associated Zendesk users.

        This uses `update_or_create` to avoid integrity errors, demanding that
        comments and users be sync'd in a consistent order to avoid deadlock.

        Todo: only pull comments beyond those we've already got in the database
        """

        kwargs = dict(include_inline_images=True)

        remote_comments = [
            c for c in self.client.tickets.comments(remote_zd_ticket.id, **kwargs)
        ]

        remote_comments.sort(key=lambda c: (c.created_at, c.id))

        # establish a distinct, ordered list of Zendesk users
        users = set(
            [remote_zd_ticket.requester]
            + [c.author for c in remote_comments if c.author_id != -1]  # noqa
        )
        users = list(users)
        users.sort(key=lambda u: u.id)

        # sync the users and establish a mapping to local records
        user_map = {u: self.sync_user(u) for u in users}

        defaults = dict(
            requester=user_map[remote_zd_ticket.requester],
            subject=remote_zd_ticket.subject,
            url=remote_zd_ticket.url,
            status=models.Ticket.states.by_id.get(remote_zd_ticket.status.lower()),
            custom_fields=json.dumps(remote_zd_ticket.custom_fields),
            tags=json.dumps(remote_zd_ticket.tags),
            created_at=remote_zd_ticket.created_at,
            updated_at=remote_zd_ticket.updated_at,
        )

        # In some API responses we don't get a priority, but it could be an existing ticket with
        # priority already initialised so we don't want to overwrite the priority to the Ticket
        # object.
        if remote_zd_ticket.priority is not None:
            defaults["priority"] = models.Ticket.priorities.by_id.get(
                remote_zd_ticket.priority.lower()
            )

        # update or create the ticket
        local_ticket, created = models.Ticket.objects.update_or_create(
            zendesk_id=remote_zd_ticket.id,
            defaults=defaults,
        )
        # and now update or create the comments - baring in mind some might be type `VoiceComment`
        # https://developer.zendesk.com/rest_api/docs/support/ticket_audits#voice-comment-event
        for remote_comment in remote_comments:
            # if we know Zendesk created this comment as part of an automation or
            # merge, link it to the Zendesk user (skipping any zenpy/network hits)
            if remote_comment.author_id == -1:
                author = self.get_special_zendesk_user()
            else:
                author = user_map[remote_comment.author]

            local_comment, _created = models.Comment.objects.update_or_create(
                zendesk_id=remote_comment.id,
                ticket=local_ticket,
                defaults=dict(
                    author=author,
                    body=remote_comment.body,
                    html_body=remote_comment.html_body,
                    # VoiceComments have no `plain_body` content
                    plain_body=getattr(remote_comment, "plain_body", None),
                    public=remote_comment.public,
                    created_at=remote_comment.created_at,
                ),
            )
            for attachment in remote_comment.attachments:
                local_attachment, _created = models.Attachment.objects.update_or_create(
                    zendesk_id=attachment.id,
                    comment=local_comment,
                    defaults=dict(
                        file_name=attachment.file_name,
                        content_url=attachment.content_url,
                        content_type=attachment.content_type,
                        size=attachment.size,
                        width=attachment.width,
                        height=attachment.height,
                        inline=attachment.inline,
                    ),
                )
                for photo in attachment.thumbnails:
                    local_photo, _created = models.Photo.objects.update_or_create(
                        zendesk_id=photo.id,
                        attachment=local_attachment,
                        defaults=dict(
                            file_name=photo.file_name,
                            content_url=photo.content_url,
                            content_type=photo.content_type,
                            size=photo.size,
                            width=photo.width,
                            height=photo.height,
                        ),
                    )

        return local_ticket, created
Exemplo n.º 13
0
# RGB LED pin mapping.
red = {{8}}
green = {{10}}
blue = {{12}}

# Set RGB LED pins as output
GPIO.setup(red, GPIO.OUT)
GPIO.setup(green, GPIO.OUT)
GPIO.setup(blue, GPIO.OUT)

turnoff()  #init rgb as off for start

last_hour = datetime.datetime.now() - datetime.timedelta(hours=1)
current_hour = datetime.datetime.now()
for ticket in zenpy_client.search("zenpy",
                                  created_between=[last_hour, current_hour],
                                  type='ticket',
                                  minus='negated'):
    tp = ticket.priority

    if tp == 'Low':
        low()  # turn rgb blue
        time.sleep(2000)  # wait for 2 seconds
        turnoff()  # turn off the RGB
    if tp == 'Normal':
        normal()  # turn rgb green
        time.sleep(2000)  # wait for 2 seconds
        turnoff()  # turn off the RGB
    if tp == 'High':
        high()  # turn rgb yellow
        time.sleep(2000)  # wait for 2 seconds
        turnoff()  # turn off the RGB
Exemplo n.º 14
0
def main():
    parser = argparse.ArgumentParser(
        description="""Zendesk APIはsubdomain/email/token の3つを認証情報として要求します。
		環境変数ZENDESK_SUBDOMAIN, ZENDESK_EMAIL, ZENDESK_TOKENで定義するか、
		コマンドライン引数で直接指定してください。
		両方で指定した場合はコマンドライン引数を優先します。
		""")

    parser.add_argument('--keyword',
                        type=str,
                        dest='keyword',
                        required=True,
                        help='keyword will serach from subject')
    parser.add_argument('--subdomain',
                        type=str,
                        dest='subdomain',
                        help='zendesk subdomain')
    parser.add_argument('--email',
                        type=str,
                        dest='email',
                        help='zendesk email')
    parser.add_argument('--token',
                        type=str,
                        dest='token',
                        help='zendesk token')
    parser.add_argument('--output',
                        type=str,
                        dest='output',
                        default='output.csv',
                        help='output file. default=output.csv')

    args = parser.parse_args()

    credential = {
        'subdomain': os.environ.get('ZENDESK_SUBDOMAIN', ''),
        'email': os.environ.get('ZENDESK_EMAIL', ''),
        'token': os.environ.get('ZENDESK_TOKEN', '')
    }

    if getattr(args, 'subdomain', False):
        credential['subdomain'] = args.subdomain
    if getattr(args, 'email', False):
        credential['email'] = args.email
    if getattr(args, 'token', False):
        credential['token'] = args.token

    zendesk_client = Zenpy(**credential)

    resp = list(zendesk_client.search(args.keyword))

    rows = []
    rows.append([
        'type', 'id', 'created_at', 'subject', 'organization_id',
        'organization_name', 'requester_id', 'requester_name', 'assignee_id',
        'assignee_name', 'status', 'url'
    ])
    for r in tqdm(resp):
        try:
            rows.append([
                r.type, r.id, r.created_at, r.subject, r.organization_id,
                r.organization.name if r.organization is not None else '',
                r.requester.id,
                r.requester.name if r.requester is not None else '',
                r.assignee_id,
                r.assignee.name if r.assignee is not None else '', r.status,
                r.url
            ])
        except Exception as e:
            logger.warning(f'skip ticketId={r.id}, url={r.url}')
            logger.warning(f'exception: {e}')
            continue

    with open(args.output, 'w') as fp:
        wr = csv.writer(fp)
        wr.writerows(rows)
Exemplo n.º 15
0
from zenpy import Zenpy
from zenpy.lib.api_objects import Ticket
from win10toast import ToastNotifier
import time

creds = {
    'email' : username,
    'password' : password,
    'subdomain' : the first part of the url
}

toaster = ToastNotifier()

newTicket = []

while 1 != 2:
    zenpyClient = Zenpy(**creds)
    for ticket in zenpyClient.search(type='ticket', status='new'):
        if str(ticket) in newTicket:
            continue
        else:
            newTicket.append(str(ticket))
            text = str(ticket.subject)
            toaster.show_toast("New Ticket", text, duration = 10)
    time.sleep(30)
Exemplo n.º 16
0
class ZendeskAction(Action):
    def __init__(self, config):
        super(ZendeskAction, self).__init__(config=config)
        self.email = self.config['email']
        self.token = self.config['api_token']
        self.subdomain = self.config['subdomain']

        self.credentials = {
            'email': self.email,
            'token': self.token,
            'subdomain': self.subdomain
        }

        self.api = Zenpy(**self.credentials)

    def clean_response(self, text):
        return text.replace('\n', ' ').replace('  ', ' ').strip()

    def url_for_ticket(self, ticket):
        return 'https://{}.zendesk.com/agent/tickets/{}'.format(
            self.subdomain, ticket)

    def api_search(self, query, search_type):
        return self.api.search(query,
                               type=search_type,
                               sort_by='created_at',
                               sort_order='desc')

    def create_ticket(self, subject, description):
        ticket = Ticket(subject=subject, description=description)

        try:
            created_ticket_audit = self.api.tickets.create(ticket)
            return {
                'ticket_id': created_ticket_audit.ticket.id,
                'ticket_url':
                self.url_for_ticket(created_ticket_audit.ticket.id),
                'subject': self.clean_response(subject),
                'description': self.clean_response(description)
            }
        except APIException:
            return {
                'error': 'Could not create ticket with provided parameters'
            }
        except Exception as e:
            self.logger.error(e)
            return {'error': 'Could not make API request'}

    def search_tickets(self, query, search_type='ticket', limit=10):
        try:
            query_results = self.api_search(query, search_type)
            results_clean = map(
                lambda t: {
                    'ticket_id': t.id,
                    'ticket_url': self.url_for_ticket(t.id),
                    'ticket_status': t.status,
                    'subject': self.clean_response(t.subject),
                    'description': self.clean_response(t.description)
                },
                list(query_results)[:limit])
            return {'search_results': results_clean}
        except APIException:
            return {
                'error': 'Could not execute search for query: {}'.format(query)
            }
        except Exception as e:
            self.logger.error(e)
            return {'error': 'There was an error executing your search'}

    def update_ticket(self, ticket_id, comment_text, public):
        try:
            ticket = self.api.tickets(id=ticket_id)
            ticket.comment = Comment(body=comment_text, public=public)
            self.api.tickets.update(ticket)
            return {
                'ticket_id': ticket_id,
                'ticket_url': self.url_for_ticket(ticket_id),
                'body': self.clean_response(comment_text),
                'public': public
            }
        except RecordNotFoundException:
            return {'error': 'Could not find ticket #{}'.format(ticket_id)}
        except Exception as e:
            self.logger.error(e)
            return {'error': 'Could not update ticket'}

    def update_ticket_status(self, ticket_id, status):
        valid_statuses = ['new', 'open', 'pending', 'solved', 'closed']
        if status in valid_statuses:
            try:
                ticket = self.api.tickets(id=ticket_id)
                ticket.status = status
                self.api.tickets.update(ticket)
                return {
                    'ticket_id': ticket_id,
                    'ticket_url': self.url_for_ticket(ticket_id),
                    'status': status
                }
            except RecordNotFoundException:
                return {'error': 'Could not find ticket #{}'.format(ticket_id)}
            except Exception as e:
                self.logger.error(e)
                return {'error': 'Could not update ticket status'}
        else:
            return {'error': 'Invalid status given for ticket'}
Exemplo n.º 17
0
class DataQuery(object):
    filter_to_zenpy = {
        'new': ['status', 'new'],
        'open': ['status', 'open'],
        'pending': ['status', 'pending'],
        'closed': ['status', 'closed'],
        'solved': ['status', 'solved'],
        'hold': ['status', 'hold'],
        #'on-hold': ['status', 'hold'],
        #'low': ['priority', 'low'],
        'low priority': ['priority', 'low'],
        #'medium': ['priority', 'medium'],
        'medium priority': ['priority', 'medium'],
        #'priority': ['priority', 'high'], # TODO is this wise? ... NO!
        #'high': ['priority', 'high'],
        'high priority': ['priority', 'high'],
        'urgent': ['priority', 'urgent'],
        'critical': ['priority', 'urgent'],
    }

    filter_to_postprocess = {
        #one-touch
        'oldest': ['age', 'max'],
        'newest': ['age', 'min'],
        'youngest': ['age', 'min'],
        'most recent': ['age', 'min']
        #Newest	Youngest, Most recent
    }

    event_to_zenpy = {
        'deleted': 'deleted_between',
        'reopened': 'reopened_between',
        'created': 'created_between',
        'added': 'created_between',
        'opened': 'created_between',
        'solved': 'solved_between',
        'closed': 'closed_between',
        'updated': 'updated_between',
        'due': 'due_date_between',
    }

    from_to_zenpy = {
        'tickets': ['type', 'ticket'],
        'issues': ['type', 'ticket'],
        'agents': ['type', 'agent'],
        'organizations': ['type', 'organization'],
        'users': ['type', 'user'],
        'incidents': ['ticket_type', 'incident'],
        'problems': ['ticket_type', 'problem'],
        'tasks': ['ticket_type', 'task'],
        'questions': ['ticket_type', 'question']
    }

    entity_to_zenpy = {
    }

    def __init__(self, parameters):
        self.zenpy_client = False
        self.filters = []
        self.query_from = False
        self.event = False
        self.period = False
        self.entity = False

        # Go through both filter and betafilter and add each word from them
        for param in ['filter', 'betafilter']:
            for allowed_filter in self.filter_to_zenpy:
                if param in parameters:
                    if (not parameters[param] is None) and (allowed_filter in parameters[param]) and (allowed_filter not in self.filters):
                        self.filters.append(allowed_filter)

        if 'event' in parameters:
            self.event = parameters['event']

        if 'from' in parameters:
            self.query_from = parameters['from']
        elif 'query_from' in parameters:
            self.query_from = parameters['query_from']

        if 'period' in parameters:
            self.period = parameters['period']

            if self.event == False or self.event is None:
                self.event = 'created'

        if 'entity' in parameters:
            self.entity = parameters['entity']

        # TODO This converts input params to lowercase, unsure if it's a good idea to be so defensive...
        for d in self.__dict__:
            if isinstance(self.__dict__[d], basestring):
                self.__dict__[d] = self.__dict__[d].lower()

    def validate(self):
        ret = []
        has_filter_type = {}

        for param in self.filters:
            if not param in self.filter_to_zenpy and not param in self.filter_to_postprocess:
                ret.append({'parameter': 'filter', 'value': param, 'reason': 'unknown'})

            # Check if filter with same type alrady exists => contradiction!
            if param in self.filter_to_zenpy:
                filter_type = self.filter_to_zenpy[param][0]
                if filter_type in has_filter_type:
                    ret.append({'parameter': 'filter', 'value': param, 'reason': 'contradiction', 'contradiction_value': has_filter_type[filter_type]})
                else:
                    has_filter_type[ filter_type ] = param

        if self.event and not self.event in self.event_to_zenpy:
            ret.append({'parameter': 'event', 'value': self.event, 'reason': 'unknown'})

        if self.query_from and not self.query_from in self.from_to_zenpy:
            ret.append({'parameter': 'from', 'value': self.event, 'reason': 'unknown'})

        if self.period != False and self.period != None and parse_period(self.period) is None:
            ret.append({'parameter': 'period', 'value': self.period, 'reason': 'unknown'})

        if self.entity and not self.entity in self.entity_to_zenpy:
            ret.append({'parameter': 'entity', 'value': self.entity, 'reason': 'unknown'})

        if len(self.filters) == 0 and self.event == False and self.entity == False:
            ret.append({'parameter': 'filter', 'value': None, 'reason': 'empty'})

        # Make request invalid if no status filter given without an event. Due to performance reasons
        if self.event == False and (not 'status' in has_filter_type):
            ret.append({'parameter': 'filter', 'value': None, 'reason': 'performance'})
        # Make request invalid if filter on closed/solved without an event. Due to performance reasons
        elif self.event == False and (has_filter_type['status'] == 'closed' or has_filter_type['status'] == 'solved'):
            ret.append({'parameter': 'filter', 'value': has_filter_type['status'], 'reason': 'performance'})

        return ret


    # Simple json serialization
    def toJson(self):
        jsonobj = self.__dict__
        jsonobj['zenpy_client'] = None
        jsonobj['filters'] = self.filters
        return json.dumps(jsonobj)

    def toDict(self):
        obj = self.__dict__
        obj['zenpy_client'] = None
        obj['filters'] = self.filters
        return obj

    # Simple json deserialization
    @staticmethod
    def fromJson(jsonIn):
        params = json.loads(jsonIn)

        if 'filters' in params:
            params['filter'] = " ".join(params['filters'])

        return DataQuery(params)

    def execute(self):
    	# select data via API from
    	#  right endpoint via from
    	#  right time period via period
    	#  filter on entity, filter and betafilter as required
    	# Apply entry = prepare_row(from, entry) for each result entry

        creds = {
            'email' : os.environ['DATABOT_ZD_EMAIL'],
            'token' : os.environ['DATABOT_ZD_TOKEN'],
            'subdomain': os.environ['DATABOT_ZD_SUBDOMAIN']
        }

        zenpy_query = {}

        query_from = self.from_to_zenpy[ self.query_from ]
        zenpy_query[ query_from[0] ] = query_from[1]

        ## Apply filters
        for filter in self.filters:
            if filter in self.filter_to_zenpy:
                f = self.filter_to_zenpy[ filter ]
                zenpy_query[ f[0] ] = f[1]

        ## Create period based on events
        if self.period:
            period_date = parse_period(self.period)
            now         = datetime.datetime.now()

            #event = self.event if self.event != False else 'created' # Done when creating query instead
            if self.event in self.event_to_zenpy:
                event = self.event_to_zenpy[ self.event ]
            else:
                evemt = self.event+"_between"

            if period_date < now:
                zenpy_query[event] = [period_date, now]
            else:
                zenpy_query[event] = [now, period_date]

        # Execute the actual search
        self.zenpy_client = Zenpy(**creds)
        logger.info("Query sent to Zendesk: {}".format(zenpy_query))
        zenpy_search = self.zenpy_client.search(**zenpy_query)

        result = []
        print zenpy_search
        for ticket in zenpy_search:
            result.append(self.prepare_row(self.query_from, ticket))

        # Apply post process filters, gettin oldest, newest entry etc.
        for filter in self.filters:
            if filter in self.filter_to_postprocess:
                f = self.filter_to_postprocess[ filter ]
                metric = DataMetric({
                    'value': f[0],
                    'metric': f[1]
                }, self.query_from)
                res = metric.calc_on_resultSet(result)

                if res.entry:
                    result = [res.entry]
                elif isinstance(res.result, list):
                    result = res.result


        return result

    def prepare_row(self, frm, entry):
        ret = {}
        #if frm == 'tickets':
        #print entry
        if isinstance(entry, Ticket):
            age = datetime.datetime.now() - datetime.datetime.strptime(entry.created_at, '%Y-%m-%dT%H:%M:%SZ')
            ret['age'] = age.total_seconds()
            ret['ticket_id'] = entry.id
            #print entry.via.source
            #ret['from_email'] = entry.via.source.from_.address if not entry.via.source.from_ is None else None
            ret['updated'] = entry.updated_at
            ret['created'] = entry.created_at
            ret['subject'] = entry.subject
            ret['priority'] = entry.priority
            ret['type'] = entry.type
            ret['status'] = entry.status
            ret['tags'] = entry.tags

            #metrics = self.zenpy_client.tickets.metrics(entry.id)
            #ret['replies'] = metrics.replies

            #if not metrics.assigned_at is None:
            #    assignment_time = datetime.datetime.now() - datetime.datetime.strptime(metrics.assigned_at, '%Y-%m-%dT%H:%M:%SZ')
            #    ret['assignment_time'] = assignment_time.total_seconds()

            #satisfaction_ratings = {
                #'offered': False, 'unoffered': False,
            #    'bad': 0, 'good': 1}
            #if entry.satisfaction_rating.score in satisfaction_ratings:
            #    ret['satisfaction_rating'] = satisfaction_ratings[ entry.satisfaction_rating.score ]

        return ret