mirror of
https://github.com/grokability/snipe-it.git
synced 2026-03-12 17:52:00 +08:00
Merge remote-tracking branch 'origin/develop'
This commit is contained in:
24
app/Events/CheckoutablesCheckedOutInBulk.php
Normal file
24
app/Events/CheckoutablesCheckedOutInBulk.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class CheckoutablesCheckedOutInBulk
|
||||
{
|
||||
use Dispatchable, SerializesModels;
|
||||
|
||||
public function __construct(
|
||||
public Collection $assets,
|
||||
public Model $target,
|
||||
public User $admin,
|
||||
public string $checkout_at,
|
||||
public string $expected_checkin,
|
||||
public string $note,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Assets;
|
||||
|
||||
use App\Events\CheckoutablesCheckedOutInBulk;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\CheckInOutRequest;
|
||||
use App\Http\Controllers\Controller;
|
||||
@@ -12,6 +13,7 @@ use App\Models\Setting;
|
||||
use App\View\Label;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Context;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
@@ -644,6 +646,8 @@ class BulkAssetsController extends Controller
|
||||
*/
|
||||
public function storeCheckout(AssetCheckoutRequest $request) : RedirectResponse | ModelNotFoundException
|
||||
{
|
||||
Context::add('action', 'bulk_asset_checkout');
|
||||
|
||||
$this->authorize('checkout', Asset::class);
|
||||
|
||||
try {
|
||||
@@ -730,6 +734,15 @@ class BulkAssetsController extends Controller
|
||||
});
|
||||
|
||||
if (! $errors) {
|
||||
CheckoutablesCheckedOutInBulk::dispatch(
|
||||
$assets,
|
||||
$target,
|
||||
$admin,
|
||||
$checkout_at,
|
||||
$expected_checkin,
|
||||
e($request->get('note')),
|
||||
);
|
||||
|
||||
// Redirect to the new asset page
|
||||
return redirect()->to('hardware')->with('success', trans_choice('admin/hardware/message.multi-checkout.success', $asset_ids));
|
||||
}
|
||||
|
||||
@@ -32,15 +32,16 @@ use App\Models\Location;
|
||||
use App\Models\Maintenance;
|
||||
use App\Models\Supplier;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Traits\DisablesDebugbar;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
abstract class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
use AuthorizesRequests, DisablesDebugbar, DispatchesJobs, ValidatesRequests;
|
||||
|
||||
static $map_object_type = [
|
||||
'accessories' => Accessory::class,
|
||||
|
||||
@@ -315,7 +315,8 @@ class LicensesController extends Controller
|
||||
public function getExportLicensesCsv()
|
||||
{
|
||||
$this->authorize('view', License::class);
|
||||
\Debugbar::disable();
|
||||
|
||||
$this->disableDebugbar();
|
||||
|
||||
$response = new StreamedResponse(function () {
|
||||
// Open output stream
|
||||
|
||||
@@ -38,7 +38,7 @@ class ModalController extends Controller
|
||||
|
||||
|
||||
if (in_array($type, $allowed_types)) {
|
||||
$view = view("modals.${type}");
|
||||
$view = view("modals.{$type}");
|
||||
|
||||
if ($type == "statuslabel") {
|
||||
$view->with('statuslabel_types', Helper::statusTypeList());
|
||||
|
||||
@@ -242,7 +242,8 @@ class ReportsController extends Controller
|
||||
ini_set('max_execution_time', 12000);
|
||||
$this->authorize('reports.view');
|
||||
|
||||
\Debugbar::disable();
|
||||
$this->disableDebugbar();
|
||||
|
||||
$response = new StreamedResponse(function () {
|
||||
Log::debug('Starting streamed response');
|
||||
|
||||
@@ -437,8 +438,8 @@ class ReportsController extends Controller
|
||||
ini_set('max_execution_time', env('REPORT_TIME_LIMIT', 12000)); //12000 seconds = 200 minutes
|
||||
$this->authorize('reports.view');
|
||||
|
||||
$this->disableDebugbar();
|
||||
|
||||
\Debugbar::disable();
|
||||
$customfields = CustomField::get();
|
||||
$response = new StreamedResponse(function () use ($customfields, $request) {
|
||||
Log::debug('Starting streamed response');
|
||||
|
||||
@@ -510,7 +510,8 @@ class UsersController extends Controller
|
||||
public function getExportUserCsv()
|
||||
{
|
||||
$this->authorize('view', User::class);
|
||||
\Debugbar::disable();
|
||||
|
||||
$this->disableDebugbar();
|
||||
|
||||
$response = new StreamedResponse(function () {
|
||||
// Open output stream
|
||||
|
||||
@@ -206,7 +206,7 @@ class ViewAssetsController extends Controller
|
||||
if ($fullItemType == Asset::class) {
|
||||
$data['item_url'] = route('hardware.show', $item->id);
|
||||
} else {
|
||||
$data['item_url'] = route("view/${itemType}", $item->id);
|
||||
$data['item_url'] = route("view/{$itemType}", $item->id);
|
||||
}
|
||||
|
||||
$settings = Setting::getSettings();
|
||||
|
||||
@@ -211,7 +211,7 @@ class AssetsTransformer
|
||||
return $asset->assigned ? [
|
||||
'id' => (int) $asset->assigned->id,
|
||||
'username' => e($asset->assigned->username),
|
||||
'name' => e($asset->assigned->getFullNameAttribute()),
|
||||
'name' => e($asset->assigned->display_name),
|
||||
'first_name'=> e($asset->assigned->first_name),
|
||||
'last_name'=> ($asset->assigned->last_name) ? e($asset->assigned->last_name) : null,
|
||||
'email'=> ($asset->assigned->email) ? e($asset->assigned->email) : null,
|
||||
|
||||
@@ -141,7 +141,7 @@ class UsersTransformer
|
||||
'id' => (int) $user->id,
|
||||
'image' => e($user->present()->gravatar) ?? null,
|
||||
'type' => 'user',
|
||||
'name' => e($user->getFullNameAttribute()),
|
||||
'name' => e($user->display_name),
|
||||
'first_name' => e($user->first_name),
|
||||
'last_name' => e($user->last_name),
|
||||
'username' => e($user->username),
|
||||
|
||||
@@ -33,6 +33,7 @@ use App\Notifications\CheckoutConsumableNotification;
|
||||
use App\Notifications\CheckoutLicenseSeatNotification;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Context;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Exception;
|
||||
@@ -441,12 +442,17 @@ class CheckoutableListener
|
||||
private function shouldSendCheckoutEmailToUser(Model $checkoutable): bool
|
||||
{
|
||||
/**
|
||||
* Send an email if any of the following conditions are met:
|
||||
* Send an email if we didn't get here from a bulk checkout
|
||||
* and any of the following conditions are met:
|
||||
* 1. The asset requires acceptance
|
||||
* 2. The item has a EULA
|
||||
* 3. The item should send an email at check-in/check-out
|
||||
*/
|
||||
|
||||
if (Context::get('action') === 'bulk_asset_checkout') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($checkoutable->requireAcceptance()) {
|
||||
return true;
|
||||
}
|
||||
@@ -464,6 +470,10 @@ class CheckoutableListener
|
||||
|
||||
private function shouldSendEmailToAlertAddress($acceptance = null): bool
|
||||
{
|
||||
if (Context::get('action') === 'bulk_asset_checkout') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$setting = Setting::getSettings();
|
||||
|
||||
if (!$setting) {
|
||||
|
||||
154
app/Listeners/CheckoutablesCheckedOutInBulkListener.php
Normal file
154
app/Listeners/CheckoutablesCheckedOutInBulkListener.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\CheckoutablesCheckedOutInBulk;
|
||||
use App\Mail\BulkAssetCheckoutMail;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Location;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class CheckoutablesCheckedOutInBulkListener
|
||||
{
|
||||
|
||||
public function subscribe($events)
|
||||
{
|
||||
$events->listen(
|
||||
CheckoutablesCheckedOutInBulk::class,
|
||||
CheckoutablesCheckedOutInBulkListener::class
|
||||
);
|
||||
}
|
||||
|
||||
public function handle(CheckoutablesCheckedOutInBulk $event): void
|
||||
{
|
||||
$notifiableUser = $this->getNotifiableUser($event);
|
||||
|
||||
$shouldSendEmailToUser = $this->shouldSendCheckoutEmailToUser($notifiableUser, $event->assets);
|
||||
$shouldSendEmailToAlertAddress = $this->shouldSendEmailToAlertAddress($event->assets);
|
||||
|
||||
if ($shouldSendEmailToUser && $notifiableUser) {
|
||||
try {
|
||||
Mail::to($notifiableUser)->send(new BulkAssetCheckoutMail(
|
||||
$event->assets,
|
||||
$event->target,
|
||||
$event->admin,
|
||||
$event->checkout_at,
|
||||
$event->expected_checkin,
|
||||
$event->note,
|
||||
));
|
||||
|
||||
Log::info('BulkAssetCheckoutMail sent to checkout target');
|
||||
} catch (Exception $e) {
|
||||
Log::debug("Exception caught during BulkAssetCheckoutMail to target: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if ($shouldSendEmailToAlertAddress && Setting::getSettings()->admin_cc_email) {
|
||||
try {
|
||||
Mail::to(Setting::getSettings()->admin_cc_email)->send(new BulkAssetCheckoutMail(
|
||||
$event->assets,
|
||||
$event->target,
|
||||
$event->admin,
|
||||
$event->checkout_at,
|
||||
$event->expected_checkin,
|
||||
$event->note,
|
||||
));
|
||||
|
||||
Log::info('BulkAssetCheckoutMail sent to admin_cc_email');
|
||||
} catch (Exception $e) {
|
||||
Log::debug("Exception caught during BulkAssetCheckoutMail to admin_cc_email: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function shouldSendCheckoutEmailToUser(?User $user, Collection $assets): bool
|
||||
{
|
||||
if (!$user?->email) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->hasAssetWithEula($assets)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->hasAssetWithCategorySettingToSendEmail($assets)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->hasAssetThatRequiresAcceptance($assets);
|
||||
}
|
||||
|
||||
private function shouldSendEmailToAlertAddress(Collection $assets): bool
|
||||
{
|
||||
$setting = Setting::getSettings();
|
||||
|
||||
if (!$setting) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($setting->admin_cc_always) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$this->hasAssetThatRequiresAcceptance($assets)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $setting->admin_cc_email;
|
||||
}
|
||||
|
||||
private function hasAssetWithEula(Collection $assets): bool
|
||||
{
|
||||
foreach ($assets as $asset) {
|
||||
if ($asset->getEula()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function hasAssetWithCategorySettingToSendEmail(Collection $assets): bool
|
||||
{
|
||||
foreach ($assets as $asset) {
|
||||
if ($asset->checkin_email()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function hasAssetThatRequiresAcceptance(Collection $assets): bool
|
||||
{
|
||||
foreach ($assets as $asset) {
|
||||
if ($asset->requireAcceptance()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getNotifiableUser(CheckoutablesCheckedOutInBulk $event): ?Model
|
||||
{
|
||||
$target = $event->target;
|
||||
|
||||
if ($target instanceof Asset) {
|
||||
$target->load('assignedTo');
|
||||
return $target->assignedto;
|
||||
}
|
||||
|
||||
if ($target instanceof Location) {
|
||||
return $target->manager;
|
||||
}
|
||||
|
||||
return $target;
|
||||
}
|
||||
}
|
||||
165
app/Mail/BulkAssetCheckoutMail.php
Normal file
165
app/Mail/BulkAssetCheckoutMail.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\Location;
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class BulkAssetCheckoutMail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public bool $requires_acceptance;
|
||||
|
||||
public Collection $assetsByCategory;
|
||||
|
||||
public function __construct(
|
||||
public Collection $assets,
|
||||
public Model $target,
|
||||
public User $admin,
|
||||
public string $checkout_at,
|
||||
public string $expected_checkin,
|
||||
public string $note,
|
||||
) {
|
||||
$this->requires_acceptance = $this->requiresAcceptance();
|
||||
|
||||
$this->loadCustomFieldsOnAssets();
|
||||
$this->loadEulasOnAssets();
|
||||
|
||||
$this->assetsByCategory = $this->groupAssetsByCategory();
|
||||
}
|
||||
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: $this->getSubject(),
|
||||
);
|
||||
}
|
||||
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
markdown: 'mail.markdown.bulk-asset-checkout-mail',
|
||||
with: [
|
||||
'introduction' => $this->getIntroduction(),
|
||||
'requires_acceptance' => $this->requires_acceptance,
|
||||
'requires_acceptance_info' => $this->getRequiresAcceptanceInfo(),
|
||||
'requires_acceptance_prompt' => $this->getRequiresAcceptancePrompt(),
|
||||
'singular_eula' => $this->getSingularEula(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
public function attachments(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
private function getSubject(): string
|
||||
{
|
||||
if ($this->assets->count() > 1) {
|
||||
return ucfirst(trans('general.assets_checked_out_count'));
|
||||
}
|
||||
|
||||
return trans('mail.Asset_Checkout_Notification', ['tag' => $this->assets->first()->asset_tag]);
|
||||
}
|
||||
|
||||
private function loadCustomFieldsOnAssets(): void
|
||||
{
|
||||
$this->assets = $this->assets->map(function (Asset $asset) {
|
||||
$fields = $asset->model?->fieldset?->fields->filter(function (CustomField $field) {
|
||||
return $field->show_in_email && !$field->field_encrypted;
|
||||
});
|
||||
|
||||
$asset->setRelation('fields', $fields);
|
||||
|
||||
return $asset;
|
||||
});
|
||||
}
|
||||
|
||||
private function loadEulasOnAssets(): void
|
||||
{
|
||||
$this->assets = $this->assets->map(function (Asset $asset) {
|
||||
$asset->eula = $asset->getEula();
|
||||
|
||||
return $asset;
|
||||
});
|
||||
}
|
||||
|
||||
private function groupAssetsByCategory(): Collection
|
||||
{
|
||||
return $this->assets->groupBy(fn($asset) => $asset->model->category->id);
|
||||
}
|
||||
|
||||
private function getIntroduction(): string
|
||||
{
|
||||
if ($this->target instanceof Location) {
|
||||
return trans_choice('mail.new_item_checked_location', $this->assets->count(), ['location' => $this->target->name]);
|
||||
}
|
||||
|
||||
return trans_choice('mail.new_item_checked', $this->assets->count());
|
||||
}
|
||||
|
||||
private function getRequiresAcceptanceInfo(): ?string
|
||||
{
|
||||
if (!$this->requires_acceptance) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return trans_choice('mail.items_checked_out_require_acceptance', $this->assets->count());
|
||||
}
|
||||
|
||||
private function getRequiresAcceptancePrompt(): ?string
|
||||
{
|
||||
if (!$this->requires_acceptance) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$acceptanceUrl = $this->assets->count() === 1
|
||||
? route('account.accept.item', $this->assets->first())
|
||||
: route('account.accept');
|
||||
|
||||
return
|
||||
sprintf(
|
||||
'**[✔ %s](%s)**',
|
||||
trans_choice('mail.click_here_to_review_terms_and_accept_item', $this->assets->count()),
|
||||
$acceptanceUrl,
|
||||
);
|
||||
}
|
||||
|
||||
private function getSingularEula()
|
||||
{
|
||||
// get unique categories from all assets
|
||||
$categories = $this->assets->pluck('model.category.id')->unique();
|
||||
|
||||
// if assets do not have the same category then return early...
|
||||
if ($categories->count() > 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if assets do have the same category then return the shared EULA
|
||||
if ($categories->count() === 1) {
|
||||
return $this->assets->first()->getEula();
|
||||
}
|
||||
}
|
||||
|
||||
private function requiresAcceptance(): bool
|
||||
{
|
||||
foreach ($this->assets as $asset) {
|
||||
if ($asset->requireAcceptance()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Attachment;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class CheckoutAssetMail extends BaseMailable
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Listeners\CheckoutableListener;
|
||||
use App\Listeners\CheckoutablesCheckedOutInBulkListener;
|
||||
use App\Listeners\LogListener;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
|
||||
@@ -31,5 +32,6 @@ class EventServiceProvider extends ServiceProvider
|
||||
protected $subscribe = [
|
||||
LogListener::class,
|
||||
CheckoutableListener::class,
|
||||
CheckoutablesCheckedOutInBulkListener::class,
|
||||
];
|
||||
}
|
||||
|
||||
13
app/Traits/DisablesDebugbar.php
Normal file
13
app/Traits/DisablesDebugbar.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
trait DisablesDebugbar
|
||||
{
|
||||
public function disableDebugbar()
|
||||
{
|
||||
if (class_exists(\Fruitcake\LaravelDebugbar\Facades\Debugbar::class)) {
|
||||
\Fruitcake\LaravelDebugbar\Facades\Debugbar::disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,6 @@
|
||||
"alek13/slack": "^2.0",
|
||||
"arietimmerman/laravel-scim-server": "dev-master",
|
||||
"bacon/bacon-qr-code": "^2.0",
|
||||
"barryvdh/laravel-debugbar": "^3.13",
|
||||
"doctrine/cache": "^1.10",
|
||||
"doctrine/dbal": "^3.1",
|
||||
"doctrine/instantiator": "^1.3",
|
||||
@@ -84,6 +83,7 @@
|
||||
"ext-exif": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"fruitcake/laravel-debugbar": "^4.0",
|
||||
"larastan/larastan": "^2.9",
|
||||
"laravel/telescope": "^5.11",
|
||||
"mockery/mockery": "^1.4",
|
||||
|
||||
518
composer.lock
generated
518
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b1dfc90a20cecf851224ea8a5c71f26d",
|
||||
"content-hash": "895ab3cf22a77918f3239ef4774d628b",
|
||||
"packages": [
|
||||
{
|
||||
"name": "alek13/slack",
|
||||
@@ -340,91 +340,6 @@
|
||||
},
|
||||
"time": "2022-12-07T17:46:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "barryvdh/laravel-debugbar",
|
||||
"version": "v3.16.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/barryvdh/laravel-debugbar.git",
|
||||
"reference": "f265cf5e38577d42311f1a90d619bcd3740bea23"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/f265cf5e38577d42311f1a90d619bcd3740bea23",
|
||||
"reference": "f265cf5e38577d42311f1a90d619bcd3740bea23",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/routing": "^9|^10|^11|^12",
|
||||
"illuminate/session": "^9|^10|^11|^12",
|
||||
"illuminate/support": "^9|^10|^11|^12",
|
||||
"php": "^8.1",
|
||||
"php-debugbar/php-debugbar": "~2.2.0",
|
||||
"symfony/finder": "^6|^7"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.3.3",
|
||||
"orchestra/testbench-dusk": "^7|^8|^9|^10",
|
||||
"phpunit/phpunit": "^9.5.10|^10|^11",
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"Debugbar": "Barryvdh\\Debugbar\\Facades\\Debugbar"
|
||||
},
|
||||
"providers": [
|
||||
"Barryvdh\\Debugbar\\ServiceProvider"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "3.16-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Barryvdh\\Debugbar\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP Debugbar integration for Laravel",
|
||||
"keywords": [
|
||||
"debug",
|
||||
"debugbar",
|
||||
"dev",
|
||||
"laravel",
|
||||
"profiler",
|
||||
"webprofiler"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/barryvdh/laravel-debugbar/issues",
|
||||
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.16.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://fruitcake.nl",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/barryvdh",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-14T11:56:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
"version": "0.14.0",
|
||||
@@ -5840,79 +5755,6 @@
|
||||
},
|
||||
"time": "2025-12-30T16:16:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-debugbar/php-debugbar",
|
||||
"version": "v2.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-debugbar/php-debugbar.git",
|
||||
"reference": "3146d04671f51f69ffec2a4207ac3bdcf13a9f35"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/3146d04671f51f69ffec2a4207ac3bdcf13a9f35",
|
||||
"reference": "3146d04671f51f69ffec2a4207ac3bdcf13a9f35",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8",
|
||||
"psr/log": "^1|^2|^3",
|
||||
"symfony/var-dumper": "^4|^5|^6|^7"
|
||||
},
|
||||
"replace": {
|
||||
"maximebf/debugbar": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"dbrekelmans/bdi": "^1",
|
||||
"phpunit/phpunit": "^8|^9",
|
||||
"symfony/panther": "^1|^2.1",
|
||||
"twig/twig": "^1.38|^2.7|^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"kriswallsmith/assetic": "The best way to manage assets",
|
||||
"monolog/monolog": "Log using Monolog",
|
||||
"predis/predis": "Redis storage"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"DebugBar\\": "src/DebugBar/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maxime Bouroumeau-Fuseau",
|
||||
"email": "maxime.bouroumeau@gmail.com",
|
||||
"homepage": "http://maximebf.com"
|
||||
},
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Debug bar in the browser for php application",
|
||||
"homepage": "https://github.com/php-debugbar/php-debugbar",
|
||||
"keywords": [
|
||||
"debug",
|
||||
"debug bar",
|
||||
"debugbar",
|
||||
"dev"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-debugbar/php-debugbar/issues",
|
||||
"source": "https://github.com/php-debugbar/php-debugbar/tree/v2.2.4"
|
||||
},
|
||||
"time": "2025-07-22T14:01:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
"version": "2.2.0",
|
||||
@@ -9103,23 +8945,23 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v7.3.2",
|
||||
"version": "v7.4.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
|
||||
"reference": "01b24a145bbeaa7141e75887ec904c34a6728a5f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
|
||||
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/01b24a145bbeaa7141e75887ec904c34a6728a5f",
|
||||
"reference": "01b24a145bbeaa7141e75887ec904c34a6728a5f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/filesystem": "^6.4|^7.0"
|
||||
"symfony/filesystem": "^6.4|^7.0|^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -9147,7 +8989,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v7.3.2"
|
||||
"source": "https://github.com/symfony/finder/tree/v7.4.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -9167,27 +9009,26 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-15T13:41:35+00:00"
|
||||
"time": "2026-01-12T12:19:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "v7.3.7",
|
||||
"version": "v7.4.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-foundation.git",
|
||||
"reference": "db488a62f98f7a81d5746f05eea63a74e55bb7c4"
|
||||
"reference": "977a554a34cf8edc95ca351fbecb1bb1ad05cc94"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/db488a62f98f7a81d5746f05eea63a74e55bb7c4",
|
||||
"reference": "db488a62f98f7a81d5746f05eea63a74e55bb7c4",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/977a554a34cf8edc95ca351fbecb1bb1ad05cc94",
|
||||
"reference": "977a554a34cf8edc95ca351fbecb1bb1ad05cc94",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/deprecation-contracts": "^2.5|^3.0",
|
||||
"symfony/polyfill-mbstring": "~1.1",
|
||||
"symfony/polyfill-php83": "^1.27"
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/polyfill-mbstring": "^1.1"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/dbal": "<3.6",
|
||||
@@ -9196,13 +9037,13 @@
|
||||
"require-dev": {
|
||||
"doctrine/dbal": "^3.6|^4",
|
||||
"predis/predis": "^1.1|^2.0",
|
||||
"symfony/cache": "^6.4.12|^7.1.5",
|
||||
"symfony/clock": "^6.4|^7.0",
|
||||
"symfony/dependency-injection": "^6.4|^7.0",
|
||||
"symfony/expression-language": "^6.4|^7.0",
|
||||
"symfony/http-kernel": "^6.4|^7.0",
|
||||
"symfony/mime": "^6.4|^7.0",
|
||||
"symfony/rate-limiter": "^6.4|^7.0"
|
||||
"symfony/cache": "^6.4.12|^7.1.5|^8.0",
|
||||
"symfony/clock": "^6.4|^7.0|^8.0",
|
||||
"symfony/dependency-injection": "^6.4|^7.0|^8.0",
|
||||
"symfony/expression-language": "^6.4|^7.0|^8.0",
|
||||
"symfony/http-kernel": "^6.4|^7.0|^8.0",
|
||||
"symfony/mime": "^6.4|^7.0|^8.0",
|
||||
"symfony/rate-limiter": "^6.4|^7.0|^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -9230,7 +9071,7 @@
|
||||
"description": "Defines an object-oriented layer for the HTTP specification",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v7.3.7"
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v7.4.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -9250,7 +9091,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-08T16:41:12+00:00"
|
||||
"time": "2026-01-09T12:14:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-kernel",
|
||||
@@ -9456,20 +9297,21 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/mime",
|
||||
"version": "v7.3.2",
|
||||
"version": "v7.4.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/mime.git",
|
||||
"reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1"
|
||||
"reference": "40945014c0a9471ccfe19673c54738fa19367a3c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/e0a0f859148daf1edf6c60b398eb40bfc96697d1",
|
||||
"reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/40945014c0a9471ccfe19673c54738fa19367a3c",
|
||||
"reference": "40945014c0a9471ccfe19673c54738fa19367a3c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/polyfill-intl-idn": "^1.10",
|
||||
"symfony/polyfill-mbstring": "^1.0"
|
||||
},
|
||||
@@ -9484,11 +9326,11 @@
|
||||
"egulias/email-validator": "^2.1.10|^3.1|^4",
|
||||
"league/html-to-markdown": "^5.0",
|
||||
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
|
||||
"symfony/dependency-injection": "^6.4|^7.0",
|
||||
"symfony/process": "^6.4|^7.0",
|
||||
"symfony/property-access": "^6.4|^7.0",
|
||||
"symfony/property-info": "^6.4|^7.0",
|
||||
"symfony/serializer": "^6.4.3|^7.0.3"
|
||||
"symfony/dependency-injection": "^6.4|^7.0|^8.0",
|
||||
"symfony/process": "^6.4|^7.0|^8.0",
|
||||
"symfony/property-access": "^6.4|^7.0|^8.0",
|
||||
"symfony/property-info": "^6.4|^7.0|^8.0",
|
||||
"symfony/serializer": "^6.4.3|^7.0.3|^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -9520,7 +9362,7 @@
|
||||
"mime-type"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/mime/tree/v7.3.2"
|
||||
"source": "https://github.com/symfony/mime/tree/v7.4.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -9540,7 +9382,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-15T13:41:35+00:00"
|
||||
"time": "2026-01-08T16:12:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
@@ -10872,16 +10714,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v7.3.3",
|
||||
"version": "v7.4.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f"
|
||||
"reference": "0e4769b46a0c3c62390d124635ce59f66874b282"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/34d8d4c4b9597347306d1ec8eb4e1319b1e6986f",
|
||||
"reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/0e4769b46a0c3c62390d124635ce59f66874b282",
|
||||
"reference": "0e4769b46a0c3c62390d124635ce59f66874b282",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -10893,10 +10735,10 @@
|
||||
"symfony/console": "<6.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/console": "^6.4|^7.0",
|
||||
"symfony/http-kernel": "^6.4|^7.0",
|
||||
"symfony/process": "^6.4|^7.0",
|
||||
"symfony/uid": "^6.4|^7.0",
|
||||
"symfony/console": "^6.4|^7.0|^8.0",
|
||||
"symfony/http-kernel": "^6.4|^7.0|^8.0",
|
||||
"symfony/process": "^6.4|^7.0|^8.0",
|
||||
"symfony/uid": "^6.4|^7.0|^8.0",
|
||||
"twig/twig": "^3.12"
|
||||
},
|
||||
"bin": [
|
||||
@@ -10935,7 +10777,7 @@
|
||||
"dump"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/var-dumper/tree/v7.3.3"
|
||||
"source": "https://github.com/symfony/var-dumper/tree/v7.4.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -10955,7 +10797,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-13T11:49:31+00:00"
|
||||
"time": "2026-01-01T22:13:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tabuna/breadcrumbs",
|
||||
@@ -12771,6 +12613,108 @@
|
||||
],
|
||||
"time": "2025-09-10T09:51:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fruitcake/laravel-debugbar",
|
||||
"version": "v4.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fruitcake/laravel-debugbar.git",
|
||||
"reference": "a9cc62c81cd0bda4ca7410229487638d7df786be"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fruitcake/laravel-debugbar/zipball/a9cc62c81cd0bda4ca7410229487638d7df786be",
|
||||
"reference": "a9cc62c81cd0bda4ca7410229487638d7df786be",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/routing": "^11|^12",
|
||||
"illuminate/session": "^11|^12",
|
||||
"illuminate/support": "^11|^12",
|
||||
"php": "^8.2",
|
||||
"php-debugbar/php-debugbar": "^3.1",
|
||||
"php-debugbar/symfony-bridge": "^1.1"
|
||||
},
|
||||
"replace": {
|
||||
"barryvdh/laravel-debugbar": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"larastan/larastan": "^3",
|
||||
"laravel/octane": "^2",
|
||||
"laravel/pennant": "^1",
|
||||
"laravel/pint": "^1",
|
||||
"laravel/telescope": "^5.16",
|
||||
"livewire/livewire": "^3.7|^4",
|
||||
"mockery/mockery": "^1.3.3",
|
||||
"orchestra/testbench-dusk": "^9|^10",
|
||||
"php-debugbar/twig-bridge": "^2.0",
|
||||
"phpstan/phpstan-phpunit": "^2",
|
||||
"phpstan/phpstan-strict-rules": "^2.0",
|
||||
"phpunit/phpunit": "^11",
|
||||
"shipmonk/phpstan-rules": "^4.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"Debugbar": "Fruitcake\\LaravelDebugbar\\Facades\\Debugbar"
|
||||
},
|
||||
"providers": [
|
||||
"Fruitcake\\LaravelDebugbar\\ServiceProvider"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "4.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Fruitcake\\LaravelDebugbar\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fruitcake",
|
||||
"homepage": "https://fruitcake.nl"
|
||||
},
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP Debugbar integration for Laravel",
|
||||
"keywords": [
|
||||
"barryvdh",
|
||||
"debug",
|
||||
"debugbar",
|
||||
"dev",
|
||||
"laravel",
|
||||
"profiler",
|
||||
"webprofiler"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/fruitcake/laravel-debugbar/issues",
|
||||
"source": "https://github.com/fruitcake/laravel-debugbar/tree/v4.0.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://fruitcake.nl",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/barryvdh",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-06T20:53:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hamcrest/hamcrest-php",
|
||||
"version": "v2.1.1",
|
||||
@@ -13608,6 +13552,174 @@
|
||||
},
|
||||
"time": "2022-02-21T01:04:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-debugbar/php-debugbar",
|
||||
"version": "v3.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-debugbar/php-debugbar.git",
|
||||
"reference": "a1f4e156811f000efb6e118178832581fab94f11"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/a1f4e156811f000efb6e118178832581fab94f11",
|
||||
"reference": "a1f4e156811f000efb6e118178832581fab94f11",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"psr/log": "^1|^2|^3",
|
||||
"symfony/var-dumper": "^5.4|^6|^7|^8"
|
||||
},
|
||||
"replace": {
|
||||
"maximebf/debugbar": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"dbrekelmans/bdi": "^1.4",
|
||||
"friendsofphp/php-cs-fixer": "^3.92",
|
||||
"monolog/monolog": "^3.9",
|
||||
"php-debugbar/doctrine-bridge": "^3@dev",
|
||||
"php-debugbar/monolog-bridge": "^1@dev",
|
||||
"php-debugbar/symfony-bridge": "^1@dev",
|
||||
"php-debugbar/twig-bridge": "^2@dev",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0",
|
||||
"phpunit/phpunit": "^10",
|
||||
"predis/predis": "^3.3",
|
||||
"shipmonk/phpstan-rules": "^4.3",
|
||||
"symfony/browser-kit": "^6.4|7.0",
|
||||
"symfony/dom-crawler": "^6.4|^7",
|
||||
"symfony/event-dispatcher": "^5.4|^6.4|^7.3|^8.0",
|
||||
"symfony/http-foundation": "^5.4|^6.4|^7.3|^8.0",
|
||||
"symfony/mailer": "^5.4|^6.4|^7.3|^8.0",
|
||||
"symfony/panther": "^1|^2.1",
|
||||
"twig/twig": "^3.11.2"
|
||||
},
|
||||
"suggest": {
|
||||
"php-debugbar/doctrine-bridge": "To integrate Doctrine with php-debugbar.",
|
||||
"php-debugbar/monolog-bridge": "To integrate Monolog with php-debugbar.",
|
||||
"php-debugbar/symfony-bridge": "To integrate Symfony with php-debugbar.",
|
||||
"php-debugbar/twig-bridge": "To integrate Twig with php-debugbar."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"DebugBar\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maxime Bouroumeau-Fuseau",
|
||||
"email": "maxime.bouroumeau@gmail.com",
|
||||
"homepage": "http://maximebf.com"
|
||||
},
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Debug bar in the browser for php application",
|
||||
"homepage": "https://github.com/php-debugbar/php-debugbar",
|
||||
"keywords": [
|
||||
"debug",
|
||||
"debug bar",
|
||||
"debugbar",
|
||||
"dev",
|
||||
"profiler",
|
||||
"toolbar"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-debugbar/php-debugbar/issues",
|
||||
"source": "https://github.com/php-debugbar/php-debugbar/tree/v3.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://fruitcake.nl",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/barryvdh",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-25T20:59:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-debugbar/symfony-bridge",
|
||||
"version": "v1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-debugbar/symfony-bridge.git",
|
||||
"reference": "e37d2debe5d316408b00d0ab2688d9c2cf59b5ad"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-debugbar/symfony-bridge/zipball/e37d2debe5d316408b00d0ab2688d9c2cf59b5ad",
|
||||
"reference": "e37d2debe5d316408b00d0ab2688d9c2cf59b5ad",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"php-debugbar/php-debugbar": "^3.1",
|
||||
"symfony/http-foundation": "^5.4|^6.4|^7.3|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dbrekelmans/bdi": "^1.4",
|
||||
"phpunit/phpunit": "^10",
|
||||
"symfony/browser-kit": "^6|^7",
|
||||
"symfony/dom-crawler": "^6|^7",
|
||||
"symfony/mailer": "^5.4|^6.4|^7.3|^8.0",
|
||||
"symfony/panther": "^1|^2.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"DebugBar\\Bridge\\Symfony\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maxime Bouroumeau-Fuseau",
|
||||
"email": "maxime.bouroumeau@gmail.com",
|
||||
"homepage": "http://maximebf.com"
|
||||
},
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Symfony bridge for PHP Debugbar",
|
||||
"homepage": "https://github.com/php-debugbar/php-debugbar",
|
||||
"keywords": [
|
||||
"debugbar",
|
||||
"dev",
|
||||
"symfony"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-debugbar/symfony-bridge/issues",
|
||||
"source": "https://github.com/php-debugbar/symfony-bridge/tree/v1.1.0"
|
||||
},
|
||||
"time": "2026-01-15T14:47:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-mock/php-mock",
|
||||
"version": "2.6.2",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
@@ -10,98 +12,53 @@ return [
|
||||
| Debugbar is enabled by default, when debug is set to true in app.php.
|
||||
| You can override the value by setting enable to true or false instead of null.
|
||||
|
|
||||
*/
|
||||
|
||||
'enabled' => null,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Storage settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| DebugBar stores data for session/ajax requests.
|
||||
| You can disable this, so the debugbar stores data in headers/session,
|
||||
| but this can cause problems with large data collectors.
|
||||
| By default, file storage (in the storage folder) is used. Redis and PDO
|
||||
| can also be used. For PDO, run the package migrations first.
|
||||
| You can provide an array of URI's that must be ignored (eg. 'api/*')
|
||||
|
|
||||
*/
|
||||
'storage' => [
|
||||
'enabled' => true,
|
||||
'driver' => 'file', // redis, file, pdo
|
||||
'path' => storage_path().'/debugbar', // For file driver
|
||||
'connection' => null, // Leave null for default connection (Redis/PDO)
|
||||
|
||||
'enabled' => env('DEBUGBAR_ENABLED'),
|
||||
'collect_jobs' => env('DEBUGBAR_COLLECT_JOBS', false),
|
||||
'except' => [
|
||||
'telescope*',
|
||||
'horizon*',
|
||||
'_boost/browser-logs',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Vendors
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Vendor files are included by default, but can be set to false.
|
||||
| This can also be set to 'js' or 'css', to only include javascript or css vendor files.
|
||||
| Vendor files are for css: font-awesome (including fonts) and highlight.js (css files)
|
||||
| and for js: jquery and and highlight.js
|
||||
| So if you want syntax highlighting, set it to true.
|
||||
| jQuery is set to not conflict with existing jQuery scripts.
|
||||
|
|
||||
*/
|
||||
|
||||
'include_vendors' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Capture Ajax Requests
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors),
|
||||
| you can use this option to disable sending the data through the headers.
|
||||
|
|
||||
*/
|
||||
|
||||
'capture_ajax' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Clockwork integration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The Debugbar can emulate the Clockwork headers, so you can use the Chrome
|
||||
| Extension, without the server-side code. It uses Debugbar collectors instead.
|
||||
|
|
||||
*/
|
||||
'clockwork' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DataCollectors
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enable/disable DataCollectors
|
||||
|
|
||||
*/
|
||||
|--------------------------------------------------------------------------
|
||||
| DataCollectors
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enable/disable DataCollectors
|
||||
|
|
||||
*/
|
||||
|
||||
'collectors' => [
|
||||
'phpinfo' => true, // Php version
|
||||
'messages' => true, // Messages
|
||||
'time' => true, // Time Datalogger
|
||||
'memory' => true, // Memory usage
|
||||
'exceptions' => true, // Exception displayer
|
||||
'log' => true, // Logs from Monolog (merged in messages if enabled)
|
||||
'db' => true, // Show database (PDO) queries and bindings
|
||||
'views' => true, // Views with their data
|
||||
'route' => true, // Current route information
|
||||
'laravel' => true, // Laravel version and environment
|
||||
'events' => true, // All events fired
|
||||
'default_request' => false, // Regular or special Symfony request logger
|
||||
'symfony_request' => true, // Only one can be enabled..
|
||||
'mail' => true, // Catch mail messages
|
||||
'logs' => true, // Add the latest log messages
|
||||
'files' => true, // Show the included files
|
||||
'config' => false, // Display config settings
|
||||
'auth' => true, // Display Laravel authentication status
|
||||
'gate' => true, // Display Laravel Gate checks
|
||||
'session' => true, // Display session data
|
||||
'phpinfo' => env('DEBUGBAR_COLLECTORS_PHPINFO', true), // Php version
|
||||
'messages' => env('DEBUGBAR_COLLECTORS_MESSAGES', true), // Messages
|
||||
'time' => env('DEBUGBAR_COLLECTORS_TIME', true), // Time Datalogger
|
||||
'memory' => env('DEBUGBAR_COLLECTORS_MEMORY', true), // Memory usage
|
||||
'exceptions' => env('DEBUGBAR_COLLECTORS_EXCEPTIONS', true), // Exception displayer
|
||||
'log' => env('DEBUGBAR_COLLECTORS_LOG', true), // Logs from Monolog (merged in messages if enabled)
|
||||
'db' => env('DEBUGBAR_COLLECTORS_DB', true), // Show database (PDO) queries and bindings
|
||||
'views' => env('DEBUGBAR_COLLECTORS_VIEWS', true), // Views with their data
|
||||
'route' => env('DEBUGBAR_COLLECTORS_ROUTE', true), // Current route information
|
||||
'auth' => env('DEBUGBAR_COLLECTORS_AUTH', true), // Display Laravel authentication status
|
||||
'gate' => env('DEBUGBAR_COLLECTORS_GATE', true), // Display Laravel Gate checks
|
||||
'session' => env('DEBUGBAR_COLLECTORS_SESSION', true), // Display session data
|
||||
'symfony_request' => env('DEBUGBAR_COLLECTORS_SYMFONY_REQUEST', false), // Default Request Data
|
||||
'mail' => env('DEBUGBAR_COLLECTORS_MAIL', true), // Catch mail messages
|
||||
'laravel' => env('DEBUGBAR_COLLECTORS_LARAVEL', true), // Laravel version and environment
|
||||
'events' => env('DEBUGBAR_COLLECTORS_EVENTS', true), // All events fired
|
||||
'logs' => env('DEBUGBAR_COLLECTORS_LOGS', true), // Add the latest log messages
|
||||
'config' => env('DEBUGBAR_COLLECTORS_CONFIG', false), // Display config settings
|
||||
'cache' => env('DEBUGBAR_COLLECTORS_CACHE', true), // Display cache events
|
||||
'models' => env('DEBUGBAR_COLLECTORS_MODELS', true), // Display models
|
||||
'livewire' => env('DEBUGBAR_COLLECTORS_LIVEWIRE', true), // Display Livewire (when available)
|
||||
'inertia' => env('DEBUGBAR_COLLECTORS_INERTIA', true), // Display Inertia (when available)
|
||||
'jobs' => env('DEBUGBAR_COLLECTORS_JOBS', true), // Display dispatched jobs
|
||||
'pennant' => env('DEBUGBAR_COLLECTORS_PENNANT', true), // Display Pennant feature flags
|
||||
'http_client' => env('DEBUGBAR_COLLECTORS_HTTP_CLIENT', true), // Display HTTP Client requests
|
||||
],
|
||||
|
||||
/*
|
||||
@@ -114,56 +71,298 @@ return [
|
||||
*/
|
||||
|
||||
'options' => [
|
||||
'time' => [
|
||||
'memory_usage' => env('DEBUGBAR_OPTIONS_TIME_MEMORY_USAGE', false), // Calculated by subtracting memory start and end, it may be inaccurate
|
||||
],
|
||||
'messages' => [
|
||||
'trace' => env('DEBUGBAR_OPTIONS_MESSAGES_TRACE', true), // Trace the origin of the debug message
|
||||
'backtrace_exclude_paths' => [], // Paths to exclude from backtrace. (in addition to defaults)
|
||||
'capture_dumps' => env('DEBUGBAR_OPTIONS_MESSAGES_CAPTURE_DUMPS', false), // Capture laravel `dump();` as message
|
||||
'timeline' => env('DEBUGBAR_OPTIONS_MESSAGES_TIMELINE', true), // Add messages to the timeline
|
||||
],
|
||||
'memory' => [
|
||||
'reset_peak' => env('DEBUGBAR_OPTIONS_MEMORY_RESET_PEAK', false), // run memory_reset_peak_usage before collecting
|
||||
'with_baseline' => env('DEBUGBAR_OPTIONS_MEMORY_WITH_BASELINE', false), // Set boot memory usage as memory peak baseline
|
||||
'precision' => (int) env('DEBUGBAR_OPTIONS_MEMORY_PRECISION', 0), // Memory rounding precision
|
||||
],
|
||||
'auth' => [
|
||||
'show_name' => false, // Also show the users name/email in the debugbar
|
||||
'show_name' => env('DEBUGBAR_OPTIONS_AUTH_SHOW_NAME', false), // Also show the users name/email in the debugbar
|
||||
'show_guards' => env('DEBUGBAR_OPTIONS_AUTH_SHOW_GUARDS', true), // Show the guards that are used
|
||||
],
|
||||
'gate' => [
|
||||
'trace' => false, // Trace the origin of the Gate checks
|
||||
'timeline' => env('DEBUGBAR_OPTIONS_GATE_TIMELINE', false), // Add mails to the timeline
|
||||
],
|
||||
'db' => [
|
||||
'with_params' => true, // Render SQL with the parameters substituted
|
||||
'timeline' => true, // Add the queries to the timeline
|
||||
'backtrace' => true, // EXPERIMENTAL: Use a backtrace to find the origin of the query in your files.
|
||||
'explain' => [ // EXPERIMENTAL: Show EXPLAIN output on queries
|
||||
'enabled' => false,
|
||||
'types' => ['SELECT'], // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+
|
||||
'with_params' => env('DEBUGBAR_OPTIONS_WITH_PARAMS', true), // Render SQL with the parameters substituted
|
||||
'exclude_paths' => [ // Paths to exclude entirely from the collector
|
||||
//'vendor/laravel/framework/src/Illuminate/Session', // Exclude sessions queries
|
||||
],
|
||||
'hints' => true, // Show hints for common mistakes
|
||||
'backtrace' => env('DEBUGBAR_OPTIONS_DB_BACKTRACE', true), // Use a backtrace to find the origin of the query in your files.
|
||||
'backtrace_exclude_paths' => [], // Paths to exclude from backtrace. (in addition to defaults)
|
||||
'timeline' => env('DEBUGBAR_OPTIONS_DB_TIMELINE', true), // Add the queries to the timeline
|
||||
'duration_background' => env('DEBUGBAR_OPTIONS_DB_DURATION_BACKGROUND', true), // Show shaded background on each query relative to how long it took to execute.
|
||||
'explain' => [ // Show EXPLAIN output on queries
|
||||
'enabled' => env('DEBUGBAR_OPTIONS_DB_EXPLAIN_ENABLED', false),
|
||||
],
|
||||
'only_slow_queries' => env('DEBUGBAR_OPTIONS_DB_ONLY_SLOW_QUERIES', true), // Only track queries that last longer than `slow_threshold`
|
||||
'slow_threshold' => env('DEBUGBAR_OPTIONS_DB_SLOW_THRESHOLD', false), // Max query execution time (ms). Exceeding queries will be highlighted
|
||||
'memory_usage' => env('DEBUGBAR_OPTIONS_DB_MEMORY_USAGE', false), // Show queries memory usage
|
||||
'soft_limit' => (int) env('DEBUGBAR_OPTIONS_DB_SOFT_LIMIT', 100), // After the soft limit, no parameters/backtrace are captured
|
||||
'hard_limit' => (int) env('DEBUGBAR_OPTIONS_DB_HARD_LIMIT', 500), // After the hard limit, queries are ignored
|
||||
],
|
||||
'mail' => [
|
||||
'full_log' => false,
|
||||
'timeline' => env('DEBUGBAR_OPTIONS_MAIL_TIMELINE', true), // Add mails to the timeline
|
||||
'show_body' => env('DEBUGBAR_OPTIONS_MAIL_SHOW_BODY', true),
|
||||
],
|
||||
'views' => [
|
||||
'data' => false, //Note: Can slow down the application, because the data can be quite large..
|
||||
'timeline' => env('DEBUGBAR_OPTIONS_VIEWS_TIMELINE', true), // Add the views to the timeline
|
||||
'data' => env('DEBUGBAR_OPTIONS_VIEWS_DATA', false), // True for all data, 'keys' for only names, false for no parameters.
|
||||
'group' => (int) env('DEBUGBAR_OPTIONS_VIEWS_GROUP', 50), // Group duplicate views. Pass value to auto-group, or true/false to force
|
||||
'exclude_paths' => [ // Add the paths which you don't want to appear in the views
|
||||
'vendor/filament', // Exclude Filament components by default
|
||||
],
|
||||
],
|
||||
'inertia' => [
|
||||
'pages' => env('DEBUGBAR_OPTIONS_VIEWS_INERTIA_PAGES', 'js/Pages'), // Path for Inertia views
|
||||
],
|
||||
'route' => [
|
||||
'label' => true, // show complete route on bar
|
||||
'label' => env('DEBUGBAR_OPTIONS_ROUTE_LABEL', true), // Show complete route on bar
|
||||
],
|
||||
'session' => [
|
||||
'masked' => [], // List of keys that are masked
|
||||
],
|
||||
'symfony_request' => [
|
||||
'label' => env('DEBUGBAR_OPTIONS_SYMFONY_REQUEST_LABEL', true), // Show route on bar
|
||||
'masked' => [], // List of keys that are masked
|
||||
],
|
||||
'events' => [
|
||||
'data' => env('DEBUGBAR_OPTIONS_EVENTS_DATA', false), // Collect events data
|
||||
'listeners' => env('DEBUGBAR_OPTIONS_EVENTS_LISTENERS', false), // Add listeners to the events data
|
||||
'excluded' => [], // Example: ['eloquent.*', 'composing', Illuminate\Cache\Events\CacheHit::class]
|
||||
],
|
||||
'logs' => [
|
||||
'file' => null,
|
||||
'file' => env('DEBUGBAR_OPTIONS_LOGS_FILE'),
|
||||
],
|
||||
'cache' => [
|
||||
'values' => env('DEBUGBAR_OPTIONS_CACHE_VALUES', true), // Collect cache values
|
||||
'timeline' => env('DEBUGBAR_OPTIONS_CACHE_TIMELINE', false), // Add mails to the timeline
|
||||
],
|
||||
'http_client' => [
|
||||
'masked' => [],
|
||||
'timeline' => env('DEBUGBAR_OPTIONS_HTTP_CLIENT_TIMELINE', true), // Add requests to the timeline
|
||||
],
|
||||
],
|
||||
|
||||
/**
|
||||
* Add any additional DataCollectors by adding the class name of a DataCollector or invokable class.
|
||||
*/
|
||||
'custom_collectors' => [
|
||||
// MyCollector::class => env('DEBUGBAR_COLLECTORS_MYCOLLECTOR', true),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Editor
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Choose your preferred editor to use when clicking file name.
|
||||
|
|
||||
| Supported: "sublime", "textmate", "emacs", "macvim", "codelite",
|
||||
| "phpstorm", "phpstorm-remote", "idea", "idea-remote",
|
||||
| "vscode", "vscode-insiders", "vscode-remote", "vscode-insiders-remote",
|
||||
| "vscodium", "nova", "xdebug", "atom", "espresso",
|
||||
| "netbeans", "cursor", "windsurf", "zed", "antigravity"
|
||||
|
|
||||
*/
|
||||
|
||||
'editor' => env('DEBUGBAR_EDITOR') ?: env('IGNITION_EDITOR', 'phpstorm'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Capture Ajax Requests
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors),
|
||||
| you can use this option to disable sending the data through the headers.
|
||||
|
|
||||
| Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools.
|
||||
|
|
||||
| Note for your request to be identified as ajax requests they must either send the header
|
||||
| X-Requested-With with the value XMLHttpRequest (most JS libraries send this), or have application/json as a Accept header.
|
||||
|
|
||||
| By default `ajax_handler_auto_show` is set to true allowing ajax requests to be shown automatically in the Debugbar.
|
||||
| Changing `ajax_handler_auto_show` to false will prevent the Debugbar from reloading.
|
||||
|
|
||||
| You can defer loading the dataset, so it will be loaded with ajax after the request is done. (Experimental)
|
||||
*/
|
||||
|
||||
'capture_ajax' => env('DEBUGBAR_CAPTURE_AJAX', true),
|
||||
'add_ajax_timing' => env('DEBUGBAR_ADD_AJAX_TIMING', false),
|
||||
'ajax_handler_auto_show' => env('DEBUGBAR_AJAX_HANDLER_AUTO_SHOW', true),
|
||||
'ajax_handler_enable_tab' => env('DEBUGBAR_AJAX_HANDLER_ENABLE_TAB', true),
|
||||
'defer_datasets' => env('DEBUGBAR_DEFER_DATASETS', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Remote Path Mapping
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If you are using a remote dev server, like Laravel Homestead, Docker, or
|
||||
| even a remote VPS, it will be necessary to specify your path mapping.
|
||||
|
|
||||
| Leaving one, or both of these, empty or null will not trigger the remote
|
||||
| URL changes and Debugbar will treat your editor links as local files.
|
||||
|
|
||||
| "remote_sites_path" is an absolute base path for your sites or projects
|
||||
| in Homestead, Vagrant, Docker, or another remote development server.
|
||||
|
|
||||
| Example value: "/home/vagrant/Code"
|
||||
|
|
||||
| "local_sites_path" is an absolute base path for your sites or projects
|
||||
| on your local computer where your IDE or code editor is running on.
|
||||
|
|
||||
| Example values: "/Users/<name>/Code", "C:\Users\<name>\Documents\Code"
|
||||
|
|
||||
*/
|
||||
|
||||
'remote_sites_path' => env('DEBUGBAR_REMOTE_SITES_PATH'),
|
||||
'local_sites_path' => env('DEBUGBAR_LOCAL_SITES_PATH', env('IGNITION_LOCAL_SITES_PATH')),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Storage settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Debugbar stores data for session/ajax requests.
|
||||
| You can disable this, so the debugbar stores data in headers/session,
|
||||
| but this can cause problems with large data collectors.
|
||||
| By default, file storage (in the storage folder) is used. Sqlite will
|
||||
| create a database file in the storage folder.
|
||||
| Redis and PDO can also be used. For PDO, run the package migrations first.
|
||||
|
|
||||
| Warning: Enabling storage.open will allow everyone to access previous
|
||||
| request, do not enable open storage in publicly available environments!
|
||||
| Specify a callback if you want to limit based on IP or authentication.
|
||||
| Leaving it to null will allow localhost only.
|
||||
*/
|
||||
'storage' => [
|
||||
'enabled' => env('DEBUGBAR_STORAGE_ENABLED', true),
|
||||
'open' => env('DEBUGBAR_OPEN_STORAGE'), // bool/callback.
|
||||
'driver' => env('DEBUGBAR_STORAGE_DRIVER', 'file'), // redis, file, sqlite, pdo, custom
|
||||
'path' => env('DEBUGBAR_STORAGE_PATH', storage_path('debugbar')), // For file driver
|
||||
'connection' => env('DEBUGBAR_STORAGE_CONNECTION'), // Leave null for default connection (Redis/PDO)
|
||||
'provider' => env('DEBUGBAR_STORAGE_PROVIDER', ''), // Instance of StorageInterface for custom driver
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Assets
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Vendor files are included by default, but can be set to false.
|
||||
| This can also be set to 'js' or 'css', to only include javascript or css vendor files.
|
||||
| Vendor files are for css: (none)
|
||||
| and for js: highlight.js
|
||||
| So if you want syntax highlighting, set it to true.
|
||||
|
|
||||
*/
|
||||
'use_dist_files' => env('DEBUGBAR_USE_DIST_FILES', true),
|
||||
'include_vendors' => env('DEBUGBAR_INCLUDE_VENDORS', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Error Handler for Deprecated warnings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When enabled, the Debugbar shows deprecated warnings for Symfony components
|
||||
| in the Messages tab.
|
||||
|
|
||||
| You can set a custom error reporting level to filter which errors are
|
||||
| handled. For example, to exclude deprecation warnings:
|
||||
| E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED
|
||||
|
|
||||
| To exclude notices, strict warnings, and deprecations:
|
||||
| E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED & ~E_USER_DEPRECATED
|
||||
|
|
||||
| Defaults to E_ALL (all errors).
|
||||
|
|
||||
*/
|
||||
'error_handler' => env('DEBUGBAR_ERROR_HANDLER', false),
|
||||
'error_level' => env('DEBUGBAR_ERROR_LEVEL', E_ALL),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Clockwork integration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The Debugbar can emulate the Clockwork headers, so you can use the Chrome
|
||||
| Extension, without the server-side code. It uses Debugbar collectors instead.
|
||||
|
|
||||
*/
|
||||
'clockwork' => env('DEBUGBAR_CLOCKWORK', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Inject Debugbar in Response
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Usually, the debugbar is added just before <body>, by listening to the
|
||||
| Usually, the debugbar is added just before </body>, by listening to the
|
||||
| Response after the App is done. If you disable this, you have to add them
|
||||
| in your template yourself. See http://phpdebugbar.com/docs/rendering.html
|
||||
|
|
||||
*/
|
||||
|
||||
'inject' => true,
|
||||
'inject' => env('DEBUGBAR_INJECT', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DebugBar route prefix
|
||||
| Debugbar route prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Sometimes you want to set route prefix to be used by DebugBar to load
|
||||
| Sometimes you want to set route prefix to be used by Debugbar to load
|
||||
| its resources from. Usually the need comes from misconfigured web server or
|
||||
| from trying to overcome bugs like this: http://trac.nginx.org/nginx/ticket/97
|
||||
|
|
||||
*/
|
||||
'route_prefix' => '_debugbar',
|
||||
'route_prefix' => env('DEBUGBAR_ROUTE_PREFIX', '_debugbar'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Debugbar route middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Additional middleware to run on the Debugbar routes
|
||||
*/
|
||||
'route_middleware' => [],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Debugbar route domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default Debugbar route served from the same domain that request served.
|
||||
| To override default domain, specify it as a non-empty value.
|
||||
*/
|
||||
'route_domain' => env('DEBUGBAR_ROUTE_DOMAIN'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Debugbar theme
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Switches between light and dark theme. If set to auto it will respect system preferences
|
||||
| Possible values: auto, light, dark
|
||||
*/
|
||||
'theme' => env('DEBUGBAR_THEME', 'auto'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Backtrace stack limit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default, the Debugbar limits the number of frames returned by the 'debug_backtrace()' function.
|
||||
| If you need larger stacktraces, you can increase this number. Setting it to 0 will result in no limit.
|
||||
*/
|
||||
'debug_backtrace_limit' => (int) env('DEBUGBAR_DEBUG_BACKTRACE_LIMIT', 50),
|
||||
];
|
||||
|
||||
@@ -215,4 +215,34 @@ class CategoryFactory extends Factory
|
||||
'require_acceptance' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
public function sendsCheckinEmail()
|
||||
{
|
||||
return $this->state([
|
||||
'checkin_email' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function doesNotSendCheckinEmail()
|
||||
{
|
||||
return $this->state([
|
||||
'checkin_email' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
public function hasLocalEula()
|
||||
{
|
||||
return $this->state([
|
||||
'use_default_eula' => false,
|
||||
'eula_text' => 'Some EULA text here',
|
||||
]);
|
||||
}
|
||||
|
||||
public function withNoLocalOrGlobalEula()
|
||||
{
|
||||
return $this->state([
|
||||
'use_default_eula' => false,
|
||||
'eula_text' => '',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ return [
|
||||
'bulk_update_warn' => 'You are about to edit the properties of :user_count users. Please note that you cannot change your own user attributes using this form, and must make edits to your own user individually.',
|
||||
'bulk_update_help' => 'This form allows you to update multiple users at once. Only fill in the fields you need to change. Any fields left blank will remain unchanged.',
|
||||
'current_assets' => 'Assets currently checked out to this user',
|
||||
'current_items' => ':item currently checked out to this user',
|
||||
'clone' => 'Clone User',
|
||||
'contact_user' => 'Contact :name',
|
||||
'edit' => 'Edit User',
|
||||
|
||||
@@ -84,12 +84,14 @@ return [
|
||||
'new_item_checked' => 'A new item has been checked out under your name, details are below.|:count new items have been checked out under your name, details are below.',
|
||||
'new_item_checked_with_acceptance' => 'A new item has been checked out under your name that requires acceptance, details are below.|:count new items have been checked out under your name that requires acceptance, details are below.',
|
||||
'new_item_checked_location' => 'A new item has been checked out to :location, details are below.|:count new items have been checked out to :location, details are below.',
|
||||
'items_checked_out_require_acceptance' => 'The checked out item requires acceptance.|One or more items require acceptance.',
|
||||
'recent_item_checked' => 'An item was recently checked out under your name that requires acceptance, details are below.',
|
||||
'notes' => 'Notes',
|
||||
'password' => 'Password',
|
||||
'password_reset' => 'Password Reset',
|
||||
'read_the_terms' => 'Please read the terms of use below.',
|
||||
'read_the_terms_and_click' => 'Please read the terms of use below, and click on the link at the bottom to confirm that you read and agree to the terms of use, and have received the asset.',
|
||||
'click_here_to_review_terms_and_accept_item' => 'Click here to review the terms of use and accept the item|Click here to review the terms of use and accept the items',
|
||||
'requested' => 'Requested',
|
||||
'reset_link' => 'Your Password Reset Link',
|
||||
'reset_password' => 'Click here to reset your password:',
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<!-- left column -->
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-7">
|
||||
<form class="form-horizontal" method="post" action="" autocomplete="off">
|
||||
{{csrf_field()}}
|
||||
|
||||
@@ -130,6 +130,21 @@
|
||||
</div> <!-- /.box-->
|
||||
</form>
|
||||
</div> <!-- /.col-md-7-->
|
||||
<!-- right column -->
|
||||
<div class="col-md-5" id="current_license_box" style="display:none;">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h2 class="box-title">{{ trans('admin/users/general.current_items', ['item' => trans('general.licenses')]) }}</h2>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div id="current_license_content">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('moar_scripts')
|
||||
@include('partials.licenses-assigned')
|
||||
@endsection
|
||||
@@ -0,0 +1,92 @@
|
||||
<x-mail::message>
|
||||
|
||||
<style>
|
||||
th, td {
|
||||
vertical-align: top;
|
||||
}
|
||||
hr {
|
||||
display: block;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
border-top: 1px solid #ccc;
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
{{ $introduction }}
|
||||
|
||||
@if ($requires_acceptance)
|
||||
{{ $requires_acceptance_info }}
|
||||
|
||||
{{ $requires_acceptance_prompt }}
|
||||
<hr>
|
||||
@endif
|
||||
|
||||
@if ((isset($expected_checkin)) && ($expected_checkin!=''))
|
||||
**{{ trans('mail.expecting_checkin_date') }}**: {{ Helper::getFormattedDateObject($expected_checkin, 'date', false) }}
|
||||
@endif
|
||||
|
||||
@if ($note)
|
||||
**{{ trans('mail.additional_notes') }}**: {{ $note }}
|
||||
@endif
|
||||
|
||||
@foreach($assetsByCategory as $group)
|
||||
<x-mail::panel>
|
||||
|
||||
**{{ $group->first()->model->category->name }}**
|
||||
|
||||
<x-mail::table>
|
||||
| | |
|
||||
| ------------- | ------------- |
|
||||
@foreach($group as $asset)
|
||||
| **{{ trans('general.asset_tag') }}** | <a href="{{ route('hardware.show', $asset->id) }}">{{ $asset->display_name }}</a><br><small>{{trans('mail.serial').': '.$asset->serial}}</small> |
|
||||
@if (isset($asset->manufacturer))
|
||||
| **{{ trans('general.manufacturer') }}** | {{ $asset->manufacturer->name }} |
|
||||
@endif
|
||||
@if (isset($asset->model))
|
||||
| **{{ trans('general.asset_model') }}** | {{ $asset->model->name }} |
|
||||
@endif
|
||||
@if ((isset($asset->model?->model_number)))
|
||||
| **{{ trans('general.model_no') }}** | {{ $asset->model->model_number }} |
|
||||
@endif
|
||||
@if (isset($asset->assetstatus))
|
||||
| **{{ trans('general.status') }}** | {{ $asset->assetstatus->name }} |
|
||||
@endif
|
||||
@if($asset->fields)
|
||||
@foreach($asset->fields as $field)
|
||||
@if ($asset->{ $field->db_column_name() } != '')
|
||||
| **{{ $field->name }}** | {{ $asset->{ $field->db_column_name() } }} |
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
@if(!$loop->last)
|
||||
| <hr> | <hr> |
|
||||
@endif
|
||||
@endforeach
|
||||
</x-mail::table>
|
||||
|
||||
@if (!$singular_eula && $group->first()->eula)
|
||||
<hr>
|
||||
{{ $group->first()->eula }}
|
||||
@endif
|
||||
|
||||
</x-mail::panel>
|
||||
@endforeach
|
||||
|
||||
@if ($singular_eula)
|
||||
<x-mail::panel>
|
||||
{{ $singular_eula }}
|
||||
</x-mail::panel>
|
||||
@endif
|
||||
|
||||
@if ($requires_acceptance)
|
||||
{{ $requires_acceptance_prompt }}
|
||||
@endif
|
||||
|
||||
**{{ trans('general.administrator') }}**: {{ $admin->display_name }}
|
||||
|
||||
{{ trans('mail.best_regards') }}<br>
|
||||
|
||||
{{ $snipeSettings->site_name }}
|
||||
</x-mail::message>
|
||||
68
resources/views/partials/licenses-assigned.blade.php
Normal file
68
resources/views/partials/licenses-assigned.blade.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<script nonce="{{ csrf_token() }}">
|
||||
let canViewKeys = @json(Gate::check('viewKeys', $license));
|
||||
// create the assigned licenses listing box for the right side of the screen
|
||||
$(function() {
|
||||
$('#assigned_user').on("change",function () {
|
||||
var userid = $('#assigned_user option:selected').val();
|
||||
|
||||
if(userid=='') {
|
||||
console.warn('no user selected');
|
||||
$('#current_license_box').fadeOut();
|
||||
$('#current_license_content').html("");
|
||||
} else {
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '{{ config('app.url') }}/api/v1/users/' + userid + '/licenses',
|
||||
headers: {
|
||||
"X-Requested-With": 'XMLHttpRequest',
|
||||
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
$('#current_license_box').fadeIn();
|
||||
|
||||
var table_html = '<div class="row">';
|
||||
table_html += '<div class="col-md-12">';
|
||||
table_html += '<table class="table table-striped">';
|
||||
table_html += '<thead><tr>';
|
||||
table_html += '<th>{{ trans('admin/licenses/form.name') }}</th>';
|
||||
table_html += '<th>{{ trans('admin/licenses/form.license_key') }}</th>';
|
||||
table_html += '</tr></thead><tbody>';
|
||||
|
||||
$('#current_license_content').append('');
|
||||
|
||||
if (data.rows.length > 0) {
|
||||
|
||||
for (var i in data.rows) {
|
||||
var license = data.rows[i];
|
||||
table_html += '<tr>';
|
||||
table_html += '<td><a href="{{ config('app.url') }}/licenses/' + license.id + '">';
|
||||
|
||||
if ((license.name == '') && (license.name != null)) {
|
||||
table_html += " " + license.name;
|
||||
} else {
|
||||
table_html += license.name;
|
||||
}
|
||||
table_html += '</a></td>';
|
||||
if (canViewKeys) {
|
||||
table_html += '<td>' + license.product_key + '</td>';
|
||||
}
|
||||
table_html += "</tr>";
|
||||
}
|
||||
} else {
|
||||
table_html += '<tr><td colspan="4">{{ trans('admin/users/message.user_has_no_assets_assigned') }}</td></tr>';
|
||||
}
|
||||
$('#current_license_content').html(table_html + '</tbody></table></div></div>');
|
||||
|
||||
},
|
||||
error: function (data) {
|
||||
$('#current_license_box').fadeOut();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Tests\Feature\Checkouts\Ui;
|
||||
|
||||
use App\Mail\BulkAssetCheckoutMail;
|
||||
use App\Mail\CheckoutAssetMail;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
@@ -59,10 +60,16 @@ class BulkAssetCheckoutTest extends TestCase
|
||||
$asset->last_checkout = $checkoutAt;
|
||||
$asset->expected_checkin = $expectedCheckin;
|
||||
$this->assertHasTheseActionLogs($asset, ['create', 'checkout']); //Note: '$this' gets auto-bound in closures, so this does work.
|
||||
$this->assertDatabaseHas('checkout_acceptances', [
|
||||
'checkoutable_type' => Asset::class,
|
||||
'checkoutable_id' => $asset->id,
|
||||
'assigned_to_id' => $user->id,
|
||||
'qty' => 1,
|
||||
]);
|
||||
});
|
||||
|
||||
Mail::assertSent(CheckoutAssetMail::class, 2);
|
||||
Mail::assertSent(CheckoutAssetMail::class, function (CheckoutAssetMail $mail) {
|
||||
Mail::assertNotSent(CheckoutAssetMail::class);
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, function (BulkAssetCheckoutMail $mail) {
|
||||
return $mail->hasTo('someone@example.com');
|
||||
});
|
||||
}
|
||||
|
||||
252
tests/Feature/Notifications/Email/BulkCheckoutEmailTest.php
Normal file
252
tests/Feature/Notifications/Email/BulkCheckoutEmailTest.php
Normal file
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Notifications\Email;
|
||||
|
||||
use App\Mail\BulkAssetCheckoutMail;
|
||||
use App\Mail\CheckoutAssetMail;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Category;
|
||||
use App\Models\Location;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use Tests\TestCase;
|
||||
|
||||
#[Group('notifications')]
|
||||
class BulkCheckoutEmailTest extends TestCase
|
||||
{
|
||||
private Collection $assets;
|
||||
private Model $assignee;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Mail::fake();
|
||||
|
||||
$this->settings->disableAdminCC();
|
||||
$this->settings->disableAdminCCAlways();
|
||||
|
||||
$this->assets = Asset::factory()->requiresAcceptance()->count(2)->create();
|
||||
$this->assignee = User::factory()->create();
|
||||
}
|
||||
|
||||
public function test_sent_to_user()
|
||||
{
|
||||
$this->sendRequest();
|
||||
|
||||
$this->assertSingularCheckoutEmailNotSent();
|
||||
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, 1);
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, function (BulkAssetCheckoutMail $mail) {
|
||||
return $mail->hasTo($this->assignee->email);
|
||||
});
|
||||
}
|
||||
|
||||
public function test_sent_to_location_manager()
|
||||
{
|
||||
$manager = User::factory()->create();
|
||||
|
||||
$this->assignee = Location::factory()->for($manager, 'manager')->create();
|
||||
|
||||
$this->sendRequest();
|
||||
|
||||
$this->assertSingularCheckoutEmailNotSent();
|
||||
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, 1);
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, function (BulkAssetCheckoutMail $mail) use ($manager) {
|
||||
return $mail->hasTo($manager->email);
|
||||
});
|
||||
}
|
||||
|
||||
public function test_sent_to_user_asset_is_checked_out_to()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->assignee = Asset::factory()->assignedToUser($user)->create();
|
||||
|
||||
$this->sendRequest();
|
||||
|
||||
$this->assertSingularCheckoutEmailNotSent();
|
||||
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, 1);
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, function (BulkAssetCheckoutMail $mail) use ($user) {
|
||||
return $mail->hasTo($user->email);
|
||||
});
|
||||
}
|
||||
|
||||
public function test_not_sent_to_user_when_user_does_not_have_email_address()
|
||||
{
|
||||
$this->assignee = User::factory()->create(['email' => null]);
|
||||
|
||||
$this->sendRequest();
|
||||
|
||||
$this->assertSingularCheckoutEmailNotSent();
|
||||
Mail::assertNotSent(BulkAssetCheckoutMail::class);
|
||||
}
|
||||
|
||||
public function test_not_sent_to_user_if_assets_do_not_require_acceptance()
|
||||
{
|
||||
$this->assets = Asset::factory()->doesNotRequireAcceptance()->count(2)->create();
|
||||
|
||||
$category = Category::factory()
|
||||
->doesNotRequireAcceptance()
|
||||
->doesNotSendCheckinEmail()
|
||||
->withNoLocalOrGlobalEula()
|
||||
->create();
|
||||
|
||||
$this->assets->each(fn($asset) => $asset->model->category()->associate($category)->save());
|
||||
|
||||
$this->sendRequest();
|
||||
|
||||
$this->assertSingularCheckoutEmailNotSent();
|
||||
Mail::assertNotSent(BulkAssetCheckoutMail::class);
|
||||
}
|
||||
|
||||
public function test_sent_when_assets_do_not_require_acceptance_but_have_a_eula()
|
||||
{
|
||||
$this->assets = Asset::factory()->count(2)->create();
|
||||
|
||||
$category = Category::factory()
|
||||
->doesNotRequireAcceptance()
|
||||
->doesNotSendCheckinEmail()
|
||||
->hasLocalEula()
|
||||
->create();
|
||||
|
||||
$this->assets->each(fn($asset) => $asset->model->category()->associate($category)->save());
|
||||
|
||||
$this->sendRequest();
|
||||
|
||||
$this->assertSingularCheckoutEmailNotSent();
|
||||
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, 1);
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, function (BulkAssetCheckoutMail $mail) {
|
||||
return $mail->hasTo($this->assignee->email);
|
||||
});
|
||||
}
|
||||
|
||||
public function test_sent_when_assets_do_not_require_acceptance_or_have_a_eula_but_category_is_set_to_send_email()
|
||||
{
|
||||
$this->assets = Asset::factory()->count(2)->create();
|
||||
|
||||
$category = Category::factory()
|
||||
->doesNotRequireAcceptance()
|
||||
->withNoLocalOrGlobalEula()
|
||||
->sendsCheckinEmail()
|
||||
->create();
|
||||
|
||||
$this->assets->each(fn($asset) => $asset->model->category()->associate($category)->save());
|
||||
|
||||
$this->sendRequest();
|
||||
|
||||
$this->assertSingularCheckoutEmailNotSent();
|
||||
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, 1);
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, function (BulkAssetCheckoutMail $mail) {
|
||||
return $mail->hasTo($this->assignee->email);
|
||||
});
|
||||
}
|
||||
|
||||
public function test_sent_to_cc_address_when_assets_require_acceptance()
|
||||
{
|
||||
$this->assets = Asset::factory()->requiresAcceptance()->count(2)->create();
|
||||
|
||||
$this->settings->enableAdminCC('cc@example.com')->disableAdminCCAlways();
|
||||
|
||||
$this->sendRequest();
|
||||
|
||||
$this->assertSingularCheckoutEmailNotSent();
|
||||
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, 2);
|
||||
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, function (BulkAssetCheckoutMail $mail) {
|
||||
return $mail->hasTo($this->assignee->email);
|
||||
});
|
||||
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, function (BulkAssetCheckoutMail $mail) {
|
||||
return $mail->hasTo('cc@example.com');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_sent_to_cc_address_when_assets_do_not_require_acceptance_or_have_eula_but_admin_cc_always_enabled()
|
||||
{
|
||||
$this->settings->enableAdminCC('cc@example.com')->enableAdminCCAlways();
|
||||
|
||||
$this->assets = Asset::factory()->doesNotRequireAcceptance()->count(2)->create();
|
||||
|
||||
$category = Category::factory()
|
||||
->doesNotRequireAcceptance()
|
||||
->doesNotSendCheckinEmail()
|
||||
->withNoLocalOrGlobalEula()
|
||||
->create();
|
||||
|
||||
$this->assets->each(fn($asset) => $asset->model->category()->associate($category)->save());
|
||||
|
||||
$this->sendRequest();
|
||||
|
||||
$this->assertSingularCheckoutEmailNotSent();
|
||||
|
||||
Mail::assertSent(BulkAssetCheckoutMail::class, function (BulkAssetCheckoutMail $mail) {
|
||||
return $mail->hasTo('cc@example.com');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_not_sent_to_cc_address_if_assets_do_not_require_acceptance()
|
||||
{
|
||||
$this->settings->enableAdminCC('cc@example.com')->disableAdminCCAlways();
|
||||
|
||||
$this->assets = Asset::factory()->doesNotRequireAcceptance()->count(2)->create();
|
||||
|
||||
$category = Category::factory()
|
||||
->doesNotRequireAcceptance()
|
||||
->doesNotSendCheckinEmail()
|
||||
->withNoLocalOrGlobalEula()
|
||||
->create();
|
||||
|
||||
$this->assets->each(fn($asset) => $asset->model->category()->associate($category)->save());
|
||||
|
||||
$this->sendRequest();
|
||||
|
||||
$this->assertSingularCheckoutEmailNotSent();
|
||||
Mail::assertNotSent(BulkAssetCheckoutMail::class);
|
||||
}
|
||||
|
||||
private function sendRequest()
|
||||
{
|
||||
$assigned = match (get_class($this->assignee)) {
|
||||
User::class => [
|
||||
'checkout_to_type' => 'user',
|
||||
'assigned_user' => $this->assignee->id,
|
||||
],
|
||||
Location::class => [
|
||||
'checkout_to_type' => 'location',
|
||||
'assigned_location' => $this->assignee->id,
|
||||
],
|
||||
Asset::class => [
|
||||
'checkout_to_type' => 'asset',
|
||||
'assigned_asset' => $this->assignee->id,
|
||||
],
|
||||
// we shouldn't get here...
|
||||
default => [],
|
||||
};
|
||||
|
||||
$this->actingAs(User::factory()->checkoutAssets()->viewAssets()->create())
|
||||
->followingRedirects()
|
||||
->post(route('hardware.bulkcheckout.store'), [
|
||||
'selected_assets' => $this->assets->pluck('id')->toArray(),
|
||||
'checkout_at' => now()->subWeek()->format('Y-m-d'),
|
||||
'expected_checkin' => now()->addWeek()->format('Y-m-d'),
|
||||
'note' => null,
|
||||
] + $assigned)
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
private function assertSingularCheckoutEmailNotSent(): static
|
||||
{
|
||||
Mail::assertNotSent(CheckoutAssetMail::class);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Notifications\Webhooks;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckoutAssetNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use Tests\TestCase;
|
||||
|
||||
#[Group('notifications')]
|
||||
class WebhookNotificationsUponBulkAssetCheckoutTest extends TestCase
|
||||
{
|
||||
public function test_webbook_is_sent_upon_bulk_asset_checkout()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$this->settings->enableSlackWebhook();
|
||||
|
||||
$assets = Asset::factory()->count(2)->create();
|
||||
|
||||
$this->actingAs(User::factory()->checkoutAssets()->viewAssets()->create())
|
||||
->followingRedirects()
|
||||
->post(route('hardware.bulkcheckout.store'), [
|
||||
'selected_assets' => $assets->pluck('id')->toArray(),
|
||||
'checkout_to_type' => 'user',
|
||||
'assigned_user' => User::factory()->create()->id,
|
||||
'assigned_asset' => null,
|
||||
'checkout_at' => now()->subWeek()->format('Y-m-d'),
|
||||
'expected_checkin' => now()->addWeek()->format('Y-m-d'),
|
||||
'note' => null,
|
||||
])
|
||||
->assertOk();
|
||||
|
||||
$this->assertSlackNotificationSent(CheckoutAssetNotification::class);
|
||||
Notification::assertSentTimes(CheckoutAssetNotification::class, 2);
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,7 @@ class CustomReportTest extends TestCase implements TestsPermissionsRequirement
|
||||
'asset_tag' => '1',
|
||||
'serial' => '1',
|
||||
])->assertOk()
|
||||
->assertHeader('content-type', 'text/csv; charset=UTF-8')
|
||||
->assertHeader('content-type', 'text/csv; charset=utf-8')
|
||||
->assertSeeTextInStreamedResponse('Asset A')
|
||||
->assertSeeTextInStreamedResponse('Asset B');
|
||||
}
|
||||
@@ -168,7 +168,7 @@ class CustomReportTest extends TestCase implements TestsPermissionsRequirement
|
||||
'checkin_date_start' => '2023-08-02',
|
||||
'checkin_date_end' => '2023-08-04',
|
||||
])->assertOk()
|
||||
->assertHeader('content-type', 'text/csv; charset=UTF-8')
|
||||
->assertHeader('content-type', 'text/csv; charset=utf-8')
|
||||
->assertDontSeeTextInStreamedResponse('Asset A')
|
||||
->assertSeeTextInStreamedResponse('Asset B')
|
||||
->assertSeeTextInStreamedResponse('Asset C')
|
||||
|
||||
Reference in New Issue
Block a user