Merge pull request #12570 from Godmartinz/generalize_webhooks

Adds General option to the webhooks settings
This commit is contained in:
snipe 2023-03-13 14:54:51 -07:00 committed by GitHub
commit 477bd27cba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 286 additions and 162 deletions

View file

@ -8,47 +8,86 @@ use App\Models\Setting;
class SlackSettingsForm extends Component
{
public $slack_endpoint;
public $slack_channel;
public $slack_botname;
public $webhook_endpoint;
public $webhook_channel;
public $webhook_botname;
public $isDisabled ='disabled' ;
public $webhook_name;
public $webhook_link;
public $webhook_placeholder;
public $webhook_icon;
public $webhook_selected;
public Setting $setting;
protected $rules = [
'slack_endpoint' => 'url|required_with:slack_channel|starts_with:https://hooks.slack.com/|nullable',
'slack_channel' => 'required_with:slack_endpoint|starts_with:#|nullable',
'slack_botname' => 'string|nullable',
'webhook_endpoint' => 'url|required_with:webhook_channel|starts_with:https://hooks.slack.com/services|nullable',
'webhook_channel' => 'required_with:webhook_endpoint|starts_with:#|nullable',
'webhook_botname' => 'string|nullable',
];
static $webhook_text= [
"Slack" => array(
"name" => "Slack",
"icon" => 'fab fa-slack',
"placeholder" => "https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXX",
"link" => 'https://api.slack.com/messaging/webhooks',
),
// "Discord" => array(
// "name" => "Discord",
// "icon" => 'fab fa-discord',
// "placeholder" => "https://discord.com/api/webhooks/XXXXXXXXXXXXXXXXXXXXX",
// "link" => 'https://support.discord.com/hc/en-us/articles/360045093012-Server-Integrations-Page',
// ),
"General"=> array(
"name" => "General",
"icon" => "fab fa-hashtag",
"placeholder" => "",
"link" => "",
),
];
public function mount(){
$this->setting = Setting::getSettings();
$this->slack_endpoint = $this->setting->slack_endpoint;
$this->slack_channel = $this->setting->slack_channel;
$this->slack_botname = $this->setting->slack_botname;
$this->webhook_selected = $this->setting->webhook_selected;
$this->webhook_placeholder = self::$webhook_text[$this->setting->webhook_selected]["placeholder"];
$this->webhook_name = self::$webhook_text[$this->setting->webhook_selected]["name"];
$this->webhook_icon = self::$webhook_text[$this->setting->webhook_selected]["icon"];
$this->webhook_endpoint = $this->setting->webhook_endpoint;
$this->webhook_channel = $this->setting->webhook_channel;
$this->webhook_botname = $this->setting->webhook_botname;
$this->webhook_options = $this->setting->webhook_selected;
}
public function updated($field){
if($this->webhook_selected != 'General') {
$this->validateOnly($field, $this->rules);
}
}
public function updatedWebhookSelected(){
$this->webhook_name = self::$webhook_text[$this->webhook_selected]['name'];
$this->webhook_icon = self::$webhook_text[$this->webhook_selected]["icon"]; ;
$this->webhook_placeholder = self::$webhook_text[$this->webhook_selected]["placeholder"];
$this->webhook_link = self::$webhook_text[$this->webhook_selected]["link"];
$this->validateOnly($field ,$this->rules);
}
public function render()
{
if(empty($this->slack_channel || $this->slack_endpoint)){
if(empty($this->webhook_channel || $this->webhook_endpoint)){
$this->isDisabled= 'disabled';
}
if(empty($this->slack_endpoint && $this->slack_channel)){
if(empty($this->webhook_endpoint && $this->webhook_channel)){
$this->isDisabled= '';
}
return view('livewire.slack-settings-form');
}
public function testSlack(){
public function testWebhook(){
$slack = new Client([
'base_url' => e($this->slack_endpoint),
$webhook = new Client([
'base_url' => e($this->webhook_endpoint),
'defaults' => [
'exceptions' => false,
],
@ -56,35 +95,39 @@ class SlackSettingsForm extends Component
$payload = json_encode(
[
'channel' => e($this->slack_channel),
'text' => trans('general.slack_test_msg'),
'username' => e($this->slack_botname),
'channel' => e($this->webhook_channel),
'text' => trans('general.webhook_test_msg'),
'username' => e($this->webhook_botname),
'icon_emoji' => ':heart:',
]);
try {
$slack->post($this->slack_endpoint, ['body' => $payload]);
$webhook->post($this->webhook_endpoint, ['body' => $payload]);
$this->isDisabled='';
return session()->flash('success' , 'Your Slack Integration works!');
return session()->flash('success' , 'Your '.$this->webhook_name.' Integration works!');
} catch (\Exception $e) {
$this->isDisabled= 'disabled';
return session()->flash('error' , trans('admin/settings/message.slack.error', ['error_message' => $e->getMessage()]));
return session()->flash('error' , trans('admin/settings/message.webhook.error', ['error_message' => $e->getMessage(), 'app' => $this->webhook_name]));
}
//}
return session()->flash('message' , trans('admin/settings/message.slack.error_misc'));
return session()->flash('message' , trans('admin/settings/message.webhook.error_misc'));
}
public function submit()
{
$this->validate($this->rules);
if($this->webhook_selected != 'General') {
$this->validate($this->rules);
}
$this->setting->webhook_selected = $this->webhook_selected;
$this->setting->webhook_endpoint = $this->webhook_endpoint;
$this->setting->webhook_channel = $this->webhook_channel;
$this->setting->webhook_botname = $this->webhook_botname;
$this->setting->slack_endpoint = $this->slack_endpoint;
$this->setting->slack_channel = $this->slack_channel;
$this->setting->slack_botname = $this->slack_botname;
$this->setting->save();

View file

@ -127,6 +127,9 @@
"sort-packages": true,
"optimize-autoloader": true,
"discard-changes": true,
"process-timeout": 3000
"process-timeout": 3000,
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}

View file

@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddsWebhookOptionToSettingsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('settings', function (Blueprint $table) {
$table->string('webhook_selected')->after('slack_botname')->default('Slack')->nullable();
$table->renameColumn('slack_botname', 'webhook_botname');
$table->renameColumn('slack_endpoint', 'webhook_endpoint');
$table->renameColumn('slack_channel', 'webhook_channel');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('settings', function (Blueprint $table) {
$table->dropColumn('webhook_selected');
$table->renameColumn('webhook_botname', 'slack_botname');
$table->renameColumn('webhook_endpoint', 'slack_endpoint');
$table->renameColumn('webhook_channel', 'slack_channel');
});
}
}

View file

@ -198,16 +198,18 @@ return [
'show_images_in_email' => 'Show images in emails',
'show_images_in_email_help' => 'Uncheck this box if your Snipe-IT installation is behind a VPN or closed network and users outside the network will not be able to load images served from this installation in their emails.',
'site_name' => 'Site Name',
'slack' => 'Slack',
'slack_title' => 'Update Slack Settings',
'slack_help' => 'Slack settings',
'slack_botname' => 'Slack Botname',
'slack_channel' => 'Slack Channel',
'slack_endpoint' => 'Slack Endpoint',
'slack_integration' => 'Slack Settings',
'slack_integration_help' => 'Slack integration is optional, however the endpoint and channel are required if you wish to use it. To configure Slack integration, you must first <a href=":slack_link" target="_new" rel="noopener">create an incoming webhook</a> on your Slack account. Click on the <strong>Test Slack Integration</strong> button to confirm your settings are correct before saving. ',
'slack_integration_help_button' => 'Once you have saved your Slack information, a test button will appear.',
'slack_test_help' => 'Test whether your Slack integration is configured correctly. YOU MUST SAVE YOUR UPDATED SLACK SETTINGS FIRST.',
'integrations' => 'Integrations',
'webhook' => ':app',
'webhook_title' => 'Update Webhook Settings',
'webhook_help' => 'Integration settings',
'webhook_botname' => ':app Botname',
'webhook_channel' => ':app Channel',
'webhook_endpoint' => ':app Endpoint',
'webhook_integration' => ':app Settings',
'webhook_test' =>'Test :app integration',
'webhook_integration_help' => ':app integration is optional, however the endpoint and channel are required if you wish to use it. To configure :app integration, you must first <a href=":webhook_link" target="_new" rel="noopener">create an incoming webhook</a> on your :app account. Click on the <strong>Test :app Integration</strong> button to confirm your settings are correct before saving. ',
'webhook_integration_help_button' => 'Once you have saved your :app information, a test button will appear.',
'webhook_test_help' => 'Test whether your :app integration is configured correctly. YOU MUST SAVE YOUR UPDATED :app SETTINGS FIRST.',
'snipe_version' => 'Snipe-IT version',
'support_footer' => 'Support Footer Links ',
'support_footer_help' => 'Specify who sees the links to the Snipe-IT Support info and Users Manual',

View file

@ -33,12 +33,12 @@ return [
'testing_authentication' => 'Testing LDAP Authentication...',
'authentication_success' => 'User authenticated against LDAP successfully!'
],
'slack' => [
'sending' => 'Sending Slack test message...',
'webhook' => [
'sending' => 'Sending :app test message...',
'success_pt1' => 'Success! Check the ',
'success_pt2' => ' channel for your test message, and be sure to click SAVE below to store your settings.',
'500' => '500 Server Error.',
'error' => 'Something went wrong. Slack responded with: :error_message',
'error' => 'Something went wrong. :app responded with: :error_message',
'error_misc' => 'Something went wrong. :( ',
]
];

View file

@ -250,8 +250,8 @@ return [
'signature' => 'Signature',
'signed_off_by' => 'Signed Off By',
'skin' => 'Skin',
'slack_msg_note' => 'A slack message will be sent',
'slack_test_msg' => 'Oh hai! Looks like your Slack integration with Snipe-IT is working!',
'webhook_msg_note' => 'A :app message will be sent',
'webhook_test_msg' => 'Oh hai! Looks like your :app integration with Snipe-IT is working!',
'some_features_disabled' => 'DEMO MODE: Some features are disabled for this installation.',
'site_name' => 'Site Name',
'state' => 'State',

View file

@ -1,99 +1,168 @@
{{-- Page title --}}
@section('title')
{{ trans('admin/settings/general.webhook_title') }}
@parent
@stop
@section('header_right')
<a href="{{ route('settings.index') }}" class="btn btn-primary"> {{ trans('general.back') }}</a>
@stop
<div class="col-md-12" style="border-top: 0px;">
@if (session()->has('save'))
<div class="alert alert-success fade in">
{{session('save')}}
{{-- Page content --}}
@section('content')
<div>
<div class="row">
<div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2">
<div class="panel box box-default">
<div class="box-header with-border">
<h2 class="box-title">
<i class="{{$webhook_icon}}"></i> {{ trans('admin/settings/general.webhook', ['app'=>$webhook_name] ) }}
</h2>
</div>
@endif
@if(session()->has('success'))
<div class="alert alert-success fade in">
{{session('success')}}
</div>
@endif
@if(session()->has('error'))
<div class="alert alert-danger fade in">
{{session('error')}}
</div>
@endif
@if(session()->has('message'))
<div class="alert alert-danger fade in">
{{session('message')}}
</div>
@endif
<form class="form-horizontal" role="form" wire:submit.prevent="submit">
{{csrf_field()}}
<!--slack endpoint-->
<div class="form-group{{ $errors->has('slack_endpoint') ? ' error' : '' }}">
<div class="col-md-2">
{{ Form::label('slack_endpoint', trans('admin/settings/general.slack_endpoint')) }}
</div>
<div class="col-md-8 required">
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p>
<input type="text" wire:model="slack_endpoint" class= 'form-control' placeholder="https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXX" {{old('slack_endpoint', $slack_endpoint)}}>
@else
<input type="text" wire:model="slack_endpoint" class= 'form-control' placeholder="https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXX" {{old('slack_endpoint', $slack_endpoint)}}>
<div class="box-body">
<div class="col-md-12">
@if($webhook_selected != 'General')
<p>
{!! trans('admin/settings/general.webhook_integration_help',array('webhook_link' => $webhook_link, 'app' => $webhook_name)) !!}
</p>
@endif
{!! $errors->first('slack_endpoint', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<br>
</div>
</div>
<!-- slack channel -->
<div class="form-group{{ $errors->has('slack_channel') ? ' error' : '' }}">
<div class="col-md-2">
{{ Form::label('slack_channel', trans('admin/settings/general.slack_channel')) }}
</div>
<div class="col-md-8 required">
@if (config('app.lock_passwords')===true)
<input type="text" wire:model="slack_channel" class='form-control' placeholder="#IT-Ops" value="{{old('slack_channel', $slack_channel)}}">
<p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p>
<div class="col-md-12" style="border-top: 0px;">
@if (session()->has('save'))
<div class="alert alert-success fade in">
{{session('save')}}
</div>
@endif
@else
<input type="text" wire:model="slack_channel" class= 'form-control' placeholder="#IT-Ops" value="{{old('slack_channel', $slack_channel)}}">
@endif
{!! $errors->first('slack_channel', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
@if(session()->has('success'))
<div class="alert alert-success fade in">
{{session('success')}}
</div>
@endif
@if(session()->has('error'))
<div class="alert alert-danger fade in">
{{session('error')}}
</div>
@endif
@if(session()->has('message'))
<div class="alert alert-danger fade in">
{{session('message')}}
</div>
@endif
<!-- slack botname -->
<div class="form-group{{ $errors->has('slack_botname') ? ' error' : '' }}">
<div class="col-md-2">
{{ Form::label('slack_botname', trans('admin/settings/general.slack_botname')) }}
</div>
<div class="col-md-8">
@if (config('app.lock_passwords')===true)
<input type="text" wire:model="slack_botname" class= 'form-control' placeholder="Snipe-Bot" {{old('slack_botname', $slack_botname)}}>
<p class="text-warning"><i class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p>
<div class="form-group" style="margin-left:-14px;">
<div class="col-md-2">
<label>Integration Option</label>
</div>
<div class="col-md-8"style="margin-left: 2px;">
<select wire:model="webhook_selected"
aria-label="webhook_selected"
class="form-control "
>
<option value="Slack">Slack</option>
{{-- <option value="Discord">Discord</option>--}}
<option value="General">General Webhook</option>
</select>
</div>
<br><br><br>
@else
<input type="text" wire:model="slack_botname" class= 'form-control' placeholder="Snipe-Bot" {{old('slack_botname', $slack_botname)}}>
@endif
{!! $errors->first('slack_botname', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div><!--col-md-10-->
</div>
</div>
<form class="form-horizontal" role="form" wire:submit.prevent="submit">
{{csrf_field()}}
<!--Slack Integration Test-->
@if($slack_endpoint != null && $slack_channel != null)
<div class="form-group">
<div class="col-md-offset-2 col-md-8">
<a href="#" wire:click.prevent="testSlack" class="btn btn-default btn-sm pull-left"><span>{!! trans('admin/settings/general.slack_test') !!}</span></a>
<div wire:loading><span style="padding-left: 5px; font-size: 20px"><i class="fas fa-spinner fa-spin"></i></span></div>
</div>
</div>
@endif
<!--Webhook endpoint-->
<div class="form-group{{ $errors->has('webhook_endpoint') ? ' error' : '' }}">
<div class="col-md-2">
{{ Form::label('webhook_endpoint', trans('admin/settings/general.webhook_endpoint',['app' => $webhook_selected ])) }}
</div>
<div class="col-md-8 required">
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i
class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p>
<input type="text" wire:model="webhook_endpoint" class='form-control'
placeholder="{{$webhook_placeholder}}"
value="{{old('webhook_endpoint', $webhook_endpoint)}}">
@else
<input type="text" wire:model="webhook_endpoint" class='form-control'
placeholder="{{$webhook_placeholder}}"
value="{{old('webhook_endpoint', $webhook_endpoint)}}">
@endif
{!! $errors->first('webhook_endpoint', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
<div class="box-footer" style="margin-top: 45px;">
<div class="text-right col-md-12">
<a class="btn btn-link text-left" href="{{ route('settings.index') }}">{{ trans('button.cancel') }}</a>
<button type="submit" {{$isDisabled}} class="btn btn-primary"><i class="fas fa-check icon-white" aria-hidden="true"></i> {{ trans('general.save') }}</button>
</div>
</div><!--box-footer-->
</form>
<!-- Webhook channel -->
<div class="form-group{{ $errors->has('webhook_channel') ? ' error' : '' }}">
<div class="col-md-2">
{{ Form::label('webhook_channel', trans('admin/settings/general.webhook_channel',['app' => $webhook_selected ])) }}
</div>
<div class="col-md-8 required">
@if (config('app.lock_passwords')===true)
<input type="text" wire:model="webhook_channel" class='form-control'
placeholder="#IT-Ops"
value="{{old('webhook_channel', $webhook_channel)}}">
<p class="text-warning"><i
class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p>
</div> <!-- /box -->
@else
<input type="text" wire:model="webhook_channel" class='form-control'
placeholder="#IT-Ops"
value="{{old('webhook_channel', $webhook_channel)}}">
@endif
{!! $errors->first('webhook_channel', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>
<!-- Webhook botname -->
<div class="form-group{{ $errors->has('webhook_botname') ? ' error' : '' }}">
<div class="col-md-2">
{{ Form::label('webhook_botname', trans('admin/settings/general.webhook_botname',['app' => $webhook_selected ])) }}
</div>
<div class="col-md-8">
@if (config('app.lock_passwords')===true)
<input type="text" wire:model="webhook_botname" class='form-control'
placeholder="Snipe-Bot" {{old('webhook_botname', $webhook_botname)}}>
<p class="text-warning"><i
class="fas fa-lock"></i> {{ trans('general.feature_disabled') }}</p>
@else
<input type="text" wire:model="webhook_botname" class='form-control'
placeholder="Snipe-Bot" {{old('webhook_botname', $webhook_botname)}}>
@endif
{!! $errors->first('webhook_botname', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div><!--col-md-10-->
</div>
<!--Webhook Integration Test-->
@if($webhook_selected == 'Slack' || $webhook_selected == 'Discord')
@if($webhook_endpoint != null && $webhook_channel != null)
<div class="form-group">
<div class="col-md-offset-2 col-md-8">
<a href="#" wire:click.prevent="testWebhook"
class="btn btn-default btn-sm pull-left"><span><i class="{{$webhook_icon}}"></i> {!! trans('admin/settings/general.webhook_test',['app' => $webhook_selected ]) !!}</span></a>
<div wire:loading><span style="padding-left: 5px; font-size: 20px"><i
class="fas fa-spinner fa-spin"></i></span></div>
</div>
</div>
@endif
@endif
<div class="box-footer" style="margin-top: 45px;">
<div class="text-right col-md-12">
<a class="btn btn-link text-left"
href="{{ route('settings.index') }}">{{ trans('button.cancel') }}</a>
<button type="submit" {{$isDisabled}} class="btn btn-primary"><i
class="fas fa-check icon-white"
aria-hidden="true"></i> {{ trans('general.save') }}</button>
</div>
</div><!--box-footer-->
</form>
</div> <!-- /box -->
</div> <!-- /.col-md-8-->

View file

@ -164,12 +164,12 @@
<div class="box-body text-center">
<h5>
<a href="{{ route('settings.slack.index') }}" class="settings_button">
<i class="fab fa-slack fa-4x" aria-hidden="true"></i>
<i class="fa-solid fa-hashtag fa-4x" aria-hidden="true"></i>
<br><br>
<span class="name">{{ trans('admin/settings/general.slack') }}</span>
<span class="name">{{ trans('admin/settings/general.integrations') }}</span>
</a>
</h5>
<p class="help-block">{{ trans('admin/settings/general.slack_help') }}</p>
<p class="help-block">{{ trans('admin/settings/general.webhook_help') }}</p>
</div>
</div>
</div>

View file

@ -1,39 +1,7 @@
@extends('layouts/default')
{{-- Page title --}}
@section('title')
{{ trans('admin/settings/general.slack_title') }}
@parent
@stop
@section('header_right')
<a href="{{ route('settings.index') }}" class="btn btn-primary"> {{ trans('general.back') }}</a>
@stop
{{-- Page content --}}
@section('content')
<div class="row">
<div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2">
<div class="panel box box-default">
<div class="box-header with-border">
<h2 class="box-title">
<i class="fab fa-slack"></i> {{ trans('admin/settings/general.slack') }}
</h2>
</div>
<div class="box-body">
<div class="col-md-12">
<p>
{!! trans('admin/settings/general.slack_integration_help',array('slack_link' => 'https://my.slack.com/services/new/incoming-webhook')) !!}
</p>
<br>
</div>
@livewire('slack-settings-form')
</div> <!-- /.col-md-8-->
</div> <!-- /.row-->