Started webhook implementation

This commit is contained in:
Dan Brown 2021-12-07 14:55:11 +00:00
parent 867cbe15ea
commit a3a3055695
No known key found for this signature in database
GPG key ID: 46D9F943C24A2EF9
12 changed files with 135 additions and 12 deletions

11
app/Actions/Webhook.php Normal file
View file

@ -0,0 +1,11 @@
<?php
namespace BookStack\Actions;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Webhook extends Model
{
use HasFactory;
}

View file

@ -23,7 +23,7 @@ class RoleController extends Controller
/** /**
* Show a listing of the roles in the system. * Show a listing of the roles in the system.
*/ */
public function list() public function index()
{ {
$this->checkPermission('user-roles-manage'); $this->checkPermission('user-roles-manage');
$roles = $this->permissionsRepo->getAllRoles(); $roles = $this->permissionsRepo->getAllRoles();

View file

@ -0,0 +1,16 @@
<?php
namespace BookStack\Http\Controllers;
use Illuminate\Http\Request;
class WebhookController extends Controller
{
/**
* Show all webhooks configured in the system.
*/
public function index()
{
return view('settings.webhooks.index');
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class WebhookFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => 'My webhook for ' . $this->faker->country(),
'endpoint' => $this->faker->url,
];
}
}

View file

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateWebhooksTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('webhooks', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 150);
$table->string('endpoint', 500);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('webhooks');
}
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10,15l5.88,0c0.27-0.31,0.67-0.5,1.12-0.5c0.83,0,1.5,0.67,1.5,1.5c0,0.83-0.67,1.5-1.5,1.5c-0.44,0-0.84-0.19-1.12-0.5 l-3.98,0c-0.46,2.28-2.48,4-4.9,4c-2.76,0-5-2.24-5-5c0-2.42,1.72-4.44,4-4.9l0,2.07C4.84,13.58,4,14.7,4,16c0,1.65,1.35,3,3,3 s3-1.35,3-3V15z M12.5,4c1.65,0,3,1.35,3,3h2c0-2.76-2.24-5-5-5l0,0c-2.76,0-5,2.24-5,5c0,1.43,0.6,2.71,1.55,3.62l-2.35,3.9 C6.02,14.66,5.5,15.27,5.5,16c0,0.83,0.67,1.5,1.5,1.5s1.5-0.67,1.5-1.5c0-0.16-0.02-0.31-0.07-0.45l3.38-5.63 C10.49,9.61,9.5,8.42,9.5,7C9.5,5.35,10.85,4,12.5,4z M17,13c-0.64,0-1.23,0.2-1.72,0.54l-3.05-5.07C11.53,8.35,11,7.74,11,7 c0-0.83,0.67-1.5,1.5-1.5S14,6.17,14,7c0,0.15-0.02,0.29-0.06,0.43l2.19,3.65C16.41,11.03,16.7,11,17,11l0,0c2.76,0,5,2.24,5,5 c0,2.76-2.24,5-5,5c-1.85,0-3.47-1.01-4.33-2.5l2.67,0C15.82,18.82,16.39,19,17,19c1.65,0,3-1.35,3-3S18.65,13,17,13z"/></svg>

After

Width:  |  Height:  |  Size: 903 B

View file

