Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: 2
updates:
- package-ecosystem: "composer"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"
35 changes: 35 additions & 0 deletions .github/workflows/fix-php-code-style-issues.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Fix PHP code style issues

on:
push:
branches: [main, master]

permissions:
contents: write

jobs:
php-code-styling:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
coverage: none

- name: Install dependencies
run: composer install --no-interaction --prefer-dist

- name: Fix PHP code style issues
run: vendor/bin/pint

- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: Fix styling
101 changes: 101 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: Run Tests

on:
push:
branches: [main, master]
pull_request:
branches: [main, master]

jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
php: [8.2, 8.3, 8.4]
laravel: [9.*, 10.*, 11.*, 12.*]
stability: [prefer-stable]
include:
- laravel: 9.*
testbench: 7.*
pest: 1.*
- laravel: 10.*
testbench: 8.*
pest: 2.*
- laravel: 11.*
testbench: 9.*
pest: 2.*
- laravel: 12.*
testbench: 10.*
pest: 3.*
exclude:
- laravel: 9.*
php: 8.4
- laravel: 10.*
php: 8.4
- laravel: 11.*
php: 8.2
- laravel: 12.*
php: 8.2

name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
coverage: none

- name: Setup problem matchers
run: |
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"

- name: Install dependencies
run: |
composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" "pestphp/pest:${{ matrix.pest }}" --dev --no-interaction --no-update
composer update --${{ matrix.stability }} --prefer-dist --no-interaction

- name: List Installed Dependencies
run: composer show -D

- name: Execute tests
run: vendor/bin/pest

php85-test:
runs-on: ubuntu-latest
name: P8.5 - L12.* - prefer-stable - ubuntu-latest
continue-on-error: true

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.5'
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
coverage: none

- name: Setup problem matchers
run: |
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"

- name: Install dependencies
run: |
composer require "laravel/framework:12.*" "orchestra/testbench:10.*" "pestphp/pest:3.*" --dev --no-interaction --no-update
composer update --prefer-stable --prefer-dist --no-interaction

- name: List Installed Dependencies
run: composer show -D

- name: Execute tests
run: vendor/bin/pest
8 changes: 5 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,18 @@
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
"php": "^8.2",
"php": "^8.2 || ^8.3 || ^8.4 || ^8.5",
"illuminate/contracts": "^9.0 || ^10.0 || ^11.0 || ^12.0",
"laravel/prompts": "^0.1.18 || ^0.2.0 || ^0.3.0"
"illuminate/http": "^9.0 || ^10.0 || ^11.0 || ^12.0",
"illuminate/support": "^9.0 || ^10.0 || ^11.0 || ^12.0"
},
"require-dev": {
"laravel/pint": "^1.0",
"mockery/mockery": "^1.6",
"nunomaduro/collision": "^6.0 || ^7.0 || ^8.0",
"orchestra/testbench": "^7.0 || ^8.0 || ^9.0 || ^10.0",
"pestphp/pest": "^1.0 || ^2.0 || ^3.0",
"pestphp/pest-plugin-laravel": "^1.0 || ^2.0 || ^v3.0"
"pestphp/pest-plugin-laravel": "^1.0 || ^2.0 || ^3.0"
},
"autoload": {
"psr-4": {
Expand Down
19 changes: 10 additions & 9 deletions src/Api/TalentLmsApiClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,11 @@

class TalentLmsApiClient
{
public PendingRequest $request;

public function __construct(
protected string $apiKey,
protected string $domain,
protected string $version,
)
{
$this->request = Http::withBasicAuth($this->apiKey, '')
->acceptJson();
) {
}

public static function fromConfig(array $config): self
Expand All @@ -28,17 +23,23 @@ public static function fromConfig(array $config): self
);
}

protected function request(): PendingRequest
{
return Http::withBasicAuth($this->apiKey, '')
->acceptJson();
}

public function get(string $endpoint, array $query = []): object|array|null
{
return $this->request
return $this->request()
->throw()
->get($this->buildEndpointUrl($endpoint, $query))
->object();
}

public function post(string $endpoint, array $data = []): object|array|null
{
return $this->request
return $this->request()
->throw()
->post($this->buildEndpointUrl($endpoint), $data)
->object();
Expand All @@ -53,7 +54,7 @@ protected function buildEndpointUrl(string $endpoint, array $query = []): string
}

$urlQuery = collect($query)
->map(fn($value, $key) => "{$key}:{$value}")
->map(fn ($value, $key) => "{$key}:{$value}")
->implode(',');

return "{$baseRequest}/{$urlQuery}";
Expand Down
13 changes: 8 additions & 5 deletions src/Data/ApiResources/Group.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,23 @@ public function __construct(

public static function fromResponse(object $response): self
{
$maxRedemptions = $response->max_redemptions ?? null;
$redemptionsSoFar = $response->redemptions_sofar ?? null;

return new self(
id: $response->id,
name: $response->name,
description: $response->description ?? null,
key: $response->key ?? null,
price: $response->price ?? null,
ownerId: $response->owner_id ?? null,
belongsToBranch: empty($response->belongs_to_branch) ? null : $response->belongs_to_branch,
maxRedemptions: empty($response->max_redemptions) && $response->max_redemptions != 0 ? null : $response->max_redemptions,
redemptionsSoFar: empty($response->redemptions_sofar) && $response->redemptions_sofar != 0 ? null : $response->redemptions_sofar,
belongsToBranch: empty($response->belongs_to_branch ?? null) ? null : $response->belongs_to_branch,
maxRedemptions: $maxRedemptions === null || ($maxRedemptions === '' && $maxRedemptions !== 0) ? null : (int) $maxRedemptions,
redemptionsSoFar: $redemptionsSoFar === null || ($redemptionsSoFar === '' && $redemptionsSoFar !== 0) ? null : (int) $redemptionsSoFar,
users: collect($response->users ?? [])
->map(fn($user) => UserGroup::fromResponse($user)),
->map(fn ($user) => UserGroup::fromResponse($user)),
courses: collect($response->courses ?? [])
->map(fn($course) => GroupCourse::fromResponse($course))
->map(fn ($course) => GroupCourse::fromResponse($course))
);
}
}
6 changes: 3 additions & 3 deletions src/Data/ApiResources/UserCertification.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ public static function fromResponse(object $response): self
id: $response->unique_id,
courseId: $response->course_id,
courseName: $response->course_name,
issuedAt: ApiParsing::parseTimestamp($response->issued_date_timestamp),
expiresAt: ApiParsing::parseTimestamp($response->expiration_date_timestamp),
issuedAt: ApiParsing::parseTimestamp($response->issued_date_timestamp ?? null),
expiresAt: ApiParsing::parseTimestamp($response->expiration_date_timestamp ?? null),
downloadUrl: $response->download_url ?? null,
publicUrl: $response->public_url ?? null,
badges: collect($response->badges ?? [])
->map(fn($badge) => CertificationBadge::fromResponse($badge))
->map(fn ($badge) => CertificationBadge::fromResponse($badge))
);
}

