Skip to content

Commit

Permalink
access to email suprresed for user that not is admin
Browse files Browse the repository at this point in the history
  • Loading branch information
rigonlucas committed Aug 25, 2024
1 parent 4833e37 commit e90a4a5
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace App\Http\Controllers\V1\Users;
namespace App\Http\Controllers\V1\User;

use App\Http\Controllers\Controller;
use Core\Application\User\Commons\Gateways\UserRepositoryInterface;
Expand All @@ -13,6 +13,11 @@

class AccountUserListController extends Controller
{
private array $userRoles = [
UserRoles::ADMIN,
UserRoles::EDITOR,
];

public function __construct(
private readonly FrameworkContract $framework,
private readonly UserRepositoryInterface $userRepository
Expand All @@ -26,7 +31,7 @@ public function __construct(
public function __invoke(Request $request)
{
$user = $this->framework->auth()->user();
if ($user->hasNotPermission(UserRoles::ADMIN)) {
if ($user->hasNotAnyPermissionFromArray($this->userRoles)) {
abort(ResponseStatus::FORBIDDEN->value);
}
$accountEntity = $user->getAccount();
Expand Down
6 changes: 1 addition & 5 deletions core/Domain/Collections/User/UserCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ public function toArray(): array
fn(UserEntity $user) => [
'uuid' => $user->getUuid(),
'name' => $user->getName(),
'email' => $user->getEmail(),
'account' => [
'uuid' => $user->getAccount()->getUuid(),
'name' => $user->getAccount()->getName(),
],
'email' => $user->getEmail()->getEmail(),
'birthday' => $user->getBirthday()->getTimestamp(),
'role' => $user->getRoleName(),
],
Expand Down
20 changes: 18 additions & 2 deletions core/Domain/Entities/User/Traits/HasUserRoleTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

trait HasUserRoleTrait
{
private int $permissions = 0;
private ?int $permissions = null;

public function hasNotPermission(int $permission): bool
{
Expand All @@ -20,7 +20,7 @@ public function hasPermission(int $permission): bool
return ($this->permissions & $permission) === $permission;
}

public function getPermissions(): int
public function getPermissions(): ?int
{
return $this->permissions;
}
Expand All @@ -30,6 +30,22 @@ public function setPermissions(int $permissions): void
$this->permissions = $permissions;
}

public function hasNotAnyPermissionFromArray(array $permissions): bool
{
return !$this->hasAnyPermissionFromArray($permissions);
}

public function hasAnyPermissionFromArray(array $permissions): bool
{
foreach ($permissions as $permission) {
if ($this->hasPermission($permission)) {
return true;
}
}

return false;
}

/**
* @throws InvalidRoleException
*/
Expand Down
7 changes: 7 additions & 0 deletions core/Domain/Entities/User/Traits/UserEntityAcessors.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Core\Domain\Entities\Account\AccountEntity;
use Core\Domain\ValueObjects\EmailValueObject;
use Core\Support\Exceptions\InvalidEmailException;
use Core\Support\Permissions\UserRoles;
use DateTimeInterface;
use Ramsey\Uuid\UuidInterface;
use SensitiveParameter;
Expand All @@ -18,6 +19,12 @@ public function getName(): string

public function getEmail(): EmailValueObject
{
if ($this->getPermissions()) {
if ($this->hasNotPermission(UserRoles::ADMIN)) {
return $this->email->supress();
}
}

return $this->email;
}

Expand Down
10 changes: 10 additions & 0 deletions core/Domain/ValueObjects/EmailValueObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ public function isValid(): bool
return filter_var($this->email, FILTER_VALIDATE_EMAIL) !== false;
}

public function isSuppressed(): bool
{
return static::isEmailSuppressed($this->email);
}

public static function isEmailSuppressed(string $email): bool
{
return str_contains($email, '*');
}

public function supress(): self
{
$this->emailUnsuppressed = $this->getEmail();
Expand Down
24 changes: 10 additions & 14 deletions infra/Database/User/Repository/UserRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
use Core\Support\Collections\Paginations\Inputs\DefaultPaginationData;
use Core\Support\Exceptions\InvalidEmailException;
use DateTime;
use Exception;
use Infra\Services\Framework\DefaultPaginationConverter;
use Infra\Services\Framework\FrameworkService;

class UserRepository implements UserRepositoryInterface
{
/**
* @throws InvalidEmailException
* @throws Exception
*/
public function findById(int $id): ?UserEntity
{
Expand All @@ -39,6 +42,7 @@ public function findById(int $id): ?UserEntity

/**
* @throws InvalidEmailException
* @throws Exception
*/
public function findByUuid(string $uuid): ?UserEntity
{
Expand All @@ -63,6 +67,7 @@ public function findByUuid(string $uuid): ?UserEntity

/**
* @throws InvalidEmailException
* @throws Exception
*/
public function findByEmail(string $email): ?UserEntity
{
Expand Down Expand Up @@ -95,6 +100,9 @@ public function existsId(int $id): bool
return User::query()->where('id', '=', $id)->exists();
}

/**
* @throws InvalidEmailException
*/
public function paginatedAccountUserList(
AccountEntity $account,
DefaultPaginationData $paginationData
Expand All @@ -104,7 +112,7 @@ public function paginatedAccountUserList(
->where('account_id', '=', $account->getId())
->with('account:id,name,uuid')
->paginate(perPage: $paginationData->perPage, page: $paginationData->page);

$userCollection = new UserCollection();
foreach ($userModels->items() as $userModel) {
$userCollection->add(
Expand All @@ -124,18 +132,6 @@ public function paginatedAccountUserList(
);
}

return $userCollection
->setCurrentPage($userModels->currentPage())
->setFirstPageUrl($userModels->url(1))
->setFrom($userModels->firstItem())
->setLastPage($userModels->lastPage())
->setLastPageUrl($userModels->url($userModels->lastPage()))
->setLinks($userModels->linkCollection()->toArray())
->setNextPageUrl($userModels->nextPageUrl())
->setPath($userModels->path())
->setPerPage($userModels->perPage())
->setPrevPageUrl($userModels->previousPageUrl())
->setTo($userModels->lastItem())
->setTotal($userModels->total());
return DefaultPaginationConverter::convert($userCollection, $userModels);
}
}
27 changes: 27 additions & 0 deletions infra/Services/Framework/DefaultPaginationConverter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Infra\Services\Framework;

use Illuminate\Pagination\LengthAwarePaginator;

class DefaultPaginationConverter
{
public static function convert(
mixed $collectionBase,
LengthAwarePaginator $lengthAwarePaginator
): mixed {
return $collectionBase
->setCurrentPage($lengthAwarePaginator->currentPage())
->setFirstPageUrl($lengthAwarePaginator->url(1))
->setFrom($lengthAwarePaginator->firstItem())
->setLastPage($lengthAwarePaginator->lastPage())
->setLastPageUrl($lengthAwarePaginator->url($lengthAwarePaginator->lastPage()))
->setLinks($lengthAwarePaginator->linkCollection()->toArray())
->setNextPageUrl($lengthAwarePaginator->nextPageUrl())
->setPath($lengthAwarePaginator->path())
->setPerPage($lengthAwarePaginator->perPage())
->setPrevPageUrl($lengthAwarePaginator->previousPageUrl())
->setTo($lengthAwarePaginator->lastItem())
->setTotal($lengthAwarePaginator->total());
}
}
2 changes: 1 addition & 1 deletion routes/api.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<?php

use App\Http\Controllers\V1\User\AccountUserListController;
use App\Http\Controllers\V1\User\ChangeUserRoleController;
use App\Http\Controllers\V1\User\CreateUserController;
use App\Http\Controllers\V1\User\ShowUserController;
use App\Http\Controllers\V1\User\UpdateUserController;
use App\Http\Controllers\V1\Users\AccountUserListController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Expand Down
43 changes: 21 additions & 22 deletions tests/Integration/e2e/User/AccountUserListE2eTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Tests\Integration\e2e\User;

use App\Models\User;
use Core\Domain\ValueObjects\EmailValueObject;
use Core\Support\Http\ResponseStatus;
use Core\Support\Permissions\UserRoles;
use Illuminate\Foundation\Testing\DatabaseMigrations;
Expand All @@ -26,6 +27,7 @@ public function test_success_case_user_list_with_authenticated_admin()
$data = json_decode($response->content());
$this->assertEquals(1, $data->total);
$this->assertCount(1, $data->data);
$this->assertFalse(EmailValueObject::isEmailSuppressed($data->data[0]->email));


$response->assertJsonStructure([
Expand All @@ -35,10 +37,6 @@ public function test_success_case_user_list_with_authenticated_admin()
'uuid',
'name',
'email',
'account' => [
'uuid',
'name',
],
'birthday',
'role',
],
Expand All @@ -57,6 +55,24 @@ public function test_success_case_user_list_with_authenticated_admin()
]);
}

public function test_success_case_user_list_with_authenticated_user_as_editor()
{
Sanctum::actingAs(
User::factory()->create([
'role' => UserRoles::EDITOR,
]),
['*']
);
$response = $this->getJson(route('api.v1.user.list'));
$data = json_decode($response->content());
$this->assertEquals(1, $data->total);
$this->assertCount(1, $data->data);
$this->assertTrue(EmailValueObject::isEmailSuppressed($data->data[0]->email));


$response->assertStatus(ResponseStatus::OK->value);
}

public function test_success_case_for_paginated_user_list_with_authenticated_admin()
{
User::factory()->count(15)->create([
Expand All @@ -75,10 +91,6 @@ public function test_success_case_for_paginated_user_list_with_authenticated_adm
'uuid',
'name',
'email',
'account' => [
'uuid',
'name',
],
'birthday',
'role',
],
Expand All @@ -97,7 +109,7 @@ public function test_success_case_for_paginated_user_list_with_authenticated_adm
]);
}

public function test_fail_case_user_list_with_unauthenticated_user_as_viewer()
public function test_fail_case_user_list_with_authenticated_user_as_viewer()
{
Sanctum::actingAs(
User::factory()->create([
Expand All @@ -110,19 +122,6 @@ public function test_fail_case_user_list_with_unauthenticated_user_as_viewer()
$response->assertStatus(ResponseStatus::FORBIDDEN->value);
}

public function test_fail_case_user_list_with_unauthenticated_user_as_editor()
{
Sanctum::actingAs(
User::factory()->create([
'role' => UserRoles::EDITOR,
]),
['*']
);
$response = $this->getJson(route('api.v1.user.list'));

$response->assertStatus(ResponseStatus::FORBIDDEN->value);
}

protected function setUp(): void
{
parent::setUp();
Expand Down
21 changes: 21 additions & 0 deletions tests/Unit/ValueObjects/EmailValueObjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
use Core\Support\Http\ResponseStatus;
use Tests\TestCase;

/**
* @group email_value_objects
*/
class EmailValueObjectTest extends TestCase
{
public function test_valid_email()
Expand Down Expand Up @@ -34,4 +37,22 @@ public function test_unsuppressed_email()
$this->assertEquals('te**@ex*********', $email->supress());
$this->assertEquals('[email protected]', $email->unsupress());
}

public function test_is_email_suppressed()
{
$this->assertTrue(EmailValueObject::isEmailSuppressed('te**@ex*********'));
$this->assertFalse(EmailValueObject::isEmailSuppressed('[email protected]'));
}

public function test_is_valid_email()
{
$this->assertTrue((new EmailValueObject('[email protected]', false))->isValid());
$this->assertFalse((new EmailValueObject('invalid-email', false))->isValid());
}

public function test_is_invalid_email()
{
$this->assertFalse((new EmailValueObject('[email protected]', false))->isInvalid());
$this->assertTrue((new EmailValueObject('invalid-email', false))->isInvalid());
}
}

0 comments on commit e90a4a5

Please sign in to comment.