@ -233,6 +233,10 @@ return [
'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?',
'user_api_token_delete_success' => 'API token successfully deleted', 'user_api_token_delete_success' => 'API token successfully deleted',
// Webhooks
'webhooks' => 'Webhooks',
'webhooks_create' => 'Create New Webhook',
//! If editing translations files directly please ignore this in all //! If editing translations files directly please ignore this in all
//! languages apart from en. Content will be auto-copied from en. //! languages apart from en. Content will be auto-copied from en.
//!//////////////////////////////// //!////////////////////////////////

View file

@ -10,7 +10,7 @@
</div> </div>
<div class="card content-wrap auto-height"> <div class="card content-wrap auto-height">
<h2 class="list-heading">{{ trans('settings.audit') }}</h2> <h1 class="list-heading">{{ trans('settings.audit') }}</h1>
<p class="text-muted">{{ trans('settings.audit_desc') }}</p> <p class="text-muted">{{ trans('settings.audit_desc') }}</p>
<div class="flex-container-row"> <div class="flex-container-row">

View file

@ -6,10 +6,12 @@ $version - Version of bookstack to display
<div class="py-m flex fit-content"> <div class="py-m flex fit-content">
@include('settings.parts.navbar', ['selected' => $selected]) @include('settings.parts.navbar', ['selected' => $selected])
</div> </div>
<div class="flex"></div> </div>
<div class="text-right p-m flex fit-content"> <div class="px-s">
<a target="_blank" rel="noopener noreferrer" href="https://github.com/BookStackApp/BookStack/releases"> <hr class="darker m-none">
BookStack @if(strpos($version, 'v') !== 0) version @endif {{ $version }} </div>
</a> <div class="py-l px-m flex fit-content">
</div> <a target="_blank" rel="noopener noreferrer" href="https://github.com/BookStackApp/BookStack/releases">
BookStack @if(strpos($version, 'v') !== 0) version @endif {{ $version }}
</a>
</div> </div>

View file

@ -13,4 +13,7 @@
@if(userCan('user-roles-manage')) @if(userCan('user-roles-manage'))
<a href="{{ url('/settings/roles') }}" @if($selected == 'roles') class="active" @endif>@icon('lock-open'){{ trans('settings.roles') }}</a> <a href="{{ url('/settings/roles') }}" @if($selected == 'roles') class="active" @endif>@icon('lock-open'){{ trans('settings.roles') }}</a>
@endif @endif
@if(userCan('settings-manage'))
<a href="{{ url('/settings/webhooks') }}" @if($selected == 'webhooks') class="active" @endif>@icon('webhooks'){{ trans('settings.webhooks') }}</a>
@endif
</nav> </nav>

View file

@ -0,0 +1,25 @@
@extends('layouts.simple')
@section('body')
<div class="container small">
<div class="py-m">
@include('settings.parts.navbar', ['selected' => 'webhooks'])
</div>
<div class="card content-wrap auto-height">
<div class="grid half v-center">
<h1 class="list-heading">{{ trans('settings.webhooks') }}</h1>
<div class="text-right">
<a href="{{ url("/settings/webhooks/new") }}" class="button outline">{{ trans('settings.webhooks_create') }}</a>
</div>
</div>
</div>
</div>
@stop

View file

@ -29,7 +29,11 @@ use BookStack\Http\Controllers\UserApiTokenController;
use BookStack\Http\Controllers\UserController; use BookStack\Http\Controllers\UserController;
use BookStack\Http\Controllers\UserProfileController; use BookStack\Http\Controllers\UserProfileController;
use BookStack\Http\Controllers\UserSearchController; use BookStack\Http\Controllers\UserSearchController;
use BookStack\Http\Controllers\WebhookController;
use BookStack\Http\Middleware\VerifyCsrfToken;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use Illuminate\View\Middleware\ShareErrorsFromSession;
Route::get('/status', [StatusController::class, 'show']); Route::get('/status', [StatusController::class, 'show']);
Route::get('/robots.txt', [HomeController::class, 'robots']); Route::get('/robots.txt', [HomeController::class, 'robots']);
@ -244,13 +248,16 @@ Route::middleware('auth')->group(function () {
Route::delete('/settings/users/{userId}/api-tokens/{tokenId}', [UserApiTokenController::class, 'destroy']); Route::delete('/settings/users/{userId}/api-tokens/{tokenId}', [UserApiTokenController::class, 'destroy']);
// Roles // Roles
Route::get('/settings/roles', [RoleController::class, 'list']); Route::get('/settings/roles', [RoleController::class, 'index']);
Route::get('/settings/roles/new', [RoleController::class, 'create']); Route::get('/settings/roles/new', [RoleController::class, 'create']);
Route::post('/settings/roles/new', [RoleController::class, 'store']); Route::post('/settings/roles/new', [RoleController::class, 'store']);
Route::get('/settings/roles/delete/{id}', [RoleController::class, 'showDelete']); Route::get('/settings/roles/delete/{id}', [RoleController::class, 'showDelete']);
Route::delete('/settings/roles/delete/{id}', [RoleController::class, 'delete']); Route::delete('/settings/roles/delete/{id}', [RoleController::class, 'delete']);
Route::get('/settings/roles/{id}', [RoleController::class, 'edit']); Route::get('/settings/roles/{id}', [RoleController::class, 'edit']);
Route::put('/settings/roles/{id}', [RoleController::class, 'update']); Route::put('/settings/roles/{id}', [RoleController::class, 'update']);
// Webhooks
Route::get('/settings/webhooks', [WebhookController::class, 'index']);
}); });
// MFA routes // MFA routes
@ -291,9 +298,9 @@ Route::post('/saml2/logout', [Auth\Saml2Controller::class, 'logout']);
Route::get('/saml2/metadata', [Auth\Saml2Controller::class, 'metadata']); Route::get('/saml2/metadata', [Auth\Saml2Controller::class, 'metadata']);
Route::get('/saml2/sls', [Auth\Saml2Controller::class, 'sls']); Route::get('/saml2/sls', [Auth\Saml2Controller::class, 'sls']);
Route::post('/saml2/acs', [Auth\Saml2Controller::class, 'startAcs'])->withoutMiddleware([ Route::post('/saml2/acs', [Auth\Saml2Controller::class, 'startAcs'])->withoutMiddleware([
\Illuminate\Session\Middleware\StartSession::class, StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class, ShareErrorsFromSession::class,
\BookStack\Http\Middleware\VerifyCsrfToken::class, VerifyCsrfToken::class,
]); ]);
Route::get('/saml2/acs', [Auth\Saml2Controller::class, 'processAcs']); Route::get('/saml2/acs', [Auth\Saml2Controller::class, 'processAcs']);