Merge remote-tracking branch 'origin/develop'
This commit is contained in:
@@ -19,6 +19,7 @@ use Illuminate\Validation\ValidationException;
|
||||
use Intervention\Image\Exception\NotSupportedException;
|
||||
use JsonException;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use Livewire\Exceptions\PublicPropertyNotFoundException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Throwable;
|
||||
|
||||
@@ -41,6 +42,7 @@ class Handler extends ExceptionHandler
|
||||
JsonException::class,
|
||||
SCIMException::class, // these generally don't need to be reported
|
||||
InvalidFormatException::class,
|
||||
PublicPropertyNotFoundException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -71,6 +73,11 @@ class Handler extends ExceptionHandler
|
||||
public function render($request, Throwable $e)
|
||||
{
|
||||
|
||||
// Livewire tried to set a property that doesn't exist (e.g. stale browser state sending a bare "0" as a property name)
|
||||
if ($e instanceof PublicPropertyNotFoundException) {
|
||||
return response()->json(['message' => $e->getMessage()], 422);
|
||||
}
|
||||
|
||||
// CSRF token mismatch error
|
||||
if ($e instanceof TokenMismatchException) {
|
||||
return redirect()->back()->with('error', trans('general.token_expired'));
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -17,6 +16,9 @@ class ActionlogController extends Controller
|
||||
{
|
||||
$filename = basename((string) $filename);
|
||||
|
||||
$actionlog = Actionlog::where('accept_signature', $filename)->with('item')->firstOrFail();
|
||||
$this->authorize('view', $actionlog->item);
|
||||
|
||||
// PHP doesn't let you handle file not found errors well with
|
||||
// file_get_contents, so we set the error reporting for just this class
|
||||
error_reporting(0);
|
||||
@@ -29,7 +31,6 @@ class ActionlogController extends Controller
|
||||
|
||||
return redirect()->away(Storage::disk($disk)->temporaryUrl($file, now()->addMinutes(5)));
|
||||
default:
|
||||
$this->authorize('view', Asset::class);
|
||||
$file = config('app.private_uploads').'/signatures/'.$filename;
|
||||
$filetype = Helper::checkUploadIsImage($file);
|
||||
|
||||
|
||||
@@ -171,8 +171,6 @@ class BulkUsersController extends Controller
|
||||
->conditionallyAddItem('company_id')
|
||||
->conditionallyAddItem('locale')
|
||||
->conditionallyAddItem('remote')
|
||||
->conditionallyAddItem('ldap_import')
|
||||
->conditionallyAddItem('activated')
|
||||
->conditionallyAddItem('display_name')
|
||||
->conditionallyAddItem('start_date')
|
||||
->conditionallyAddItem('end_date')
|
||||
@@ -235,11 +233,21 @@ class BulkUsersController extends Controller
|
||||
->update(['location_id' => $this->update_array['location_id']]);
|
||||
}
|
||||
|
||||
// Only sync groups if groups were selected
|
||||
if ($request->filled('groups')) {
|
||||
|
||||
foreach ($users as $user) {
|
||||
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
|
||||
// Fields that require canEditAuthFields (non-admins cannot touch admins/superusers,
|
||||
// admins cannot touch superusers) must be applied per-user, not via mass update.
|
||||
foreach ($users as $user) {
|
||||
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
|
||||
$authFieldUpdate = [];
|
||||
if ($request->filled('activated')) {
|
||||
$authFieldUpdate['activated'] = $request->input('activated');
|
||||
}
|
||||
if ($request->filled('ldap_import')) {
|
||||
$authFieldUpdate['ldap_import'] = $request->input('ldap_import');
|
||||
}
|
||||
if (! empty($authFieldUpdate)) {
|
||||
$user->update($authFieldUpdate);
|
||||
}
|
||||
if ($request->filled('groups')) {
|
||||
$user->groups()->sync($request->input('groups'));
|
||||
}
|
||||
}
|
||||
@@ -398,7 +406,7 @@ class BulkUsersController extends Controller
|
||||
*/
|
||||
public function merge(Request $request)
|
||||
{
|
||||
$this->authorize('update', User::class);
|
||||
$this->authorize('delete', User::class);
|
||||
|
||||
if (config('app.lock_passwords')) {
|
||||
return redirect()->route('users.index')->with('error', trans('general.feature_disabled'));
|
||||
@@ -419,6 +427,10 @@ class BulkUsersController extends Controller
|
||||
// Walk users
|
||||
foreach ($users_to_merge as $user_to_merge) {
|
||||
|
||||
if (! auth()->user()->can('canEditAuthFields', $user_to_merge) || ! auth()->user()->can('editableOnDemo')) {
|
||||
return redirect()->route('users.index')->with('error', trans('general.insufficient_permissions'));
|
||||
}
|
||||
|
||||
foreach ($user_to_merge->assets as $asset) {
|
||||
Log::debug('Updating asset: '.$asset->asset_tag.' to '.$merge_into_user->id);
|
||||
$asset->assigned_to = $request->input('merge_into_id');
|
||||
|
||||
@@ -720,6 +720,12 @@ class Importer extends Component
|
||||
$this->message_type = 'danger';
|
||||
}
|
||||
|
||||
public function process(): void
|
||||
{
|
||||
$this->message = trans('general.token_expired');
|
||||
$this->message_type = 'danger';
|
||||
}
|
||||
|
||||
public function clearMessage()
|
||||
{
|
||||
$this->message = null;
|
||||
|
||||
+1
-3
@@ -85,9 +85,7 @@
|
||||
"nunomaduro/phpinsights": "^2.11",
|
||||
"php-mock/php-mock-phpunit": "^2.10",
|
||||
"phpunit/phpunit": "^11.0",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"symfony/css-selector": "^4.4",
|
||||
"symfony/dom-crawler": "^4.4"
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
|
||||
Generated
+12
-83
@@ -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": "2d0e79dc07fa3389dba6fd8005bde5aa",
|
||||
"content-hash": "ed0655f6c3c75cda1939dfc27b492029",
|
||||
"packages": [
|
||||
{
|
||||
"name": "alek13/slack",
|
||||
@@ -8485,21 +8485,20 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
"version": "v4.4.44",
|
||||
"version": "v7.4.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/css-selector.git",
|
||||
"reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed"
|
||||
"reference": "b75663ed96cf4756e28e3105476f220f92886cc4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/bd0a6737e48de45b4b0b7b6fc98c78404ddceaed",
|
||||
"reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/b75663ed96cf4756e28e3105476f220f92886cc4",
|
||||
"reference": "b75663ed96cf4756e28e3105476f220f92886cc4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1.3",
|
||||
"symfony/polyfill-php80": "^1.16"
|
||||
"php": ">=8.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -8531,7 +8530,7 @@
|
||||
"description": "Converts CSS selectors to XPath expressions",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/css-selector/tree/v4.4.44"
|
||||
"source": "https://github.com/symfony/css-selector/tree/v7.4.9"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8542,12 +8541,16 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-06-27T13:16:42+00:00"
|
||||
"time": "2026-04-18T13:18:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
@@ -16290,80 +16293,6 @@
|
||||
],
|
||||
"time": "2026-05-05T15:33:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v4.4.45",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
"reference": "4b8daf6c56801e6d664224261cb100b73edc78a5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4b8daf6c56801e6d664224261cb100b73edc78a5",
|
||||
"reference": "4b8daf6c56801e6d664224261cb100b73edc78a5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1.3",
|
||||
"symfony/polyfill-ctype": "~1.8",
|
||||
"symfony/polyfill-mbstring": "~1.0",
|
||||
"symfony/polyfill-php80": "^1.16"
|
||||
},
|
||||
"conflict": {
|
||||
"masterminds/html5": "<2.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"masterminds/html5": "^2.6",
|
||||
"symfony/css-selector": "^3.4|^4.0|^5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/css-selector": ""
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\DomCrawler\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Eases DOM navigation for HTML and XML documents",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/dom-crawler/tree/v4.4.45"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-08-03T12:57:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
"version": "v7.4.9",
|
||||
|
||||
@@ -618,6 +618,11 @@ document.addEventListener('livewire:init', () => {
|
||||
console.error("For data-livewire-component, you probably want to use $this->getId() or {{ $this->getId() }}, as appropriate")
|
||||
return false
|
||||
}
|
||||
// PHP property names cannot start with a digit — skip bare numeric names (e.g. "0") that would cause a 500
|
||||
if (/^\d+$/.test(event.target.name)) {
|
||||
console.error("Livewire select2: name attribute '" + event.target.name + "' is not a valid Livewire property name — skipping")
|
||||
return false
|
||||
}
|
||||
Livewire.find(target.data('livewire-component')).set(event.target.name, this.options[this.selectedIndex].value)
|
||||
});
|
||||
|
||||
|
||||
@@ -679,6 +679,7 @@ return [
|
||||
'user_managed_passwords' => 'Password Management',
|
||||
'user_managed_passwords_disallow' => 'Disallow users from managing their own passwords',
|
||||
'user_managed_passwords_allow' => 'Allow users to manage their own passwords',
|
||||
'user_managed_passwords_bulk_help' => 'This setting will only be applied to users that you are able to edit authentication settings on.',
|
||||
'from' => 'From',
|
||||
'by' => 'By',
|
||||
'by_user' => 'By',
|
||||
|
||||
@@ -159,6 +159,7 @@
|
||||
<input type="radio" name="ldap_import" id="ldap_import" value="1" aria-label="ldap_import">
|
||||
{{ trans('general.user_managed_passwords_disallow') }}
|
||||
</label>
|
||||
<p class="help-block">{{ trans('general.user_managed_passwords_bulk_help') }}</p>
|
||||
</div>
|
||||
</div> <!--/form-group-->
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\ActionLogs;
|
||||
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\License;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DisplaySigTest extends TestCase
|
||||
{
|
||||
public function test_requires_authentication(): void
|
||||
{
|
||||
$actionlog = Actionlog::factory()->acceptedSignature()->create();
|
||||
|
||||
$this->get(route('log.signature.view', ['filename' => $actionlog->accept_signature]))
|
||||
->assertRedirect(route('login'));
|
||||
}
|
||||
|
||||
public function test_nonexistent_filename_redirects_with_error(): void
|
||||
{
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->get(route('log.signature.view', ['filename' => 'does-not-exist.png']))
|
||||
->assertRedirect(route('home'));
|
||||
}
|
||||
|
||||
public function test_user_without_view_permission_cannot_view_asset_signature(): void
|
||||
{
|
||||
$actionlog = Actionlog::factory()->acceptedSignature()->create();
|
||||
|
||||
$this->actingAs(User::factory()->create())
|
||||
->get(route('log.signature.view', ['filename' => $actionlog->accept_signature]))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_user_with_asset_view_permission_can_view_asset_signature(): void
|
||||
{
|
||||
$asset = Asset::factory()->create();
|
||||
$actionlog = Actionlog::factory()->create([
|
||||
'action_type' => 'accepted',
|
||||
'item_id' => $asset->id,
|
||||
'item_type' => Asset::class,
|
||||
'accept_signature' => 'test-asset-sig-'.uniqid().'.png',
|
||||
]);
|
||||
|
||||
$this->actingAs(User::factory()->viewAssets()->create())
|
||||
->get(route('log.signature.view', ['filename' => $actionlog->accept_signature]))
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_user_with_asset_view_permission_cannot_view_license_signature(): void
|
||||
{
|
||||
$license = License::factory()->create();
|
||||
$actionlog = Actionlog::factory()->create([
|
||||
'action_type' => 'accepted',
|
||||
'item_id' => $license->id,
|
||||
'item_type' => License::class,
|
||||
'accept_signature' => 'test-license-sig-'.uniqid().'.png',
|
||||
]);
|
||||
|
||||
$this->actingAs(User::factory()->viewAssets()->create())
|
||||
->get(route('log.signature.view', ['filename' => $actionlog->accept_signature]))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_user_with_license_view_permission_can_view_license_signature(): void
|
||||
{
|
||||
$license = License::factory()->create();
|
||||
$actionlog = Actionlog::factory()->create([
|
||||
'action_type' => 'accepted',
|
||||
'item_id' => $license->id,
|
||||
'item_type' => License::class,
|
||||
'accept_signature' => 'test-license-sig-'.uniqid().'.png',
|
||||
]);
|
||||
|
||||
$this->actingAs(User::factory()->viewLicenses()->create())
|
||||
->get(route('log.signature.view', ['filename' => $actionlog->accept_signature]))
|
||||
->assertOk();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Users\Ui\BulkActions;
|
||||
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class BulkEditUsersTest extends TestCase
|
||||
{
|
||||
public function test_requires_correct_permission()
|
||||
{
|
||||
$this->actingAs(User::factory()->create())
|
||||
->post(route('users/bulkeditsave'), [
|
||||
'ids' => [User::factory()->create()->id],
|
||||
])
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_non_admin_cannot_deactivate_admin_via_bulk_edit()
|
||||
{
|
||||
$actor = User::factory()->editUsers()->create();
|
||||
$admin = User::factory()->admin()->create(['activated' => 1]);
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('users/bulkeditsave'), [
|
||||
'ids' => [$admin->id],
|
||||
'activated' => '0',
|
||||
])
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->assertEquals(1, $admin->fresh()->activated);
|
||||
}
|
||||
|
||||
public function test_non_admin_cannot_deactivate_superuser_via_bulk_edit()
|
||||
{
|
||||
$actor = User::factory()->editUsers()->create();
|
||||
$superuser = User::factory()->superuser()->create(['activated' => 1]);
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('users/bulkeditsave'), [
|
||||
'ids' => [$superuser->id],
|
||||
'activated' => '0',
|
||||
])
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->assertEquals(1, $superuser->fresh()->activated);
|
||||
}
|
||||
|
||||
public function test_admin_cannot_deactivate_superuser_via_bulk_edit()
|
||||
{
|
||||
$admin = User::factory()->admin()->create();
|
||||
$superuser = User::factory()->superuser()->create(['activated' => 1]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->post(route('users/bulkeditsave'), [
|
||||
'ids' => [$superuser->id],
|
||||
'activated' => '0',
|
||||
])
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->assertEquals(1, $superuser->fresh()->activated);
|
||||
}
|
||||
|
||||
public function test_non_admin_can_deactivate_regular_user_via_bulk_edit()
|
||||
{
|
||||
$actor = User::factory()->editUsers()->create();
|
||||
$target = User::factory()->create(['activated' => 1]);
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('users/bulkeditsave'), [
|
||||
'ids' => [$target->id],
|
||||
'activated' => '0',
|
||||
])
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->assertEquals(0, $target->fresh()->activated);
|
||||
}
|
||||
|
||||
public function test_admin_can_deactivate_regular_user_via_bulk_edit()
|
||||
{
|
||||
$admin = User::factory()->admin()->create();
|
||||
$target = User::factory()->create(['activated' => 1]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->post(route('users/bulkeditsave'), [
|
||||
'ids' => [$target->id],
|
||||
'activated' => '0',
|
||||
])
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->assertEquals(0, $target->fresh()->activated);
|
||||
}
|
||||
|
||||
public function test_non_admin_cannot_set_ldap_import_on_admin_via_bulk_edit()
|
||||
{
|
||||
$actor = User::factory()->editUsers()->create();
|
||||
$admin = User::factory()->admin()->create(['ldap_import' => 0]);
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('users/bulkeditsave'), [
|
||||
'ids' => [$admin->id],
|
||||
'ldap_import' => '1',
|
||||
])
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->assertEquals(0, $admin->fresh()->ldap_import);
|
||||
}
|
||||
|
||||
public function test_non_auth_fields_are_still_updated_for_admin_targets()
|
||||
{
|
||||
$actor = User::factory()->editUsers()->create();
|
||||
$admin = User::factory()->admin()->create(['city' => 'Springfield']);
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('users/bulkeditsave'), [
|
||||
'ids' => [$admin->id],
|
||||
'city' => 'Shelbyville',
|
||||
])
|
||||
->assertRedirect(route('users.index'));
|
||||
|
||||
$this->assertEquals('Shelbyville', $admin->fresh()->city);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Users\Ui\BulkActions;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class BulkMergeUsersTest extends TestCase
|
||||
{
|
||||
public function test_requires_delete_permission()
|
||||
{
|
||||
$target = User::factory()->create();
|
||||
$to_merge = User::factory()->create();
|
||||
|
||||
$this->actingAs(User::factory()->editUsers()->create())
|
||||
->post(route('users.merge.save'), [
|
||||
'ids_to_merge' => [$to_merge->id],
|
||||
'merge_into_id' => $target->id,
|
||||
])
|
||||
->assertForbidden();
|
||||
|
||||
$this->assertNotSoftDeleted($to_merge);
|
||||
}
|
||||
|
||||
public function test_non_admin_cannot_merge_admin_into_self()
|
||||
{
|
||||
$actor = User::factory()->deleteUsers()->create();
|
||||
$admin = User::factory()->admin()->create();
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('users.merge.save'), [
|
||||
'ids_to_merge' => [$admin->id],
|
||||
'merge_into_id' => $actor->id,
|
||||
])
|
||||
->assertRedirect(route('users.index'))
|
||||
->assertSessionHas('error');
|
||||
|
||||
$this->assertNotSoftDeleted($admin);
|
||||
}
|
||||
|
||||
public function test_non_admin_cannot_merge_superuser_into_self()
|
||||
{
|
||||
$actor = User::factory()->deleteUsers()->create();
|
||||
$superuser = User::factory()->superuser()->create();
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('users.merge.save'), [
|
||||
'ids_to_merge' => [$superuser->id],
|
||||
'merge_into_id' => $actor->id,
|
||||
])
|
||||
->assertRedirect(route('users.index'))
|
||||
->assertSessionHas('error');
|
||||
|
||||
$this->assertNotSoftDeleted($superuser);
|
||||
}
|
||||
|
||||
public function test_admin_cannot_merge_superuser_into_self()
|
||||
{
|
||||
$admin = User::factory()->admin()->create();
|
||||
$superuser = User::factory()->superuser()->create();
|
||||
|
||||
$this->actingAs($admin)
|
||||
->post(route('users.merge.save'), [
|
||||
'ids_to_merge' => [$superuser->id],
|
||||
'merge_into_id' => $admin->id,
|
||||
])
|
||||
->assertRedirect(route('users.index'))
|
||||
->assertSessionHas('error');
|
||||
|
||||
$this->assertNotSoftDeleted($superuser);
|
||||
}
|
||||
|
||||
public function test_assets_are_transferred_and_source_user_is_deleted_on_merge()
|
||||
{
|
||||
$admin = User::factory()->admin()->create();
|
||||
$source = User::factory()->create();
|
||||
$target = User::factory()->create();
|
||||
$asset = Asset::factory()->assignedToUser($source)->create();
|
||||
|
||||
$this->actingAs($admin)
|
||||
->post(route('users.merge.save'), [
|
||||
'ids_to_merge' => [$source->id],
|
||||
'merge_into_id' => $target->id,
|
||||
])
|
||||
->assertRedirect(route('users.index'))
|
||||
->assertSessionHas('success');
|
||||
|
||||
$this->assertSoftDeleted($source);
|
||||
$this->assertEquals($target->id, $asset->fresh()->assigned_to);
|
||||
}
|
||||
|
||||
public function test_merge_does_not_transfer_assets_when_source_is_protected()
|
||||
{
|
||||
$actor = User::factory()->deleteUsers()->create();
|
||||
$admin = User::factory()->admin()->create();
|
||||
$asset = Asset::factory()->assignedToUser($admin)->create();
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('users.merge.save'), [
|
||||
'ids_to_merge' => [$admin->id],
|
||||
'merge_into_id' => $actor->id,
|
||||
])
|
||||
->assertRedirect(route('users.index'))
|
||||
->assertSessionHas('error');
|
||||
|
||||
$this->assertEquals($admin->id, $asset->fresh()->assigned_to);
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ class MergeUsersTest extends TestCase
|
||||
Asset::factory()->count(3)->assignedToUser($user2)->create();
|
||||
Asset::factory()->count(3)->assignedToUser($user_to_merge_into)->create();
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
$response = $this->actingAs(User::factory()->deleteUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
@@ -50,7 +50,7 @@ class MergeUsersTest extends TestCase
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->licenses->count());
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
$response = $this->actingAs(User::factory()->deleteUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
@@ -78,7 +78,7 @@ class MergeUsersTest extends TestCase
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->accessories->count());
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
$response = $this->actingAs(User::factory()->deleteUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
@@ -106,7 +106,7 @@ class MergeUsersTest extends TestCase
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->consumables->count());
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
$response = $this->actingAs(User::factory()->deleteUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
@@ -134,7 +134,7 @@ class MergeUsersTest extends TestCase
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->uploads->count());
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
$response = $this->actingAs(User::factory()->deleteUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
@@ -162,7 +162,7 @@ class MergeUsersTest extends TestCase
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->acceptances->count());
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
$response = $this->actingAs(User::factory()->deleteUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
@@ -190,7 +190,7 @@ class MergeUsersTest extends TestCase
|
||||
|
||||
$this->assertEquals(3, $user_to_merge_into->refresh()->userlog->count());
|
||||
|
||||
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
|
||||
$response = $this->actingAs(User::factory()->deleteUsers()->viewUsers()->create())
|
||||
->post(route('users.merge.save', $user1->id),
|
||||
[
|
||||
'ids_to_merge' => [$user1->id, $user2->id],
|
||||
|
||||
Reference in New Issue
Block a user