Initial commit
This commit is contained in:
commit
e747e04af6
|
@ -0,0 +1,2 @@
|
||||||
|
vendor/
|
||||||
|
.phpunit.cache/
|
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
"name": "zoomyboy/matrix-api",
|
||||||
|
"description": "PHP Matrix API to send a message",
|
||||||
|
"type": "library",
|
||||||
|
"require": {
|
||||||
|
"laravel/framework": "^9.0",
|
||||||
|
"guzzlehttp/guzzle": "^7.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"orchestra/testbench": "^7.0"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Zoomyboy\\MatrixApi\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Philipp Lang",
|
||||||
|
"email": "philipp@zoomyboy.de"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Workbench\\App\\": "workbench/app/",
|
||||||
|
"Workbench\\Database\\Factories\\": "workbench/database/factories/",
|
||||||
|
"Workbench\\Database\\Seeders\\": "workbench/database/seeders/",
|
||||||
|
"Zoomyboy\\MatrixApi\\Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"post-autoload-dump": [
|
||||||
|
"@clear",
|
||||||
|
"@prepare"
|
||||||
|
],
|
||||||
|
"clear": "@php vendor/bin/testbench package:purge-skeleton --ansi",
|
||||||
|
"prepare": "@php vendor/bin/testbench package:discover --ansi",
|
||||||
|
"build": "@php vendor/bin/testbench workbench:build --ansi",
|
||||||
|
"serve": [
|
||||||
|
"Composer\\Config::disableProcessTimeout",
|
||||||
|
"@build",
|
||||||
|
"@php vendor/bin/testbench serve"
|
||||||
|
],
|
||||||
|
"lint": [
|
||||||
|
"@php vendor/bin/phpstan analyse"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'base_url' => env('MATRIX_BASE_URL'),
|
||||||
|
'token' => env('MATRIX_TOKEN'),
|
||||||
|
'room_id' => env('MATRIX_ROOM_ID'),
|
||||||
|
];
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.6/phpunit.xsd"
|
||||||
|
bootstrap="vendor/autoload.php"
|
||||||
|
cacheResultFile=".phpunit.cache/test-results"
|
||||||
|
executionOrder="depends,defects"
|
||||||
|
forceCoversAnnotation="true"
|
||||||
|
beStrictAboutCoversAnnotation="true"
|
||||||
|
beStrictAboutOutputDuringTests="true"
|
||||||
|
beStrictAboutTodoAnnotatedTests="true"
|
||||||
|
convertDeprecationsToExceptions="true"
|
||||||
|
failOnRisky="true"
|
||||||
|
failOnWarning="true"
|
||||||
|
verbose="true">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="Unit">
|
||||||
|
<directory suffix="Test.php">./tests/Unit</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
<php>
|
||||||
|
<server name="MATRIX_BASE_URL" value="https://example.com"/>
|
||||||
|
<server name="MATRIX_TOKEN" value="lktzzgggg"/>
|
||||||
|
<server name="MATRIX_ROOM_ID" value="!ttggzzuu:example.com"/>
|
||||||
|
</php>
|
||||||
|
|
||||||
|
</phpunit>
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Zoomyboy\MatrixApi;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionProperty;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class Matrix
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct(private string $baseUrl, private string $roomId, private string $token)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function message(string $message): void
|
||||||
|
{
|
||||||
|
Http::withToken($this->token)
|
||||||
|
->put("{$this->baseUrl}/_matrix/client/v3/rooms/{$this->roomParam()}/send/m.room.message/{$this->transactionId()}", [
|
||||||
|
'body' => $message,
|
||||||
|
'msgtype' => 'm.text',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exception(Throwable $e): void
|
||||||
|
{
|
||||||
|
$return = '';
|
||||||
|
|
||||||
|
$publicProperties = collect((new ReflectionClass($e))->getProperties(ReflectionProperty::IS_PUBLIC));
|
||||||
|
|
||||||
|
foreach ($publicProperties as $property) {
|
||||||
|
if ($property->name === 'message') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$return .= '<li><b>' . $property->getName() . ':</b> ' . $property->getValue($e) . '</li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($publicProperties->count()) {
|
||||||
|
$return = '<ul>' . $return . '</ul>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->message('<p>' . $e->getMessage() . '</p>' . $return);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function roomParam(): string
|
||||||
|
{
|
||||||
|
return rawurlencode($this->roomId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function transactionId(): string
|
||||||
|
{
|
||||||
|
return str()->random(16);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Zoomyboy\MatrixApi;
|
||||||
|
|
||||||
|
trait ReportsToMatrix
|
||||||
|
{
|
||||||
|
|
||||||
|
public function report(): bool
|
||||||
|
{
|
||||||
|
app(Matrix::class)->exception($this);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Zoomyboy\MatrixApi;
|
||||||
|
|
||||||
|
use Illuminate\Support\ServiceProvider as BaseServiceProvider;
|
||||||
|
|
||||||
|
class ServiceProvider extends BaseServiceProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
$this->mergeConfigFrom(__DIR__ . '/../config/matrix.php', 'matrix');
|
||||||
|
|
||||||
|
$this->publishes([
|
||||||
|
__DIR__ . '/../config/matrix.php' => config_path('matrix.php'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->app->bind(Matrix::class, function ($app) {
|
||||||
|
return new Matrix(config('matrix.base_url'), config('matrix.room_id'), config('matrix.token'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
providers:
|
||||||
|
# - Workbench\App\Providers\WorkbenchServiceProvider
|
||||||
|
|
||||||
|
migrations:
|
||||||
|
- workbench/database/migrations
|
||||||
|
|
||||||
|
seeders:
|
||||||
|
- Workbench\Database\Seeders\DatabaseSeeder
|
||||||
|
|
||||||
|
workbench:
|
||||||
|
start: '/'
|
||||||
|
install: true
|
||||||
|
discovers:
|
||||||
|
web: true
|
||||||
|
api: false
|
||||||
|
commands: false
|
||||||
|
components: false
|
||||||
|
views: false
|
||||||
|
build: []
|
||||||
|
assets: []
|
||||||
|
sync: []
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Zoomyboy\MatrixApi\Tests\Fakes;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
|
||||||
|
class HttpFake
|
||||||
|
{
|
||||||
|
|
||||||
|
public string $roomId;
|
||||||
|
public string $baseUrl;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->roomId = config('matrix.room_id');
|
||||||
|
$this->baseUrl = config('matrix.base_url');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendsMessage(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
Http::fake(function ($request) {
|
||||||
|
if ($request->method() !== 'PUT') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!str($request->url())->startsWith("{$this->baseUrl}/_matrix/client/v3/rooms/{$this->roomIdParam()}/send/m.room.message/")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Http::response(json_encode([
|
||||||
|
'event_id' => str()->random(32),
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function assertMessageSent(string $message): void
|
||||||
|
{
|
||||||
|
Http::assertSent(function ($request) use ($message) {
|
||||||
|
if ($request['body'] !== $message) {
|
||||||
|
dump($message, $request['body']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $request->method() === 'PUT'
|
||||||
|
&& $request['body'] === $message
|
||||||
|
&& $request['msgtype'] === 'm.text'
|
||||||
|
&& str($request->url())->startsWith("{$this->baseUrl}/_matrix/client/v3/rooms/{$this->roomIdParam()}/send/m.room.message/");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function roomIdParam(): string
|
||||||
|
{
|
||||||
|
return rawurlencode($this->roomId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Zoomyboy\MatrixApi\Tests;
|
||||||
|
|
||||||
|
use Orchestra\Testbench\Concerns\WithWorkbench;
|
||||||
|
use Orchestra\Testbench\TestCase as TestbenchTestCase;
|
||||||
|
use Zoomyboy\MatrixApi\ServiceProvider;
|
||||||
|
use Zoomyboy\MatrixApi\Tests\Fakes\HttpFake;
|
||||||
|
|
||||||
|
class TestCase extends TestbenchTestCase
|
||||||
|
{
|
||||||
|
use WithWorkbench;
|
||||||
|
|
||||||
|
public HttpFake $httpFake;
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->httpFake = app(HttpFake::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function defineEnvironment($app)
|
||||||
|
{
|
||||||
|
$app->register(ServiceProvider::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Zoomyboy\MatrixApi\Tests\Unit;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Http\Client\HttpClientException;
|
||||||
|
use Zoomyboy\MatrixApi\Matrix;
|
||||||
|
use Zoomyboy\MatrixApi\ReportsToMatrix;
|
||||||
|
use Zoomyboy\MatrixApi\Tests\TestCase;
|
||||||
|
|
||||||
|
class MessageTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers Matrix
|
||||||
|
*/
|
||||||
|
public function testItSendsMessageViaMethod(): void
|
||||||
|
{
|
||||||
|
$this->httpFake->sendsMessage();
|
||||||
|
|
||||||
|
app(Matrix::class)->message('lalatt');
|
||||||
|
|
||||||
|
$this->httpFake->assertMessageSent('lalatt');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers Matrix
|
||||||
|
*/
|
||||||
|
public function testItSendsMessageWithException(): void
|
||||||
|
{
|
||||||
|
$this->httpFake->sendsMessage();
|
||||||
|
|
||||||
|
app(Matrix::class)->exception(new TestException('The error Message'));
|
||||||
|
|
||||||
|
$this->httpFake->assertMessageSent('<p>The error Message</p>');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers Matrix
|
||||||
|
*/
|
||||||
|
public function testItSendsExceptionWhenExceptionIsReported(): void
|
||||||
|
{
|
||||||
|
$this->httpFake->sendsMessage();
|
||||||
|
|
||||||
|
try {
|
||||||
|
throw new MatrixException('This is the error');
|
||||||
|
} catch (MatrixException $e) {
|
||||||
|
$e->report();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->httpFake->assertMessageSent('<p>This is the error</p>');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers Matrix
|
||||||
|
*/
|
||||||
|
public function testItSendsExceptionsWithStringParameters(): void
|
||||||
|
{
|
||||||
|
$this->httpFake->sendsMessage();
|
||||||
|
|
||||||
|
app(Matrix::class)->exception((new StringPropertyException('This is the error', '::param content::', 'third param')));
|
||||||
|
|
||||||
|
$this->httpFake->assertMessageSent('<p>This is the error</p><ul><li><b>testParam:</b> ::param content::</li><li><b>thirdParam:</b> third param</li></ul>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestException extends Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class MatrixException extends Exception
|
||||||
|
{
|
||||||
|
use ReportsToMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
class StringPropertyException extends HttpClientException
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct(public $message, public string $testParam, public string $thirdParam)
|
||||||
|
{
|
||||||
|
parent::__construct($message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
.env
|
||||||
|
.env.dusk
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Workbench\App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class WorkbenchServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Workbench\Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class DatabaseSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| API Routes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here is where you can register API routes for your application. These
|
||||||
|
| routes are loaded by the RouteServiceProvider and all of them will
|
||||||
|
| be assigned to the "api" middleware group. Make something great!
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
|
||||||
|
// return $request->user();
|
||||||
|
// });
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Inspiring;
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Console Routes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This file is where you may define all of your Closure based console
|
||||||
|
| commands. Each Closure is bound to a command instance allowing a
|
||||||
|
| simple approach to interacting with each command's IO methods.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Artisan::command('inspire', function () {
|
||||||
|
// $this->comment(Inspiring::quote());
|
||||||
|
// })->purpose('Display an inspiring quote');
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Web Routes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here is where you can register web routes for your application. These
|
||||||
|
| routes are loaded by the RouteServiceProvider and all of them will
|
||||||
|
| be assigned to the "web" middleware group. Make something great!
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
Route::get('/', function () {
|
||||||
|
return view('welcome');
|
||||||
|
});
|
Loading…
Reference in New Issue