Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature tickets #2

Merged
merged 13 commits into from
Jul 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 194 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,18 @@ knowledge base and online communities.
## 🛠 Requirements

| Package | PHP | Laravel | Zendesk |
|-----------|-------|----------------|-----------|
| >v1.0 | >8.2 | > Laravel 10.0 | ✅ |
|-----------|-------|----------------|:---------:|
| >v1.0 | >8.2 | > Laravel 10.0 | ✅ |

## Authentication

The currently supported authentication methods are:

| Method | Supported |
|--------------------|:-----------:|
| Basic Auth | ✅ |
| API token | ✅ |
| OAuth access token | ❌ |

## ⚙️ Installation

Expand All @@ -26,17 +36,192 @@ You can install the package via composer:
composer require codebar-ag/laravel-zendesk
```

Optionally, you can publish the config file with:

```bash
php artisan vendor:publish --provider="CodebarAg\Zendesk\ZendeskServiceProvider" --tag="config"
```

You can add the following env variables to your `.env` file:

```dotenv
ZENDESK_SUBDOMAIN=your-subdomain #required
ZENDESK_AUTHENTICATION_METHOD=token #default ['basic', 'token']
[email protected] #required
ZENDESK_API_TOKEN=your-api-token #required only for token authentication
ZENDESK_API_PASSWORD=your-password #required only for basic authentication
```

`Note: We handle base64 encoding for you so you don't have to encode your credentials.`

