implements #11 Ticket type templating
This commit is contained in:
parent
22a3f7bf27
commit
b44d3bb07a
14 changed files with 334 additions and 12 deletions
|
|
@ -12,7 +12,7 @@ use Kwaadpepper\Enum\BaseEnumRoutable;
|
|||
* @method static self qrcode()
|
||||
* @method static self advice()
|
||||
*/
|
||||
class TicketType extends BaseEnumRoutable
|
||||
class TicketTypeEnum extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Enum values
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Enums\TicketStatus;
|
||||
use App\Enums\TicketType;
|
||||
use App\Enums\TicketTypeEnum;
|
||||
use App\Events\NotifySubscriptions;
|
||||
use App\Events\TicketStatusChanged;
|
||||
use App\Http\Requests\AssignTicketToUserRequest;
|
||||
|
|
@ -578,9 +578,9 @@ class TicketController extends Controller
|
|||
})->map(function (TicketStatus $ticket) {
|
||||
return $ticket->value;
|
||||
});
|
||||
$t = collect(TicketType::toArray())->filter(function (TicketType $s) use ($word) {
|
||||
$t = collect(TicketTypeEnum::toArray())->filter(function (TicketTypeEnum $s) use ($word) {
|
||||
return Str::slug($s->label) === Str::slug($word);
|
||||
})->map(function (TicketType $ticket) {
|
||||
})->map(function (TicketTypeEnum $ticket) {
|
||||
return $ticket->value;
|
||||
});
|
||||
$q->orWhere('id', $word)
|
||||
|
|
|
|||
37
app/Http/Controllers/TicketTypeController.php
Normal file
37
app/Http/Controllers/TicketTypeController.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Ticket\TicketType;
|
||||
use Kwaadpepper\CrudPolicies\Traits\CrudController;
|
||||
|
||||
class TicketTypeController extends Controller
|
||||
{
|
||||
use CrudController {
|
||||
edit as crudEdit;
|
||||
}
|
||||
|
||||
/** @var \App\Models\MacroSchedule\Marker */
|
||||
public static $modelClass = TicketType::class;
|
||||
|
||||
/**
|
||||
* Crud Layout
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $layout = 'layout.app';
|
||||
|
||||
/**
|
||||
* Edit model action
|
||||
*
|
||||
* @param mixed ...$params
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function edit(...$params)
|
||||
{
|
||||
/** @var \Illuminate\View\View */
|
||||
$view = call_user_func_array([$this, 'crudEdit'], $params);
|
||||
|
||||
return view('ticket_types.edit', \array_merge($view->getData()));
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
namespace App\Http\Requests;
|
||||
|
||||
use App\Enums\TicketStatus;
|
||||
use App\Enums\TicketType;
|
||||
use App\Enums\TicketTypeEnum;
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
|
|
@ -78,9 +78,9 @@ class StoreTicket extends FormRequest
|
|||
'required',
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
if (!in_array($value, TicketType::toValues())) {
|
||||
if (!in_array($value, TicketTypeEnum::toValues())) {
|
||||
$fail(__('Veuillez choisir entre :values', [
|
||||
'value' => implode(',', TicketType::toLabels())
|
||||
'value' => implode(',', TicketTypeEnum::toLabels())
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ namespace App\Models;
|
|||
|
||||
use App\Enums\Role;
|
||||
use App\Enums\TicketStatus;
|
||||
use App\Enums\TicketType;
|
||||
use App\Enums\TicketTypeEnum;
|
||||
use App\Events\NotifyAdmin;
|
||||
use App\Events\NotifySubscriptions;
|
||||
use App\Events\TicketStatusChanged;
|
||||
|
|
@ -12,6 +12,7 @@ use App\Jobs\SendTicketMentionMail;
|
|||
use App\Mail\TicketMention;
|
||||
use App\Models\Credit\Account;
|
||||
use App\Models\Credit\Estimation;
|
||||
use App\Models\Ticket\TicketType;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
|
@ -29,7 +30,7 @@ class Ticket extends Model
|
|||
* @var array
|
||||
*/
|
||||
protected $enumCasts = [
|
||||
'type' => TicketType::class,
|
||||
'type' => TicketTypeEnum::class,
|
||||
'status' => TicketStatus::class
|
||||
];
|
||||
|
||||
|
|
@ -64,7 +65,7 @@ class Ticket extends Model
|
|||
{
|
||||
static::creating(function (Ticket $ticket) {
|
||||
// If bug force the ticket status on new. All the others are estimateTodo.
|
||||
if ($ticket->type->equals(TicketType::bug())) {
|
||||
if ($ticket->type->equals(TicketTypeEnum::bug())) {
|
||||
$ticket->status = TicketStatus::new();
|
||||
} else {
|
||||
$ticket->status = TicketStatus::estimateTodo();
|
||||
|
|
@ -168,6 +169,16 @@ class Ticket extends Model
|
|||
return $this->belongsToMany(Label::class, 'label_ticket');
|
||||
}
|
||||
|
||||
/**
|
||||
* BelongsTo ticket_type
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function ticketType()
|
||||
{
|
||||
return $this->belongsTo(TicketType::class, 'type', 'type');
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
|
|
|
|||
109
app/Models/Ticket/TicketType.php
Normal file
109
app/Models/Ticket/TicketType.php
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Ticket;
|
||||
|
||||
use App\Enums\TicketTypeEnum;
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Kwaadpepper\CrudPolicies\Enums\CrudAction;
|
||||
use Kwaadpepper\CrudPolicies\Enums\CrudType;
|
||||
use Kwaadpepper\CrudPolicies\Traits\IsCrudModel;
|
||||
use Kwaadpepper\Enum\Traits\CastsEnums;
|
||||
|
||||
class TicketType extends Model
|
||||
{
|
||||
use CastsEnums;
|
||||
use HasFactory;
|
||||
use IsCrudModel;
|
||||
|
||||
/**
|
||||
* Crud Label
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $crudLabelColumn = 'type';
|
||||
|
||||
/**
|
||||
* Crud Value
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $crudValueColumn = 'id';
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to Enums.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $enumCasts = [
|
||||
'type' => TicketTypeEnum::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'type',
|
||||
'template'
|
||||
];
|
||||
|
||||
/**
|
||||
* TicketType
|
||||
*
|
||||
* @param array $attributes
|
||||
*/
|
||||
public function __construct(array $attributes = [])
|
||||
{
|
||||
self::$editableProperties = [
|
||||
'type' => [
|
||||
'label' => trans('Type'),
|
||||
'type' => CrudType::enum(),
|
||||
'enum' => TicketTypeEnum::class,
|
||||
'required' => true,
|
||||
'readonly' => true,
|
||||
'nullable' => false,
|
||||
'actions' => [
|
||||
CrudAction::viewAny(),
|
||||
CrudAction::update()
|
||||
]
|
||||
],
|
||||
'template' => [
|
||||
'label' => trans('Template'),
|
||||
'type' => CrudType::text(),
|
||||
'required' => true,
|
||||
'readonly' => false,
|
||||
'nullable' => false,
|
||||
'actions' => [
|
||||
CrudAction::view(),
|
||||
CrudAction::update()
|
||||
]
|
||||
],
|
||||
];
|
||||
parent::__construct($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function () {
|
||||
throw new \Error('Denied');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* BelongsToMany tickets
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function tickets()
|
||||
{
|
||||
return $this->hasMany(Ticket::class, 'type', 'type');
|
||||
}
|
||||
}
|
||||
32
app/Policies/TicketTypePolicy.php
Normal file
32
app/Policies/TicketTypePolicy.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Policies\Rules\UserRoleRules as URR;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Kwaadpepper\CrudPolicies\Policies\RootPolicy;
|
||||
|
||||
class TicketTypePolicy extends RootPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Init policies on call
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return void
|
||||
*/
|
||||
public function setPolicies(User $user)
|
||||
{
|
||||
/**
|
||||
* This first rule to return true in a policy action authorises the action
|
||||
*/
|
||||
$this->policies = [
|
||||
'tickettype' => [
|
||||
'viewAny' => URR::make('userIsAdmin', $user),
|
||||
'update' => URR::make('userIsAdmin', $user)
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ use App\Models\Package;
|
|||
use App\Models\Project;
|
||||
use App\Models\Site;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\Ticket\TicketType;
|
||||
use App\Models\User;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
|
|
@ -102,6 +103,7 @@ class RouteServiceProvider extends ServiceProvider
|
|||
Route::model('user', User::class);
|
||||
Route::model('site', Site::class);
|
||||
Route::model('project', Project::class);
|
||||
Route::model('ticket_type', TicketType::class);
|
||||
Route::bind('ticket', function ($value) {
|
||||
return Ticket::where('id', $value)->has('site')->firstOrFail();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ return [
|
|||
'Carbon' => 'Carbon\Carbon',
|
||||
|
||||
// * Application custom
|
||||
'TicketType' => App\Enums\TicketType::class,
|
||||
'TicketTypeEnum' => App\Enums\TicketTypeEnum::class,
|
||||
'TicketStatus' => App\Enums\TicketStatus::class,
|
||||
'ToolboxHelper' => App\Lib\ToolboxHelper::class,
|
||||
'CrudAction' => App\Enums\CrudAction::class,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
use App\Enums\TicketTypeEnum;
|
||||
use App\Models\Ticket\TicketType;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateTicketTypesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('ticket_types', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->unsignedTinyInteger('type')->unique()->comment('TicketType Enum');
|
||||
$table->text('template')->comment('Le template du type de ticket');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
collect(TicketTypeEnum::toArray())->each(function (TicketTypeEnum $ticketTypeEnum) {
|
||||
(new TicketType([
|
||||
'type' => $ticketTypeEnum,
|
||||
'template' => "Problème recontré :\n\nUrl pertinents :\n\nCi-joint une capture d'écran.\nCordialement.",
|
||||
]))->saveQuietly();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('ticket_types');
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ $userPr = Auth::user()->sites ?? collect([]);
|
|||
<div class="form-group col">
|
||||
<label for="type" class="col-form-label">{{ __('Type') }}</label>
|
||||
<select class="form-select" name="type" id="type">
|
||||
@foreach(TicketType::toArray() as $ticketType)
|
||||
@foreach(\App\Enums\TicketTypeEnum::toArray() as $ticketType)
|
||||
<option value="{{ $ticketType->value }}" @if($ticketType->value == old('type') or (isset($ticket) and $ticketType->equals($ticket->type)))selected @endif>{{ $ticketType->label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
|
|
@ -31,6 +31,41 @@ $userPr = Auth::user()->sites ?? collect([]);
|
|||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
@push('scripts')
|
||||
<script nonce="{{ $nonce ?? null }}">
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const typeSwitch = document.getElementById('type');
|
||||
const textArea = document.getElementById('text');
|
||||
const templates = {
|
||||
@foreach(\App\Models\Ticket\TicketType::query()->get() as $ticketTypeModel)
|
||||
@php $value = str_replace(["\r\n", "\n", "\r"], '\n', str_replace("<br />", '\n', strip_tags(nl2br($ticketTypeModel->template), '<br />'))); @endphp
|
||||
"{{ $ticketTypeModel->type->value }}" : "{!! $value !!}",
|
||||
@endforeach
|
||||
};
|
||||
|
||||
const changeTextValue = () => {
|
||||
switch(typeSwitch.value) {
|
||||
@foreach(\App\Models\Ticket\TicketType::query()->get() as $ticketTypeModel)
|
||||
case "{{ $ticketTypeModel->type->value }}":
|
||||
// * Ignore if template already changed.
|
||||
if(textArea.value !== (templates[textArea.template] ?? null) && textArea.value.length) {
|
||||
return;
|
||||
}
|
||||
// Save actual template
|
||||
textArea.template = typeSwitch.value;
|
||||
// apply template
|
||||
textArea.value = templates[typeSwitch.value];
|
||||
break;
|
||||
@endforeach
|
||||
default:
|
||||
console.error(`Unkown value ${typeSwitch.value}`);
|
||||
}
|
||||
};
|
||||
typeSwitch.addEventListener('change', changeTextValue);
|
||||
changeTextValue();
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@else
|
||||
<input type="hidden" name="status" value="{{ \App\Enums\TicketStatus::new() }}" required>
|
||||
@endcan
|
||||
|
|
|
|||
24
resources/views/ticket_types/edit.blade.php
Normal file
24
resources/views/ticket_types/edit.blade.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
@extends('layout.app')
|
||||
|
||||
@section('bodyClass', 'col-md-8')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="col h4">
|
||||
<a href="{{ route('ticket_types.index') }}" class="text-decoration-none btn btn-sm btn-primary" role="button" aria-roledescription="{{ _('Revenir en arrière') }}"><i class="fa-solid fa-arrow-left-long"></i></a>
|
||||
<span> {{ __('Modifier un type de ticket') }}</span> - {{ $model->type->label }}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('ticket_types.update', $model->id) }}" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
@include('ticket_types.form-inputs')
|
||||
<div class="form-group text-center">
|
||||
<input type="submit" class="btn btn-primary" value="Modifier">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
19
resources/views/ticket_types/form-inputs.blade.php
Normal file
19
resources/views/ticket_types/form-inputs.blade.php
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<div class="form-group mb-5">
|
||||
<label for="type"><b>{{ __('Type') }}</b></label>
|
||||
<select class="form-select" name="type" id="type" readonly>
|
||||
<option value="" @if(!old('credit_account_id')) selected @endif disabled>{{ __('Veuillez sélectionner un compte à débiter') }}</option>
|
||||
@foreach(\App\Enums\TicketTypeEnum::toArray() as $ticketTypeEnum)
|
||||
<option value="{{ $ticketTypeEnum->value }}" @if($model->type->value === $ticketTypeEnum->value or old('type') == $ticketTypeEnum->value) selected @endif>{{ $ticketTypeEnum->label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@include('modules.input-error', [
|
||||
'inputName' => 'type'
|
||||
])
|
||||
</div>
|
||||
<div class="form-group mb-5">
|
||||
<label for="template" class="col-form-label text-md-right">{{ __('Template') }}</label>
|
||||
<textarea rows="15" class="form-control" name="template" id="text" placeholder="{{ __('Template du type de ticket') }} *">{{ old('template') ?? $model->template ?? ''}}</textarea>
|
||||
@include('modules.input-error', [
|
||||
'inputName' => 'template'
|
||||
])
|
||||
</div>
|
||||
|
|
@ -19,6 +19,7 @@ use App\Http\Controllers\ProjectController;
|
|||
use App\Http\Controllers\ScheduleController;
|
||||
use App\Http\Controllers\SiteController;
|
||||
use App\Http\Controllers\TicketController;
|
||||
use App\Http\Controllers\TicketTypeController;
|
||||
use App\Http\Controllers\UserController;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
|
@ -93,6 +94,14 @@ Route::middleware('auth:web')->group(function () {
|
|||
'macro_markers' => 'marker'
|
||||
]);
|
||||
|
||||
// * Types de tickets
|
||||
Route::resource('ticket_types', TicketTypeController::class)->only(['index', 'edit', 'update'])
|
||||
->withoutMiddleware('htmlsanitize')
|
||||
->middleware('htmlsanitize:template')
|
||||
->parameters([
|
||||
'ticket_types' => 'ticket_type'
|
||||
]);
|
||||
|
||||
// * Brands and Accounts
|
||||
Route::resource('credit_accounts', AccountController::class)->only(['index'])
|
||||
->parameters([
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue