Merge remote-tracking branch 'origin/develop'
This commit is contained in:
@@ -220,7 +220,10 @@ class AccessoriesController extends Controller
|
||||
*/
|
||||
public function show(Accessory $accessory) : View | RedirectResponse
|
||||
{
|
||||
$accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessory->id);
|
||||
$accessory->loadCount('checkouts as checkouts_count');
|
||||
|
||||
$accessory->load(['adminuser' => fn($query) => $query->withTrashed()]);
|
||||
|
||||
$this->authorize('view', $accessory);
|
||||
return view('accessories.view', compact('accessory'));
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ class SlackSettingsForm extends Component
|
||||
|
||||
$this->setting = Setting::getSettings();
|
||||
$this->save_button = trans('general.save');
|
||||
$this->webhook_selected = $this->setting->webhook_selected ?? 'slack';
|
||||
$this->webhook_selected = ($this->setting->webhook_selected !== '') ? $this->setting->webhook_selected : 'slack';
|
||||
$this->webhook_name = $this->webhook_text[$this->setting->webhook_selected]["name"] ?? $this->webhook_text['slack']["name"];
|
||||
$this->webhook_icon = $this->webhook_text[$this->setting->webhook_selected]["icon"] ?? $this->webhook_text['slack']["icon"];
|
||||
$this->webhook_placeholder = $this->webhook_text[$this->setting->webhook_selected]["placeholder"] ?? $this->webhook_text['slack']["placeholder"];
|
||||
@@ -191,7 +191,6 @@ class SlackSettingsForm extends Component
|
||||
$this->setting->webhook_endpoint = '';
|
||||
$this->setting->webhook_channel = '';
|
||||
$this->setting->webhook_botname = '';
|
||||
$this->setting->webhook_selected = '';
|
||||
|
||||
$this->setting->save();
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$settings = DB::table('settings')->first();
|
||||
|
||||
if ($settings) {
|
||||
/** If webhook settings were cleared via the integration settings page,
|
||||
* the webhook_selected was cleared as well when it should have reset to "slack".
|
||||
*/
|
||||
if (
|
||||
empty($settings->webhook_selected) &&
|
||||
(empty($settings->webhook_botname) && empty($settings->webhook_channel) && empty($settings->webhook_endpoint))
|
||||
) {
|
||||
DB::table('settings')->update(['webhook_selected' => 'slack']);
|
||||
}
|
||||
|
||||
/** If webhook settings were cleared via the integration settings page,
|
||||
* then slack settings were re-added; then webhook_selected was not being set to "slack" as needed.
|
||||
*/
|
||||
if (str_contains($settings->webhook_endpoint, 'slack.com')) {
|
||||
DB::table('settings')->update(['webhook_selected' => 'slack']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
};
|
||||
@@ -317,20 +317,18 @@
|
||||
|
||||
@endif
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3" style="padding-bottom: 10px;">
|
||||
<strong>
|
||||
{{ trans('general.created_by') }}
|
||||
</strong>
|
||||
@if ($accessory->adminuser)
|
||||
<div class="row">
|
||||
<div class="col-md-3" style="padding-bottom: 10px;">
|
||||
<strong>
|
||||
{{ trans('general.created_by') }}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="col-md-9" style="word-wrap: break-word;">
|
||||
<x-full-user-name :user="$accessory->adminuser" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9" style="word-wrap: break-word;">
|
||||
@if ($accessory->adminuser)
|
||||
{{ $accessory->adminuser->present()->fullName() }}
|
||||
@else
|
||||
{{ trans('admin/reports/general.deleted_user') }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
27
resources/views/blade/full-user-name.blade.php
Normal file
27
resources/views/blade/full-user-name.blade.php
Normal file
@@ -0,0 +1,27 @@
|
||||
@props([
|
||||
'user'
|
||||
])
|
||||
|
||||
@if($user)
|
||||
@php
|
||||
$fullName = $user->present()->fullName();
|
||||
@endphp
|
||||
|
||||
@can('view', $user)
|
||||
@if(! $user->trashed())
|
||||
{{-- if the user is in database but soft-deleted --}}
|
||||
<a href="{{ route('users.show', $user->id) }}">{{ $fullName }}</a>
|
||||
@else
|
||||
{{-- if the user exists --}}
|
||||
<s><a href="{{ route('users.show', $user->id) }}">{{ $fullName }}</a></s>
|
||||
@endif
|
||||
@else
|
||||
@if(! $user->trashed())
|
||||
{{-- if the user is in database but soft-deleted --}}
|
||||
<span>{{ $fullName }}</span>
|
||||
@else
|
||||
{{-- if the user exists --}}
|
||||
<s><span>{{ $fullName }}</span></s>
|
||||
@endif
|
||||
@endcan
|
||||
@endif
|
||||
@@ -72,6 +72,7 @@
|
||||
:options="['slack' => trans('admin/settings/general.slack'), 'general' => trans('admin/settings/general.general_webhook'),'google' => trans('admin/settings/general.google_workspaces'), 'microsoft' => trans('admin/settings/general.ms_teams')]"
|
||||
:selected="old('webhook_selected', $webhook_selected)"
|
||||
:disabled="Helper::isDemoMode()"
|
||||
:for-livewire="true"
|
||||
data-minimum-results-for-search="-1"
|
||||
class="form-control"
|
||||
style="width:100%"
|
||||
@@ -174,22 +175,3 @@
|
||||
</div> <!-- /.row -->
|
||||
</form>
|
||||
</div> <!-- /livewire div -->
|
||||
|
||||
|
||||
|
||||
|
||||
@section('moar_scripts')
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('#select2').select2();
|
||||
$('#select2').on('change', function (e) {
|
||||
var data = $('#select2').select2("val");
|
||||
@this.set('webhook_selected', data);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
|
||||
|
||||
81
tests/Feature/Assets/Api/CheckinCheckoutCounters.php
Normal file
81
tests/Feature/Assets/Api/CheckinCheckoutCounters.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Assets\Api;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\User;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* You could argue that this should go somewhere else - that'd be fair.
|
||||
* But, as of now, the only way to properly ensure that the counters are set properly
|
||||
* is to directly hit the app. So that's what this does - via API.
|
||||
*/
|
||||
class CheckinCheckoutCounters extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
function counters()
|
||||
{
|
||||
//make an admin who can check in and out stuff
|
||||
$admin = User::factory()->superuser()->create();
|
||||
|
||||
//make a user
|
||||
$user = User::factory()->create();
|
||||
|
||||
//need a model for the asset
|
||||
$model = AssetModel::factory()->create();
|
||||
|
||||
//need a status for the asset, too
|
||||
$status = Statuslabel::factory()->readyToDeploy()->create();
|
||||
|
||||
|
||||
//make an asset using the API (this is for the API after all!)
|
||||
$response = $this->actingAsForApi($admin)
|
||||
->postJson(route('api.assets.store'), [
|
||||
'asset_tag' => 'random_string',
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
])->assertOk()
|
||||
->assertStatusMessageIs('success')
|
||||
->json();
|
||||
\Log::error(print_r($response, true));
|
||||
|
||||
//check the counters
|
||||
$asset = Asset::find($response['payload']['id']);
|
||||
$this->assertEquals(0, $asset->checkin_counter);
|
||||
$this->assertEquals(0, $asset->checkout_counter);
|
||||
|
||||
//do a checkout
|
||||
$this->actingAsForApi($admin)
|
||||
->postJson(route('api.asset.checkout', $asset), [
|
||||
'checkout_to_type' => 'user',
|
||||
'assigned_user' => $user->id,
|
||||
'checkout_at' => '2024-04-01',
|
||||
'expected_checkin' => '2024-04-08',
|
||||
'name' => 'Changed Name',
|
||||
'note' => 'Here is a cool note!',
|
||||
])
|
||||
->assertOk();
|
||||
|
||||
$asset->refresh();
|
||||
//check the counters. both.
|
||||
$this->assertEquals(0, $asset->checkin_counter);
|
||||
$this->assertEquals(1, $asset->checkout_counter); //why does _this_ fail?!
|
||||
|
||||
//do a checkin
|
||||
$this->actingAsForApi(User::factory()->checkinAssets()->create())
|
||||
->postJson(route('api.asset.checkin', $asset), [
|
||||
'name' => 'Changed Name',
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk();
|
||||
|
||||
//check the counters, again.
|
||||
$asset->refresh();
|
||||
$this->assertEquals(1, $asset->checkin_counter); //wait, _this_ fails too?! WTH?
|
||||
$this->assertEquals(1, $asset->checkout_counter); //okay, _nothing_ works. Now I'm confused.
|
||||
}
|
||||
}
|
||||
65
tests/Feature/Assets/Ui/CheckinCheckoutCounters.php
Normal file
65
tests/Feature/Assets/Ui/CheckinCheckoutCounters.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Assets\Ui;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\User;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CheckinCheckoutCounters extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
function counters()
|
||||
{
|
||||
$admin = User::factory()->admin()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
// create an asset using the GUI
|
||||
$this->actingAs($admin)
|
||||
->post(route('hardware.store'), [
|
||||
'asset_tags' => ['1' => '1234'],
|
||||
'model_id' => AssetModel::factory()->create()->id,
|
||||
'status_id' => Statuslabel::factory()->readyToDeploy()->create()->id,
|
||||
])->assertRedirect();
|
||||
|
||||
$asset = Asset::where('asset_tag', '1234')->sole();
|
||||
|
||||
//ensure counters are initialized properly
|
||||
$this->assertEquals(0,$asset->checkout_counter);
|
||||
$this->assertEquals(0,$asset->checkin_counter);
|
||||
|
||||
//perform a checkout
|
||||
$this->actingAs($admin)
|
||||
->post(route('hardware.checkout.store', $asset), [
|
||||
'checkout_to_type' => 'user',
|
||||
// overwrite the value from the default fields set above
|
||||
'assigned_user' => (string) $user->id,
|
||||
'name' => 'Changed Name',
|
||||
'checkout_at' => '2024-03-18',
|
||||
'expected_checkin' => '2024-03-28',
|
||||
'note' => 'An awesome note',
|
||||
])->assertRedirect()->assertSessionHasNoErrors();
|
||||
|
||||
$asset->refresh();
|
||||
// dump($asset);
|
||||
$this->assertEquals(1,$asset->checkout_counter);
|
||||
$this->assertEquals(0,$asset->checkin_counter);
|
||||
|
||||
//perform a check-in
|
||||
$this->actingAs($admin)
|
||||
->post(
|
||||
route('hardware.checkin.store', [$asset]),
|
||||
[
|
||||
'name' => 'Changed Name Again',
|
||||
],
|
||||
)->assertRedirect()->assertSessionHasNoErrors();
|
||||
|
||||
$asset->refresh();
|
||||
// dump($asset);
|
||||
$this->assertEquals(1,$asset->checkout_counter);
|
||||
$this->assertEquals(1,$asset->checkin_counter);
|
||||
}
|
||||
}
|
||||
91
tests/Unit/BladeComponents/UserFullNameTest.php
Normal file
91
tests/Unit/BladeComponents/UserFullNameTest.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\BladeComponents;
|
||||
|
||||
use App\Models\User;
|
||||
use Generator;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UserFullNameTest extends TestCase
|
||||
{
|
||||
public static function provider(): Generator
|
||||
{
|
||||
yield 'Renders link to user if they exist and the authenticated user can view them' => [
|
||||
function () {
|
||||
return [
|
||||
'actor' => User::factory()->viewUsers()->create(),
|
||||
'user' => User::factory()->create(['first_name' => 'Jim', 'last_name' => 'Bagg']),
|
||||
'assertions' => function ($rendered) {
|
||||
Assert::assertStringContainsString('<a ', $rendered);
|
||||
Assert::assertStringContainsString('Jim Bagg', $rendered);
|
||||
},
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
yield 'Renders struck-through link to user if they are deleted and the authenticated user can view them' => [
|
||||
function () {
|
||||
return [
|
||||
'actor' => User::factory()->viewUsers()->create(),
|
||||
'user' => User::factory()->deleted()->create(['first_name' => 'Jim', 'last_name' => 'Bagg']),
|
||||
'assertions' => function ($rendered) {
|
||||
Assert::assertStringContainsString('<s><a ', $rendered);
|
||||
Assert::assertStringContainsString('Jim Bagg', $rendered);
|
||||
},
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
yield 'Renders name without link if the authenticated user cannot view them' => [
|
||||
function () {
|
||||
return [
|
||||
'actor' => User::factory()->create(),
|
||||
'user' => User::factory()->create(['first_name' => 'Jim', 'last_name' => 'Bagg']),
|
||||
'assertions' => function ($rendered) {
|
||||
Assert::assertStringContainsString('<span>Jim Bagg', $rendered);
|
||||
Assert::assertStringNotContainsString('<a ', $rendered);
|
||||
},
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
yield 'Renders struck-through name without link if the user is deleted and the authenticated user cannot view them' => [
|
||||
function () {
|
||||
return [
|
||||
'actor' => User::factory()->create(),
|
||||
'user' => User::factory()->deleted()->create(['first_name' => 'Jim', 'last_name' => 'Bagg']),
|
||||
'assertions' => function ($rendered) {
|
||||
Assert::assertStringContainsString('<s><span>Jim Bagg', $rendered);
|
||||
},
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
yield 'Renders nothing if the provided user is null' => [
|
||||
function () {
|
||||
return [
|
||||
'actor' => User::factory()->create(),
|
||||
'user' => null,
|
||||
'assertions' => function ($rendered) {
|
||||
Assert::assertEmpty($rendered);
|
||||
},
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
#[DataProvider('provider')]
|
||||
public function testComponent($provided)
|
||||
{
|
||||
['actor' => $actor, 'user' => $user, 'assertions' => $assertions] = $provided();
|
||||
|
||||
$this->actingAs($actor);
|
||||
|
||||
$renderedTemplateString = View::make('blade.full-user-name', ['user' => $user])->render();
|
||||
|
||||
$assertions($renderedTemplateString);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user