You can retrieve your API token from
your [Zendesk Dashboard](https://developer.zendesk.com/api-reference/introduction/security-and-auth/)

## Usage

### Authentication
To make use of the package, you need to create a ZendeskConnector instance.

The currently supported authentication methods are:
```php
use CodebarAg\Zendesk\ZendeskConnector;
...

$connector = new ZendeskConnector();
````

### Requests

The following requests are currently supported:

| Request | Supported |
|-------------------|:-----------:|
| List Tickets | ✅ |
| Count Tickets | ✅ |
| Show Ticket | ✅ |
| Create Ticket | ✅ |
| Create Attachment | ✅ |

### Responses

The following responses are currently supported for retrieving the response body:

| Response Methods | Description | Supported |
|-------------------|------------------------------------------------------------------------------------------------------------------------------------|:-----------:|
| body | Returns the HTTP body as a string | ✅ |
| json | Retrieves a JSON response body and json_decodes it into an array. | ✅ |
| object | Retrieves a JSON response body and json_decodes it into an object. | ✅ |
| collect | Retrieves a JSON response body and json_decodes it into a Laravel collection. **Requires illuminate/collections to be installed.** | ✅ |
| dto | Converts the response into a data-transfer object. You must define your DTO first | ✅ |

See https://docs.saloon.dev/the-basics/responses for more information.

### Enums

We provide enums for the following values:

| Enum | Values |
|-------------------|:---------------------------------------------------------------------:|
| TicketPriority | 'urgent', 'high', 'normal', 'low' |
| TicketType | 'incident', 'problem', 'question', 'task' |
| MalwareScanResult | 'malware_found', 'malware_not_found', 'failed_to_scan', 'not_scanned' |

`Note: When using the dto method on a response, the enum values will be converted to their respective enum class.`

| Method | |
|----------------------|-----|
| Basic authentication | No |
| API token | Yes |
| OAuth access token | No |
### DTOs

We provide DTOs for the following:

| DTO |
|-----------------|
| AttachmentDTO |
| ThumbnailDTO |
| UploadDTO |
| CommentDTO |
| AllTicketsDTO |
| CountTicketsDTO |
| SingleTicketDTO |

`Note: This is the prefered method of interfacing with Requests and Responses however you can still use the json, object and collect methods. and pass arrays to the requests.`

### Examples

#### Create a ticket

```php
use CodebarAg\Zendesk\Requests\CreateSingleTicketRequest;
use CodebarAg\Zendesk\DTOs\SingleTicketDTO;
use CodebarAg\Zendesk\DTOs\CommentDTO;
use CodebarAg\Zendesk\Enums\TicketPriority;
...

$ticketResponse = $connector->send(
new CreateSingleTicketRequest(
SingleTicketDTO::fromArray([
'comment' => CommentDTO::fromArray([
'body' => 'The smoke is very colorful.',
]),
'priority' => TicketPriority::URGENT,
"subject" => "My printer is on fire!",
"custom_fields" => [
[
"id" => 12345678910111,
"value" => "Your custom field value"
],
[
"id" => 12345678910112,
"value" => "Your custom field value 2"
],
],
])
)
);

$ticket = $ticketResponse->dto();
````

#### List all tickets

```php
use CodebarAg\Zendesk\Requests\AllTicketsRequest;
...

$listTicketResponse = $connector->send(new AllTicketsRequest());
$listTicketResponse->dto();
````

#### Count all tickets

```php
use CodebarAg\Zendesk\Requests\CountTicketsRequest;
...

$countTicketResponse = $connector->send(new CountTicketsRequest());
$countTicketResponse->dto();
````

#### Show a ticket

```php
use CodebarAg\Zendesk\Requests\ShowTicketRequest;
...

$ticketID = 1;

$showTicketResponse = $connector->send(new ShowTicketRequest($ticketID));
$showTicketResponse->dto();
````

#### Upload an attachment

```php
use CodebarAg\Zendesk\Requests\CreateAttachmentRequest;
use CodebarAg\Zendesk\Requests\CreateSingleTicketRequest;
use Illuminate\Support\Facades\Storage;

$uploadResponse = $connector->send(
new CreateAttachmentRequest(
fileName: 'someimage.png',
mimeType: Storage::disk('local')->mimeType('public/someimage.png'),
stream: Storage::disk('local')->readStream('public/someimage.png')
)
);

$token = $uploadResponse->dto()->token;

$ticketResponse = $connector->send(
new CreateSingleTicketRequest(
SingleTicketDTO::fromArray([
'comment' => CommentDTO::fromArray([
...
'uploads' => [
$token,
],
]),
])
)
);

$ticket = $ticketResponse->dto();
```

## 🚧 Testing

Expand Down
11 changes: 6 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "codebar-ag/laravel-flatfox",
"name": "codebar-ag/laravel-zendesk",
"description": "Zendesk integration with Laravel",
"keywords": [
"zendesk",
Expand All @@ -21,21 +21,22 @@
"php": "^8.2",
"guzzlehttp/guzzle": "^7.2",
"illuminate/contracts": "^10.0",
"sammyjo20/saloon": "^2.6",
"saloonphp/cache-plugin": "^2.1",
"sammyjo20/saloon": "^2.0",
"sammyjo20/saloon-laravel": "^2.0",
"spatie/laravel-data": "^3.6",
"spatie/laravel-package-tools": "^1.9.2"
},
"require-dev": {
"laravel/pint": "^1.5",
"nunomaduro/collision": "^7.0",
"nunomaduro/larastan": "^2.4.0",
"orchestra/testbench": "^8.0",
"pestphp/pest": "2.x-dev",
"pestphp/pest-plugin-laravel": "2.x-dev",
"pestphp/pest": "^2.0",
"pestphp/pest-plugin-laravel": "^2.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^10.0",
"spatie/laravel-ray": "^1.9"
},
"autoload": {
Expand Down
10 changes: 8 additions & 2 deletions config/zendesk.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
<?php

return [
'api_token' => env('ZENDESK_API_TOKEN'),
'email_address' => env('ZENDESK_EMAIL_ADDRESS'),
'subdomain' => env('ZENDESK_SUBDOMAIN'), // 'yoursubdomain'

'auth' => [
'method' => env('ZENDESK_AUTHENTICATION_METHOD', 'token'), // 'basic' or 'token'
'email_address' => env('ZENDESK_EMAIL_ADDRESS'), // Used for both authentication methods
'password' => env('ZENDESK_PASSWORD'), // Only used if 'basic' is selected as authentication method
'api_token' => env('ZENDESK_API_TOKEN'), // Only used if 'apitoken' is selected as authentication method
],
];
1 change: 1 addition & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<junit outputFile="build/report.junit.xml"/>
</logging>
<php>
<env name="ZENDESK_ENDPOINT" value="endpoint"/>
<env name="ZENDESK_EMAIL_ADDRESS" value="email_Address"/>
<env name="ZENDESK_API_TOKEN" value="token"/>
</php>
Expand Down
32 changes: 32 additions & 0 deletions src/Dto/Tickets/AllTicketsDTO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace CodebarAg\Zendesk\Dto\Tickets;

use Illuminate\Support\Collection;
use Saloon\Http\Response;
use Spatie\LaravelData\Data;

class AllTicketsDTO extends Data
{
public function __construct(
public array $tickets,
public int $count,
public ?string $next_page_url,
public ?string $previous_page_url,
) {
}

public static function fromResponse(Response $response): self
{
$data = $response->json();

return new static(
tickets: collect($data['tickets'])->map(function (array $ticket) {
return SingleTicketDTO::fromArray($ticket);
})->toArray(),
count: $data['count'],
next_page_url: $data['next_page'],
previous_page_url: $data['previous_page'],
);
}
}
68 changes: 68 additions & 0 deletions src/Dto/Tickets/Attachments/AttachmentDTO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace CodebarAg\Zendesk\Dto\Tickets\Attachments;

use CodebarAg\Zendesk\Enums\MalwareScanResult;
use Illuminate\Support\Carbon;
use Saloon\Http\Response;
use Spatie\LaravelData\Data;

class AttachmentDTO extends Data
{
public function __construct(
public ?string $content_type,
public ?string $content_url,
public ?bool $deleted,
public ?string $file_name,
public ?string $height,
public ?int $id,
public ?bool $inline,
public ?bool $malware_access_override,
public ?MalwareScanResult $malware_scan_result,
public ?string $mapped_content_url,
public ?int $size,
public ?array $thumbnails,
public ?string $url,
public ?string $width,
) {
}

public static function fromArray(array $data): self
{
$thumbnails = $data['thumbnails'] ?? null;

if ($thumbnails) {
foreach ($thumbnails as $key => $thumbnail) {
$thumbnails[$key] = self::getThumbnail($thumbnail);
}
}

return new static(
content_type: $data['content_type'] ?? null,
content_url: $data['content_url'] ?? null,
deleted: $data['deleted'] ?? null,
file_name: $data['file_name'] ?? null,
height: $data['height'] ?? null,
id: $data['id'] ?? null,
inline: $data['inline'] ?? null,
malware_access_override: $data['malware_access_override'] ?? null,
malware_scan_result: MalwareScanResult::tryFrom($data['malware_scan_result'] ?? null),
mapped_content_url: $data['mapped_content_url'] ?? null,
size: $data['size'] ?? null,
thumbnails: $thumbnails ?? null,
url: $data['url'] ?? null,
width: $data['width'] ?? null,
);
}

private static function getThumbnail(null|array|ThumbnailDTO $data): ThumbnailDTO
{
$attachment = $data ?? null;

if (! $attachment instanceof ThumbnailDTO) {
$attachment = ThumbnailDTO::fromArray($attachment);
}

return $attachment;
}
}
Loading