Expand Down
9 changes: 6 additions & 3 deletions src/LaravelTalentLmsServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Bernskiold\LaravelTalentLms\Api\TalentLms;
use Bernskiold\LaravelTalentLms\Api\TalentLmsApiClient;
use Bernskiold\LaravelTalentLms\Commands\PurgeDownloadedFilesCommand;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Console\AboutCommand;
use Illuminate\Support\Facades\RateLimiter;
Expand All @@ -18,7 +17,7 @@ public function boot(): void
{
AboutCommand::add('Laravel TalentLMS', fn () => ['Version' => '1.0.0']);

RateLimiter::for('talentlms', function() {
RateLimiter::for('talentlms', function () {
return Limit::perSecond(200, 5);
});

Expand All @@ -33,10 +32,14 @@ public function register(): void
__DIR__.'/../config/talentlms.php', 'talentlms'
);

$this->app->bind(TalentLmsApiClient::class, function () {
$this->app->singleton(TalentLmsApiClient::class, function () {
return TalentLmsApiClient::fromConfig(config('talentlms.api'));
});

$this->app->singleton(TalentLms::class, function ($app) {
return new TalentLms($app->make(TalentLmsApiClient::class));
});

$this->app->alias(TalentLms::class, 'laravel-talentlms');
}
}
26 changes: 26 additions & 0 deletions tests/Feature/FacadeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

use Bernskiold\LaravelTalentLms\Api\Resources\Courses;
use Bernskiold\LaravelTalentLms\Api\Resources\Groups;
use Bernskiold\LaravelTalentLms\Api\Resources\Users;
use Bernskiold\LaravelTalentLms\Facades\TalentLms;

describe('TalentLms Facade', function () {
it('can access courses resource', function () {
$courses = TalentLms::courses();

expect($courses)->toBeInstanceOf(Courses::class);
});

it('can access users resource', function () {
$users = TalentLms::users();

expect($users)->toBeInstanceOf(Users::class);
});

it('can access groups resource', function () {
$groups = TalentLms::groups();

expect($groups)->toBeInstanceOf(Groups::class);
});
});
41 changes: 41 additions & 0 deletions tests/Feature/ServiceProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

use Bernskiold\LaravelTalentLms\Api\TalentLms;
use Bernskiold\LaravelTalentLms\Api\TalentLmsApiClient;

describe('LaravelTalentLmsServiceProvider', function () {
it('registers the TalentLmsApiClient binding', function () {
$client = app(TalentLmsApiClient::class);

expect($client)->toBeInstanceOf(TalentLmsApiClient::class);
});

it('registers the laravel-talentlms alias', function () {
$talentLms = app('laravel-talentlms');

expect($talentLms)->toBeInstanceOf(TalentLms::class);
});

it('publishes the config file', function () {
$this->artisan('vendor:publish', [
'--provider' => 'Bernskiold\LaravelTalentLms\LaravelTalentLmsServiceProvider',
'--tag' => 'config',
]);

expect(config('talentlms'))->toBeArray();
expect(config('talentlms.api'))->toHaveKeys(['api_key', 'domain', 'version']);
});

it('loads the config file', function () {
expect(config('talentlms.api.api_key'))->toBe('test-api-key');
expect(config('talentlms.api.domain'))->toBe('https://test.talentlms.com');
expect(config('talentlms.api.version'))->toBe('1');
});

it('registers the rate limiter', function () {
$limiter = app(\Illuminate\Cache\RateLimiting\Limit::class);

// Rate limiter is registered, we can check if the RateLimiter facade has a 'talentlms' limiter
expect(\Illuminate\Support\Facades\RateLimiter::limiter('talentlms'))->not->toBeNull();
});
});
Loading
Loading