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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
build
.idea/
.phpunit.result.cache
composer.lock
docs
vendor
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to `laravel-bigbluebutton-webhooks` will be documented in this file

## 9.0.0 - 2022-01-26

- Drop support for PHP 7
- Upgrade spatie/laravel-webhook-client to version 3.0
- Test Laravel 9 integration

## 1.0.0 - 2020-06-08

- initial release
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ return [
/*
* You can define the job that should be run when a certain webhook hits your application
* here. The key is the name of the BigBlueButton event type with the `.` replaced by a `_`.
*
* The package will automatically convert the keys to lowercase, but you should
* be cognisant of the fact that array keys are case-sensitive
*/
'jobs' => [
'meeting-created' => \BinaryCats\BigBlueButtonWebhooks\Jobs\MeetingCreatedJob::class,
Expand Down Expand Up @@ -103,10 +106,18 @@ Unless something goes terribly wrong, this package will always respond with a `2
If the signature is not valid, the request will NOT be logged in the `webhook_calls` table but a `BinaryCats\BigBlueButtonWebhooks\Exceptions\WebhookFailed` exception will be thrown.
If something goes wrong during the webhook request the thrown exception will be saved in the `exception` column. In that case the controller will send a `500` instead of `200`.

**The package will ALWAYS cast events to lowercase - so your configured keys must be lowercase, too**

**N.B.: According to the docs:**

> Hooks are only removed if a call to /hooks/destroy is made or if the callbacks for the hook fail too many times (~12) for a long period of time (~5min).

**N.N.B.: Payload structure:**

> The payload that is sent from BigBlueButton is sort of split between into three sections.
> Out of the box the package will store whatever BBB sends back to you within payload via `$request->input()`.
> If you want to transform the payload, you may want to use custom model. [Advanced Usage](#advanced-usage)

There are two ways this package enables you to handle webhook requests: you can opt to queue a job or listen to the events the package will fire.

### Handling webhook requests using jobs
Expand Down Expand Up @@ -206,6 +217,46 @@ The above example is only one way to handle events in Laravel. To learn the othe

## Advanced usage

### Transforming the payload

If you want to change how the payload is saved into the database, for instance, to have the `event` name as a top tier element, you may want to use custom model:

```php
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Spatie\WebhookClient\Models\WebhookCall as Model;
use Spatie\WebhookClient\WebhookConfig;

class WebhookCall extends Model
{
/**
* @param \Spatie\WebhookClient\WebhookConfig $config
* @param \Illuminate\Http\Request $request
* @return \Spatie\WebhookClient\Models\WebhookCall
*/
public static function storeWebhook(WebhookConfig $config, Request $request): Model
{
// bigblubutton payload is build in expectation of multiple events
$payload = $request->input();
// transform event
if ($event = Arr::get($payload, 'event', null) and is_string($event)) {
$payload['event'] = json_decode($event, true);
}
// take the headers form the top
$headers = self::headersToStore($config, $request);
// parse and return
return self::create([
'name' => $config->name,
'url' => $request->fullUrl(),
'headers' => $headers,
'payload' => $payload,
]);
}
}
```

and register it in `bitbluebutton-webhooks.model` config key. The above example is based on

### Retry handling a webhook

All incoming webhook requests are written to the database. This is incredibly valuable when something goes wrong while handling a webhook call. You can easily retry processing the webhook call, after you've investigated and fixed the cause of failure, like this:
Expand Down
4 changes: 4 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
# Upgrading

## v1.0 -> 9.0

If you are upgrading from previous version, please note that `spatie/laravel-webhook-client` has been upgraded to ^3.0 - which adds an extra field into the webhooks table. Read [upgrading instructions](https://github.com/spatie/laravel-webhook-client/blob/main/UPGRADING.md) for more details.
33 changes: 16 additions & 17 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"keywords": [
"binary-cats",
"laravel",
"bbb",
"bigbluebutton",
"webhooks"
],
Expand All @@ -18,42 +19,40 @@
}
],
"require": {
"php": "^7.2||^8.0",
"illuminate/support": "~5.8.0|^6.0|^7.0|^8.0",
"spatie/laravel-webhook-client": "^2.0"
"php": "^8.0",
"illuminate/support": "^8.0|^9.0",
"spatie/laravel-webhook-client": "^3.0"
},
"require-dev": {
"orchestra/testbench": "~3.8.0|^4.0|^5.0|^6.0",
"phpunit/phpunit": "^8.2|^9.0"
"orchestra/testbench": "^6.0|^7.0",
"phpunit/phpunit": "^9.4"
},
"autoload": {
"psr-4": {
"BinaryCats\\BigBlueButtonWebhooks\\": "src"
"BinaryCats\\BigBlueButtonWebhooks\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"BinaryCats\\BigBlueButtonWebhooks\\Tests\\": "tests"
"Tests\\": "tests/"
}
},
"suggest": {
"binary-cats/laravel-mailgun-webhooks": "^1.0"
"binary-cats/laravel-lob-webhooks": "Handle lob.com webhooks in your Laravel application",
"binary-cats/laravel-mailgun-webhooks": "Handle mailgun.com webhooks in your Laravel application"
},
"scripts": {
"test": "vendor/bin/phpunit --color=always",
"check": [
"php-cs-fixer fix --ansi --dry-run --diff",
"phpcs --report-width=200 --report-summary --report-full src/ tests/ --standard=PSR2 -n",
"phpmd src/,tests/ text ./phpmd.xml.dist"
],
"fix": [
"php-cs-fixer fix --ansi"
]
"coverage": "XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-html coverage -d pcov.enabled",
"test": "./vendor/bin/phpunit --color=always -vvv"
},
"config": {
"optimize-autoloader": true,
"sort-packages": true
},
"extra": {
"branch-alias": {
"dev-master": "9.x-dev"
},
"laravel": {
"providers": [
"BinaryCats\\BigBlueButtonWebhooks\\BigBlueButtonWebhooksServiceProvider"
Expand Down
3 changes: 3 additions & 0 deletions config/bigbluebutton-webhooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
/*
* You can define the job that should be run when a certain webhook hits your application
* here. The key is the name of the BigBlueButton event type with the `.` replaced by a `_`.
*
* The package will automatically convert the keys to lowercase, but you should
* be cognisant of the fact that array keys are case-sensitive
*/
'jobs' => [
// 'meeting-created' => \BinaryCats\BigBlueButtonWebhooks\Jobs\MeetingCreatedJob::class,
Expand Down
27 changes: 15 additions & 12 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
Expand All @@ -8,22 +9,24 @@
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="true"
stopOnFailure="false">
stopOnFailure="false"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory suffix=".php">src/</directory>
</include>
<report>
<clover outputFile="build/logs/clover.xml"/>
<html outputDirectory="build/coverage"/>
<text outputFile="build/coverage.txt"/>
</report>
</coverage>
<testsuites>
<testsuite name="Binary Cats Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
<logging>
<log type="tap" target="build/report.tap"/>
<log type="junit" target="build/report.junit.xml"/>
<log type="coverage-html" target="build/coverage"/>
<log type="coverage-text" target="build/coverage.txt"/>
<log type="coverage-clover" target="build/logs/clover.xml"/>
<junit outputFile="build/report.junit.xml"/>
</logging>
</phpunit>
21 changes: 4 additions & 17 deletions src/BigBlueButtonSignatureValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,18 @@

class BigBlueButtonSignatureValidator implements SignatureValidator
{
/**
* Bind the implemetation.
*
* @var Illuminate\Http\Request
*/
protected $request;

/**
* Inject the config.
*
* @var Spatie\WebhookClient\WebhookConfig
*/
protected $config;

/**
* True if the signature has been valiates.
*
* @param Illuminate\Http\Request $request
* @param Spatie\WebhookClient\WebhookConfig $config
*
* @param \Illuminate\Http\Request $request
* @param \Spatie\WebhookClient\WebhookConfig $config
* @return bool
*/
public function isValid(Request $request, WebhookConfig $config): bool
{
// idenfity signature
$signature = $request->bearerToken();
// "pretend" to fetch secret
$secret = $config->signingSecret;
// For the webhooks with a signature
try {
Expand Down
10 changes: 4 additions & 6 deletions src/BigBlueButtonWebhooksController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ class BigBlueButtonWebhooksController
/**
* Invoke controller method.
*
* @param \Illuminate\Http\Request $request
* @param string|null $configKey
* @return \Illuminate\Http\Response
* @param \Illuminate\Http\Request $request
* @param string|null $configKey
* @return \Symfony\Component\HttpFoundation\Response
*/
public function __invoke(Request $request, string $configKey = null)
{
Expand All @@ -30,8 +30,6 @@ public function __invoke(Request $request, string $configKey = null)
'process_webhook_job' => config('bigbluebutton-webhooks.process_webhook_job'),
]);

(new WebhookProcessor($request, $webhookConfig))->process();

return response()->json(['message' => 'ok']);
return (new WebhookProcessor($request, $webhookConfig))->process();
}
}
4 changes: 1 addition & 3 deletions src/BigBlueButtonWebhooksServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ public function boot()
], 'config');
}

Route::macro('bigbluebuttonWebhooks', function ($url) {
return Route::post($url, '\BinaryCats\BigBlueButtonWebhooks\BigBlueButtonWebhooksController');
});
Route::macro('bigbluebuttonWebhooks', fn ($url) => Route::post($url, BigBlueButtonWebhooksController::class));
}

/**
Expand Down
13 changes: 6 additions & 7 deletions src/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,30 @@

use BinaryCats\BigBlueButtonWebhooks\Contracts\WebhookEvent;

class Event implements WebhookEvent
final class Event implements WebhookEvent
{
/**
* Attributes from the event.
*
* @var array
* @var string[]
*/
public $attributes = [];

/**
* Create new Event.
*
* @param array $attributes
* @param string[] $attributes
*/
public function __construct($attributes)
{
$this->attributes = $attributes;
}

/**
* Construct the event.
*
* @return Event
* @param mixed[] $data
* @return static
*/
public static function constructFrom($data): self
public static function constructFrom(array $data): self
{
return new static($data);
}
Expand Down
4 changes: 4 additions & 0 deletions src/Exceptions/UnexpectedValueException.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

class UnexpectedValueException extends BaseUnexpectedValueException
{
/**
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function render($request)
{
return response(['error' => $this->getMessage()], 400);
Expand Down
20 changes: 18 additions & 2 deletions src/Exceptions/WebhookFailed.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,39 @@
use Exception;
use Spatie\WebhookClient\Models\WebhookCall;

class WebhookFailed extends Exception
final class WebhookFailed extends Exception
{
/**
* @return static
*/
public static function signingSecretNotSet(): self
{
return new static('The webhook signing secret is not set. Make sure that the `signing_secret` config key is set to the correct value.');
}

/**
* @param string $jobClass
* @param \Spatie\WebhookClient\Models\WebhookCall $webhookCall
* @return static
*/
public static function jobClassDoesNotExist(string $jobClass, WebhookCall $webhookCall): self
{
return new static("Could not process webhook id `{$webhookCall->id}` of type `{$webhookCall->type} because the configured jobclass `$jobClass` does not exist.");
return new static("Could not process webhook id `{$webhookCall->id}` of type `{$webhookCall->name} because the configured jobclass `$jobClass` does not exist.");
}

/**
* @param \Spatie\WebhookClient\Models\WebhookCall $webhookCall
* @return static
*/
public static function missingType(WebhookCall $webhookCall): self
{
return new static("Webhook call id `{$webhookCall->id}` did not contain a type. Valid BigBlueButton webhook calls should always contain a type.");
}

/**
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function render($request)
{
return response(['error' => $this->getMessage()], 400);
Expand Down
Loading