mirror of
https://github.com/snipe/snipe-it.git
synced 2025-03-05 20:52:15 -08:00
Adds accepting/declining to new controller
This commit is contained in:
parent
39e6b59335
commit
830a6cf67e
32
app/Events/ItemAccepted.php
Normal file
32
app/Events/ItemAccepted.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use App\Models\Accessory;
|
||||||
|
use App\Models\Actionlog;
|
||||||
|
use App\Models\Contracts\Acceptable;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Broadcasting\Channel;
|
||||||
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class ItemAccepted
|
||||||
|
{
|
||||||
|
use Dispatchable, SerializesModels;
|
||||||
|
|
||||||
|
public $item;
|
||||||
|
public $acceptedBy;
|
||||||
|
public $signature;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Acceptable $item, User $acceptedBy, string $signature)
|
||||||
|
{
|
||||||
|
$this->item = $item;
|
||||||
|
$this->acceptedBy = $acceptedBy;
|
||||||
|
$this->signature = $signature;
|
||||||
|
}
|
||||||
|
}
|
32
app/Events/ItemDeclined.php
Normal file
32
app/Events/ItemDeclined.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use App\Models\Accessory;
|
||||||
|
use App\Models\Actionlog;
|
||||||
|
use App\Models\Contracts\Acceptable;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Broadcasting\Channel;
|
||||||
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class ItemDeclined
|
||||||
|
{
|
||||||
|
use Dispatchable, SerializesModels;
|
||||||
|
|
||||||
|
public $item;
|
||||||
|
public $declinedBy;
|
||||||
|
public $signature;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Acceptable $item, User $declinedBy, string $signature)
|
||||||
|
{
|
||||||
|
$this->item = $item;
|
||||||
|
$this->declinedBy = $declinedBy;
|
||||||
|
$this->signature = $signature;
|
||||||
|
}
|
||||||
|
}
|
119
app/Http/Controllers/Account/AcceptanceController.php
Normal file
119
app/Http/Controllers/Account/AcceptanceController.php
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
<?php
|
||||||
|
namespace App\Http\Controllers\Account;
|
||||||
|
|
||||||
|
use App\Events\ItemAccepted;
|
||||||
|
use App\Events\ItemDeclined;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Asset;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\Consumable;
|
||||||
|
use App\Models\Contracts\Acceptable;
|
||||||
|
use App\Models\License;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class AcceptanceController extends Controller {
|
||||||
|
|
||||||
|
public function index(Request $request) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
public function edit(Request $request, $type, $id) {
|
||||||
|
|
||||||
|
$item = $this->getItemById($type, $id);
|
||||||
|
|
||||||
|
if (is_null($item)) {
|
||||||
|
return redirect()->reoute('account.accept')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($item->isAccepted()) {
|
||||||
|
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.asset_already_accepted'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $item->isCheckedOutTo(Auth::user())) {
|
||||||
|
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Company::isCurrentUserHasAccess($item)) {
|
||||||
|
return redirect()->route('account.accept')->with('error', trans('general.insufficient_permissions'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('account/accept', compact('item'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request, $type, $id) {
|
||||||
|
$item = $this->getItemById($type, $id);
|
||||||
|
|
||||||
|
if (is_null($item)) {
|
||||||
|
return redirect()->reoute('account.accept')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($item->isAccepted()) {
|
||||||
|
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.asset_already_accepted'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $item->isCheckedOutTo(Auth::user())) {
|
||||||
|
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Company::isCurrentUserHasAccess($item)) {
|
||||||
|
return redirect()->route('account.accept')->with('error', trans('general.insufficient_permissions'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$request->filled('asset_acceptance')) {
|
||||||
|
return redirect()->back()->with('error', trans('admin/users/message.error.accept_or_decline'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the signature and save it
|
||||||
|
*/
|
||||||
|
if ($request->filled('signature_output')) {
|
||||||
|
$path = config('app.private_uploads').'/signatures';
|
||||||
|
$sig_filename = "siglog-" .Str::uuid() . '-'.date('Y-m-d-his').".png";
|
||||||
|
$data_uri = e($request->input('signature_output'));
|
||||||
|
$encoded_image = explode(",", $data_uri);
|
||||||
|
$decoded_image = base64_decode($encoded_image[1]);
|
||||||
|
file_put_contents($path."/".$sig_filename, $decoded_image);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($request->input('asset_acceptance') == 'accepted') {
|
||||||
|
|
||||||
|
$item->accept(Auth::user(), $sig_filename);
|
||||||
|
|
||||||
|
event(new ItemAccepted($item, Auth::user(), $sig_filename));
|
||||||
|
|
||||||
|
$return_msg = trans('admin/users/message.accepted');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$item->decline(Auth::user(), $sig_filename);
|
||||||
|
|
||||||
|
event(new ItemDeclined($item, Auth::user(), $sig_filename));
|
||||||
|
|
||||||
|
$return_msg = trans('admin/users/message.declined');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->to('account/accept')->with('success', $return_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getItemById($type, $id) : ? Acceptable {
|
||||||
|
switch ($type) {
|
||||||
|
case 'asset':
|
||||||
|
$item = Asset::findOrFail($id);
|
||||||
|
break;
|
||||||
|
case 'consumable':
|
||||||
|
$item = Consumable::findOrFail($id);
|
||||||
|
break;
|
||||||
|
case 'license':
|
||||||
|
$item = License::findOrFail($id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$item = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,8 @@ use App\Events\AssetCheckedOut;
|
||||||
use App\Events\ComponentCheckedIn;
|
use App\Events\ComponentCheckedIn;
|
||||||
use App\Events\ComponentCheckedOut;
|
use App\Events\ComponentCheckedOut;
|
||||||
use App\Events\ConsumableCheckedOut;
|
use App\Events\ConsumableCheckedOut;
|
||||||
|
use App\Events\ItemAccepted;
|
||||||
|
use App\Events\ItemDeclined;
|
||||||
use App\Events\LicenseCheckedIn;
|
use App\Events\LicenseCheckedIn;
|
||||||
use App\Events\LicenseCheckedOut;
|
use App\Events\LicenseCheckedOut;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
|
@ -63,6 +65,26 @@ class LogListener
|
||||||
$event->license->logCheckout($event->note, $event->checkedOutTo);
|
$event->license->logCheckout($event->note, $event->checkedOutTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onItemAccepted(ItemAccepted $event) {
|
||||||
|
$logaction = new Actionlog();
|
||||||
|
$logaction->item()->associate($event->item);
|
||||||
|
$logaction->target()->associate($event->acceptedBy);
|
||||||
|
$logaction->accept_signature = $event->signature;
|
||||||
|
$logaction->action_type = 'accepted';
|
||||||
|
|
||||||
|
$logaction->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onItemDeclined(ItemDeclined $event) {
|
||||||
|
$logaction = new Actionlog();
|
||||||
|
$logaction->item()->associate($event->item);
|
||||||
|
$logaction->target()->associate($event->declinedBy);
|
||||||
|
$logaction->accept_signature = $event->signature;
|
||||||
|
$logaction->action_type = 'declined';
|
||||||
|
|
||||||
|
$logaction->save();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the listeners for the subscriber.
|
* Register the listeners for the subscriber.
|
||||||
*
|
*
|
||||||
|
@ -80,6 +102,8 @@ class LogListener
|
||||||
'ConsumableCheckedOut',
|
'ConsumableCheckedOut',
|
||||||
'LicenseCheckedIn',
|
'LicenseCheckedIn',
|
||||||
'LicenseCheckedOut',
|
'LicenseCheckedOut',
|
||||||
|
'ItemAccepted',
|
||||||
|
'ItemDeclined',
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach($list as $event) {
|
foreach($list as $event) {
|
||||||
|
|
135
resources/views/account/accept.blade.php
Normal file
135
resources/views/account/accept.blade.php
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
@extends('layouts/default')
|
||||||
|
|
||||||
|
{{-- Page title --}}
|
||||||
|
@section('title')
|
||||||
|
Accept {{ $item->present()->name() }}
|
||||||
|
@parent
|
||||||
|
@stop
|
||||||
|
|
||||||
|
|
||||||
|
{{-- Page content --}}
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="{{ asset('css/signature-pad.css') }}">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.form-horizontal .control-label, .form-horizontal .radio, .form-horizontal .checkbox, .form-horizontal .radio-inline, .form-horizontal .checkbox-inline {
|
||||||
|
padding-top: 17px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#eula_div {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
overflow: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<form class="form-horizontal" method="post" action="" autocomplete="off">
|
||||||
|
<!-- CSRF Token -->
|
||||||
|
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
|
||||||
|
|
||||||
|
|
||||||
|
<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-body">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="radio">
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="asset_acceptance" id="accepted" value="accepted">
|
||||||
|
I accept
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="radio">
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="asset_acceptance" id="declined" value="declined">
|
||||||
|
I decline
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if ($item->getEula())
|
||||||
|
<div class="col-md-12" style="padding-top: 20px">
|
||||||
|
<div id="eula_div">
|
||||||
|
{!! $item->getEula() !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if ($snipeSettings->require_accept_signature=='1')
|
||||||
|
<div class="col-md-12 col-sm-12 text-center" style="padding-top: 20px">
|
||||||
|
|
||||||
|
<h3>Sign below to indicate that you agree to the terms of service:</h3>
|
||||||
|
|
||||||
|
<div id="signature-pad" class="m-signature-pad">
|
||||||
|
<div class="m-signature-pad--body col-md-12 col-sm-12 col-lg-12 col-xs-12">
|
||||||
|
<canvas></canvas>
|
||||||
|
<input type="hidden" name="signature_output" id="signature_output">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12 col-sm-12 col-lg-12 col-xs-12 text-center">
|
||||||
|
<button type="button" class="btn btn-sm btn-default clear" data-action="clear" id="clear_button">Clear Signature</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> <!-- .col-md-12.text-center-->
|
||||||
|
@endif
|
||||||
|
|
||||||
|
</div><!-- / col-md-12 -->
|
||||||
|
|
||||||
|
</div> <!-- / box-body -->
|
||||||
|
<div class="box-footer text-right">
|
||||||
|
<button type="submit" class="btn btn-success" id="submit-button"><i class="fa fa-check icon-white"></i> {{ trans('general.submit') }}</button>
|
||||||
|
</div><!-- /.box-footer -->
|
||||||
|
</div> <!-- / box-default -->
|
||||||
|
</div> <!-- / col -->
|
||||||
|
</div> <!-- / row -->
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@section('moar_scripts')
|
||||||
|
|
||||||
|
<script src="{{ asset('js/signature_pad.min.js') }}"></script>
|
||||||
|
<script nonce="{{ csrf_token() }}">
|
||||||
|
var wrapper = document.getElementById("signature-pad"),
|
||||||
|
clearButton = wrapper.querySelector("[data-action=clear]"),
|
||||||
|
saveButton = wrapper.querySelector("[data-action=save]"),
|
||||||
|
canvas = wrapper.querySelector("canvas"),
|
||||||
|
signaturePad;
|
||||||
|
|
||||||
|
// Adjust canvas coordinate space taking into account pixel ratio,
|
||||||
|
// to make it look crisp on mobile devices.
|
||||||
|
// This also causes canvas to be cleared.
|
||||||
|
function resizeCanvas() {
|
||||||
|
// When zoomed out to less than 100%, for some very strange reason,
|
||||||
|
// some browsers report devicePixelRatio as less than 1
|
||||||
|
// and only part of the canvas is cleared then.
|
||||||
|
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||||
|
canvas.width = canvas.offsetWidth * ratio;
|
||||||
|
canvas.height = canvas.offsetHeight * ratio;
|
||||||
|
canvas.getContext("2d").scale(ratio, ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onresize = resizeCanvas;
|
||||||
|
resizeCanvas();
|
||||||
|
|
||||||
|
signaturePad = new SignaturePad(canvas);
|
||||||
|
|
||||||
|
$('#clear_button').on("click", function (event) {
|
||||||
|
signaturePad.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#submit-button').on("click", function (event) {
|
||||||
|
if (signaturePad.isEmpty()) {
|
||||||
|
alert("Please provide signature first.");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
$('#signature_output').val(signaturePad.toDataURL());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
@stop
|
|
@ -274,6 +274,15 @@ Route::group([ 'prefix' => 'account', 'middleware' => ['auth']], function () {
|
||||||
# Account Dashboard
|
# Account Dashboard
|
||||||
Route::get('/', [ 'as' => 'account', 'uses' => 'ViewAssetsController@getIndex' ]);
|
Route::get('/', [ 'as' => 'account', 'uses' => 'ViewAssetsController@getIndex' ]);
|
||||||
|
|
||||||
|
|
||||||
|
Route::get('accept', 'Account\AcceptanceController@index')
|
||||||
|
->name('account.accept');
|
||||||
|
|
||||||
|
Route::get('accept/{type}/{id}', 'Account\AcceptanceController@edit')
|
||||||
|
->name('account.accept.item');
|
||||||
|
|
||||||
|
Route::post('accept/{type}/{id}', 'Account\AcceptanceController@update');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue