From f2602b0b7acecd05538edf8eec99c0d6fa8e0bcc Mon Sep 17 00:00:00 2001 From: Nathan Moinvaziri Date: Tue, 24 Apr 2018 21:12:07 -0700 Subject: [PATCH] Fixed help desk history id not being associated with correct post. Fixed some Zendesk comments not being imported properly. #6 Added support for saving private notes in Zendesk. --- src/API/Provider/Zendesk/ApiController.php | 51 ++++++++++++++++++--- src/API/Provider/Zendesk/DataMapper.php | 53 ++++++++++++++++------ src/API/Repository/HistoryRepository.php | 8 +++- src/Importer/Importer.php | 20 ++++---- src/Importer/Inserter.php | 21 ++++++--- 5 files changed, 111 insertions(+), 42 deletions(-) diff --git a/src/API/Provider/Zendesk/ApiController.php b/src/API/Provider/Zendesk/ApiController.php index b7fd4ca..c9a9284 100755 --- a/src/API/Provider/Zendesk/ApiController.php +++ b/src/API/Provider/Zendesk/ApiController.php @@ -18,7 +18,7 @@ class ApiController extends ProviderController ******************************************/ /** - * Request the Tickets from Help Scout. + * Request the Tickets from Zendesk. * * @since 0.1.0 * @@ -39,23 +39,59 @@ protected function request() $this->dataMapper->mapJSON($json, $whichEndpoint); } } + + // Process each of the items and request each comment. + foreach ($this->jsonResponses['tickets'] as $json) { + $packet = $this->fromJSON($json); + foreach ($packet->tickets as $ticket) { + echo '
Getting '.$ticket->comment_count.' comments for ticket '.$ticket->id.'
'; + if ((int)$ticket->comment_count > 0 && $ticket->status != 'deleted') { + $this->requestComments($ticket->id); + } + } + } } protected function requestPackets($whichEndpoint) { $nextPage = ''; do { - $packet = $this->get( + $packet = $this->get( $this->getEndpoint($whichEndpoint, $nextPage) ); $this->jsonResponses[$whichEndpoint][] = $packet; // Unpack to get the next page and count. - $packet = $this->fromJSON($packet); - $nextPage = $packet->next_page; - } while ($packet->count > self::MAX_PACKET_SIZE); + $packet = $this->fromJSON($packet); + if ($nextPage == urldecode($packet->next_page)) { + break; + } + $nextPage = urldecode($packet->next_page); + } while ($packet->count >= self::MAX_PACKET_SIZE); } + /** + * Request and map the comments for the specific ticket ID from Zendesk. + * + * @since 0.1.0 + * + * @param int|string $ticketId + * + * @return void + */ + protected function requestComments($ticketId) + { + $pattern = 'https://%s.zendesk.com/api/v2/tickets/%d/comments.json?include=users'; + $url = sprintf( + $pattern, + $this->subdomain, + $ticketId + ); + + $packet = $this->get($url); + + $this->dataMapper->mapJSON($packet, 'comments', $ticketId); + } /** * Get the endpoint for the selected task, i.e. tickets or ticket events. * @@ -78,12 +114,13 @@ protected function getEndpoint($whichEndpoint, $endpoint = '') } $pattern = 'https://%s.zendesk.com/api/v2/incremental/'; $pattern .= 'ticketEvents' === $whichEndpoint - ? 'ticket_events.json?start_time=%s&include=comment_events' + ? 'ticket_events.json?start_time=%s' : 'tickets.json?start_time=%s&include=users,comment_count'; - return sprintf( + $url = sprintf( $pattern, $this->subdomain, $this->getStartTime() ); + return $url; } } diff --git a/src/API/Provider/Zendesk/DataMapper.php b/src/API/Provider/Zendesk/DataMapper.php index 5213e7e..a877f89 100755 --- a/src/API/Provider/Zendesk/DataMapper.php +++ b/src/API/Provider/Zendesk/DataMapper.php @@ -21,7 +21,7 @@ class DataMapper extends AbstractDataMapper * * @return void */ - public function mapJSON($json, $key = '') + public function mapJSON($json, $key = '', $ticketId = null) { $packets = $this->fromJSON($json); @@ -33,6 +33,11 @@ public function mapJSON($json, $key = '') if ('ticketEvents' === $key) { $this->mapEvents($packets->ticket_events); } + + if ('comments' === $key) { + $this->mapUsers($packets->users); + $this->mapComments($packets->comments, $ticketId); + } } /** @@ -110,9 +115,7 @@ protected function mapEvents(array $ticketEvents) // Psst...using a closure to pass $data byRef. array_walk($ticketEvent->child_events, function ($childEvent) use (&$data) { - if (!isset($childEvent->public) || $childEvent->public) { - $this->mapChildEvent($childEvent, $data); - } + $this->mapChildEvent($childEvent, $data); }); // If there's a reply, then let's process it. @@ -138,17 +141,6 @@ protected function mapEvents(array $ticketEvents) protected function mapChildEvent(\stdClass $event, array &$data) { if ('Comment' === $event->event_type) { - $data['date'] = $this->toFormattedDate($event->created_at); - - $data['replyId'] = $event->id; - $data['reply'] = [ - 'userId' => $event->author_id, - 'reply' => $event->body, - 'timestamp' => $data['date'], - ]; - if ($this->hasAttachments($event)) { - $data['attachments'] = $event->attachments; - } return; } @@ -172,6 +164,36 @@ protected function mapChildEvent(\stdClass $event, array &$data) } } + protected function mapComments(array $comments, $ticketId) + { + foreach ($comments as $comment) { + $data = [ + 'id' => $comment->id, + 'ticketId' => $ticketId, + 'date' => $this->toFormattedDate($comment->created_at), + 'timestamp' => $this->toFormattedDate($comment->created_at), + 'isOriginalTicket' => false, + 'requesterId' => 0, + 'reply' => null, + 'replyId' => $comment->id, + 'attachments' => $comment->attachments + ]; + + $data['reply'] = [ + 'userId' => $comment->author_id, + 'reply' => $comment->body, + 'timestamp' => $data['date'], + 'private' => false + ]; + + if (isset($comment->public) && !$comment->public) { + $data['private'] = true; + } + + $this->mapReplyOrTicket($data); + } + } + /** * Map the reply/comment for this ticket. * @@ -197,6 +219,7 @@ protected function mapReplyOrTicket(array $data) } $this->replyRepository->create($data['ticketId'], $data['replyId'], $data['reply']); + if (isset($data['attachments'])) { $this->mapAttachments($data['attachments'], $data['ticketId'], $data['replyId']); } diff --git a/src/API/Repository/HistoryRepository.php b/src/API/Repository/HistoryRepository.php index 9efd00a..a6ac5a2 100755 --- a/src/API/Repository/HistoryRepository.php +++ b/src/API/Repository/HistoryRepository.php @@ -16,14 +16,18 @@ class HistoryRepository extends Repository * * @return void */ - public function create($ticketId, $userId, $status, $timestamp, $id = 0) + public function create($ticketId, $userId, $status, $timestamp, $historyId = 0) { if (!$this->has($ticketId)) { $this->set($ticketId, []); } + if ($historyId == 0) { + $historyId = sha1($userId.$timestamp.$status); + } + $this->items[$ticketId][] = [ - 'id' => $id, + 'id' => $historyId, 'user' => (int)$userId, 'value' => $status, 'date' => $timestamp, diff --git a/src/Importer/Importer.php b/src/Importer/Importer.php index 718f3a1..7905d21 100755 --- a/src/Importer/Importer.php +++ b/src/Importer/Importer.php @@ -249,7 +249,7 @@ protected function processReply(array $reply, $ticketId, $helpDeskReplyId) { $author = $this->processUser($reply['user']); - $replyId = $this->inserter->insertReply( + $replyId = $this->inserter->insertReply( $ticketId, $reply['reply'], $author, @@ -288,19 +288,15 @@ protected function processHistory(Ticket $ticket, $ticketId) } foreach ($ticket->getHistory() as $history) { // If it exists in the db, no need to import. - if (!empty($history['id'])) { - $historyId = $this->locator->findHistoryByHelpDeskId($history['id']); - if ($this->validator->isValidHistoryId($historyId)) { - continue; - } - } + $historyId = $this->locator->findHistoryByHelpDeskId($history['id']); + if ($this->validator->isValidHistoryId($historyId)) { + continue; + } $author = $this->processUser($history['user']); - $this->inserter->insertHistoryItem($ticketId, $author, $history['date'], $history['value']); - if (!empty($history['id'])) { - $this->inserter->setHelpDeskHistoryId($ticketId, $history['id']); - } + $historyId = $this->inserter->insertHistoryItem($ticketId, $author, $history['date'], $history['value']); + $this->inserter->setHelpDeskHistoryId($historyId, $history['id']); } } @@ -315,7 +311,7 @@ protected function processHistory(Ticket $ticket, $ticketId) */ protected function processUser($userEntity) { - if (!$userEntity instanceof User || empty($userEntity->getEmail())) { + if (!$userEntity instanceof User) { return $this->currentUser; } diff --git a/src/Importer/Inserter.php b/src/Importer/Inserter.php index 88c5ef9..383bb67 100755 --- a/src/Importer/Inserter.php +++ b/src/Importer/Inserter.php @@ -198,7 +198,7 @@ public function insertAttachment($postId, array $attachment) * @return int|WP_Error * @throws ImportException */ - public function insertReply($ticketId, $reply, WP_User $author, $date, $read) + public function insertReply($ticketId, $reply, WP_User $author, $date, $read, $private = false) { wp_set_current_user($author->ID); @@ -212,6 +212,13 @@ public function insertReply($ticketId, $reply, WP_User $author, $date, $read) $ticketId ); + if ($private) { + $response = wp_update_post([ + 'ID' => $replyId, + 'post_type' => 'ticket_note' + ]); + } + wp_set_current_user($this->currentUserId); if ($replyId instanceof WP_Error) { @@ -263,9 +270,9 @@ public function insertHistoryItem($ticketId, WP_User $author, $date, $status) wpas_update_ticket_status($ticketId, $status); } - $postId = $this->locator->findPostByMetaId($this->wpdb->insert_id); + $historyId = $this->locator->findPostByMetaId($this->wpdb->insert_id); $response = wp_update_post([ - 'ID' => $postId, + 'ID' => $historyId, 'post_author' => $author->ID, 'post_date' => $date, 'post_date_gmt' => get_gmt_from_date($date), @@ -292,6 +299,8 @@ public function insertHistoryItem($ticketId, WP_User $author, $date, $status) ], __CLASS__ ); + + return $historyId; } /** @@ -299,15 +308,15 @@ public function insertHistoryItem($ticketId, WP_User $author, $date, $status) * * @since 0.2.0 * - * @param int $replyId The history's post ID. + * @param int $historyId The history's post ID. * @param string|int $helpDeskId The original ID. * * @return bool|int */ - public function setHelpDeskHistoryId($replyId, $helpDeskId) + public function setHelpDeskHistoryId($historyId, $helpDeskId) { - return update_post_meta($replyId, '_wpas_help_desk_history_id', sanitize_text_field($helpDeskId)); + return update_post_meta($historyId, '_wpas_help_desk_history_id', sanitize_text_field($helpDeskId)); } /**