diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..56f3b6b
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,12 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+indent_style = space
+indent_size = 4
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
new file mode 100644
index 0000000..3ea40fa
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -0,0 +1,19 @@
+---
+name: Bug Report
+about: Report a bug in a package.
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+### Description & Steps to reproduce
+
+
+
+### Versions:
+
+
+- PHP version: #.#.#
+- Laravel version: #.#.#
+- Package version: #.#.#
diff --git a/.github/ISSUE_TEMPLATE/new-feature-or-enhancement.md b/.github/ISSUE_TEMPLATE/new-feature-or-enhancement.md
new file mode 100644
index 0000000..3f808f8
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/new-feature-or-enhancement.md
@@ -0,0 +1,12 @@
+---
+name: New Feature or Enhancement
+about: Suggest an idea for this package.
+title: ''
+labels: enhancement
+assignees: ''
+
+---
+
+### Description
+
+
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
new file mode 100644
index 0000000..669219e
--- /dev/null
+++ b/.github/workflows/static-analysis.yml
@@ -0,0 +1,64 @@
+name: Static Analysis
+
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ phpstan:
+ name: PHPStan Analysis
+ runs-on: ubuntu-latest
+ env:
+ COMPOSER_NO_INTERACTION: 1
+ steps:
+ - uses: actions/checkout@v2
+
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: 8.1
+ coverage: none
+
+ - name: Get composer cache directory
+ id: composercache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache dependencies
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.composercache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - run: composer update --prefer-dist --no-progress
+
+ - run: composer phpstan -- --no-progress
+
+ style:
+ name: PHP-CS-Fixer Analysis
+ runs-on: ubuntu-latest
+ env:
+ COMPOSER_NO_INTERACTION: 1
+ steps:
+ - uses: actions/checkout@v2
+
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: 8.1
+ coverage: none
+
+ - name: Get composer cache directory
+ id: composercache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache dependencies
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.composercache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - run: composer update --prefer-dist --no-progress
+
+ - run: composer lint
+
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..6b35034
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,49 @@
+name: Tests
+
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ tests:
+ strategy:
+ fail-fast: false
+ matrix:
+ php: [ 8.1, 8.2 ]
+ laravel: [ ^9.0 ]
+ name: PHP=${{ matrix.php }} LARAVEL=${{ matrix.laravel }}
+ runs-on: ubuntu-latest
+ env:
+ COMPOSER_NO_INTERACTION: 1
+ XDEBUG_MODE: coverage
+ steps:
+ - uses: actions/checkout@v2
+
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ coverage: xdebug
+
+ - name: Get composer cache directory
+ id: composercache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache dependencies
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.composercache.outputs.dir }}
+ key: ${{ runner.os }}-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}
+ restore-keys: ${{ runner.os }}-${{ matrix.php }}-composer-
+
+ - run: composer update --prefer-dist --no-progress
+
+ - name: Run tests
+ run: composer test -- --coverage-clover ./coverage.xml
+
+ - name: Upload to Codecov
+ uses: codecov/codecov-action@v2
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ files: ./coverage.xml
+ verbose: true
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5e7061d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+composer.lock
+vendor/
+.idea
+.git
+phpunit-coverage/
+.phpunit.result.cache
+.php-cs-fixer.cache
+coverage.xml
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
new file mode 100644
index 0000000..095023d
--- /dev/null
+++ b/.php-cs-fixer.dist.php
@@ -0,0 +1,28 @@
+setFinder(
+ PhpCsFixer\Finder::create()
+ ->in(__DIR__ . '/src')
+ ->in(__DIR__ . '/tests')
+ )
+ ->setRules([
+ 'line_ending' => false,
+ 'concat_space' => [
+ 'spacing' => 'one',
+ ],
+ 'cast_spaces' => [
+ 'space' => 'none',
+ ],
+ 'not_operator_with_successor_space' => false,
+ 'simplified_null_return' => false,
+ 'explicit_string_variable' => true,
+ 'phpdoc_to_comment' => false,
+ ])
+ ->setRiskyAllowed(true);
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..ba61d69
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,7 @@
+Copyright (c) 2023 Edgars Neimanis
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1c0e108
--- /dev/null
+++ b/README.md
@@ -0,0 +1,547 @@
+# Laravel TET Media Services API Client
+
+This package helps you to make API calls to TET Media Services API v5.
+
+https://api.cloudycdn.services/api/v5/docs
+
+## Requirements
+- Laravel 9.0+
+- PHP 8.1+
+
+## Installation
+Require the package via Composer:
+
+```bash
+composer require newman/laravel-tms-api-client
+```
+
+Copy config file to your `config` directory.
+```bash
+php artisan vendor:publish --tag=tms-api-config
+```
+
+Add environment variables to your `.env` file.
+
+```dotenv
+TMS_DEFAULT_USERNAME="API Key"
+TMS_DEFAULT_PASSWORD="API Secret"
+```
+
+At last, you can add extra client to your `tms-api.php` config file with other credentials or different default settings.
+
+# :book: Documentation & Usage
+
+## Clients
+
+### Access client from config
+
+```php
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+TmsApi::client('default')->run(...);
+```
+
+### Create a client dynamically
+
+We recommend to do this on your `AppServiceProvider`, inside `boot` function.
+
+```php
+use Newman\LaravelTmsApiClient\Auth\BasicAuthMethod;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$client = TmsApi::createClient('live', new BasicAuthMethod('api key', 'api secret'));
+
+// and from now on you can access using client() as well
+// TmsApi::client('live')->run(...);
+```
+
+### Authenticate via Bearer token
+
+There are some endpoints (e.g. `/User/Login`) which doesn't require any authentication at all.
+
+```php
+use Newman\LaravelTmsApiClient\Auth\BearerAuthMethod;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+// 1) Retrieve Bearer token without any authentication.
+$response = TmsApi::nullClient()->run(new Login('my@email.com', 'mypassword'));
+
+$bearerToken = $response->json('data.auth_token');
+
+// ... you may want to cache this token for some time
+
+// 2) Override default client dynamically with other auth method.
+TmsApi::createClient('default', new BearerAuthMethod($bearerToken));
+
+// 3) now all calls on default client will use Bearer token as auth method.
+// TmsApi::client('default')->run(...);
+```
+
+### Configure Client
+
+**Note:** This will override settings for upcoming requests on `default` client.
+
+#### `timeout` and `connectTimeout`
+
+```php
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+TmsApi::client('default')->timeout(30)->connectTimeout(45);
+```
+
+#### `withMiddleware`
+
+Append HTTP middleware to this client upcoming requests.
+
+https://laravel.com/docs/9.x/http-client#guzzle-middleware
+
+```php
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+TmsApi::client('default')->withMiddleware(...);
+```
+
+## Response
+
+Response of the request is `\Illuminate\Http\Client\Reponse` object.
+
+# Endpoints
+
+We created this package with only few implementations of TMS endpoints. PRs are welcome to add more.
+
+For each endpoint argument (except required ones) you'll find a correspoding setter function.
+
+Here is the list of implemented endpoints:
+
+## `/Token`
+
+### Endpoint: `/Token/Generate`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Token/Generate
+
+Generates a new token.
+
+**Accepted Auth Methods:** `Basic`, `Bearer token`, `API Key`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Token\Generate as TokenGenerate;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$endpoint = new TokenGenerate(123456, TokenGenerate\ItemTypeEnum::MEDIA);
+
+// Optional
+$endpoint->allowedCountries(['lv', 'lt', 'ee']);
+$endpoint->allowedIp('85.110.62.99');
+
+$endpoint->expireTime(1674074046);
+$endpoint->expireTime('2023-01-18 12:34:56');
+$endpoint->expireTime(\Carbon\Carbon::now()->addHour());
+
+$endpoint->subitemId(5);
+$endpoint->subitemType(TokenGenerate\SubitemTypeEnum::PLAYBACK_HLS);
+
+$response = TmsApi::client('default')->run($endpoint);
+```
+
+## `/Media`
+
+### Endpoint: `/Media/List`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/List
+
+Retrieve a list of media.
+
+**Accepted Auth Methods:** `Basic`, `Bearer token`, `API Key`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\MediaList;
+use Newman\LaravelTmsApiClient\EndpointSupport\Enums\OrderDirectionEnum;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$endpoint = new MediaList();
+
+// Optional
+$endpoint->ids([123]); // media IDs
+$endpoint->assetIds(['asset_id']);
+$endpoint->categoryIds([5]);
+$endpoint->onlyAvailable(true);
+$endpoint->published(true);
+$endpoint->search('lorem ipsum');
+$endpoint->tags(['archive']);
+$endpoint->return(['embed_player_codes', 'sources']);
+$endpoint->imagesFallback(false);
+
+$endpoint->publisherStatus(MediaList\PublisherStatusEnum::PUBLISHED);
+
+$endpoint->status(MediaList\StatusEnum::INGESTED);
+$endpoint->status([MediaList\StatusEnum::INGESTED, MediaList\StatusEnum::PLAYABLE]);
+
+$endpoint->createdFrom(1674074046);
+$endpoint->createdFrom('2023-01-18 12:34:56');
+$endpoint->createdFrom(\Carbon\Carbon::now()->addHour());
+
+$endpoint->createdTo(1674074046);
+$endpoint->createdTo('2023-01-18 12:34:56');
+$endpoint->createdTo(\Carbon\Carbon::now()->addHour());
+
+$endpoint->updatedFrom(1674074046);
+$endpoint->updatedFrom('2023-01-18 12:34:56');
+$endpoint->updatedFrom(\Carbon\Carbon::now()->addHour());
+
+$endpoint->updatedTo(1674074046);
+$endpoint->updatedTo('2023-01-18 12:34:56');
+$endpoint->updatedTo(\Carbon\Carbon::now()->addHour());
+
+$endpoint->limit(5);
+$endpoint->offset(10);
+
+$endpoint->orderBy(MediaList\OrderByEnum::CREATED_AT);
+$endpoint->orderDir(OrderDirectionEnum::ASC);
+
+$response = TmsApi::client('default')->run($endpoint);
+```
+
+### Endpoint: `/Media/Update`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Update
+
+Update media.
+
+**Accepted Auth Methods:** `Basic`, `Bearer token`, `API Key`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\Update as MediaUpdate;
+use Newman\LaravelTmsApiClient\EndpointSupport\Callback;
+use Newman\LaravelTmsApiClient\EndpointSupport\Enums\CallbackHttpMethodEnum;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+use Newman\LaravelTmsApiClient\Endpoints\Media\Update\ByMediaId;
+use Newman\LaravelTmsApiClient\Endpoints\Media\Update\ByAssetId;
+
+// Select by which identificator to update
+// by media ID
+$endpoint = new MediaUpdate(new ByMediaId(123));
+// by asset ID
+$endpoint = new MediaUpdate(new ByAssetId('99_asset_id'));
+
+// Optional
+$endpoint->name('Name of media');
+$endpoint->description('Description of media');
+
+$images = new MediaUpdate\Images();
+$images->thumbnail('thumbnail base64');
+$images->placeholder('placeholder base64');
+$images->playbutton('playbutton base64');
+$images->logo('logo base64');
+$endpoint->images($images);
+
+$endpoint->callback(new Callback('https://mysite.com', CallbackHttpMethodEnum::POST));
+
+$response = TmsApi::client('default')->run($endpoint);
+```
+
+### Endpoint: `/Media/Delete`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Delete
+
+Delete media by ID/s.
+
+**Accepted Auth Methods:** `Basic`, `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\Delete as MediaDelete;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+// Multiple IDs.
+$endpoint = new MediaDelete([1234, 5678]);
+
+$response = TmsApi::client('default')->run($endpoint);
+
+// Single ID.
+$endpoint = new MediaDelete(1234);
+
+$response = TmsApi::client('default')->run($endpoint);
+```
+
+### Endpoint: `/Media/Clone`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Clone
+
+Clone media by ID.
+
+**Accepted Auth Methods:** `Basic`, `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\CloneMedia;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$endpoint = new CloneMedia(1234, 'asset_id_for_the_new_asset');
+
+// Optional
+$endpoint->name('Name for the new asset');
+
+$response = TmsApi::client('default')->run($endpoint);
+```
+
+### Endpoint: `/Media/Trim`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Trim
+
+**Accepted Auth Methods:** `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\Trim;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$endpoint = new Trim(1234, '00:00:10', '00:59:59', Trim\TypeEnum::NEW);
+
+// Optional
+$endpoint->name('Name');
+
+$response = TmsApi::client('default')->run($endpoint);
+```
+
+### Endpoint: `/Media/Generateimage`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Generateimage
+
+**Accepted Auth Methods:** `Basic`, `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\GenerateImage;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$endpoint = new GenerateImage(1234);
+
+// Optional
+$endpoint->mediaFileId(1902);
+$endpoint->thumbnail('01:20:39');
+$endpoint->placeholder('00:05:30');
+
+$response = TmsApi::client('default')->run($endpoint);
+```
+
+### Endpoint: `/Media/Reset`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Reset
+
+**Accepted Auth Methods:** `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\Reset;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$response = TmsApi::client('default')->run(new Reset(1234));
+```
+
+### Endpoint: `/Media/Transcode`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Transcode
+
+**Accepted Auth Methods:** `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\Transcode;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$response = TmsApi::client('default')->run(new Transcode(1234));
+```
+
+### Endpoint: `/Media/Canceltranscode`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Canceltranscode
+
+**Accepted Auth Methods:** `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\CancelTranscode;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$response = TmsApi::client('default')->run(new CancelTranscode(1234));
+```
+
+### Endpoint: `/Media/Updatesubtitlesfromsource`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Updatesubtitlesfromsource
+
+**Accepted Auth Methods:** `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\UpdateSubtitlesFromSource;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$response = TmsApi::client('default')->run(new UpdateSubtitlesFromSource(1234));
+```
+
+### Endpoint: `/Media/Regeneratepackages`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Regeneratepackages
+
+**Accepted Auth Methods:** `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\RegeneratePackages;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$endpoint = new RegeneratePackages(1234);
+
+// Optional
+$endpoint->packageId([10, 15]);
+
+$response = TmsApi::client('default')->run($endpoint);
+```
+
+## `/Media/Manifest`
+
+### Endpoint: `/Media/Manifest/List`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Manifest/List
+
+Retrieve list of manifests.
+
+**Accepted Auth Methods:** `Basic`, `Bearer token`, `API Key`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\Manifest\List\OrderByEnum;
+use Newman\LaravelTmsApiClient\Endpoints\Media\Manifest\ManifestList;
+use Newman\LaravelTmsApiClient\EndpointSupport\Enums\OrderDirectionEnum;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$endpoint = new ManifestList();
+
+// Optional
+$endpoint->ids([1, 2]); // manifest IDs
+$endpoint->limit(10);
+$endpoint->mediaIds([1234]);
+$endpoint->offset(10);
+$endpoint->orderBy(OrderByEnum::NAME);
+$endpoint->orderDir(OrderDirectionEnum::DESC);
+
+$response = TmsApi::client('default')->run($endpoint);
+```
+
+### Endpoint: `/Media/Manifest/Create`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Manifest/Create
+
+Create a new media manifest.
+
+**Accepted Auth Methods:** `Basic`, `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\Manifest\Create as MediaManifestCreate;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$endpoint = new MediaManifestCreate(1234); // media ID
+
+// Optional
+$endpoint->name('Name of the manifest');
+$endpoint->default(true);
+$endpoint->startAt(1000);
+$endpoint->endAt(60000);
+$endpoint->files([582, 583]);
+$endpoint->packageId(4020);
+
+$response = TmsApi::client('default')->run($endpoint);
+```
+
+### Endpoint: `/Media/Manifest/Update`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Manifest/Update
+
+Update media manifest by manifest ID.
+
+**Accepted Auth Methods:** `Basic`, `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\Manifest\Update as MediaManifestUpdate;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$endpoint = new MediaManifestUpdate(85291); // manifest ID
+
+// Same optional functions as "/Media/Manifest/Create" endpoint.
+
+$response = TmsApi::client('default')->run($endpoint);
+```
+
+### Endpoint: `/Media/Manifest/Delete`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/Media/Manifest/Delete
+
+Delete media manifest by manifest ID.
+
+**Accepted Auth Methods:** `Basic`, `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\Media\Manifest\Delete as MediaManifestDelete;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$response = TmsApi::client('default')->run(new MediaManifestDelete(85291)); // manifest ID
+```
+
+## `/User`
+
+### Endpoint: `/User/Get`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/User/Get
+
+Return current user info. Returns the same values as login action, but without auth_token.
+
+**Accepted Auth Methods:** `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\User\Get as UserGet;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$endpoint = new UserGet();
+
+// Optional
+$endpoint->return(['client.limits']);
+
+$response = TmsApi::client('default')->run($endpoint);
+```
+
+### Endpoint: `/User/Login`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/User/Login
+
+Login user by email & password to retrieve Bearer token.
+
+**Accepted Auth Methods:** `Null`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\User\Login as UserLogin;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$endpoint = new UserLogin('my@email.com', 'password');
+
+// Optional
+$endpoint->twoFaCode('123456');
+$endpoint->return(['client.limits']);
+
+$response = TmsApi::nullClient()->run($endpoint);
+```
+
+### Endpoint: `/User/Logout`
+
+https://api.cloudycdn.services/api/v5/docs#/operations/User/Logout
+
+Logout currently authenticated user.
+
+**Accepted Auth Methods:** `Bearer token`
+
+```php
+use Newman\LaravelTmsApiClient\Endpoints\User\Logout as UserLogout;
+use Newman\LaravelTmsApiClient\Support\Facades\TmsApi;
+
+$response = TmsApi::client('default')->run(new UserLogout());
+```
+
+# :handshake: Contributing
+
+We'll appreciate your collaboration to this package.
+
+When making pull requests, make sure:
+* All tests are passing: `composer test`
+* Test coverage is not reduced: `composer test-coverage`
+* There are no PHPStan errors: `composer phpstan`
+* Coding standard is followed: `composer lint` or `composer fix-style` to automatically fix it.
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..0a16284
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,70 @@
+{
+ "name": "newman/laravel-tms-api-client",
+ "description": "Laravel TMS Api client.",
+ "keywords": [
+ "laravel",
+ "tms",
+ "api",
+ "telia",
+ "tet",
+ "media",
+ "tet-media-services",
+ "cloudycdn"
+ ],
+ "type": "library",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Edgars Neimanis",
+ "email": "neimanis.edgars@gmail.com"
+ }
+ ],
+ "require": {
+ "php": "^8.1",
+ "guzzlehttp/guzzle": "^7.5",
+ "illuminate/contracts": "^9.0",
+ "illuminate/http": "^9.0",
+ "illuminate/support": "^9.0",
+ "nesbot/carbon": "^2.13"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^3.0",
+ "nunomaduro/larastan": "^1.0",
+ "orchestra/testbench": "^7.0",
+ "phpunit/phpunit": "^9.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Newman\\LaravelTmsApiClient\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Newman\\LaravelTmsApiClient\\Tests\\": "tests/"
+ }
+ },
+ "scripts": {
+ "phpstan": "phpstan analyse --memory-limit=256M",
+ "lint": "php-cs-fixer fix --diff --dry-run",
+ "fix-style": "php-cs-fixer fix",
+ "test": "./vendor/bin/phpunit --colors=always --verbose",
+ "test-coverage": "php -dpcov.enabled=1 -dpcov.directory=src/ -dpcov.exclude=\"~vendor~\" ./vendor/bin/phpunit --colors=always --verbose --coverage-text",
+ "test-coverage-html": "php -dpcov.enabled=1 -dpcov.directory=src/ -dpcov.exclude=\"~vendor~\" ./vendor/bin/phpunit --colors=always --verbose --coverage-html phpunit-coverage"
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Newman\\LaravelTsmApiClient\\ServiceProvider"
+ ],
+ "aliases": {
+ "TmsApi": "Newman\\LaravelTsmApiClient\\Support\\Facades\\TmsApi"
+ }
+ }
+ },
+ "minimum-stability": "dev",
+ "prefer-stable": true,
+ "config": {
+ "preferred-install": "dist",
+ "sort-packages": true
+ }
+}
diff --git a/config/tms-api.php b/config/tms-api.php
new file mode 100644
index 0000000..01c7c1a
--- /dev/null
+++ b/config/tms-api.php
@@ -0,0 +1,33 @@
+ [
+ 'default' => [
+ // Basic Auth credentials (Required)
+ 'auth' => [
+ 'username' => env('TMS_DEFAULT_USERNAME'),
+ 'password' => env('TMS_DEFAULT_PASSWORD'),
+ ],
+
+ // Default HTTP settings (Optional)
+ 'http' => [
+ // Default timeout (in seconds) for the request.
+ 'timeout' => 15,
+
+ // Default connect timeout (in seconds) for the request.
+ 'connect_timeout' => 15,
+ ],
+ ],
+ ],
+];
diff --git a/docker/.gitignore b/docker/.gitignore
new file mode 100644
index 0000000..6320cd2
--- /dev/null
+++ b/docker/.gitignore
@@ -0,0 +1 @@
+data
\ No newline at end of file
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000..9dda2d5
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,12 @@
+FROM php:8.1-cli-alpine
+
+COPY --from=mlocati/php-extension-installer:1.2.25 /usr/bin/install-php-extensions /usr/local/bin/
+
+RUN install-php-extensions \
+ pcov
+
+COPY --from=composer:2.5.1 /usr/bin/composer /usr/local/bin/
+
+COPY ../ /app
+
+WORKDIR /app
diff --git a/docker/README.md b/docker/README.md
new file mode 100644
index 0000000..83ec0c0
--- /dev/null
+++ b/docker/README.md
@@ -0,0 +1 @@
+This is only meant for development purposes.
\ No newline at end of file
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
new file mode 100644
index 0000000..5a3b0e5
--- /dev/null
+++ b/docker/docker-compose.yml
@@ -0,0 +1,9 @@
+version: '3.4'
+
+services:
+ php:
+ build: .
+ volumes:
+ - '../:/app'
+ working_dir: '/app'
+ tty: true
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
new file mode 100644
index 0000000..65bb1ba
--- /dev/null
+++ b/phpstan.neon.dist
@@ -0,0 +1,6 @@
+includes:
+ - ./vendor/nunomaduro/larastan/extension.neon
+parameters:
+ level: max
+ paths:
+ - src/
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..f8151de
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,24 @@
+
+
+
+
+ ./src
+
+
+
+
+ ./tests/Endpoints
+
+
+ ./tests/Unit
+
+
+
diff --git a/src/AbstractEndpoint.php b/src/AbstractEndpoint.php
new file mode 100644
index 0000000..3ce2b29
--- /dev/null
+++ b/src/AbstractEndpoint.php
@@ -0,0 +1,31 @@
+setAuthQueryParams(['paramauth' => $this->apiKey]);
+ }
+
+ public function getAuthMethod(): AuthMethodEnum
+ {
+ return AuthMethodEnum::API_KEY;
+ }
+}
diff --git a/src/Auth/BasicAuthMethod.php b/src/Auth/BasicAuthMethod.php
new file mode 100644
index 0000000..d3d0d48
--- /dev/null
+++ b/src/Auth/BasicAuthMethod.php
@@ -0,0 +1,26 @@
+withBasicAuth($this->username, $this->password);
+ }
+
+ public function getAuthMethod(): AuthMethodEnum
+ {
+ return AuthMethodEnum::BASIC;
+ }
+}
diff --git a/src/Auth/BearerAuthMethod.php b/src/Auth/BearerAuthMethod.php
new file mode 100644
index 0000000..6bb1c61
--- /dev/null
+++ b/src/Auth/BearerAuthMethod.php
@@ -0,0 +1,26 @@
+withToken($this->bearerToken);
+ }
+
+ public function getAuthMethod(): AuthMethodEnum
+ {
+ return AuthMethodEnum::BEARER;
+ }
+}
diff --git a/src/Auth/NullAuthMethod.php b/src/Auth/NullAuthMethod.php
new file mode 100644
index 0000000..8a381f2
--- /dev/null
+++ b/src/Auth/NullAuthMethod.php
@@ -0,0 +1,29 @@
+auth = $auth;
+ }
+
+ /**
+ * Customize HTTP timeout for client.
+ *
+ * @param int $seconds
+ * @return $this
+ */
+ public function timeout(int $seconds): static
+ {
+ $this->timeout = $seconds;
+
+ return $this;
+ }
+
+ /**
+ * Customize HTTP connect timeout for client.
+ *
+ * @param int $seconds
+ * @return $this
+ */
+ public function connectTimeout(int $seconds): static
+ {
+ $this->connectTimeout = $seconds;
+
+ return $this;
+ }
+
+ /**
+ * Append HTTP Client middleware.
+ *
+ * @param callable $middleware
+ * @return $this
+ */
+ public function withMiddleware(callable $middleware): static
+ {
+ $this->middlewares[] = $middleware;
+
+ return $this;
+ }
+
+ /**
+ * Run Endpoint.
+ *
+ * @param EndpointContract $endpoint
+ * @return Response
+ * @throws Exception
+ */
+ public function run(EndpointContract $endpoint): Response
+ {
+ if (!in_array($this->auth->getAuthMethod(), $endpoint->allowedAuthMethods())) {
+ throw new TmsAuthMethodNotAllowed('This authentication method is not allowed to call given endpoint.');
+ }
+
+ $factory = $this->buildHttpFactory();
+ $request = $this->buildBaseRequest($factory);
+
+ $this->applyAuthCredentials($request);
+ $this->applyHttpMiddleware($request);
+
+ $this->applyEndpointDefaults($request, $endpoint);
+ $endpoint->prepareHttpRequest($request);
+
+ $requestOptions = $this->buildRequestOptions($request);
+
+ return $request->send($request->getHttpMethod()->value, $request->getEndpoint(), $requestOptions);
+ }
+
+ /**
+ * Build & Get HTTP factory.
+ *
+ * @return HttpFactory
+ */
+ public function buildHttpFactory(): HttpFactory
+ {
+ return $this->httpFactory = $this->httpFactory ?? new HttpFactory();
+ }
+
+ /**
+ * Build base HTTP request.
+ *
+ * @param HttpFactory $factory
+ * @return PendingRequest
+ */
+ protected function buildBaseRequest(HttpFactory $factory): PendingRequest
+ {
+ /** @var PendingRequest $request */
+ $request = $factory->baseUrl($this->getBaseUrl())
+ ->asJson()
+ ->connectTimeout($this->connectTimeout)
+ ->timeout($this->timeout);
+
+ return $request;
+ }
+
+ /**
+ * Apply auth credentials to request.
+ *
+ * @param PendingRequest $request
+ * @return void
+ */
+ protected function applyAuthCredentials(PendingRequest $request): void
+ {
+ $this->auth->applyCredentials($request);
+ }
+
+ /**
+ * Applies HTTP middleware to request.
+ *
+ * @param PendingRequest $request
+ * @return void
+ */
+ protected function applyHttpMiddleware(PendingRequest $request): void
+ {
+ foreach ($this->middlewares as $middleware) {
+ $request->withMiddleware($middleware);
+ }
+ }
+
+ /**
+ * Apply endpoint defaults to request.
+ *
+ * @param PendingRequest $request
+ * @param EndpointContract $endpoint
+ * @return void
+ */
+ protected function applyEndpointDefaults(PendingRequest $request, EndpointContract $endpoint): void
+ {
+ $request
+ ->useMethod($endpoint->useHttpMethod())
+ ->setEndpoint($endpoint->endpointUrl());
+ }
+
+ /**
+ * Build HTTP request options.
+ *
+ * @param PendingRequest $request
+ * @return array
+ */
+ protected function buildRequestOptions(PendingRequest $request): array
+ {
+ $requestOptions = [];
+
+ if ($query = $request->getCompiledQuery()) {
+ $requestOptions['query'] = $query;
+ }
+
+ if ($request->getHttpMethod() != HttpMethodEnum::GET) {
+ if ($requestData = $request->getData()) {
+ $requestOptions[$request->getBodyFormat()] = $requestData;
+ }
+ }
+
+ return $requestOptions;
+ }
+
+ /**
+ * Base URL.
+ *
+ * @return string
+ */
+ protected function getBaseUrl(): string
+ {
+ return 'https://api.cloudycdn.services/api/v5';
+ }
+}
diff --git a/src/Concerns/CompilesProperties.php b/src/Concerns/CompilesProperties.php
new file mode 100644
index 0000000..46ea7c3
--- /dev/null
+++ b/src/Concerns/CompilesProperties.php
@@ -0,0 +1,55 @@
+
+ */
+ public function compilesAsArrayExceptProperties(): array
+ {
+ return [];
+ }
+
+ /**
+ * Compile properties as array.
+ *
+ * @return array
+ */
+ public function compileAsArray(): array
+ {
+ $data = [];
+
+ $reflect = new ReflectionClass($this);
+ $properties = $reflect->getProperties(ReflectionProperty::IS_PROTECTED);
+
+ $exceptProperties = $this->compilesAsArrayExceptProperties();
+
+ foreach ($properties as $property) {
+ $value = $property->getValue($this);
+
+ if ($value !== null && !in_array($property->name, $exceptProperties)) {
+ if ($value instanceof \BackedEnum) {
+ $value = $value->value;
+ } else if (is_bool($value)) {
+ $value = $value ? 1 : 0;
+ } else if ($value instanceof CarbonInterface) {
+ $value = $value->toDateTimeString();
+ }
+
+ $data[$property->name] = $value;
+ }
+ }
+
+ return $data;
+ }
+}
diff --git a/src/Contracts/AuthMethodContract.php b/src/Contracts/AuthMethodContract.php
new file mode 100644
index 0000000..3002c7f
--- /dev/null
+++ b/src/Contracts/AuthMethodContract.php
@@ -0,0 +1,26 @@
+
+ */
+ public function getClients(): array;
+}
diff --git a/src/EndpointSupport/Callback.php b/src/EndpointSupport/Callback.php
new file mode 100644
index 0000000..d02aa12
--- /dev/null
+++ b/src/EndpointSupport/Callback.php
@@ -0,0 +1,17 @@
+withData([
+ 'id' => $this->id,
+ ]);
+ }
+}
diff --git a/src/Endpoints/Media/CloneMedia.php b/src/Endpoints/Media/CloneMedia.php
new file mode 100644
index 0000000..2a39ccb
--- /dev/null
+++ b/src/Endpoints/Media/CloneMedia.php
@@ -0,0 +1,81 @@
+name = $name;
+
+ return $this;
+ }
+
+ /**
+ * Define which authentication methods are allowed to call this endpoint.
+ *
+ * @return AuthMethodEnum[]
+ */
+ public function allowedAuthMethods(): array
+ {
+ return [AuthMethodEnum::BEARER];
+ }
+
+ /**
+ * HTTP Method to use for request.
+ *
+ * @return HttpMethodEnum
+ */
+ public function useHttpMethod(): HttpMethodEnum
+ {
+ return HttpMethodEnum::PUT;
+ }
+
+ /**
+ * Endpoint url.
+ *
+ * @return string
+ */
+ public function endpointUrl(): string
+ {
+ return '/Media/Clone';
+ }
+
+ /**
+ * Prepares HTTP request for this endpoint.
+ *
+ * @param PendingRequest $http
+ * @return void
+ */
+ public function prepareHttpRequest(PendingRequest $http): void
+ {
+ $data = [
+ 'id' => $this->media_id,
+ 'asset_id' => $this->asset_id
+ ];
+
+ if ($this->name !== null) {
+ $data['name'] = $this->name;
+ }
+
+ $http->withData($data);
+ }
+}
diff --git a/src/Endpoints/Media/Delete.php b/src/Endpoints/Media/Delete.php
new file mode 100644
index 0000000..0bdd707
--- /dev/null
+++ b/src/Endpoints/Media/Delete.php
@@ -0,0 +1,71 @@
+ $ids
+ */
+ public function __construct(int|array $ids)
+ {
+ $this->mediaIds = !is_array($ids) ? [$ids] : $ids;
+ }
+
+ /**
+ * Define which authentication methods are allowed to call this endpoint.
+ *
+ * @return AuthMethodEnum[]
+ */
+ public function allowedAuthMethods(): array
+ {
+ return [AuthMethodEnum::BASIC, AuthMethodEnum::BEARER];
+ }
+
+ /**
+ * HTTP Method to use for request.
+ *
+ * @return HttpMethodEnum
+ */
+ public function useHttpMethod(): HttpMethodEnum
+ {
+ return HttpMethodEnum::DELETE;
+ }
+
+ /**
+ * Endpoint url.
+ *
+ * @return string
+ */
+ public function endpointUrl(): string
+ {
+ return '/Media/Delete';
+ }
+
+ /**
+ * Prepares HTTP request for this endpoint.
+ *
+ * @param PendingRequest $http
+ * @return void
+ */
+ public function prepareHttpRequest(PendingRequest $http): void
+ {
+ $http->withData(['id' => $this->mediaIds]);
+ }
+}
diff --git a/src/Endpoints/Media/GenerateImage.php b/src/Endpoints/Media/GenerateImage.php
new file mode 100644
index 0000000..419ba6b
--- /dev/null
+++ b/src/Endpoints/Media/GenerateImage.php
@@ -0,0 +1,106 @@
+media_file_id = $media_file_id;
+
+ return $this;
+ }
+
+ public function thumbnail(?string $thumbnail): static
+ {
+ $this->thumbnail = $thumbnail;
+
+ return $this;
+ }
+
+ public function placeholder(?string $placeholder): static
+ {
+ $this->placeholder = $placeholder;
+
+ return $this;
+ }
+
+ /**
+ * Define which authentication methods are allowed to call this endpoint.
+ *
+ * @return AuthMethodEnum[]
+ */
+ public function allowedAuthMethods(): array
+ {
+ return [AuthMethodEnum::BASIC, AuthMethodEnum::BEARER];
+ }
+
+ /**
+ * HTTP Method to use for request.
+ *
+ * @return HttpMethodEnum
+ */
+ public function useHttpMethod(): HttpMethodEnum
+ {
+ return HttpMethodEnum::PUT;
+ }
+
+ /**
+ * Endpoint url.
+ *
+ * @return string
+ */
+ public function endpointUrl(): string
+ {
+ return '/Media/Generateimage';
+ }
+
+ /**
+ * Prepares HTTP request for this endpoint.
+ *
+ * @param PendingRequest $http
+ * @return void
+ */
+ public function prepareHttpRequest(PendingRequest $http): void
+ {
+ $data = [
+ 'id' => $this->id,
+ ];
+
+ if ($this->media_file_id !== null) {
+ $data['media_file_id'] = $this->media_file_id;
+ }
+
+ if ($this->thumbnail !== null) {
+ $data['thumbnail'] = $this->thumbnail;
+ }
+
+ if ($this->placeholder !== null) {
+ $data['placeholder'] = $this->placeholder;
+ }
+
+ $http->withData($data);
+ }
+}
diff --git a/src/Endpoints/Media/Manifest/Create.php b/src/Endpoints/Media/Manifest/Create.php
new file mode 100644
index 0000000..e957058
--- /dev/null
+++ b/src/Endpoints/Media/Manifest/Create.php
@@ -0,0 +1,70 @@
+ $this->media_id,
+ ...$this->prepareData()
+ ];
+
+ $http->withData($data);
+ }
+}
diff --git a/src/Endpoints/Media/Manifest/CreateUpdateFunctionsTrait.php b/src/Endpoints/Media/Manifest/CreateUpdateFunctionsTrait.php
new file mode 100644
index 0000000..16640ae
--- /dev/null
+++ b/src/Endpoints/Media/Manifest/CreateUpdateFunctionsTrait.php
@@ -0,0 +1,113 @@
+|null
+ */
+ protected ?array $files = null;
+
+ protected ?int $package_id = null;
+
+
+ public function name(?string $name): static
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ public function default(?bool $is_default): static
+ {
+ $this->is_default = $is_default;
+
+ return $this;
+ }
+
+ /**
+ * @param int|null $time Miliseconds
+ * @return $this
+ */
+ public function startAt(?int $time): static
+ {
+ $this->start_at = $time;
+
+ return $this;
+ }
+
+ /**
+ * @param int|null $time Miliseconds
+ * @return $this
+ */
+ public function endAt(?int $time): static
+ {
+ $this->end_at = $time;
+
+ return $this;
+ }
+
+ /**
+ * @param array|null $files
+ * @return $this
+ */
+ public function files(?array $files): static
+ {
+ $this->files = $files;
+
+ return $this;
+ }
+
+ public function packageId(?int $package_id): static
+ {
+ $this->package_id = $package_id;
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ protected function prepareData(): array
+ {
+ $data = [];
+
+ if ($this->name !== null) {
+ $data['name'] = $this->name;
+ }
+
+ if ($this->is_default !== null) {
+ $data['default'] = $this->is_default ? 1 : 0;
+ }
+
+ if ($this->start_at !== null) {
+ $data['start_at'] = $this->start_at;
+ }
+
+ if ($this->end_at !== null) {
+ $data['end_at'] = $this->end_at;
+ }
+
+ if ($this->files !== null) {
+ $data['files'] = $this->files;
+ }
+
+ if ($this->package_id !== null) {
+ $data['package_id'] = $this->package_id;
+ }
+
+ return $data;
+ }
+}
diff --git a/src/Endpoints/Media/Manifest/Delete.php b/src/Endpoints/Media/Manifest/Delete.php
new file mode 100644
index 0000000..a1c0eae
--- /dev/null
+++ b/src/Endpoints/Media/Manifest/Delete.php
@@ -0,0 +1,64 @@
+withData(['id' => $this->id]);
+ }
+}
diff --git a/src/Endpoints/Media/Manifest/List/OrderByEnum.php b/src/Endpoints/Media/Manifest/List/OrderByEnum.php
new file mode 100644
index 0000000..b588dd9
--- /dev/null
+++ b/src/Endpoints/Media/Manifest/List/OrderByEnum.php
@@ -0,0 +1,13 @@
+|null
+ */
+ protected ?array $ids = null;
+
+ protected ?int $limit = null;
+
+ /**
+ * @var array|null
+ */
+ protected ?array $media_ids = null;
+
+ protected ?int $offset = null;
+
+ protected ?OrderByEnum $order_by = null;
+
+ protected ?OrderDirectionEnum $order_dir = null;
+
+ /**
+ * @param array|null $ids
+ * @return $this
+ */
+ public function ids(?array $ids): static
+ {
+ $this->ids = $ids;
+
+ return $this;
+ }
+
+ public function limit(?int $limit): static
+ {
+ $this->limit = $limit;
+
+ return $this;
+ }
+
+ /**
+ * @param array|null $ids
+ * @return $this
+ */
+ public function mediaIds(?array $ids): static
+ {
+ $this->media_ids = $ids;
+
+ return $this;
+ }
+
+ public function offset(?int $offset): static
+ {
+ $this->offset = $offset;
+
+ return $this;
+ }
+
+ public function orderBy(?OrderByEnum $order_by): static
+ {
+ $this->order_by = $order_by;
+
+ return $this;
+ }
+
+ public function orderDir(?OrderDirectionEnum $order_dir): static
+ {
+ $this->order_dir = $order_dir;
+
+ return $this;
+ }
+
+ /**
+ * HTTP Method to use for request.
+ *
+ * @return HttpMethodEnum
+ */
+ public function useHttpMethod(): HttpMethodEnum
+ {
+ return HttpMethodEnum::GET;
+ }
+
+ /**
+ * Endpoint url.
+ *
+ * @return string
+ */
+ public function endpointUrl(): string
+ {
+ return '/Media/Manifest/List';
+ }
+
+ /**
+ * Prepares HTTP request for this endpoint.
+ *
+ * @param PendingRequest $http
+ * @return void
+ */
+ public function prepareHttpRequest(PendingRequest $http): void
+ {
+ $query = [];
+
+ if ($this->ids !== null) {
+ $query['id'] = $this->ids;
+ }
+
+ if ($this->limit !== null) {
+ $query['limit'] = $this->limit;
+ }
+
+ if ($this->media_ids !== null) {
+ $query['media_id'] = $this->media_ids;
+ }
+
+ if ($this->offset !== null) {
+ $query['offset'] = $this->offset;
+ }
+
+ if ($this->order_by !== null) {
+ $query['order_by'] = $this->order_by->value;
+ }
+
+ if ($this->order_dir !== null) {
+ $query['order_dir'] = $this->order_dir->value;
+ }
+
+ $http->withQuery($query);
+ }
+}
diff --git a/src/Endpoints/Media/Manifest/Update.php b/src/Endpoints/Media/Manifest/Update.php
new file mode 100644
index 0000000..d905a3e
--- /dev/null
+++ b/src/Endpoints/Media/Manifest/Update.php
@@ -0,0 +1,70 @@
+ $this->id,
+ ...$this->prepareData()
+ ];
+
+ $http->withData($data);
+ }
+}
diff --git a/src/Endpoints/Media/MediaList.php b/src/Endpoints/Media/MediaList.php
new file mode 100644
index 0000000..9d5ac62
--- /dev/null
+++ b/src/Endpoints/Media/MediaList.php
@@ -0,0 +1,348 @@
+|null
+ */
+ protected ?array $ids = null;
+
+ /**
+ * @var array|null
+ */
+ protected ?array $asset_ids = null;
+
+ /**
+ * @var array|null
+ */
+ protected ?array $category_ids = null;
+
+ protected string|int|CarbonInterface|null $created_from = null;
+
+ protected string|int|CarbonInterface|null $created_to = null;
+
+ protected string|int|CarbonInterface|null $updated_from = null;
+
+ protected string|int|CarbonInterface|null $updated_to = null;
+
+ protected ?bool $published = null;
+
+ protected ?PublisherStatusEnum $publisher_status = null;
+
+ protected ?bool $only_available = null;
+
+ protected ?string $search = null;
+
+ /**
+ * @var array|null
+ */
+ protected ?array $status = null;
+
+ /**
+ * @var array|null
+ */
+ protected ?array $tags = null;
+
+ protected ?int $limit = null;
+
+ protected ?int $offset = null;
+
+ protected ?OrderByEnum $order_by = null;
+
+ protected ?OrderDirectionEnum $order_dir = null;
+
+ protected ?bool $images_fallback = null;
+
+ /**
+ * @var array|null
+ */
+ protected ?array $return = null;
+
+ /**
+ * @param array|null $ids
+ * @return $this
+ */
+ public function ids(?array $ids): static
+ {
+ $this->ids = $ids;
+
+ return $this;
+ }
+
+ /**
+ * @param array|null $asset_ids
+ * @return $this
+ */
+ public function assetIds(?array $asset_ids): static
+ {
+ $this->asset_ids = $asset_ids;
+
+ return $this;
+ }
+
+ /**
+ * @param array|null $ids
+ * @return $this
+ */
+ public function categoryIds(?array $ids): static
+ {
+ $this->category_ids = $ids;
+
+ return $this;
+ }
+
+ public function createdFrom(string|int|CarbonInterface|null $created_from): static
+ {
+ $this->created_from = $created_from;
+
+ return $this;
+ }
+
+ public function createdTo(string|int|CarbonInterface|null $created_to): static
+ {
+ $this->created_to = $created_to;
+
+ return $this;
+ }
+
+ public function updatedFrom(string|int|CarbonInterface|null $updated_from): static
+ {
+ $this->updated_from = $updated_from;
+
+ return $this;
+ }
+
+ public function updatedTo(string|int|CarbonInterface|null $updated_to): static
+ {
+ $this->updated_to = $updated_to;
+
+ return $this;
+ }
+
+ public function published(?bool $published): static
+ {
+ $this->published = $published;
+
+ return $this;
+ }
+
+ public function publisherStatus(?PublisherStatusEnum $status): static
+ {
+ $this->publisher_status = $status;
+
+ return $this;
+ }
+
+ public function onlyAvailable(?bool $only_available): static
+ {
+ $this->only_available = $only_available;
+
+ return $this;
+ }
+
+ public function search(?string $phrase): static
+ {
+ $this->search = $phrase;
+
+ return $this;
+ }
+
+ /**
+ * @param StatusEnum|array|null $status
+ * @return $this
+ */
+ public function status(StatusEnum|array|null $status): static
+ {
+ $this->status = $status === null ? null : (!is_array($status) ? [$status] : $status);
+
+ return $this;
+ }
+
+ /**
+ * @param array|null $tags
+ * @return $this
+ */
+ public function tags(?array $tags): static
+ {
+ $this->tags = $tags;
+
+ return $this;
+ }
+
+ public function limit(?int $limit): static
+ {
+ if ($limit < 1 || $limit > 50) {
+ throw new OutOfBoundsException('Limit must be between 1 and 50.');
+ }
+
+ $this->limit = $limit;
+
+ return $this;
+ }
+
+ public function offset(?int $offset): static
+ {
+ $this->offset = $offset;
+
+ return $this;
+ }
+
+ public function orderBy(?OrderByEnum $order_by): static
+ {
+ $this->order_by = $order_by;
+
+ return $this;
+ }
+
+ public function orderDir(?OrderDirectionEnum $order_dir): static
+ {
+ $this->order_dir = $order_dir;
+
+ return $this;
+ }
+
+ public function imagesFallback(?bool $fallback): static
+ {
+ $this->images_fallback = $fallback;
+
+ return $this;
+ }
+
+ /**
+ * @param array|null $return
+ * @return $this
+ */
+ public function return(?array $return): static
+ {
+ $this->return = $return;
+
+ return $this;
+ }
+
+ /**
+ * HTTP Method to use for request.
+ *
+ * @return HttpMethodEnum
+ */
+ public function useHttpMethod(): HttpMethodEnum
+ {
+ return HttpMethodEnum::GET;
+ }
+
+ /**
+ * Endpoint url.
+ *
+ * @return string
+ */
+ public function endpointUrl(): string
+ {
+ return '/Media/List';
+ }
+
+ /**
+ * Prepares HTTP request for this endpoint.
+ *
+ * @param PendingRequest $http
+ * @return void
+ */
+ public function prepareHttpRequest(PendingRequest $http): void
+ {
+ $query = [];
+
+ if ($this->ids !== null) {
+ $query['id'] = $this->ids;
+ }
+
+ if ($this->asset_ids !== null) {
+ $query['asset_id'] = $this->asset_ids;
+ }
+
+ if ($this->category_ids !== null) {
+ $query['cat_id'] = $this->category_ids;
+ }
+
+ if ($this->created_from !== null) {
+ $query['created_from'] = $this->created_from instanceof CarbonInterface ? $this->created_from->toDateTimeString() : $this->created_from;
+ }
+
+ if ($this->created_to !== null) {
+ $query['created_to'] = $this->created_to instanceof CarbonInterface ? $this->created_to->toDateTimeString() : $this->created_to;
+ }
+
+ if ($this->updated_from !== null) {
+ $query['updated_from'] = $this->updated_from instanceof CarbonInterface ? $this->updated_from->toDateTimeString() : $this->updated_from;
+ }
+
+ if ($this->updated_to !== null) {
+ $query['updated_to'] = $this->updated_to instanceof CarbonInterface ? $this->updated_to->toDateTimeString() : $this->updated_to;
+ }
+
+ if ($this->published !== null) {
+ $query['published'] = $this->published ? 1 : 0;
+ }
+
+ if ($this->publisher_status !== null) {
+ $query['publisher_status'] = $this->publisher_status->value;
+ }
+
+ if ($this->only_available !== null) {
+ $query['only_available'] = $this->only_available ? 1 : 0;
+ }
+
+ if ($this->search !== null) {
+ $query['search'] = $this->search;
+ }
+
+ if ($this->status !== null) {
+ $query['status'] = array_map(fn(StatusEnum $status) => $status->value, $this->status);
+ }
+
+ if ($this->tags !== null) {
+ $query['tags'] = $this->tags;
+ }
+
+ if ($this->limit !== null) {
+ $query['limit'] = $this->limit;
+ }
+
+ if ($this->offset != null) {
+ $query['offset'] = $this->offset;
+ }
+
+ if ($this->order_by !== null) {
+ $query['order_by'] = $this->order_by->value;
+ }
+
+ if ($this->order_dir !== null) {
+ $query['order_dir'] = $this->order_dir->value;
+ }
+
+ if ($this->images_fallback !== null) {
+ $query['images_fallback'] = $this->images_fallback ? 1 : 0;
+ }
+
+ if ($this->return !== null) {
+ $query['return'] = $this->return;
+ }
+
+ $http->withQuery($query);
+ }
+}
diff --git a/src/Endpoints/Media/MediaList/OrderByEnum.php b/src/Endpoints/Media/MediaList/OrderByEnum.php
new file mode 100644
index 0000000..a8d04dc
--- /dev/null
+++ b/src/Endpoints/Media/MediaList/OrderByEnum.php
@@ -0,0 +1,20 @@
+|null
+ */
+ protected ?array $package_ids = null;
+
+ public function __construct(protected int $id)
+ {
+
+ }
+
+ /**
+ * @param array|null $package_ids
+ * @return $this
+ */
+ public function packageId(?array $package_ids): static
+ {
+ $this->package_ids = $package_ids;
+
+ return $this;
+ }
+
+ /**
+ * Define which authentication methods are allowed to call this endpoint.
+ *
+ * @return AuthMethodEnum[]
+ */
+ public function allowedAuthMethods(): array
+ {
+ return [AuthMethodEnum::BEARER];
+ }
+
+ /**
+ * HTTP Method to use for request.
+ *
+ * @return HttpMethodEnum
+ */
+ public function useHttpMethod(): HttpMethodEnum
+ {
+ return HttpMethodEnum::PUT;
+ }
+
+ /**
+ * Endpoint url.
+ *
+ * @return string
+ */
+ public function endpointUrl(): string
+ {
+ return '/Media/Regeneratepackages';
+ }
+
+ /**
+ * Prepares HTTP request for this endpoint.
+ *
+ * @param PendingRequest $http
+ * @return void
+ */
+ public function prepareHttpRequest(PendingRequest $http): void
+ {
+ $data = [
+ 'id' => $this->id,
+ ];
+
+ if ($this->package_ids !== null) {
+ $data['package_id'] = $this->package_ids;
+ }
+
+ $http->withData($data);
+ }
+}
diff --git a/src/Endpoints/Media/Reset.php b/src/Endpoints/Media/Reset.php
new file mode 100644
index 0000000..0dcc0b4
--- /dev/null
+++ b/src/Endpoints/Media/Reset.php
@@ -0,0 +1,66 @@
+withData([
+ 'id' => $this->id,
+ ]);
+ }
+}
diff --git a/src/Endpoints/Media/Transcode.php b/src/Endpoints/Media/Transcode.php
new file mode 100644
index 0000000..a432229
--- /dev/null
+++ b/src/Endpoints/Media/Transcode.php
@@ -0,0 +1,66 @@
+withData([
+ 'id' => $this->id,
+ ]);
+ }
+}
diff --git a/src/Endpoints/Media/Trim.php b/src/Endpoints/Media/Trim.php
new file mode 100644
index 0000000..12835a4
--- /dev/null
+++ b/src/Endpoints/Media/Trim.php
@@ -0,0 +1,90 @@
+name = $name;
+
+ return $this;
+ }
+
+ /**
+ * Define which authentication methods are allowed to call this endpoint.
+ *
+ * @return AuthMethodEnum[]
+ */
+ public function allowedAuthMethods(): array
+ {
+ return [AuthMethodEnum::BEARER];
+ }
+
+ /**
+ * HTTP Method to use for request.
+ *
+ * @return HttpMethodEnum
+ */
+ public function useHttpMethod(): HttpMethodEnum
+ {
+ return HttpMethodEnum::PUT;
+ }
+
+ /**
+ * Endpoint url.
+ *
+ * @return string
+ */
+ public function endpointUrl(): string
+ {
+ return '/Media/Trim';
+ }
+
+ /**
+ * Prepares HTTP request for this endpoint.
+ *
+ * @param PendingRequest $http
+ * @return void
+ */
+ public function prepareHttpRequest(PendingRequest $http): void
+ {
+ $data = [
+ 'id' => $this->id,
+ 'start' => $this->start,
+ 'end' => $this->end,
+ 'type' => $this->type->value,
+ ];
+
+ if ($this->name !== null) {
+ $data['name'] = $this->name;
+ }
+
+ $http->withData($data);
+ }
+}
diff --git a/src/Endpoints/Media/Trim/TypeEnum.php b/src/Endpoints/Media/Trim/TypeEnum.php
new file mode 100644
index 0000000..8ba8c26
--- /dev/null
+++ b/src/Endpoints/Media/Trim/TypeEnum.php
@@ -0,0 +1,11 @@
+name = $name;
+
+ return $this;
+ }
+
+ public function description(?string $description): static
+ {
+ $this->description = $description;
+
+ return $this;
+ }
+
+ public function images(?Images $images): static
+ {
+ $this->images = $images;
+
+ return $this;
+ }
+
+ public function callback(?Callback $callback): static
+ {
+ $this->callback = $callback;
+
+ return $this;
+ }
+
+ /**
+ * HTTP Method to use for request.
+ *
+ * @return HttpMethodEnum
+ */
+ public function useHttpMethod(): HttpMethodEnum
+ {
+ return HttpMethodEnum::PUT;
+ }
+
+ /**
+ * Endpoint url.
+ *
+ * @return string
+ */
+ public function endpointUrl(): string
+ {
+ return '/Media/Update';
+ }
+
+ /**
+ * Prepares HTTP request for this endpoint.
+ *
+ * @param PendingRequest $http
+ * @return void
+ */
+ public function prepareHttpRequest(PendingRequest $http): void
+ {
+ $data = [
+ $this->by->getFieldName() => $this->by->getValue(),
+ ];
+
+ if ($this->name !== null) {
+ $data['name'] = $this->name;
+ }
+
+ if ($this->description !== null) {
+ $data['description'] = $this->description;
+ }
+
+ if ($this->images !== null) {
+ $images = $this->images->compileAsArray();
+
+ if (!empty($images)) {
+ $data['images'] = $images;
+ }
+ }
+
+ if ($this->callback !== null) {
+ $data['callback'] = $this->callback->compileAsArray();
+ }
+
+ $http->withData($data);
+ }
+}
diff --git a/src/Endpoints/Media/Update/ByAssetId.php b/src/Endpoints/Media/Update/ByAssetId.php
new file mode 100644
index 0000000..ac0267e
--- /dev/null
+++ b/src/Endpoints/Media/Update/ByAssetId.php
@@ -0,0 +1,22 @@
+asset_id;
+ }
+}
diff --git a/src/Endpoints/Media/Update/ByContract.php b/src/Endpoints/Media/Update/ByContract.php
new file mode 100644
index 0000000..e3d3516
--- /dev/null
+++ b/src/Endpoints/Media/Update/ByContract.php
@@ -0,0 +1,12 @@
+media_id;
+ }
+}
diff --git a/src/Endpoints/Media/Update/Images.php b/src/Endpoints/Media/Update/Images.php
new file mode 100644
index 0000000..ed476dc
--- /dev/null
+++ b/src/Endpoints/Media/Update/Images.php
@@ -0,0 +1,60 @@
+thumbnail = $imageBase64;
+
+ return $this;
+ }
+
+ public function placeholder(?string $imageBase64): static
+ {
+ $this->placeholder = $imageBase64;
+
+ return $this;
+ }
+
+ public function playbutton(?string $imageBase64): static
+ {
+ $this->playbutton = $imageBase64;
+
+ return $this;
+ }
+
+ public function logo(?string $imageBase64): static
+ {
+ $this->logo = $imageBase64;
+
+ return $this;
+ }
+}
diff --git a/src/Endpoints/Media/UpdateSubtitlesFromSource.php b/src/Endpoints/Media/UpdateSubtitlesFromSource.php
new file mode 100644
index 0000000..1e0f573
--- /dev/null
+++ b/src/Endpoints/Media/UpdateSubtitlesFromSource.php
@@ -0,0 +1,66 @@
+withData([
+ 'id' => $this->id,
+ ]);
+ }
+}
diff --git a/src/Endpoints/Token/Generate.php b/src/Endpoints/Token/Generate.php
new file mode 100644
index 0000000..e971b7b
--- /dev/null
+++ b/src/Endpoints/Token/Generate.php
@@ -0,0 +1,131 @@
+|null
+ */
+ protected ?array $allowed_countries = null;
+
+ protected ?string $allowed_ip = null;
+
+ protected string|int|CarbonInterface|null $expire_time = null;
+
+ protected ?int $subitem_id = null;
+
+ protected ?SubitemTypeEnum $subitem_type = null;
+
+ public function __construct(protected int $item_id, protected ItemTypeEnum $item_type)
+ {
+ }
+
+ /**
+ * @param array|null $countries
+ * @return $this
+ */
+ public function allowedCountries(?array $countries): static
+ {
+ $this->allowed_countries = $countries;
+
+ return $this;
+ }
+
+ public function allowedIp(?string $ip): static
+ {
+ $this->allowed_ip = $ip;
+
+ return $this;
+ }
+
+ public function expireTime(string|int|CarbonInterface|null $expire_time): static
+ {
+ $this->expire_time = $expire_time;
+
+ return $this;
+ }
+
+ public function subitemId(?int $subitem_id): static
+ {
+ $this->subitem_id = $subitem_id;
+
+ return $this;
+ }
+
+ public function subitemType(?SubitemTypeEnum $subitem_type): static
+ {
+ $this->subitem_type = $subitem_type;
+
+ return $this;
+ }
+
+ /**
+ * HTTP Method to use for request.
+ *
+ * @return HttpMethodEnum
+ */
+ public function useHttpMethod(): HttpMethodEnum
+ {
+ return HttpMethodEnum::GET;
+ }
+
+ /**
+ * Endpoint url.
+ *
+ * @return string
+ */
+ public function endpointUrl(): string
+ {
+ return '/Token/Generate';
+ }
+
+ /**
+ * Prepares HTTP request for this endpoint.
+ *
+ * @param PendingRequest $http
+ * @return void
+ */
+ public function prepareHttpRequest(PendingRequest $http): void
+ {
+ $query = [
+ 'item_id' => $this->item_id,
+ 'item_type' => $this->item_type->value,
+ ];
+
+ if ($this->allowed_countries !== null) {
+ $query['allowed_countries'] = implode(',', $this->allowed_countries);
+ }
+
+ if ($this->allowed_ip !== null) {
+ $query['allowed_ip'] = $this->allowed_ip;
+ }
+
+ if ($this->expire_time !== null) {
+ $query['expire_time'] = $this->expire_time instanceof CarbonInterface ? $this->expire_time->toDateTimeString() : $this->expire_time;
+ }
+
+ if ($this->subitem_id !== null) {
+ $query['subitem_id'] = $this->subitem_id;
+ }
+
+ if ($this->subitem_type !== null) {
+ $query['subitem_type'] = $this->subitem_type->value;
+ }
+
+ $http->withQuery($query);
+ }
+}
diff --git a/src/Endpoints/Token/Generate/ItemTypeEnum.php b/src/Endpoints/Token/Generate/ItemTypeEnum.php
new file mode 100644
index 0000000..a5584e1
--- /dev/null
+++ b/src/Endpoints/Token/Generate/ItemTypeEnum.php
@@ -0,0 +1,13 @@
+|null
+ */
+ protected ?array $return = null;
+
+ public function __construct()
+ {
+ }
+
+ /**
+ * @param array|null $return
+ * @return $this
+ */
+ public function return(?array $return): static
+ {
+ $this->return = $return;
+
+ return $this;
+ }
+
+ /**
+ * Define which authentication methods are allowed to call this endpoint.
+ *
+ * @return AuthMethodEnum[]
+ */
+ public function allowedAuthMethods(): array
+ {
+ return [AuthMethodEnum::BEARER];
+ }
+
+ /**
+ * HTTP Method to use for request.
+ *
+ * @return HttpMethodEnum
+ */
+ public function useHttpMethod(): HttpMethodEnum
+ {
+ return HttpMethodEnum::GET;
+ }
+
+ /**
+ * Endpoint url.
+ *
+ * @return string
+ */
+ public function endpointUrl(): string
+ {
+ return '/User/Get';
+ }
+
+ /**
+ * Prepares HTTP request for this endpoint.
+ *
+ * @param PendingRequest $http
+ * @return void
+ */
+ public function prepareHttpRequest(PendingRequest $http): void
+ {
+ $query = [];
+
+ if ($this->return !== null) {
+ $query['return'] = $this->return;
+ }
+
+ $http->withQuery($query);
+ }
+}
diff --git a/src/Endpoints/User/Login.php b/src/Endpoints/User/Login.php
new file mode 100644
index 0000000..621c020
--- /dev/null
+++ b/src/Endpoints/User/Login.php
@@ -0,0 +1,102 @@
+|null
+ */
+ protected ?array $return = null;
+
+ public function __construct(protected string $email, protected string $password)
+ {
+ }
+
+ public function twoFaCode(?string $code): static
+ {
+ $this->twoFaCode = $code;
+
+ return $this;
+ }
+
+ /**
+ * @param array|null $return
+ * @return $this
+ */
+ public function return(?array $return): static
+ {
+ $this->return = $return;
+
+ return $this;
+ }
+
+ /**
+ * Define which authentication methods are allowed to call this endpoint.
+ *
+ * @return AuthMethodEnum[]
+ */
+ public function allowedAuthMethods(): array
+ {
+ return [AuthMethodEnum::NULL];
+ }
+
+ /**
+ * HTTP Method to use for request.
+ *
+ * @return HttpMethodEnum
+ */
+ public function useHttpMethod(): HttpMethodEnum
+ {
+ return HttpMethodEnum::POST;
+ }
+
+ /**
+ * Endpoint url.
+ *
+ * @return string
+ */
+ public function endpointUrl(): string
+ {
+ return '/User/Login';
+ }
+
+ /**
+ * Prepares HTTP request for this endpoint.
+ *
+ * @param PendingRequest $http
+ * @return void
+ */
+ public function prepareHttpRequest(PendingRequest $http): void
+ {
+ $data = [
+ 'email' => $this->email,
+ 'password' => $this->password,
+ ];
+
+ if ($this->twoFaCode !== null) {
+ $data['mfa'] = [
+ '2fa_code' => $this->twoFaCode,
+ ];
+ }
+
+ if ($this->return !== null) {
+ $data['return'] = $this->return;
+ }
+
+ $http->withData($data);
+ }
+}
diff --git a/src/Endpoints/User/Logout.php b/src/Endpoints/User/Logout.php
new file mode 100644
index 0000000..4d7d868
--- /dev/null
+++ b/src/Endpoints/User/Logout.php
@@ -0,0 +1,52 @@
+
+ */
+ private array $tmsAuthQueryParams = [];
+
+ /**
+ * @var array
+ */
+ private array $tmsQuery = [];
+
+ /**
+ * @var array
+ */
+ private array $tmsData = [];
+
+ /**
+ * Specifies HTTP method to use.
+ *
+ * @param HttpMethodEnum $httpMethod
+ * @return $this
+ */
+ public function useMethod(HttpMethodEnum $httpMethod): static
+ {
+ $this->tmsHttpMethod = $httpMethod;
+
+ return $this;
+ }
+
+ /**
+ * Endpoint to call, e.g. "/token/generate".
+ *
+ * @param string $endpoint
+ * @return $this
+ */
+ public function setEndpoint(string $endpoint): static
+ {
+ $this->tmsEndpoint = $endpoint;
+
+ return $this;
+ }
+
+ /**
+ * Specify authentication query parameters. Should only be used from AuthMethod implementation.
+ *
+ * @param array $query
+ * @return $this
+ */
+ public function setAuthQueryParams(array $query): static
+ {
+ $this->tmsAuthQueryParams = $query;
+
+ return $this;
+ }
+
+ /**
+ * Add optional query parameters to request.
+ *
+ * @param array $query
+ * @return $this
+ */
+ public function withQuery(array $query): static
+ {
+ $this->tmsQuery = $query;
+
+ return $this;
+ }
+
+ /**
+ * Data to POST/PUT/DELETE.
+ *
+ * @param array $data
+ * @return $this
+ */
+ public function withData(array $data): static
+ {
+ $this->tmsData = $data;
+
+ return $this;
+ }
+
+ /**
+ * Retrieve HTTP method to use.
+ *
+ * @return HttpMethodEnum
+ */
+ public function getHttpMethod(): HttpMethodEnum
+ {
+ return $this->tmsHttpMethod;
+ }
+
+ /**
+ * Retrieve Endpoint to call, e.g. "/token/generate"
+ *
+ * @return string
+ */
+ public function getEndpoint(): string
+ {
+ return $this->tmsEndpoint;
+ }
+
+ /**
+ * Compiles and returns merged query params.
+ *
+ * @return array
+ */
+ public function getCompiledQuery(): array
+ {
+ return array_merge($this->tmsAuthQueryParams, $this->tmsQuery);
+ }
+
+ /**
+ * Retrieve data to POST/PUT/DELETE.
+ *
+ * @return array
+ */
+ public function getData(): array
+ {
+ return $this->tmsData;
+ }
+
+ /**
+ * Get body format used for this request.
+ *
+ * @codeCoverageIgnore
+ * @return string
+ */
+ public function getBodyFormat(): string
+ {
+ return $this->bodyFormat;
+ }
+}
diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php
new file mode 100644
index 0000000..c3d95b3
--- /dev/null
+++ b/src/ServiceProvider.php
@@ -0,0 +1,44 @@
+registerPublishing();
+ }
+
+ /**
+ * Register any application services.
+ */
+ public function register(): void
+ {
+ $this->mergeConfigFrom(__DIR__ . '/../config/tms-api.php', 'tms-api');
+
+ $this->app->singleton(TmsApiContract::class, TmsApi::class);
+ $this->app->singleton(ClientContract::class, Client::class);
+ }
+
+ /**
+ * Register the package's publishable resources.
+ */
+ private function registerPublishing(): void
+ {
+ if ($this->app->runningInConsole()) {
+ $this->publishes([
+ __DIR__ . '/../config/tms-api.php' => config_path('tms-api.php'),
+ ], 'tms-api-config');
+ }
+ }
+}
diff --git a/src/Support/Facades/TmsApi.php b/src/Support/Facades/TmsApi.php
new file mode 100644
index 0000000..5cab0d1
--- /dev/null
+++ b/src/Support/Facades/TmsApi.php
@@ -0,0 +1,45 @@
+dispatcher = $dispatcher;
+ }
+
+ /**
+ * @param string $method
+ * @param array $args
+ * @return mixed
+ */
+ public function __call(string $method, array $args): mixed
+ {
+ return $this->dispatcher->$method(...$args);
+ }
+}
diff --git a/src/TmsApi.php b/src/TmsApi.php
new file mode 100644
index 0000000..d127675
--- /dev/null
+++ b/src/TmsApi.php
@@ -0,0 +1,110 @@
+
+ */
+ protected array $clients = [];
+
+ public function __construct(protected Application $app)
+ {
+ }
+
+ /**
+ * Get instance of a client.
+ *
+ * @param string $name
+ * @return ClientContract
+ */
+ public function client(string $name): ClientContract
+ {
+ if (!isset($this->clients[$name])) {
+ $clientConfig = Config::get('tms-api.clients.' . $name);
+
+ if (!Config::has('tms-api.clients.' . $name) || !is_array($clientConfig)) {
+ throw new InvalidTmsApiClientException('TMS Api client could\'nt be found.');
+ }
+
+ if (!Arr::has($clientConfig, 'auth.username') || !Arr::has($clientConfig, 'auth.password')) {
+ throw new InvalidTmsApiClientException('TMS Api client auth credentials are not provided.');
+ }
+
+ $basicAuth = new BasicAuthMethod($clientConfig['auth']['username'], $clientConfig['auth']['password']);
+
+ $this->clients[$name] = $this->makeClient($basicAuth);
+
+ if (isset($clientConfig['http'])) {
+ if (isset($clientConfig['http']['timeout'])) {
+ $this->clients[$name]->timeout((int)$clientConfig['http']['timeout']);
+ }
+
+ if (isset($clientConfig['http']['connect_timeout'])) {
+ $this->clients[$name]->connectTimeout((int)$clientConfig['http']['connect_timeout']);
+ }
+ }
+ }
+
+ return $this->clients[$name];
+ }
+
+ /**
+ * Get client for authentication by user login to retrieve Bearer token.
+ *
+ * @return ClientContract
+ */
+ public function nullClient(): ClientContract
+ {
+ if (isset($this->clients['null'])) {
+ return $this->clients['null'];
+ } else {
+ return $this->createClient('null', new NullAuthMethod());
+ }
+ }
+
+ /**
+ * Create a new client dynamically.
+ *
+ * @param string $name
+ * @param AuthMethodContract $auth
+ * @return ClientContract
+ */
+ public function createClient(string $name, AuthMethodContract $auth): ClientContract
+ {
+ $this->clients[$name] = $this->makeClient($auth);
+
+ return $this->clients[$name];
+ }
+
+ /**
+ * Get list of clients.
+ *
+ * @return array
+ */
+ public function getClients(): array
+ {
+ return $this->clients;
+ }
+
+ protected function makeClient(AuthMethodContract $auth): ClientContract
+ {
+ /** @var ClientContract $client */
+ $client = $this->app->makeWith(ClientContract::class, ['auth' => $auth]);
+
+ return $client;
+ }
+}
diff --git a/tests/Endpoints/Media/CancelTranscodeTest.php b/tests/Endpoints/Media/CancelTranscodeTest.php
new file mode 100644
index 0000000..78ce9e6
--- /dev/null
+++ b/tests/Endpoints/Media/CancelTranscodeTest.php
@@ -0,0 +1,16 @@
+makeBearerAuthEndpointTest(new CancelTranscode(123), [], ['id' => 123]);
+ }
+}
diff --git a/tests/Endpoints/Media/CloneMediaTest.php b/tests/Endpoints/Media/CloneMediaTest.php
new file mode 100644
index 0000000..71a475d
--- /dev/null
+++ b/tests/Endpoints/Media/CloneMediaTest.php
@@ -0,0 +1,24 @@
+makeBearerAuthEndpointTest(new CloneMedia(123, 'River_Daugava'), [], ['id' => 123, 'asset_id' => 'River_Daugava']);
+ }
+
+ public function test_with_name(): void
+ {
+ $endpoint = new CloneMedia(123, 'River_Daugava');
+ $endpoint->name('River "Daugava"');
+
+ $this->makeBearerAuthEndpointTest($endpoint, [], ['id' => 123, 'asset_id' => 'River_Daugava', 'name' => 'River "Daugava"']);
+ }
+}
diff --git a/tests/Endpoints/Media/DeleteTest.php b/tests/Endpoints/Media/DeleteTest.php
new file mode 100644
index 0000000..6c0dcc0
--- /dev/null
+++ b/tests/Endpoints/Media/DeleteTest.php
@@ -0,0 +1,21 @@
+makeBasicAuthEndpointTest(new Delete(123), [], ['id' => [123]]);
+ }
+
+ public function test_it_accepts_multiple_ids(): void
+ {
+ $this->makeBasicAuthEndpointTest(new Delete([123, 456]), [], ['id' => [123, 456]]);
+ }
+}
diff --git a/tests/Endpoints/Media/GenerateImageTest.php b/tests/Endpoints/Media/GenerateImageTest.php
new file mode 100644
index 0000000..a467d53
--- /dev/null
+++ b/tests/Endpoints/Media/GenerateImageTest.php
@@ -0,0 +1,54 @@
+makeBearerAuthEndpointTest(new GenerateImage(123), [], [
+ 'id' => 123,
+ ]);
+ }
+
+ public function test_with_media_file_id(): void
+ {
+ $endpoint = new GenerateImage(123);
+
+ $endpoint->mediaFileId(1902);
+
+ $this->makeBearerAuthEndpointTest($endpoint, [], [
+ 'id' => 123,
+ 'media_file_id' => 1902,
+ ]);
+ }
+
+ public function test_with_thumbnail(): void
+ {
+ $endpoint = new GenerateImage(123);
+
+ $endpoint->thumbnail('01:20:39');
+
+ $this->makeBearerAuthEndpointTest($endpoint, [], [
+ 'id' => 123,
+ 'thumbnail' => '01:20:39',
+ ]);
+ }
+
+ public function test_with_placeholder(): void
+ {
+ $endpoint = new GenerateImage(123);
+
+ $endpoint->placeholder('00:05:30');
+
+ $this->makeBearerAuthEndpointTest($endpoint, [], [
+ 'id' => 123,
+ 'placeholder' => '00:05:30',
+ ]);
+ }
+}
diff --git a/tests/Endpoints/Media/Manifest/CreateTest.php b/tests/Endpoints/Media/Manifest/CreateTest.php
new file mode 100644
index 0000000..6e10a09
--- /dev/null
+++ b/tests/Endpoints/Media/Manifest/CreateTest.php
@@ -0,0 +1,21 @@
+makeBasicAuthEndpointTest(new Delete(123), [], ['id' => 123]);
+ }
+}
diff --git a/tests/Endpoints/Media/Manifest/ManifestCreateAndUpdateTestCase.php b/tests/Endpoints/Media/Manifest/ManifestCreateAndUpdateTestCase.php
new file mode 100644
index 0000000..3af13cb
--- /dev/null
+++ b/tests/Endpoints/Media/Manifest/ManifestCreateAndUpdateTestCase.php
@@ -0,0 +1,99 @@
+makeBasicAuthEndpointTest($this->getEndpoint(), [], [$this->getIdFieldName() => 123]);
+ }
+
+ public function test_with_name(): void
+ {
+ $endpoint = $this->getEndpoint();
+
+ $endpoint->name('test');
+
+ $this->makeBasicAuthEndpointTest($endpoint, [], [
+ $this->getIdFieldName() => 123,
+ 'name' => 'test',
+ ]);
+ }
+
+ public function test_with_default(): void
+ {
+ $endpoint = $this->getEndpoint();
+
+ $endpoint->default(true);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [], [
+ $this->getIdFieldName() => 123,
+ 'default' => 1,
+ ]);
+
+ $endpoint->default(false);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [], [
+ $this->getIdFieldName() => 123,
+ 'default' => 0,
+ ]);
+ }
+
+ public function test_with_startAt(): void
+ {
+ $endpoint = $this->getEndpoint();
+
+ $endpoint->startAt(1000);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [], [
+ $this->getIdFieldName() => 123,
+ 'start_at' => 1000,
+ ]);
+ }
+
+ public function test_with_endAt(): void
+ {
+ $endpoint = $this->getEndpoint();
+
+ $endpoint->endAt(60000);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [], [
+ $this->getIdFieldName() => 123,
+ 'end_at' => 60000,
+ ]);
+ }
+
+ public function test_with_files(): void
+ {
+ $endpoint = $this->getEndpoint();
+
+ $endpoint->files([1, 2]);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [], [
+ $this->getIdFieldName() => 123,
+ 'files' => [1, 2],
+ ]);
+ }
+
+ public function test_with_packageId(): void
+ {
+ $endpoint = $this->getEndpoint();
+
+ $endpoint->packageId(1052);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [], [
+ $this->getIdFieldName() => 123,
+ 'package_id' => 1052,
+ ]);
+ }
+
+ abstract protected function getIdFieldName(): string;
+
+ abstract protected function getEndpoint(): EndpointContract;
+}
diff --git a/tests/Endpoints/Media/Manifest/ManifestListTest.php b/tests/Endpoints/Media/Manifest/ManifestListTest.php
new file mode 100644
index 0000000..d375d99
--- /dev/null
+++ b/tests/Endpoints/Media/Manifest/ManifestListTest.php
@@ -0,0 +1,84 @@
+makeBasicAuthEndpointTest(new ManifestList());
+ }
+
+ public function test_with_ids(): void
+ {
+ $endpoint = new ManifestList();
+
+ $endpoint->ids([1, 2]);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'id' => [1, 2],
+ ]);
+ }
+
+ public function test_with_limit(): void
+ {
+ $endpoint = new ManifestList();
+
+ $endpoint->limit(5);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'limit' => 5,
+ ]);
+ }
+
+ public function test_with_mediaIds(): void
+ {
+ $endpoint = new ManifestList();
+
+ $endpoint->mediaIds([123, 345]);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'media_id' => [123, 345],
+ ]);
+ }
+
+ public function test_with_offset(): void
+ {
+ $endpoint = new ManifestList();
+
+ $endpoint->offset(15);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'offset' => 15,
+ ]);
+ }
+
+ public function test_with_orderBy(): void
+ {
+ $endpoint = new ManifestList();
+
+ $endpoint->orderBy(OrderByEnum::MEDIA_ID);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'order_by' => OrderByEnum::MEDIA_ID->value,
+ ]);
+ }
+
+ public function test_with_orderDir(): void
+ {
+ $endpoint = new ManifestList();
+
+ $endpoint->orderDir(OrderDirectionEnum::ASC);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'order_dir' => OrderDirectionEnum::ASC->value,
+ ]);
+ }
+}
diff --git a/tests/Endpoints/Media/Manifest/UpdateTest.php b/tests/Endpoints/Media/Manifest/UpdateTest.php
new file mode 100644
index 0000000..6445115
--- /dev/null
+++ b/tests/Endpoints/Media/Manifest/UpdateTest.php
@@ -0,0 +1,21 @@
+makeBasicAuthEndpointTest(new MediaList());
+ }
+
+ public function test_with_ids(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->ids([1, 2]);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'id' => [1, 2],
+ ]);
+ }
+
+ public function test_with_assetIds(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->assetIds(['99_abc', '10_def']);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'asset_id' => ['99_abc', '10_def'],
+ ]);
+ }
+
+
+ public function test_with_categoryIds(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->categoryIds([1, 2]);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'cat_id' => [1, 2],
+ ]);
+ }
+
+ public function test_with_created_from(): void
+ {
+ $endpoint = new MediaList();
+
+ // unix
+ $endpoint->createdFrom(1674135633);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'created_from' => 1674135633,
+ ]);
+
+ // string
+ $endpoint->createdFrom('2023-01-19 15:41:43');
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'created_from' => '2023-01-19 15:41:43',
+ ]);
+
+ // Carbon
+ $endpoint->createdFrom(Carbon::create(2023, 1, 19, 15, 41, 43));
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'created_from' => '2023-01-19 15:41:43',
+ ]);
+ }
+
+ public function test_with_created_to(): void
+ {
+ $endpoint = new MediaList();
+
+ // unix
+ $endpoint->createdTo(1674135633);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'created_to' => 1674135633,
+ ]);
+
+ // string
+ $endpoint->createdTo('2023-01-19 15:41:43');
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'created_to' => '2023-01-19 15:41:43',
+ ]);
+
+ // Carbon
+ $endpoint->createdTo(Carbon::create(2023, 1, 19, 15, 41, 43));
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'created_to' => '2023-01-19 15:41:43',
+ ]);
+ }
+
+ public function test_with_updated_from(): void
+ {
+ $endpoint = new MediaList();
+
+ // unix
+ $endpoint->updatedFrom(1674135633);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'updated_from' => 1674135633,
+ ]);
+
+ // string
+ $endpoint->updatedFrom('2023-01-19 15:41:43');
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'updated_from' => '2023-01-19 15:41:43',
+ ]);
+
+ // Carbon
+ $endpoint->updatedFrom(Carbon::create(2023, 1, 19, 15, 41, 43));
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'updated_from' => '2023-01-19 15:41:43',
+ ]);
+ }
+
+ public function test_with_updated_to(): void
+ {
+ $endpoint = new MediaList();
+
+ // unix
+ $endpoint->updatedTo(1674135633);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'updated_to' => 1674135633,
+ ]);
+
+ // string
+ $endpoint->updatedTo('2023-01-19 15:41:43');
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'updated_to' => '2023-01-19 15:41:43',
+ ]);
+
+ // Carbon
+ $endpoint->updatedTo(Carbon::create(2023, 1, 19, 15, 41, 43));
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'updated_to' => '2023-01-19 15:41:43',
+ ]);
+ }
+
+ public function test_with_published(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->published(true);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'published' => 1,
+ ]);
+
+ $endpoint->published(false);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'published' => 0,
+ ]);
+ }
+
+ public function test_with_publisherStatus(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->publisherStatus(MediaList\PublisherStatusEnum::SCHEDULED);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'publisher_status' => MediaList\PublisherStatusEnum::SCHEDULED->value,
+ ]);
+ }
+
+ public function test_with_onlyAvailable(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->onlyAvailable(true);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'only_available' => 1,
+ ]);
+
+ $endpoint->onlyAvailable(false);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'only_available' => 0,
+ ]);
+ }
+
+ public function test_with_search(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->search('lorem ipsum');
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'search' => 'lorem ipsum',
+ ]);
+ }
+
+ public function test_with_status(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->status(MediaList\StatusEnum::APPROVED);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'status' => [MediaList\StatusEnum::APPROVED->value],
+ ]);
+
+ $endpoint->status([MediaList\StatusEnum::INGESTED, MediaList\StatusEnum::NEW]);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'status' => [MediaList\StatusEnum::INGESTED->value, MediaList\StatusEnum::NEW->value],
+ ]);
+ }
+
+ public function test_with_tags(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->tags(['lorem', 'ipsum']);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'tags' => ['lorem', 'ipsum'],
+ ]);
+ }
+
+ public function test_with_limit(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->limit(5);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'limit' => 5,
+ ]);
+ }
+
+ public function test_with_limit_out_of_bounds_exception(): void
+ {
+ $endpoint = new MediaList();
+
+ $this->expectException(\OutOfBoundsException::class);
+ $this->expectExceptionMessage('Limit must be between 1 and 50.');
+
+ $endpoint->limit(1000);
+ }
+
+ public function test_with_offset(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->offset(5);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'offset' => 5,
+ ]);
+ }
+
+ public function test_with_orderBy(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->orderBy(MediaList\OrderByEnum::CREATED_AT);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'order_by' => MediaList\OrderByEnum::CREATED_AT->value,
+ ]);
+ }
+
+ public function test_with_orderDir(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->orderDir(OrderDirectionEnum::ASC);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'order_dir' => OrderDirectionEnum::ASC->value,
+ ]);
+ }
+
+ public function test_with_imagesFallback(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->imagesFallback(true);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'images_fallback' => 1,
+ ]);
+
+ $endpoint->imagesFallback(false);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'images_fallback' => 0,
+ ]);
+ }
+
+ public function test_with_return(): void
+ {
+ $endpoint = new MediaList();
+
+ $endpoint->return(['actions', 'tech_status']);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'return' => ['actions', 'tech_status'],
+ ]);
+ }
+}
diff --git a/tests/Endpoints/Media/RegeneratePackagesTest.php b/tests/Endpoints/Media/RegeneratePackagesTest.php
new file mode 100644
index 0000000..5b90074
--- /dev/null
+++ b/tests/Endpoints/Media/RegeneratePackagesTest.php
@@ -0,0 +1,25 @@
+makeBearerAuthEndpointTest(new RegeneratePackages(123), [], ['id' => 123]);
+ }
+
+ public function test_with_packageId(): void
+ {
+ $endpoint = new RegeneratePackages(123);
+
+ $endpoint->packageId([5, 7]);
+
+ $this->makeBearerAuthEndpointTest($endpoint, [], ['id' => 123, 'package_id' => [5, 7]]);
+ }
+}
diff --git a/tests/Endpoints/Media/ResetTest.php b/tests/Endpoints/Media/ResetTest.php
new file mode 100644
index 0000000..f434dfd
--- /dev/null
+++ b/tests/Endpoints/Media/ResetTest.php
@@ -0,0 +1,16 @@
+makeBearerAuthEndpointTest(new Reset(123), [], ['id' => 123]);
+ }
+}
diff --git a/tests/Endpoints/Media/TranscodeTest.php b/tests/Endpoints/Media/TranscodeTest.php
new file mode 100644
index 0000000..772283a
--- /dev/null
+++ b/tests/Endpoints/Media/TranscodeTest.php
@@ -0,0 +1,16 @@
+makeBearerAuthEndpointTest(new Transcode(123), [], ['id' => 123]);
+ }
+}
diff --git a/tests/Endpoints/Media/TrimTest.php b/tests/Endpoints/Media/TrimTest.php
new file mode 100644
index 0000000..ef4749b
--- /dev/null
+++ b/tests/Endpoints/Media/TrimTest.php
@@ -0,0 +1,36 @@
+makeBearerAuthEndpointTest(new Trim(123, '00:00:00', '00:10:12', Trim\TypeEnum::EXISTING), [], [
+ 'id' => 123,
+ 'start' => '00:00:00',
+ 'end' => '00:10:12',
+ 'type' => Trim\TypeEnum::EXISTING->value,
+ ]);
+ }
+
+ public function test_with_name(): void
+ {
+ $endpoint = new Trim(123, '00:00:00', '00:10:12', Trim\TypeEnum::EXISTING);
+
+ $endpoint->name('Lorem');
+
+ $this->makeBearerAuthEndpointTest($endpoint, [], [
+ 'id' => 123,
+ 'start' => '00:00:00',
+ 'end' => '00:10:12',
+ 'type' => Trim\TypeEnum::EXISTING->value,
+ 'name' => 'Lorem',
+ ]);
+ }
+}
diff --git a/tests/Endpoints/Media/Update/ImagesTest.php b/tests/Endpoints/Media/Update/ImagesTest.php
new file mode 100644
index 0000000..630c393
--- /dev/null
+++ b/tests/Endpoints/Media/Update/ImagesTest.php
@@ -0,0 +1,28 @@
+thumbnail('aW1hZ2ViYXNlNjRfMQ==')
+ ->placeholder('aW1hZ2ViYXNlNjRfMg==')
+ ->playbutton('aW1hZ2ViYXNlNjRfMw==')
+ ->logo('aW1hZ2ViYXNlNjRfNA==');
+
+ $this->assertEquals([
+ 'thumbnail' => 'aW1hZ2ViYXNlNjRfMQ==',
+ 'placeholder' => 'aW1hZ2ViYXNlNjRfMg==',
+ 'playbutton' => 'aW1hZ2ViYXNlNjRfMw==',
+ 'logo' => 'aW1hZ2ViYXNlNjRfNA==',
+ ], $images->compileAsArray());
+ }
+}
diff --git a/tests/Endpoints/Media/UpdateSubtitlesFromSourceTest.php b/tests/Endpoints/Media/UpdateSubtitlesFromSourceTest.php
new file mode 100644
index 0000000..5774c31
--- /dev/null
+++ b/tests/Endpoints/Media/UpdateSubtitlesFromSourceTest.php
@@ -0,0 +1,16 @@
+makeBearerAuthEndpointTest(new UpdateSubtitlesFromSource(123), [], ['id' => 123]);
+ }
+}
diff --git a/tests/Endpoints/Media/UpdateTest.php b/tests/Endpoints/Media/UpdateTest.php
new file mode 100644
index 0000000..8709e32
--- /dev/null
+++ b/tests/Endpoints/Media/UpdateTest.php
@@ -0,0 +1,88 @@
+makeBasicAuthEndpointTest(new Update(new ByMediaId(1234)), [], [
+ 'id' => 1234,
+ ]);
+
+ $this->makeBasicAuthEndpointTest(new Update(new ByAssetId('99_asset')), [], [
+ 'asset_id' => '99_asset',
+ ]);
+ }
+
+ public function test_with_name(): void
+ {
+ $endpoint = new Update(new ByMediaId(1234));
+
+ $endpoint->name('Lorem');
+
+ $this->makeBasicAuthEndpointTest($endpoint, [], [
+ 'id' => 1234,
+ 'name' => 'Lorem',
+ ]);
+ }
+
+ public function test_with_description(): void
+ {
+ $endpoint = new Update(new ByMediaId(1234));
+
+ $endpoint->description('Lorem Ipsum is simply dummy text');
+
+ $this->makeBasicAuthEndpointTest($endpoint, [], [
+ 'id' => 1234,
+ 'description' => 'Lorem Ipsum is simply dummy text',
+ ]);
+ }
+
+ public function test_with_images(): void
+ {
+ $endpoint = new Update(new ByMediaId(1234));
+
+ $images = new Update\Images();
+ $images->thumbnail('aW1hZ2ViYXNlNjRfMQ==');
+
+ $endpoint->images($images);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [], [
+ 'id' => 1234,
+ 'images' => [
+ 'thumbnail' => 'aW1hZ2ViYXNlNjRfMQ==',
+ ],
+ ]);
+
+ $endpoint->images(new Update\Images());
+
+ $this->makeBasicAuthEndpointTest($endpoint, [], [
+ 'id' => 1234,
+ ]);
+ }
+
+ public function test_with_callback(): void
+ {
+ $endpoint = new Update(new ByMediaId(1234));
+
+ $endpoint->callback(new Callback('https://mysite.com', CallbackHttpMethodEnum::POST));
+
+ $this->makeBasicAuthEndpointTest($endpoint, [], [
+ 'id' => 1234,
+ 'callback' => [
+ 'url' => 'https://mysite.com',
+ 'method' => CallbackHttpMethodEnum::POST->value,
+ ],
+ ]);
+ }
+}
diff --git a/tests/Endpoints/TestCase.php b/tests/Endpoints/TestCase.php
new file mode 100644
index 0000000..6cb96bc
--- /dev/null
+++ b/tests/Endpoints/TestCase.php
@@ -0,0 +1,72 @@
+makeEndpointTestWithCilent($client, $endpoint, $query, $body, $fakeResponse);
+ }
+
+ protected function makeBearerAuthEndpointTest(EndpointContract $endpoint, array $query = [], array|string|null $body = null, ?array $fakeResponse = null): Response
+ {
+ $client = new Client(new BearerAuthMethod('abc'));
+
+ return $this->makeEndpointTestWithCilent($client, $endpoint, $query, $body, $fakeResponse);
+ }
+
+ protected function makeApiKeyAuthEndpointTest(EndpointContract $endpoint, array $query = [], array|string|null $body = null, ?array $fakeResponse = null): Response
+ {
+ $client = new Client(new ApiKeyAuthMethod('abc'));
+
+ return $this->makeEndpointTestWithCilent($client, $endpoint, $query, $body, $fakeResponse);
+ }
+
+ protected function makeNullAuthEndpointTest(EndpointContract $endpoint, array $query = [], array|string|null $body = null, ?array $fakeResponse = null): Response
+ {
+ $client = new Client(new NullAuthMethod());
+
+ return $this->makeEndpointTestWithCilent($client, $endpoint, $query, $body, $fakeResponse);
+ }
+
+ protected function makeEndpointTestWithCilent(ClientContract $client, EndpointContract $endpoint, array $query = [], array|string|null $body = null, ?array $fakeResponse = null): Response
+ {
+ $fakeUrl = 'api.cloudycdn.services/api/v5' . $endpoint->endpointUrl();
+
+ if ($query) {
+ $fakeUrl .= '?' . http_build_query($query, '', null, PHP_QUERY_RFC3986);
+ }
+
+ $fakeResponse = $fakeResponse !== null ? $fakeResponse : ['msg' => '', 'code' => 0];
+
+ $factory = $client->buildHttpFactory();
+ $factory->preventStrayRequests();
+ $factory->fake([
+ $fakeUrl => $factory->response($fakeResponse)
+ ]);
+
+ $response = $client->run($endpoint);
+
+ if ($body !== null) {
+ $this->assertEquals(is_array($body) ? json_encode($body) : $body, (string)$response->transferStats->getRequest()->getBody());
+ }
+
+ $this->assertEquals($fakeResponse, $response->json());
+
+ return $response;
+ }
+}
diff --git a/tests/Endpoints/Token/GenerateTest.php b/tests/Endpoints/Token/GenerateTest.php
new file mode 100644
index 0000000..dd9bc47
--- /dev/null
+++ b/tests/Endpoints/Token/GenerateTest.php
@@ -0,0 +1,105 @@
+makeBasicAuthEndpointTest(new Generate(1, Generate\ItemTypeEnum::MEDIA), [
+ 'item_id' => 1,
+ 'item_type' => Generate\ItemTypeEnum::MEDIA->value,
+ ]);
+ }
+
+ public function test_with_allowedCountries(): void
+ {
+ $endpoint = new Generate(1, Generate\ItemTypeEnum::MEDIA);
+
+ $endpoint->allowedCountries(['lv', 'lt']);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'item_id' => 1,
+ 'item_type' => Generate\ItemTypeEnum::MEDIA->value,
+ 'allowed_countries' => 'lv,lt',
+ ]);
+ }
+
+ public function test_with_allowedIp(): void
+ {
+ $endpoint = new Generate(1, Generate\ItemTypeEnum::MEDIA);
+
+ $endpoint->allowedIp('85.1.1.1');
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'item_id' => 1,
+ 'item_type' => Generate\ItemTypeEnum::MEDIA->value,
+ 'allowed_ip' => '85.1.1.1',
+ ]);
+ }
+
+ public function test_with_expireTime(): void
+ {
+ $endpoint = new Generate(1, Generate\ItemTypeEnum::MEDIA);
+
+ // unix
+ $endpoint->expireTime(1674135633);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'item_id' => 1,
+ 'item_type' => Generate\ItemTypeEnum::MEDIA->value,
+ 'expire_time' => 1674135633,
+ ]);
+
+ // string
+ $endpoint->expireTime('2023-01-19 15:41:43');
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'item_id' => 1,
+ 'item_type' => Generate\ItemTypeEnum::MEDIA->value,
+ 'expire_time' => '2023-01-19 15:41:43',
+ ]);
+
+ // carbon
+ $endpoint->expireTime(Carbon::create(2023, 1, 19, 15, 41, 43));
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'item_id' => 1,
+ 'item_type' => Generate\ItemTypeEnum::MEDIA->value,
+ 'expire_time' => '2023-01-19 15:41:43',
+ ]);
+ }
+
+ public function test_with_subitemId(): void
+ {
+ $endpoint = new Generate(1, Generate\ItemTypeEnum::MEDIA);
+
+ $endpoint->subitemId(830);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'item_id' => 1,
+ 'item_type' => Generate\ItemTypeEnum::MEDIA->value,
+ 'subitem_id' => 830,
+ ]);
+ }
+
+ public function test_with_subitemType(): void
+ {
+ $endpoint = new Generate(1, Generate\ItemTypeEnum::MEDIA);
+
+ $endpoint->subitemType(SubitemTypeEnum::PLAYBACK_HLS);
+
+ $this->makeBasicAuthEndpointTest($endpoint, [
+ 'item_id' => 1,
+ 'item_type' => Generate\ItemTypeEnum::MEDIA->value,
+ 'subitem_type' => SubitemTypeEnum::PLAYBACK_HLS->value,
+ ]);
+ }
+}
diff --git a/tests/Endpoints/User/GetTest.php b/tests/Endpoints/User/GetTest.php
new file mode 100644
index 0000000..f40b4d3
--- /dev/null
+++ b/tests/Endpoints/User/GetTest.php
@@ -0,0 +1,27 @@
+makeBearerAuthEndpointTest(new Get());
+ }
+
+ public function test_with_return(): void
+ {
+ $endpoint = new Get();
+
+ $endpoint->return(['client.limits']);
+
+ $this->makeBearerAuthEndpointTest($endpoint, [
+ 'return' => ['client.limits']
+ ]);
+ }
+}
diff --git a/tests/Endpoints/User/LoginTest.php b/tests/Endpoints/User/LoginTest.php
new file mode 100644
index 0000000..791aaf3
--- /dev/null
+++ b/tests/Endpoints/User/LoginTest.php
@@ -0,0 +1,47 @@
+makeNullAuthEndpointTest(new Login('my@email.com', 'pass'), [], [
+ 'email' => 'my@email.com',
+ 'password' => 'pass'
+ ]);
+ }
+
+ public function test_with_twoFaCode(): void
+ {
+ $endpoint = new Login('my@email.com', 'pass');
+
+ $endpoint->twoFaCode('564389');
+
+ $this->makeNullAuthEndpointTest($endpoint, [], [
+ 'email' => 'my@email.com',
+ 'password' => 'pass',
+ 'mfa' => [
+ '2fa_code' => '564389',
+ ],
+ ]);
+ }
+
+ public function test_with_return(): void
+ {
+ $endpoint = new Login('my@email.com', 'pass');
+
+ $endpoint->return(['client.limits']);
+
+ $this->makeNullAuthEndpointTest($endpoint, [], [
+ 'email' => 'my@email.com',
+ 'password' => 'pass',
+ 'return' => ['client.limits'],
+ ]);
+ }
+}
diff --git a/tests/Endpoints/User/LogoutTest.php b/tests/Endpoints/User/LogoutTest.php
new file mode 100644
index 0000000..c0f275b
--- /dev/null
+++ b/tests/Endpoints/User/LogoutTest.php
@@ -0,0 +1,16 @@
+makeBearerAuthEndpointTest(new Logout(), [], '');
+ }
+}
diff --git a/tests/Support/GetTestEndpoint.php b/tests/Support/GetTestEndpoint.php
new file mode 100644
index 0000000..5fb5937
--- /dev/null
+++ b/tests/Support/GetTestEndpoint.php
@@ -0,0 +1,44 @@
+withQuery(['status' => 'ingested']);
+ }
+}
diff --git a/tests/Support/PostTestBearerOnlyEndpoint.php b/tests/Support/PostTestBearerOnlyEndpoint.php
new file mode 100644
index 0000000..bdba70a
--- /dev/null
+++ b/tests/Support/PostTestBearerOnlyEndpoint.php
@@ -0,0 +1,57 @@
+withData([
+ 'status' => 'publish',
+ ]);
+ }
+}
diff --git a/tests/Support/TestClassWithProperties.php b/tests/Support/TestClassWithProperties.php
new file mode 100644
index 0000000..bf7fa4c
--- /dev/null
+++ b/tests/Support/TestClassWithProperties.php
@@ -0,0 +1,15 @@
+created_at = Carbon::create(2023, 1, 19, 15, 41, 43);
+ }
+
+ public function compilesAsArrayExceptProperties(): array
+ {
+ return ['status'];
+ }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 0000000..67534e1
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,24 @@
+baseUrl('https://api.localhost');
+
+ $auth->applyCredentials($request);
+
+ $this->assertEquals(AuthMethodEnum::API_KEY, $auth->getAuthMethod());
+ $this->assertEquals(['paramauth' => '12345'], $request->getCompiledQuery());
+ }
+}
diff --git a/tests/Unit/Auth/BasicAuthMethodTest.php b/tests/Unit/Auth/BasicAuthMethodTest.php
new file mode 100644
index 0000000..e808114
--- /dev/null
+++ b/tests/Unit/Auth/BasicAuthMethodTest.php
@@ -0,0 +1,29 @@
+baseUrl('https://api.localhost');
+
+ $auth->applyCredentials($request);
+
+ $this->assertEquals(AuthMethodEnum::BASIC, $auth->getAuthMethod());
+ $this->assertEquals(['lorem', 'ipsum'], Arr::get($request->getOptions(), 'auth'));
+ }
+}
diff --git a/tests/Unit/Auth/BearerAuthMethodTest.php b/tests/Unit/Auth/BearerAuthMethodTest.php
new file mode 100644
index 0000000..a73dd48
--- /dev/null
+++ b/tests/Unit/Auth/BearerAuthMethodTest.php
@@ -0,0 +1,29 @@
+baseUrl('https://api.localhost');
+
+ $auth->applyCredentials($request);
+
+ $this->assertEquals(AuthMethodEnum::BEARER, $auth->getAuthMethod());
+ $this->assertEquals('Bearer lorem', Arr::get($request->getOptions(), 'headers.Authorization'));
+ }
+}
diff --git a/tests/Unit/ClientTest.php b/tests/Unit/ClientTest.php
new file mode 100644
index 0000000..4c7512a
--- /dev/null
+++ b/tests/Unit/ClientTest.php
@@ -0,0 +1,101 @@
+buildHttpFactory();
+ $factory->preventStrayRequests();
+ $factory->fake([
+ 'api.cloudycdn.services/api/v5/Test?status=ingested' => $factory->response(['msg' => '', 'code' => 0])
+ ]);
+
+ $response = $client
+ ->timeout(10)
+ ->connectTimeout(20)
+ ->run(new GetTestEndpoint());
+
+ $this->assertTrue($response->successful());
+ $this->assertEquals(['msg' => '', 'code' => 0], $response->json());
+ }
+
+ public function test_it_throws_exception_when_calling_endpoint_with_not_allowed_auth_method(): void
+ {
+ $client = new Client(new BasicAuthMethod('user', 'pass'));
+
+ $factory = $client->buildHttpFactory();
+ $factory->preventStrayRequests();
+ $factory->fake([
+ 'api.cloudycdn.services/api/v5/Test/Create' => $factory->response(['msg' => 'Created', 'code' => 0])
+ ]);
+
+ $this->expectException(TmsAuthMethodNotAllowed::class);
+
+ $client->run(new PostTestBearerOnlyEndpoint());
+ }
+
+ public function test_it_posts_data(): void
+ {
+ $client = new Client(new BearerAuthMethod('abc'));
+
+ $factory = $client->buildHttpFactory();
+ $factory->preventStrayRequests();
+ $factory->fake(function (Request $request) use ($factory) {
+ if ($request->url() != 'https://api.cloudycdn.services/api/v5/Test/Create') {
+ return $factory->response('Not Found', 404);
+ }
+
+ if (isset($request->data()['status'])) {
+ return $factory->response(['msg' => 'Created', 'code' => 0]);
+ } else {
+ return $factory->response('Not Found', 404);
+ }
+ });
+
+ $response = $client->run(new PostTestBearerOnlyEndpoint());
+
+ $this->assertTrue($response->successful());
+ $this->assertEquals(['msg' => 'Created', 'code' => 0], $response->json());
+ }
+
+ public function test_apply_middleware(): void
+ {
+ $client = new Client(new BasicAuthMethod('user', 'pass'));
+
+ $factory = $client->buildHttpFactory();
+ $factory->preventStrayRequests();
+ $factory->fake([
+ 'api.cloudycdn.services/api/v5/Test?status=ingested' => $factory->response(['msg' => '', 'code' => 0])
+ ]);
+
+ $response = $client
+ ->withMiddleware(
+ Middleware::mapRequest(function (RequestInterface $request) {
+ $request = $request->withHeader('X-Example', 'Value');
+
+ return $request;
+ })
+ )
+ ->run(new GetTestEndpoint());
+
+ $this->assertEquals('Value', Arr::get($response->transferStats->getRequest()->getHeader('X-Example'), 0));
+ }
+}
diff --git a/tests/Unit/Concerns/CompilesPropertiesConcernTest.php b/tests/Unit/Concerns/CompilesPropertiesConcernTest.php
new file mode 100644
index 0000000..e939d5d
--- /dev/null
+++ b/tests/Unit/Concerns/CompilesPropertiesConcernTest.php
@@ -0,0 +1,40 @@
+assertEquals([], $testClass->compilesAsArrayExceptProperties());
+
+ $this->assertEquals([
+ 'name' => 'Name',
+ 'description' => 'Description',
+ ], $testClass->compileAsArray());
+ }
+
+ public function test_with_excepted_properties(): void
+ {
+ $testClass = new TestClassWithPropertiesAndExceptProperties();
+
+ $this->assertEquals(['status'], $testClass->compilesAsArrayExceptProperties());
+
+ $this->assertEquals([
+ 'name' => 'Name',
+ 'description' => 'Description',
+ 'created_at' => '2023-01-19 15:41:43',
+ 'is_published' => 0,
+ 'status_enum' => StatusEnum::INGESTED->value,
+ ], $testClass->compileAsArray());
+ }
+}
diff --git a/tests/Unit/PendingRequestTest.php b/tests/Unit/PendingRequestTest.php
new file mode 100644
index 0000000..084b285
--- /dev/null
+++ b/tests/Unit/PendingRequestTest.php
@@ -0,0 +1,31 @@
+baseUrl('https://api.localhost');
+
+ $request->useMethod(HttpMethodEnum::GET);
+ $request->setEndpoint('/Test');
+ $request->setAuthQueryParams(['auth_token' => 1234]);
+ $request->withQuery(['status' => 'ingested']);
+ $request->withData(['id' => 5]);
+
+ $this->assertEquals(HttpMethodEnum::GET, $request->getHttpMethod());
+ $this->assertEquals('/Test', $request->getEndpoint());
+ $this->assertEquals(['auth_token' => 1234, 'status' => 'ingested'], $request->getCompiledQuery());
+ $this->assertEquals(['id' => 5], $request->getData());
+ }
+}
diff --git a/tests/Unit/TmsApiTest.php b/tests/Unit/TmsApiTest.php
new file mode 100644
index 0000000..6cb5dae
--- /dev/null
+++ b/tests/Unit/TmsApiTest.php
@@ -0,0 +1,114 @@
+assertEquals([], TmsApi::getClients());
+
+ TmsApi::nullClient();
+
+ $this->assertInstanceOf(Client::class, Arr::get(TmsApi::getClients(), 'null'));
+
+ $client = TmsApi::nullClient();
+
+ $this->assertInstanceOf(Client::class, $client);
+ }
+
+ public function test_it_can_create_a_client(): void
+ {
+ TmsApi::fake();
+
+ $this->assertEquals([], TmsApi::getClients());
+
+ TmsApi::createClient('lorem', new ApiKeyAuthMethod('loremApiKey'));
+
+ $this->assertInstanceOf(Client::class, Arr::get(TmsApi::getClients(), 'lorem'));
+ }
+
+ public function test_it_can_build_client_from_config_and_store(): void
+ {
+ TmsApi::fake();
+
+ $this->assertEquals([], TmsApi::getClients());
+
+ /** @var ConfigRepository $config */
+ $config = $this->app->make(ConfigRepository::class);
+
+ $config->set('tms-api.clients', [
+ 'ipsum' => [
+ 'auth' => [
+ 'username' => 'lorem',
+ 'password' => 'ipsum',
+ ],
+
+ 'http' => [
+ 'timeout' => 10,
+ 'connect_timeout' => 20
+ ],
+ ],
+ ]);
+
+ TmsApi::client('ipsum');
+
+ $this->assertInstanceOf(Client::class, Arr::get(TmsApi::getClients(), 'ipsum'));
+ }
+
+ public function test_it_throws_exception_when_api_client_couldnt_be_found_in_config(): void
+ {
+ TmsApi::fake();
+
+ $this->assertEquals([], TmsApi::getClients());
+
+ /** @var ConfigRepository $config */
+ $config = $this->app->make(ConfigRepository::class);
+
+ $config->set('tms-api.clients', []);
+
+ $this->expectException(InvalidTmsApiClientException::class);
+ $this->expectExceptionMessage('TMS Api client could\'nt be found.');
+
+ TmsApi::client('lorem');
+ }
+
+ public function test_it_throws_exception_when_api_client_auth_config_is_not_provided(): void
+ {
+ TmsApi::fake();
+
+ $this->assertEquals([], TmsApi::getClients());
+
+ /** @var ConfigRepository $config */
+ $config = $this->app->make(ConfigRepository::class);
+
+ $config->set('tms-api.clients', [
+ 'ipsum' => [
+ 'auth' => [
+ ],
+
+ 'http' => [
+ 'timeout' => 10,
+ 'connect_timeout' => 20
+ ],
+ ],
+ ]);
+
+ $this->expectException(InvalidTmsApiClientException::class);
+ $this->expectExceptionMessage('TMS Api client auth credentials are not provided.');
+
+ TmsApi::client('ipsum');
+ }
+}