mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-06-06 04:56:45 +02:00
Merge branch 'Fix-CWE-362' into dev
This commit is contained in:
commit
ab5d6873f1
@ -10,6 +10,7 @@ use App\Facades\Groups;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Group;
|
use App\Models\Group;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class GroupController extends Controller
|
class GroupController extends Controller
|
||||||
@ -59,10 +60,18 @@ class GroupController extends Controller
|
|||||||
*
|
*
|
||||||
* @return \App\Api\v1\Resources\GroupResource
|
* @return \App\Api\v1\Resources\GroupResource
|
||||||
*/
|
*/
|
||||||
public function show(Group $group)
|
public function show(Request $request, Group $group)
|
||||||
{
|
{
|
||||||
$this->authorize('view', $group);
|
$this->authorize('view', $group);
|
||||||
|
|
||||||
|
// group with id==0 is the 'All' virtual group.
|
||||||
|
// Eloquent specifically returns a non-persisted Group instance
|
||||||
|
// with just the name property. The twofaccounts_count has to be
|
||||||
|
// set here.
|
||||||
|
if ($group->id === 0) {
|
||||||
|
$group->twofaccounts_count = $request->user()->twofaccounts->count();
|
||||||
|
}
|
||||||
|
|
||||||
return new GroupResource($group);
|
return new GroupResource($group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +102,14 @@ class GroupController extends Controller
|
|||||||
|
|
||||||
$validated = $request->validated();
|
$validated = $request->validated();
|
||||||
|
|
||||||
|
try {
|
||||||
Groups::assign($validated['ids'], $request->user(), $group);
|
Groups::assign($validated['ids'], $request->user(), $group);
|
||||||
|
$group->loadCount('twofaccounts');
|
||||||
|
} catch (ModelNotFoundException $exc) {
|
||||||
|
abort(404);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
abort(409, 'Conflict');
|
||||||
|
}
|
||||||
|
|
||||||
return new GroupResource($group);
|
return new GroupResource($group);
|
||||||
}
|
}
|
||||||
@ -103,11 +119,21 @@ class GroupController extends Controller
|
|||||||
*
|
*
|
||||||
* @return \App\Api\v1\Resources\TwoFAccountCollection
|
* @return \App\Api\v1\Resources\TwoFAccountCollection
|
||||||
*/
|
*/
|
||||||
public function accounts(Group $group)
|
public function accounts(Request $request, Group $group)
|
||||||
{
|
{
|
||||||
$this->authorize('view', $group);
|
$this->authorize('view', $group);
|
||||||
|
|
||||||
return new TwoFAccountCollection($group->twofaccounts);
|
// group with id==0 is the 'All' virtual group that lists
|
||||||
|
// all the user's twofaccounts. From the db pov the accounts
|
||||||
|
// are not assigned to any group record.
|
||||||
|
if ($group->id === 0) {
|
||||||
|
$twofaccounts = $request->user()->twofaccounts;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$twofaccounts = $group->twofaccounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TwoFAccountCollection($twofaccounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,6 +21,7 @@ use App\Helpers\Helpers;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\TwoFAccount;
|
use App\Models\TwoFAccount;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
@ -89,7 +90,12 @@ class TwoFAccountController extends Controller
|
|||||||
$request->user()->twofaccounts()->save($twofaccount);
|
$request->user()->twofaccounts()->save($twofaccount);
|
||||||
|
|
||||||
// Possible group association
|
// Possible group association
|
||||||
|
try {
|
||||||
Groups::assign($twofaccount->id, $request->user(), Arr::get($validated, 'group_id', null));
|
Groups::assign($twofaccount->id, $request->user(), Arr::get($validated, 'group_id', null));
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
// The group association might fail but we don't want the twofaccount
|
||||||
|
// creation to be reverted so we do nothing here.
|
||||||
|
}
|
||||||
|
|
||||||
return (new TwoFAccountReadResource($twofaccount->refresh()))
|
return (new TwoFAccountReadResource($twofaccount->refresh()))
|
||||||
->response()
|
->response()
|
||||||
@ -116,7 +122,12 @@ class TwoFAccountController extends Controller
|
|||||||
if ((int) $groupId === 0) {
|
if ((int) $groupId === 0) {
|
||||||
TwoFAccounts::withdraw($twofaccount->id);
|
TwoFAccounts::withdraw($twofaccount->id);
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
Groups::assign($twofaccount->id, $request->user(), $groupId);
|
Groups::assign($twofaccount->id, $request->user(), $groupId);
|
||||||
|
} catch (ModelNotFoundException $exc) {
|
||||||
|
// The destination group no longer exists, the twofaccount is withdrawn
|
||||||
|
TwoFAccounts::withdraw($twofaccount->id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$twofaccount->refresh();
|
$twofaccount->refresh();
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,21 @@ class GroupStoreRequest extends FormRequest
|
|||||||
'required',
|
'required',
|
||||||
'regex:/^[A-zÀ-ú0-9\s\-_]+$/',
|
'regex:/^[A-zÀ-ú0-9\s\-_]+$/',
|
||||||
'max:32',
|
'max:32',
|
||||||
|
Rule::notIn([__('commons.all')]),
|
||||||
Rule::unique('groups')->where(fn ($query) => $query->where('user_id', $this->user()->id)),
|
Rule::unique('groups')->where(fn ($query) => $query->where('user_id', $this->user()->id)),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the error messages for the defined validation rules.
|
||||||
|
*
|
||||||
|
* @return array<string, string>
|
||||||
|
*/
|
||||||
|
public function messages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name.not_in' => __('errors.reserved_name_please_choose_something_else'),
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ use App\Models\Group;
|
|||||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class GroupDeleted
|
class GroupDeleted
|
||||||
{
|
{
|
||||||
@ -24,5 +25,7 @@ class GroupDeleted
|
|||||||
public function __construct(Group $group)
|
public function __construct(Group $group)
|
||||||
{
|
{
|
||||||
$this->group = $group;
|
$this->group = $group;
|
||||||
|
|
||||||
|
Log::info(sprintf('Group %s (id #%d) deleted ', var_export($group->name, true), $group->id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Events;
|
|
||||||
|
|
||||||
use App\Models\Group;
|
|
||||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
|
|
||||||
class GroupDeleting
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var \App\Models\Group
|
|
||||||
*/
|
|
||||||
public $group;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new event instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct(Group $group)
|
|
||||||
{
|
|
||||||
$this->group = $group;
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Listeners;
|
namespace App\Listeners;
|
||||||
|
|
||||||
use App\Events\GroupDeleting;
|
use App\Events\GroupDeleted;
|
||||||
use App\Models\TwoFAccount;
|
use App\Models\TwoFAccount;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ class DissociateTwofaccountFromGroup
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function handle(GroupDeleting $event)
|
public function handle(GroupDeleted $event)
|
||||||
{
|
{
|
||||||
TwoFAccount::where('group_id', $event->group->id)
|
TwoFAccount::where('group_id', $event->group->id)
|
||||||
->update(
|
->update(
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Events\GroupDeleted;
|
use App\Events\GroupDeleted;
|
||||||
use App\Events\GroupDeleting;
|
|
||||||
use Database\Factories\GroupFactory;
|
use Database\Factories\GroupFactory;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
@ -79,7 +78,6 @@ class Group extends Model
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $dispatchesEvents = [
|
protected $dispatchesEvents = [
|
||||||
'deleting' => GroupDeleting::class,
|
|
||||||
'deleted' => GroupDeleted::class,
|
'deleted' => GroupDeleted::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -98,9 +96,31 @@ class Group extends Model
|
|||||||
static::updated(function (object $model) {
|
static::updated(function (object $model) {
|
||||||
Log::info(sprintf('Group %s (id #%d) updated by user ID #%s', var_export($model->name, true), $model->id, $model->user_id));
|
Log::info(sprintf('Group %s (id #%d) updated by user ID #%s', var_export($model->name, true), $model->id, $model->user_id));
|
||||||
});
|
});
|
||||||
static::deleted(function (object $model) {
|
}
|
||||||
Log::info(sprintf('Group %s (id #%d) deleted ', var_export($model->name, true), $model->id));
|
|
||||||
});
|
/**
|
||||||
|
* Retrieve the model for a bound value.
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
* @param string|null $field
|
||||||
|
* @return \Illuminate\Database\Eloquent\Model|null
|
||||||
|
*/
|
||||||
|
public function resolveRouteBinding($value, $field = null)
|
||||||
|
{
|
||||||
|
// The All group is a virtual group with id==0.
|
||||||
|
// It never exists in database so we enforce the route binding
|
||||||
|
// resolution logic to return an instance instead of not found.
|
||||||
|
if ($value === '0') {
|
||||||
|
$group = new self([
|
||||||
|
'name' => __('commons.all'),
|
||||||
|
]);
|
||||||
|
$group->id = 0;
|
||||||
|
|
||||||
|
return $group;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return parent::resolveRouteBinding($value, $field);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,7 +28,7 @@ class GroupPolicy
|
|||||||
*/
|
*/
|
||||||
public function view(User $user, Group $group)
|
public function view(User $user, Group $group)
|
||||||
{
|
{
|
||||||
$can = $this->isOwnerOf($user, $group);
|
$can = $this->isOwnerOf($user, $group) || $group->id === 0;
|
||||||
|
|
||||||
if (! $can) {
|
if (! $can) {
|
||||||
Log::notice(sprintf('User ID #%s cannot view group %s (ID #%s)', $user->id, var_export($group->name, true), $group->id));
|
Log::notice(sprintf('User ID #%s cannot view group %s (ID #%s)', $user->id, var_export($group->name, true), $group->id));
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use App\Events\GroupDeleted;
|
use App\Events\GroupDeleted;
|
||||||
use App\Events\GroupDeleting;
|
|
||||||
use App\Events\ScanForNewReleaseCalled;
|
use App\Events\ScanForNewReleaseCalled;
|
||||||
use App\Events\StoreIconsInDatabaseSettingChanged;
|
use App\Events\StoreIconsInDatabaseSettingChanged;
|
||||||
use App\Events\TwoFAccountDeleted;
|
use App\Events\TwoFAccountDeleted;
|
||||||
@ -44,10 +43,8 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
TwoFAccountDeleted::class => [
|
TwoFAccountDeleted::class => [
|
||||||
CleanIconStorage::class,
|
CleanIconStorage::class,
|
||||||
],
|
],
|
||||||
GroupDeleting::class => [
|
|
||||||
DissociateTwofaccountFromGroup::class,
|
|
||||||
],
|
|
||||||
GroupDeleted::class => [
|
GroupDeleted::class => [
|
||||||
|
DissociateTwofaccountFromGroup::class,
|
||||||
ResetUsersPreference::class,
|
ResetUsersPreference::class,
|
||||||
],
|
],
|
||||||
ScanForNewReleaseCalled::class => [
|
ScanForNewReleaseCalled::class => [
|
||||||
|
@ -7,6 +7,8 @@ use App\Models\TwoFAccount;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Auth\Access\AuthorizationException;
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class GroupService
|
class GroupService
|
||||||
@ -19,6 +21,7 @@ class GroupService
|
|||||||
* @param mixed $targetGroup The group the accounts should be assigned to
|
* @param mixed $targetGroup The group the accounts should be assigned to
|
||||||
*
|
*
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
|
||||||
*/
|
*/
|
||||||
public static function assign($ids, User $user, mixed $targetGroup = null) : void
|
public static function assign($ids, User $user, mixed $targetGroup = null) : void
|
||||||
{
|
{
|
||||||
@ -54,16 +57,23 @@ class GroupService
|
|||||||
|
|
||||||
if ($group) {
|
if ($group) {
|
||||||
$ids = is_array($ids) ? $ids : [$ids];
|
$ids = is_array($ids) ? $ids : [$ids];
|
||||||
$twofaccounts = TwoFAccount::find($ids);
|
|
||||||
|
DB::transaction(function () use ($group, $ids, $user) {
|
||||||
|
$group = Group::sharedLock()->find($group->id);
|
||||||
|
$twofaccounts = TwoFAccount::sharedLock()->find($ids);
|
||||||
|
|
||||||
|
if (! $group) {
|
||||||
|
throw new ModelNotFoundException('group no longer exists');
|
||||||
|
}
|
||||||
|
|
||||||
if ($user->cannot('updateEach', [(new TwoFAccount), $twofaccounts])) {
|
if ($user->cannot('updateEach', [(new TwoFAccount), $twofaccounts])) {
|
||||||
throw new AuthorizationException;
|
throw new AuthorizationException;
|
||||||
}
|
}
|
||||||
|
|
||||||
$group->twofaccounts()->saveMany($twofaccounts);
|
$group->twofaccounts()->saveMany($twofaccounts);
|
||||||
$group->loadCount('twofaccounts');
|
|
||||||
|
|
||||||
Log::info(sprintf('Twofaccounts #%s assigned to group %s (ID #%s)', implode(',', $ids), var_export($group->name, true), $group->id));
|
Log::info(sprintf('Twofaccounts #%s assigned to group %s (ID #%s)', implode(',', $ids), var_export($group->name, true), $group->id));
|
||||||
|
}, 5);
|
||||||
} else {
|
} else {
|
||||||
Log::info('Cannot find a group to assign the TwoFAccounts to');
|
Log::info('Cannot find a group to assign the TwoFAccounts to');
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
if (destinationGroupId.value === 0) {
|
if (destinationGroupId.value === 0) {
|
||||||
await twofaccountService.withdraw(props.selectedAccountsIds)
|
await twofaccountService.withdraw(props.selectedAccountsIds)
|
||||||
}
|
}
|
||||||
else await groupService.assign(props.selectedAccountsIds, destinationGroupId.value)
|
else groupService.assign(props.selectedAccountsIds, destinationGroupId.value, { returnError: true })
|
||||||
|
|
||||||
emit('accounts-moved')
|
emit('accounts-moved')
|
||||||
}
|
}
|
||||||
|
@ -74,5 +74,6 @@ return [
|
|||||||
'qrcode_has_invalid_checksum' => 'QR code has invalid checksum',
|
'qrcode_has_invalid_checksum' => 'QR code has invalid checksum',
|
||||||
'no_readable_qrcode' => 'No readable QR code',
|
'no_readable_qrcode' => 'No readable QR code',
|
||||||
'failed_icon_store_database_toggling' => 'Migration of icons failed. The setting has been restored to its previous value.',
|
'failed_icon_store_database_toggling' => 'Migration of icons failed. The setting has been restored to its previous value.',
|
||||||
'failed_to_retrieve_app_settings' => 'Failed to retrieve application settings'
|
'failed_to_retrieve_app_settings' => 'Failed to retrieve application settings',
|
||||||
|
'reserved_name_please_choose_something_else' => 'Reserved name, please choose something else',
|
||||||
];
|
];
|
@ -145,6 +145,26 @@ class GroupControllerTest extends FeatureTestCase
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function test_store_with_existing_group_name_returns_validation_error()
|
||||||
|
{
|
||||||
|
$this->actingAs($this->user, 'api-guard')
|
||||||
|
->json('POST', '/api/v1/groups', [
|
||||||
|
'name' => $this->userGroupA->name,
|
||||||
|
])
|
||||||
|
->assertStatus(422);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function test_store_with_all_group_name_returns_validation_error()
|
||||||
|
{
|
||||||
|
$this->actingAs($this->user, 'api-guard')
|
||||||
|
->json('POST', '/api/v1/groups', [
|
||||||
|
'name' => __('commons.all'),
|
||||||
|
])
|
||||||
|
->assertStatus(422);
|
||||||
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
public function test_store_invalid_data_returns_validation_error()
|
public function test_store_invalid_data_returns_validation_error()
|
||||||
{
|
{
|
||||||
@ -193,6 +213,20 @@ class GroupControllerTest extends FeatureTestCase
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function test_show_missing_group_with_id_0_returns_the_virtual_all_group_resource()
|
||||||
|
{
|
||||||
|
$userTwofaccounts = $this->user->twofaccounts;
|
||||||
|
|
||||||
|
$response = $this->actingAs($this->user, 'api-guard')
|
||||||
|
->json('GET', '/api/v1/groups/0')
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonFragment([
|
||||||
|
'name' => __('commons.all'),
|
||||||
|
'twofaccounts_count' => $userTwofaccounts->count(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
public function test_update_returns_updated_group_resource()
|
public function test_update_returns_updated_group_resource()
|
||||||
{
|
{
|
||||||
@ -392,6 +426,15 @@ class GroupControllerTest extends FeatureTestCase
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function test_accounts_of_the_all_group_returns_user_twofaccounts_collection()
|
||||||
|
{
|
||||||
|
$response = $this->actingAs($this->user, 'api-guard')
|
||||||
|
->json('GET', '/api/v1/groups/0/twofaccounts')
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonCount(2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test Group deletion via API
|
* test Group deletion via API
|
||||||
*/
|
*/
|
||||||
@ -430,6 +473,17 @@ class GroupControllerTest extends FeatureTestCase
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function test_destroy_the_all_group_is_forbidden()
|
||||||
|
{
|
||||||
|
$response = $this->actingAs($this->anotherUser, 'api-guard')
|
||||||
|
->json('DELETE', '/api/v1/groups/0')
|
||||||
|
->assertForbidden()
|
||||||
|
->assertJsonStructure([
|
||||||
|
'message',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
public function test_destroy_group_resets_user_preferences()
|
public function test_destroy_group_resets_user_preferences()
|
||||||
{
|
{
|
||||||
|
@ -88,10 +88,11 @@ class GroupControllerTest extends TestCase
|
|||||||
#[Test]
|
#[Test]
|
||||||
public function test_show_returns_api_resource()
|
public function test_show_returns_api_resource()
|
||||||
{
|
{
|
||||||
|
$request = Mockery::mock(GroupStoreRequest::class);
|
||||||
$controller = Mockery::mock(GroupController::class)->makePartial();
|
$controller = Mockery::mock(GroupController::class)->makePartial();
|
||||||
$group = Group::factory()->make();
|
$group = Group::factory()->make();
|
||||||
|
|
||||||
$response = $controller->show($group);
|
$response = $controller->show($request, $group);
|
||||||
|
|
||||||
$this->assertInstanceOf(GroupResource::class, $response);
|
$this->assertInstanceOf(GroupResource::class, $response);
|
||||||
}
|
}
|
||||||
@ -138,10 +139,11 @@ class GroupControllerTest extends TestCase
|
|||||||
#[Test]
|
#[Test]
|
||||||
public function test_accounts_returns_api_resources()
|
public function test_accounts_returns_api_resources()
|
||||||
{
|
{
|
||||||
|
$request = Mockery::mock(GroupStoreRequest::class);
|
||||||
$controller = Mockery::mock(GroupController::class)->makePartial();
|
$controller = Mockery::mock(GroupController::class)->makePartial();
|
||||||
$group = Group::factory()->make();
|
$group = Group::factory()->make();
|
||||||
|
|
||||||
$response = $controller->accounts($group);
|
$response = $controller->accounts($request, $group);
|
||||||
|
|
||||||
$this->assertContainsOnlyInstancesOf(TwoFAccountReadResource::class, $response->collection);
|
$this->assertContainsOnlyInstancesOf(TwoFAccountReadResource::class, $response->collection);
|
||||||
}
|
}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Tests\Unit\Events;
|
|
||||||
|
|
||||||
use App\Events\GroupDeleting;
|
|
||||||
use App\Models\Group;
|
|
||||||
use PHPUnit\Framework\Attributes\CoversClass;
|
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
|
||||||
use Tests\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GroupDeletingTest test class
|
|
||||||
*/
|
|
||||||
#[CoversClass(GroupDeleting::class)]
|
|
||||||
class GroupDeletingTest extends TestCase
|
|
||||||
{
|
|
||||||
#[Test]
|
|
||||||
public function test_event_constructor()
|
|
||||||
{
|
|
||||||
$group = Group::factory()->make();
|
|
||||||
$event = new GroupDeleting($group);
|
|
||||||
|
|
||||||
$this->assertSame($group, $event->group);
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,7 +3,6 @@
|
|||||||
namespace Tests\Unit;
|
namespace Tests\Unit;
|
||||||
|
|
||||||
use App\Events\GroupDeleted;
|
use App\Events\GroupDeleted;
|
||||||
use App\Events\GroupDeleting;
|
|
||||||
use App\Models\Group;
|
use App\Models\Group;
|
||||||
use App\Models\TwoFAccount;
|
use App\Models\TwoFAccount;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
@ -32,7 +31,6 @@ class GroupModelTest extends ModelTestCase
|
|||||||
'user_id' => 'integer',
|
'user_id' => 'integer',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'deleting' => GroupDeleting::class,
|
|
||||||
'deleted' => GroupDeleted::class,
|
'deleted' => GroupDeleted::class,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Tests\Unit\Listeners;
|
namespace Tests\Unit\Listeners;
|
||||||
|
|
||||||
use App\Events\GroupDeleting;
|
use App\Events\GroupDeleted;
|
||||||
use App\Listeners\DissociateTwofaccountFromGroup;
|
use App\Listeners\DissociateTwofaccountFromGroup;
|
||||||
use Illuminate\Support\Facades\Event;
|
use Illuminate\Support\Facades\Event;
|
||||||
use PHPUnit\Framework\Attributes\CoversClass;
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
@ -16,12 +16,12 @@ use Tests\TestCase;
|
|||||||
class DissociateTwofaccountFromGroupTest extends TestCase
|
class DissociateTwofaccountFromGroupTest extends TestCase
|
||||||
{
|
{
|
||||||
#[Test]
|
#[Test]
|
||||||
public function test_DissociateTwofaccountFromGroup_listen_to_groupDeleting_event()
|
public function test_DissociateTwofaccountFromGroup_listen_to_groupDeleted_event()
|
||||||
{
|
{
|
||||||
Event::fake();
|
Event::fake();
|
||||||
|
|
||||||
Event::assertListening(
|
Event::assertListening(
|
||||||
GroupDeleting::class,
|
GroupDeleted::class,
|
||||||
DissociateTwofaccountFromGroup::class
|
DissociateTwofaccountFromGroup::class
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user