Merge remote-tracking branch 'origin/develop'

This commit is contained in:
snipe 2024-07-03 23:20:24 +01:00
commit fc7809192d
19 changed files with 528 additions and 23 deletions

View file

@ -2,6 +2,7 @@
namespace App\Console\Commands;
use App\Events\UserMerged;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
@ -51,7 +52,7 @@ class MergeUsersByUsername extends Command
$bad_users = User::where('username', '=', trim($parts[0]))
->whereNull('deleted_at')
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations')
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations','uploads', 'acceptances')
->get();
@ -105,10 +106,26 @@ class MergeUsersByUsername extends Command
$managedLocation->save();
}
foreach ($bad_user->uploads as $upload) {
$this->info('Updating upload log record '.$upload->id.' to user '.$user->id);
$upload->item_id = $user->id;
$upload->save();
}
foreach ($bad_user->acceptances as $acceptance) {
$this->info('Updating acceptance log record '.$acceptance->id.' to user '.$user->id);
$acceptance->item_id = $user->id;
$acceptance->save();
}
// Mark the user as deleted
$this->info('Marking the user as deleted');
$bad_user->deleted_at = Carbon::now()->timestamp;
$bad_user->save();
event(new UserMerged($bad_user, $user, null));
}
}
}

View file

@ -15,7 +15,7 @@ class UserMerged
*
* @return void
*/
public function __construct(User $from_user, User $to_user, User $admin)
public function __construct(User $from_user, User $to_user, ?User $admin)
{
$this->merged_from = $from_user;
$this->merged_to = $to_user;

View file

@ -247,10 +247,6 @@ class UsersController extends Controller
'jobtitle',
'username',
'employee_num',
'assets',
'accessories',
'consumables',
'licenses',
'groups',
'activated',
'created_at',

View file

@ -906,6 +906,25 @@ class AssetsController extends Controller
$asset->location_id = $request->input('location_id');
}
if (($asset->model->fieldset)) {
foreach ($asset->model->fieldset->fields as $field) {
if ($field->field_encrypted == '1') {
if (Gate::allows('admin')) {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
} else {
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
}
}
} else {
if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
} else {
$asset->{$field->db_column} = $request->input($field->db_column);
}
}
}
}
/**
* Invoke Watson Validating to check the asset itself and check to make sure it saved correctly.

View file

@ -42,7 +42,7 @@ class BulkUsersController extends Controller
// Get the list of affected users
$user_raw_array = request('ids');
$users = User::whereIn('id', $user_raw_array)
->with('groups', 'assets', 'licenses', 'accessories')->get();
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations','uploads', 'acceptances')->get();
// bulk edit, display the bulk edit form
if ($request->input('bulk_actions') == 'edit') {
@ -317,7 +317,7 @@ class BulkUsersController extends Controller
// Get the users
$merge_into_user = User::find($request->input('merge_into_id'));
$users_to_merge = User::whereIn('id', $user_ids_to_merge)->with('assets', 'licenses', 'consumables','accessories')->get();
$users_to_merge = User::whereIn('id', $user_ids_to_merge)->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations','uploads', 'acceptances')->get();
$admin = User::find(Auth::user()->id);
// Walk users
@ -344,10 +344,20 @@ class BulkUsersController extends Controller
}
foreach ($user_to_merge->userlog as $log) {
$log->target_id = $user_to_merge->id;
$log->target_id = $merge_into_user->id;
$log->save();
}
foreach ($user_to_merge->uploads as $upload) {
$upload->item_id = $merge_into_user->id;
$upload->save();
}
foreach ($user_to_merge->acceptances as $acceptance) {
$acceptance->item_id = $merge_into_user->id;
$acceptance->save();
}
User::where('manager_id', '=', $user_to_merge->id)->update(['manager_id' => $merge_into_user->id]);
foreach ($user_to_merge->managedLocations as $managedLocation) {
@ -356,7 +366,6 @@ class BulkUsersController extends Controller
}
$user_to_merge->delete();
//$user_to_merge->save();
event(new UserMerged($user_to_merge, $merge_into_user, $admin));

View file

@ -111,7 +111,7 @@ class LogListener
$logaction->target_type = User::class;
$logaction->action_type = 'merged';
$logaction->note = trans('general.merged_log_this_user_from', $to_from_array);
$logaction->user_id = $event->admin->id;
$logaction->user_id = $event->admin->id ?? null;
$logaction->save();
// Add a record to the users being merged TO
@ -122,7 +122,7 @@ class LogListener
$logaction->item_type = User::class;
$logaction->action_type = 'merged';
$logaction->note = trans('general.merged_log_this_user_into', $to_from_array);
$logaction->user_id = $event->admin->id;
$logaction->user_id = $event->admin->id ?? null;
$logaction->save();

View file

@ -49,6 +49,6 @@ class PersonalAccessTokens extends Component
{
//this needs safety (though the scope of auth::user might kind of do it...)
//seems like it does, test more
Auth::user()->tokens()->find($tokenId)->delete();
Auth::user()->tokens()->find($tokenId)?->delete();
}
}

View file

@ -481,8 +481,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
/**
* Establishes the user -> uploads relationship
*
* @todo I don't think we use this?
*
* @author A. Gianotto <snipe@snipe.net>
* @since [v3.0]
* @return \Illuminate\Database\Eloquent\Relations\Relation
@ -496,6 +494,21 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
->orderBy('created_at', 'desc');
}
/**
* Establishes the user -> acceptances relationship
*
* @author A. Gianotto <snipe@snipe.net>
* @since [v7.0.7]
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function acceptances()
{
return $this->hasMany(\App\Models\Actionlog::class, 'target_id')
->where('target_type', self::class)
->where('action_type', '=', 'accepted')
->orderBy('created_at', 'desc');
}
/**
* Establishes the user -> requested assets relationship
*

View file

@ -105,4 +105,64 @@ class ActionlogFactory extends Factory
];
});
}
public function filesUploaded()
{
return $this->state(function () {
return [
'created_at' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get()),
'action_type' => 'uploaded',
'item_type' => User::class,
'filename' => $this->faker->unixTime('now'),
];
});
}
public function acceptedSignature()
{
return $this->state(function () {
$asset = Asset::factory()->create();
return [
'created_at' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get()),
'action_type' => 'accepted',
'item_id' => $asset->id,
'item_type' => Asset::class,
'target_type' => User::class,
'accept_signature' => $this->faker->unixTime('now'),
];
});
}
public function acceptedEula()
{
return $this->state(function () {
$asset = Asset::factory()->create();
return [
'created_at' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get()),
'action_type' => 'accepted',
'item_id' => $asset->id,
'item_type' => Asset::class,
'target_type' => User::class,
'filename' => $this->faker->unixTime('now'),
];
});
}
public function userUpdated()
{
return $this->state(function () {
return [
'created_at' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get()),
'action_type' => 'update',
'target_type' => User::class,
'item_type' => User::class,
];
});
}
}

View file

@ -7,6 +7,7 @@ use App\Models\Company;
use App\Models\Consumable;
use App\Models\Manufacturer;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\Factory;
use App\Models\Supplier;
@ -116,4 +117,16 @@ class ConsumableFactory extends Factory
$consumable->category->update(['require_acceptance' => 1]);
});
}
public function checkedOutToUser(User $user = null)
{
return $this->afterCreating(function (Consumable $consumable) use ($user) {
$consumable->users()->attach($consumable->id, [
'consumable_id' => $consumable->id,
'created_at' => Carbon::now(),
'user_id' => User::factory()->create()->id,
'assigned_to' => $user->id ?? User::factory()->create()->id,
]);
});
}
}

View file

@ -549,6 +549,8 @@ return [
'license_seats' => ':count License Seat|:count License Seats',
'consumables' => ':count Consumable|:count Consumables',
'components' => ':count Component|:count Components',
]
],
'more_info' => 'More Info',
'quickscan_bulk_help' => 'Checking this box will edit the asset record to reflect this new location. Leaving it unchecked will simply note the location in the audit log. Note that if this asset is checked out, it will not change the location of the person, asset or location it is checked out to.',
];

View file

@ -52,7 +52,7 @@
<input type="checkbox" value="1" name="update_location" {{ old('update_location') == '1' ? ' checked="checked"' : '' }}> {{ trans('admin/hardware/form.asset_location') }}
</label>
<a href="#" class="text-dark-gray" tabindex="0" role="button" data-toggle="popover" data-trigger="focus" title="<i class='far fa-life-ring'></i> More Info" data-html="true" data-content="Checking this box will edit the asset record to reflect this new location. Leaving it unchecked will simply note the location in the audit log.<br><br>Note that if this asset is checked out, it will not change the location of the person, asset or location it is checked out to."><i class="far fa-life-ring"></i></a>
<a href="#" class="text-dark-gray" tabindex="0" role="button" data-toggle="popover" data-trigger="focus" title="<i class='far fa-life-ring'></i>"{{ trans('general.more_info') }} data-html="true" data-content="{{ trans('general.quickscan_bulk_help') }}"><i class="far fa-life-ring"></i></a>
</div>
</div>

View file

@ -48,7 +48,8 @@
</td>
<!-- Delete Button -->
<td style="vertical-align: middle;" class="text-right">
<a class="action-link btn btn-danger btn-sm" wire:click="deleteToken('{{ $token->id }}')">
<a class="action-link btn btn-danger btn-sm" wire:click="deleteToken('{{ $token->id }}')"
wire:loading.attr="disabled">
<i class="fas fa-trash"></i>
</a>
</td>

View file

@ -1,3 +1,3 @@
<a style="padding-left: 10px; font-size: 18px;" class="text-dark-gray" data-trigger="focus" tabindex="0" role="button" data-toggle="popover" title="More Info" data-placement="right" data-html="true" data-content="{{ (isset($helpText)) ? $helpText : 'Help Info Missing' }}">
<a style="padding-left: 10px; font-size: 18px;" class="text-dark-gray" data-trigger="focus" tabindex="0" role="button" data-toggle="popover" title="{{ trans('general.more_info') }}" data-placement="right" data-html="true" data-content="{{ (isset($helpText)) ? $helpText : 'Help Info Missing' }}">
<i class="far fa-life-ring" aria-hidden="true"><span class="sr-only">{{ trans('general.moreinfo') }}</span></i>
</a>

View file

@ -66,6 +66,10 @@
<i class="fas fa-tint fa-fw" aria-hidden="true" style="font-size: 17px;"></i>
<span class="sr-only">{{ trans('general.consumables') }}</span>
</th>
<th class="col-md-1 text-right">
<i class="fas fa-paperclip fa-fw" aria-hidden="true" style="font-size: 17px;"></i>
<span class="sr-only">{{ trans('general.files') }}</span>
</th>
</tr>
</thead>
<tbody>
@ -93,16 +97,19 @@
@endforeach
</td>
<td class="text-right">
{{ number_format($user->assets()->count()) }}
{{ number_format($user->assets->count()) }}
</td>
<td class="text-right">
{{ number_format($user->accessories()->count()) }}
{{ number_format($user->accessories->count()) }}
</td>
<td class="text-right">
{{ number_format($user->licenses()->count()) }}
{{ number_format($user->licenses->count()) }}
</td>
<td class="text-right">
{{ number_format($user->consumables()->count()) }}
{{ number_format($user->consumables->count()) }}
</td>
<td class="text-right">
{{ number_format($user->uploads->count()) }}
</td>
</tr>
@endforeach

View file

@ -0,0 +1,135 @@
<?php
namespace Tests\Feature\Console;
use App\Models\Accessory;
use App\Models\Asset;
use App\Models\Consumable;
use App\Models\LicenseSeat;
use App\Models\User;
use App\Models\Actionlog;
use Tests\TestCase;
class MergeUsersTest extends TestCase
{
public function testAssetsAreTransferredOnUserMerge()
{
$user1 = User::factory()->create(['username' => 'user1']);
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
Asset::factory()->count(3)->assignedToUser($user1)->create();
Asset::factory()->count(3)->assignedToUser($user_to_merge_into)->create();
$this->artisan('snipeit:merge-users')->assertExitCode(0);
$this->assertEquals(6, $user_to_merge_into->refresh()->assets->count());
$this->assertEquals(0, $user1->refresh()->assets->count());
}
public function testLicensesAreTransferredOnUserMerge(): void
{
$user1 = User::factory()->create(['username' => 'user1']);
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
LicenseSeat::factory()->count(3)->create(['assigned_to' => $user1->id]);
LicenseSeat::factory()->count(3)->create(['assigned_to' => $user_to_merge_into->id]);
$this->assertEquals(3, $user_to_merge_into->refresh()->licenses->count());
$this->artisan('snipeit:merge-users')->assertExitCode(0);
$this->assertEquals(6, $user_to_merge_into->refresh()->licenses->count());
$this->assertEquals(0, $user1->refresh()->licenses->count());
}
public function testAccessoriesTransferredOnUserMerge(): void
{
$user1 = User::factory()->create(['username' => 'user1']);
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
Accessory::factory()->count(3)->checkedOutToUser($user1)->create();
Accessory::factory()->count(3)->checkedOutToUser($user_to_merge_into)->create();
$this->assertEquals(3, $user_to_merge_into->refresh()->accessories->count());
$this->artisan('snipeit:merge-users')->assertExitCode(0);
$this->assertEquals(6, $user_to_merge_into->refresh()->accessories->count());
$this->assertEquals(0, $user1->refresh()->accessories->count());
}
public function testConsumablesTransferredOnUserMerge(): void
{
$user1 = User::factory()->create(['username' => 'user1']);
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
Consumable::factory()->count(3)->checkedOutToUser($user1)->create();
Consumable::factory()->count(3)->checkedOutToUser($user_to_merge_into)->create();
$this->assertEquals(3, $user_to_merge_into->refresh()->consumables->count());
$this->artisan('snipeit:merge-users')->assertExitCode(0);
$this->assertEquals(6, $user_to_merge_into->refresh()->consumables->count());
$this->assertEquals(0, $user1->refresh()->consumables->count());
}
public function testFilesAreTransferredOnUserMerge(): void
{
$user1 = User::factory()->create(['username' => 'user1']);
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
Actionlog::factory()->count(3)->filesUploaded()->create(['item_id' => $user1->id]);
Actionlog::factory()->count(3)->filesUploaded()->create(['item_id' => $user_to_merge_into->id]);
$this->assertEquals(3, $user_to_merge_into->refresh()->uploads->count());
$this->artisan('snipeit:merge-users')->assertExitCode(0);
$this->assertEquals(6, $user_to_merge_into->refresh()->uploads->count());
$this->assertEquals(0, $user1->refresh()->uploads->count());
}
public function testAcceptancesAreTransferredOnUserMerge(): void
{
$user1 = User::factory()->create(['username' => 'user1']);
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
Actionlog::factory()->count(3)->acceptedSignature()->create(['target_id' => $user1->id]);
Actionlog::factory()->count(3)->acceptedSignature()->create(['target_id' => $user_to_merge_into->id]);
$this->assertEquals(3, $user_to_merge_into->refresh()->acceptances->count());
$this->artisan('snipeit:merge-users')->assertExitCode(0);
$this->assertEquals(6, $user_to_merge_into->refresh()->acceptances->count());
$this->assertEquals(0, $user1->refresh()->acceptances->count());
}
public function testUserUpdateHistoryIsTransferredOnUserMerge(): void
{
$user1 = User::factory()->create(['username' => 'user1']);
$user_to_merge_into = User::factory()->create(['username' => 'user1@example.com']);
Actionlog::factory()->count(3)->userUpdated()->create(['target_id' => $user1->id, 'item_id' => $user1->id]);
Actionlog::factory()->count(3)->userUpdated()->create(['target_id' => $user_to_merge_into->id, 'item_id' => $user_to_merge_into->id]);
$this->assertEquals(3, $user_to_merge_into->refresh()->userlog->count());
$this->artisan('snipeit:merge-users')->assertExitCode(0);
// This needs to be more than the otherwise expected because the merge action itself is logged for the two merging users
$this->assertEquals(7, $user_to_merge_into->refresh()->userlog->count());
$this->assertEquals(1, $user1->refresh()->userlog->count());
}
}

View file

@ -144,4 +144,17 @@ class UserSearchTest extends TestCase
'User index contains unexpected user from another company'
);
}
public function testUsersIndexWhenInvalidSortFieldIsPassed()
{
$this->markIncompleteIfSqlite('This test is not compatible with SQLite');
$this->actingAsForApi(User::factory()->viewUsers()->create())
->getJson(route('api.users.index', [
'sort' => 'assets',
]))
->assertOk()
->assertStatus(200)
->json();
}
}

View file

@ -0,0 +1,213 @@
<?php
namespace Tests\Feature\Users\Ui;
use App\Models\Accessory;
use App\Models\Asset;
use App\Models\Consumable;
use App\Models\LicenseSeat;
use App\Models\User;
use App\Models\Actionlog;
use Tests\TestCase;
class MergeUsersTest extends TestCase
{
public function testAssetsAreTransferredOnUserMerge()
{
$user1 = User::factory()->create();
$user2 = User::factory()->create();
$user_to_merge_into = User::factory()->create();
Asset::factory()->count(3)->assignedToUser($user1)->create();
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())
->post(route('users.merge.save', $user1->id),
[
'ids_to_merge' => [$user1->id, $user2->id],
'merge_into_id' => $user_to_merge_into->id
])
->assertStatus(302)
->assertRedirect(route('users.index'));
$this->followRedirects($response)->assertSee('Success');
$this->assertEquals(9, $user_to_merge_into->refresh()->assets->count());
$this->assertEquals(0, $user1->refresh()->assets->count());
$this->assertEquals(0, $user2->refresh()->assets->count());
}
public function testLicensesAreTransferredOnUserMerge()
{
$user1 = User::factory()->create();
$user2 = User::factory()->create();
$user_to_merge_into = User::factory()->create();
LicenseSeat::factory()->count(3)->create(['assigned_to' => $user1->id]);
LicenseSeat::factory()->count(3)->create(['assigned_to' => $user2->id]);
LicenseSeat::factory()->count(3)->create(['assigned_to' => $user_to_merge_into->id]);
$this->assertEquals(3, $user_to_merge_into->refresh()->licenses->count());
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
->post(route('users.merge.save', $user1->id),
[
'ids_to_merge' => [$user1->id, $user2->id],
'merge_into_id' => $user_to_merge_into->id
])
->assertStatus(302)
->assertRedirect(route('users.index'));
$this->followRedirects($response)->assertSee('Success');
$this->assertEquals(9, $user_to_merge_into->refresh()->licenses->count());
$this->assertEquals(0, $user1->refresh()->licenses->count());
$this->assertEquals(0, $user2->refresh()->licenses->count());
}
public function testAccessoriesTransferredOnUserMerge()
{
$user1 = User::factory()->create();
$user2 = User::factory()->create();
$user_to_merge_into = User::factory()->create();
Accessory::factory()->count(3)->checkedOutToUser($user1)->create();
Accessory::factory()->count(3)->checkedOutToUser($user2)->create();
Accessory::factory()->count(3)->checkedOutToUser($user_to_merge_into)->create();
$this->assertEquals(3, $user_to_merge_into->refresh()->accessories->count());
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
->post(route('users.merge.save', $user1->id),
[
'ids_to_merge' => [$user1->id, $user2->id],
'merge_into_id' => $user_to_merge_into->id
])
->assertStatus(302)
->assertRedirect(route('users.index'));
$this->followRedirects($response)->assertSee('Success');
$this->assertEquals(9, $user_to_merge_into->refresh()->accessories->count());
$this->assertEquals(0, $user1->refresh()->accessories->count());
$this->assertEquals(0, $user2->refresh()->accessories->count());
}
public function testConsumablesTransferredOnUserMerge()
{
$user1 = User::factory()->create();
$user2 = User::factory()->create();
$user_to_merge_into = User::factory()->create();
Consumable::factory()->count(3)->checkedOutToUser($user1)->create();
Consumable::factory()->count(3)->checkedOutToUser($user2)->create();
Consumable::factory()->count(3)->checkedOutToUser($user_to_merge_into)->create();
$this->assertEquals(3, $user_to_merge_into->refresh()->consumables->count());
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
->post(route('users.merge.save', $user1->id),
[
'ids_to_merge' => [$user1->id, $user2->id],
'merge_into_id' => $user_to_merge_into->id
])
->assertStatus(302)
->assertRedirect(route('users.index'));
$this->followRedirects($response)->assertSee('Success');
$this->assertEquals(9, $user_to_merge_into->refresh()->consumables->count());
$this->assertEquals(0, $user1->refresh()->consumables->count());
$this->assertEquals(0, $user2->refresh()->consumables->count());
}
public function testFilesAreTransferredOnUserMerge()
{
$user1 = User::factory()->create();
$user2 = User::factory()->create();
$user_to_merge_into = User::factory()->create();
Actionlog::factory()->count(3)->filesUploaded()->create(['item_id' => $user1->id]);
Actionlog::factory()->count(3)->filesUploaded()->create(['item_id' => $user2->id]);
Actionlog::factory()->count(3)->filesUploaded()->create(['item_id' => $user_to_merge_into->id]);
$this->assertEquals(3, $user_to_merge_into->refresh()->uploads->count());
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
->post(route('users.merge.save', $user1->id),
[
'ids_to_merge' => [$user1->id, $user2->id],
'merge_into_id' => $user_to_merge_into->id
])
->assertStatus(302)
->assertRedirect(route('users.index'));
$this->followRedirects($response)->assertSee('Success');
$this->assertEquals(9, $user_to_merge_into->refresh()->uploads->count());
$this->assertEquals(0, $user1->refresh()->uploads->count());
$this->assertEquals(0, $user2->refresh()->uploads->count());
}
public function testAcceptancesAreTransferredOnUserMerge()
{
$user1 = User::factory()->create();
$user2 = User::factory()->create();
$user_to_merge_into = User::factory()->create();
Actionlog::factory()->count(3)->acceptedSignature()->create(['target_id' => $user1->id]);
Actionlog::factory()->count(3)->acceptedSignature()->create(['target_id' => $user2->id]);
Actionlog::factory()->count(3)->acceptedSignature()->create(['target_id' => $user_to_merge_into->id]);
$this->assertEquals(3, $user_to_merge_into->refresh()->acceptances->count());
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
->post(route('users.merge.save', $user1->id),
[
'ids_to_merge' => [$user1->id, $user2->id],
'merge_into_id' => $user_to_merge_into->id
])
->assertStatus(302)
->assertRedirect(route('users.index'));
$this->followRedirects($response)->assertSee('Success');
$this->assertEquals(9, $user_to_merge_into->refresh()->acceptances->count());
$this->assertEquals(0, $user1->refresh()->acceptances->count());
$this->assertEquals(0, $user2->refresh()->acceptances->count());
}
public function testUserUpdateHistoryIsTransferredOnUserMerge()
{
$user1 = User::factory()->create();
$user2 = User::factory()->create();
$user_to_merge_into = User::factory()->create();
Actionlog::factory()->count(3)->userUpdated()->create(['target_id' => $user1->id, 'item_id' => $user1->id]);
Actionlog::factory()->count(3)->userUpdated()->create(['target_id' => $user2->id, 'item_id' => $user2->id]);
Actionlog::factory()->count(3)->userUpdated()->create(['target_id' => $user_to_merge_into->id, 'item_id' => $user_to_merge_into->id]);
$this->assertEquals(3, $user_to_merge_into->refresh()->userlog->count());
$response = $this->actingAs(User::factory()->editUsers()->viewUsers()->create())
->post(route('users.merge.save', $user1->id),
[
'ids_to_merge' => [$user1->id, $user2->id],
'merge_into_id' => $user_to_merge_into->id
])
->assertStatus(302)
->assertRedirect(route('users.index'));
$this->followRedirects($response)->assertSee('Success');
// This needs to be 2 more than the otherwise expected because the merge action itself is logged for the two merging users
$this->assertEquals(11, $user_to_merge_into->refresh()->userlog->count());
$this->assertEquals(2, $user1->refresh()->userlog->count());
$this->assertEquals(2, $user2->refresh()->userlog->count());
}
}

View file

@ -10,4 +10,11 @@ trait CanSkipTests
$this->markTestIncomplete($message);
}
}
public function markIncompleteIfSqlite($message = 'Test skipped due to database driver being sqlite.')
{
if (config('database.default') === 'sqlite') {
$this->markTestIncomplete($message);
}
}
}