19
common/Core/Policies/AppearancePolicy.php
Executable file
19
common/Core/Policies/AppearancePolicy.php
Executable file
@@ -0,0 +1,19 @@
|
||||
<?php namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class AppearancePolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function index(User $user)
|
||||
{
|
||||
return $user->hasPermission('appearance.index');
|
||||
}
|
||||
|
||||
public function update(User $user)
|
||||
{
|
||||
return $user->hasPermission('appearance.update');
|
||||
}
|
||||
}
|
||||
126
common/Core/Policies/BasePolicy.php
Executable file
126
common/Core/Policies/BasePolicy.php
Executable file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Common\Core\Exceptions\AccessResponseWithAction;
|
||||
use Common\Core\Exceptions\AccessResponseWithPermission;
|
||||
use Common\Settings\Settings;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Illuminate\Auth\Access\Response;
|
||||
use Illuminate\Http\Request;
|
||||
use Str;
|
||||
|
||||
abstract class BasePolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function __construct(
|
||||
protected Request $request,
|
||||
protected Settings $settings,
|
||||
) {
|
||||
}
|
||||
|
||||
protected function denyWithAction(
|
||||
$message,
|
||||
array|null $action = null,
|
||||
): AccessResponseWithAction {
|
||||
/** @var AccessResponseWithAction $response */
|
||||
$response = AccessResponseWithAction::deny($message);
|
||||
$response->action = $action;
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function storeWithCountRestriction(
|
||||
User $user,
|
||||
string $namespace,
|
||||
): Response {
|
||||
[
|
||||
$relationName,
|
||||
$permission,
|
||||
$singularName,
|
||||
$pluralName,
|
||||
] = $this->parseNamespace($namespace);
|
||||
|
||||
// user can't create resource at all
|
||||
if (!$this->hasPermission($user, $permission)) {
|
||||
return Response::deny();
|
||||
}
|
||||
|
||||
// user is admin, can ignore count restriction
|
||||
if ($user->hasPermission('admin')) {
|
||||
return Response::allow();
|
||||
}
|
||||
|
||||
// user does not have any restriction on maximum resource count
|
||||
$maxCount = $user->getRestrictionValue($permission, 'count');
|
||||
if (!$maxCount) {
|
||||
return Response::allow();
|
||||
}
|
||||
|
||||
// check if user did not go over their max quota
|
||||
if ($user->$relationName->count() >= $maxCount) {
|
||||
$message = __('policies.quota_exceeded', [
|
||||
'resources' => $pluralName,
|
||||
'resource' => $singularName,
|
||||
]);
|
||||
return $this->denyWithAction($message, $this->upgradeAction());
|
||||
}
|
||||
|
||||
return Response::allow();
|
||||
}
|
||||
|
||||
protected function hasPermission(?User $user, string $permission): bool
|
||||
{
|
||||
$model = $user ?: app('guestRole');
|
||||
return $model?->hasPermission($permission) ?? false;
|
||||
}
|
||||
|
||||
protected function authorizePermission(
|
||||
?User $user,
|
||||
string $permission,
|
||||
): AccessResponseWithPermission {
|
||||
return new AccessResponseWithPermission(
|
||||
$this->hasPermission($user, $permission),
|
||||
$permission,
|
||||
'',
|
||||
403,
|
||||
);
|
||||
}
|
||||
|
||||
protected function parseNamespace(
|
||||
string $namespace,
|
||||
string $ability = 'create',
|
||||
): array {
|
||||
// 'App\SomeModel' => 'Some_Model'
|
||||
$resourceName = Str::snake(class_basename($namespace));
|
||||
|
||||
// 'Some_Model' => 'someModels'
|
||||
$relationName = Str::camel(Str::plural($resourceName));
|
||||
|
||||
// 'Some_Model' => 'Some Model'
|
||||
$singularName = str_replace('_', ' ', $resourceName);
|
||||
|
||||
// 'Some Model' => 'Some Models'
|
||||
$pluralName = Str::plural($singularName);
|
||||
|
||||
// parent might need to override permission name. custom_domains instead of links_domains for example.
|
||||
$permissionName = $this->permissionName ?? Str::snake($relationName);
|
||||
|
||||
return [
|
||||
$relationName,
|
||||
"$permissionName.$ability",
|
||||
$singularName,
|
||||
$pluralName,
|
||||
];
|
||||
}
|
||||
|
||||
protected function upgradeAction(): ?array
|
||||
{
|
||||
if ($this->settings->get('billing.enable')) {
|
||||
return ['label' => __('Upgrade'), 'action' => '/pricing'];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
187
common/Core/Policies/FileEntryPolicy.php
Executable file
187
common/Core/Policies/FileEntryPolicy.php
Executable file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Arr;
|
||||
use Common\Files\FileEntry;
|
||||
use Common\Files\FileEntryUser;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
use Illuminate\Support\Collection;
|
||||
use Laravel\Sanctum\PersonalAccessToken;
|
||||
|
||||
class FileEntryPolicy extends BasePolicy
|
||||
{
|
||||
public function index(
|
||||
?User $user,
|
||||
array $entryIds = null,
|
||||
int $userId = null,
|
||||
): bool {
|
||||
if ($entryIds) {
|
||||
return $this->userCan($user, 'files.view', $entryIds);
|
||||
} else {
|
||||
return $user->hasPermission('files.view') || $userId === $user->id;
|
||||
}
|
||||
}
|
||||
|
||||
public function show(?User $user, FileEntry $entry): bool
|
||||
{
|
||||
$token = $this->getAccessTokenFromRequest();
|
||||
|
||||
if ($token) {
|
||||
if ($entry->preview_token === $token) {
|
||||
return true;
|
||||
} elseif (
|
||||
$accessToken = app(PersonalAccessToken::class)->findToken(
|
||||
$token,
|
||||
)
|
||||
) {
|
||||
$user = $accessToken->tokenable;
|
||||
}
|
||||
}
|
||||
|
||||
return $user && $this->userCan($user, 'files.view', $entry);
|
||||
}
|
||||
|
||||
public function download(User $user, $entries): bool
|
||||
{
|
||||
$token = $this->getAccessTokenFromRequest();
|
||||
if ($token) {
|
||||
$previewTokenMatches = collect($entries)->every(function (
|
||||
$entry,
|
||||
) use ($token) {
|
||||
return $entry['preview_token'] === $token;
|
||||
});
|
||||
if ($previewTokenMatches) {
|
||||
return true;
|
||||
} elseif (
|
||||
$accessToken = app(PersonalAccessToken::class)->findToken(
|
||||
$token,
|
||||
)
|
||||
) {
|
||||
$user = $accessToken->tokenable;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->userCan($user, 'files.download', $entries);
|
||||
}
|
||||
|
||||
public function store(User $user, int $parentId = null): bool
|
||||
{
|
||||
//check if user can modify parent entry (if specified)
|
||||
if ($parentId) {
|
||||
return $this->userCan($user, 'files.update', [$parentId]);
|
||||
}
|
||||
|
||||
return $user->hasPermission('files.create');
|
||||
}
|
||||
|
||||
public function update(User $user, Collection|array|FileEntry $entries)
|
||||
{
|
||||
return $this->userCan($user, 'files.update', $entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param Collection|array|FileEntry $entries
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(User $user, $entries)
|
||||
{
|
||||
return $this->userCan($user, 'files.delete', $entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $currentUser
|
||||
* @param string $permission
|
||||
* @param FileEntry|array|Collection $entries
|
||||
* @return bool
|
||||
*/
|
||||
protected function userCan(User $currentUser, string $permission, $entries)
|
||||
{
|
||||
if ($currentUser->hasPermission($permission)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$entries = $this->findEntries($entries);
|
||||
|
||||
// extending class might use "findEntries" method so we load users here
|
||||
if (!$entries->every->relationLoaded('users')) {
|
||||
$entries->load([
|
||||
'users' => function (MorphToMany $builder) use ($currentUser) {
|
||||
$builder->where('users.id', $currentUser->id);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
return $entries->every(function (FileEntry $entry) use (
|
||||
$permission,
|
||||
$currentUser,
|
||||
) {
|
||||
$user = $entry->users->find($currentUser->id);
|
||||
return $this->userOwnsEntryOrWasGrantedPermission(
|
||||
$user,
|
||||
$permission,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|array|FileEntryUser $user
|
||||
* @param string $permission
|
||||
* @return bool
|
||||
*/
|
||||
public function userOwnsEntryOrWasGrantedPermission(
|
||||
$user,
|
||||
string $permission,
|
||||
) {
|
||||
return $user &&
|
||||
($user['owns_entry'] ||
|
||||
Arr::get(
|
||||
$user['entry_permissions'],
|
||||
$this->sharedFilePermission($permission),
|
||||
));
|
||||
}
|
||||
|
||||
protected function findEntries(
|
||||
FileEntry|array|Collection $entries,
|
||||
): Collection {
|
||||
if ($entries instanceof FileEntry) {
|
||||
return $entries->newCollection([$entries]);
|
||||
} elseif (isset($entries[0]) && is_numeric($entries[0])) {
|
||||
return app(FileEntry::class)
|
||||
->whereIn('id', $entries)
|
||||
->get();
|
||||
} else {
|
||||
return $entries;
|
||||
}
|
||||
}
|
||||
|
||||
protected function sharedFilePermission($fullPermission): string
|
||||
{
|
||||
switch ($fullPermission) {
|
||||
case 'files.view':
|
||||
return 'view';
|
||||
case 'files.create':
|
||||
case 'files.update':
|
||||
return 'edit';
|
||||
case 'files.delete':
|
||||
return 'delete';
|
||||
case 'files.download':
|
||||
return 'download';
|
||||
}
|
||||
}
|
||||
|
||||
protected function getAccessTokenFromRequest(): ?string
|
||||
{
|
||||
if ($token = request()->bearerToken()) {
|
||||
return $token;
|
||||
} elseif ($token = request()->get('preview_token')) {
|
||||
return $token;
|
||||
} elseif ($token = request()->get('accessToken')) {
|
||||
return $token;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
common/Core/Policies/LocalizationPolicy.php
Executable file
34
common/Core/Policies/LocalizationPolicy.php
Executable file
@@ -0,0 +1,34 @@
|
||||
<?php namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class LocalizationPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function index(?User $user)
|
||||
{
|
||||
return $user->hasPermission('localizations.view');
|
||||
}
|
||||
|
||||
public function show(?User $user)
|
||||
{
|
||||
return $user->hasPermission('localizations.view');
|
||||
}
|
||||
|
||||
public function store(User $user)
|
||||
{
|
||||
return $user->hasPermission('localizations.create');
|
||||
}
|
||||
|
||||
public function update(User $user)
|
||||
{
|
||||
return $user->hasPermission('localizations.update');
|
||||
}
|
||||
|
||||
public function destroy(User $user)
|
||||
{
|
||||
return $user->hasPermission('localizations.delete');
|
||||
}
|
||||
}
|
||||
24
common/Core/Policies/MailTemplatePolicy.php
Executable file
24
common/Core/Policies/MailTemplatePolicy.php
Executable file
@@ -0,0 +1,24 @@
|
||||
<?php namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class MailTemplatePolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function index(User $user)
|
||||
{
|
||||
return $user->hasPermission('mail_templates.view');
|
||||
}
|
||||
|
||||
public function show(User $user)
|
||||
{
|
||||
return $user->hasPermission('mail_templates.view');
|
||||
}
|
||||
|
||||
public function update(User $user)
|
||||
{
|
||||
return $user->hasPermission('mail_templates.update');
|
||||
}
|
||||
}
|
||||
40
common/Core/Policies/PagePolicy.php
Executable file
40
common/Core/Policies/PagePolicy.php
Executable file
@@ -0,0 +1,40 @@
|
||||
<?php namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Common\Pages\CustomPage;
|
||||
|
||||
class PagePolicy extends BasePolicy
|
||||
{
|
||||
public function index(?User $user, int $userId = null)
|
||||
{
|
||||
return $user->hasPermission('custom_pages.view') || $user->id === $userId;
|
||||
}
|
||||
|
||||
public function show(?User $user, CustomPage $customPage)
|
||||
{
|
||||
return $user->hasPermission('custom_pages.view') || $customPage->user_id === $user->id;
|
||||
}
|
||||
|
||||
public function store(User $user)
|
||||
{
|
||||
return $user->hasPermission('custom_pages.create');
|
||||
}
|
||||
|
||||
public function update(User $user)
|
||||
{
|
||||
return $user->hasPermission('custom_pages.update');
|
||||
}
|
||||
|
||||
public function destroy(User $user, $pageIds)
|
||||
{
|
||||
if ($user->hasPermission('custom_pages.delete')) {
|
||||
return true;
|
||||
} else {
|
||||
$dbCount = app(CustomPage::class)
|
||||
->whereIn('id', $pageIds)
|
||||
->where('user_id', $user->id)
|
||||
->count();
|
||||
return $dbCount === count($pageIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
common/Core/Policies/ProductPolicy.php
Executable file
34
common/Core/Policies/ProductPolicy.php
Executable file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\Response;
|
||||
|
||||
class ProductPolicy extends BasePolicy
|
||||
{
|
||||
public function index(?User $user): bool|Response
|
||||
{
|
||||
return settings('billing.enable') || $user->hasPermission('plans.view');
|
||||
}
|
||||
|
||||
public function show(?User $user): bool|Response
|
||||
{
|
||||
return settings('billing.enable') || $user->hasPermission('plans.view');
|
||||
}
|
||||
|
||||
public function store(User $user): bool|Response
|
||||
{
|
||||
return $user->hasPermission('plans.create');
|
||||
}
|
||||
|
||||
public function update(User $user): bool|Response
|
||||
{
|
||||
return $user->hasPermission('plans.update');
|
||||
}
|
||||
|
||||
public function destroy(User $user): bool|Response
|
||||
{
|
||||
return $user->hasPermission('plans.delete');
|
||||
}
|
||||
}
|
||||
14
common/Core/Policies/ReportPolicy.php
Executable file
14
common/Core/Policies/ReportPolicy.php
Executable file
@@ -0,0 +1,14 @@
|
||||
<?php namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class ReportPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function index(User $user)
|
||||
{
|
||||
return $user->hasPermission('admin.access');
|
||||
}
|
||||
}
|
||||
35
common/Core/Policies/RolePolicy.php
Executable file
35
common/Core/Policies/RolePolicy.php
Executable file
@@ -0,0 +1,35 @@
|
||||
<?php namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Common\Auth\Roles\Role;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class RolePolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function index(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('roles.view');
|
||||
}
|
||||
|
||||
public function show(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('roles.show');
|
||||
}
|
||||
|
||||
public function store(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('roles.create');
|
||||
}
|
||||
|
||||
public function update(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('roles.update');
|
||||
}
|
||||
|
||||
public function destroy(User $user, Role $role): bool
|
||||
{
|
||||
return !$role->internal && $user->hasPermission('roles.delete');
|
||||
}
|
||||
}
|
||||
19
common/Core/Policies/SettingPolicy.php
Executable file
19
common/Core/Policies/SettingPolicy.php
Executable file
@@ -0,0 +1,19 @@
|
||||
<?php namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class SettingPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function index(User $user)
|
||||
{
|
||||
return $user->hasPermission('settings.view');
|
||||
}
|
||||
|
||||
public function update(User $user)
|
||||
{
|
||||
return $user->hasPermission('settings.update');
|
||||
}
|
||||
}
|
||||
36
common/Core/Policies/SubscriptionPolicy.php
Executable file
36
common/Core/Policies/SubscriptionPolicy.php
Executable file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class SubscriptionPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function index(User $user)
|
||||
{
|
||||
return $user->hasPermission('subscription.view');
|
||||
}
|
||||
|
||||
public function show(User $user)
|
||||
{
|
||||
return $user->hasPermission('subscription.view');
|
||||
}
|
||||
|
||||
public function store(User $user)
|
||||
{
|
||||
return $user->hasPermission('subscription.create');
|
||||
}
|
||||
|
||||
public function update(User $user)
|
||||
{
|
||||
return $user->hasPermission('subscription.update');
|
||||
}
|
||||
|
||||
public function destroy(User $user)
|
||||
{
|
||||
return $user->hasPermission('subscription.delete');
|
||||
}
|
||||
}
|
||||
33
common/Core/Policies/TagPolicy.php
Executable file
33
common/Core/Policies/TagPolicy.php
Executable file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
class TagPolicy extends BasePolicy
|
||||
{
|
||||
public function index(?User $user)
|
||||
{
|
||||
return $this->hasPermission($user, 'tags.view');
|
||||
}
|
||||
|
||||
public function show(?User $user)
|
||||
{
|
||||
return $this->hasPermission($user, 'tags.view');
|
||||
}
|
||||
|
||||
public function store(User $user)
|
||||
{
|
||||
return $this->hasPermission($user, 'tags.create');
|
||||
}
|
||||
|
||||
public function update(User $user)
|
||||
{
|
||||
return $this->hasPermission($user, 'tags.update');
|
||||
}
|
||||
|
||||
public function destroy(User $user)
|
||||
{
|
||||
return $this->hasPermission($user, 'tags.delete');
|
||||
}
|
||||
}
|
||||
56
common/Core/Policies/UserPolicy.php
Executable file
56
common/Core/Policies/UserPolicy.php
Executable file
@@ -0,0 +1,56 @@
|
||||
<?php namespace Common\Core\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
class UserPolicy extends BasePolicy
|
||||
{
|
||||
public function index(?User $user)
|
||||
{
|
||||
return $this->hasPermission($user, 'users.view');
|
||||
}
|
||||
|
||||
public function show(?User $current, User $requested)
|
||||
{
|
||||
return $this->hasPermission($current, 'users.view') ||
|
||||
$current->id === $requested->id;
|
||||
}
|
||||
|
||||
public function store(User $user)
|
||||
{
|
||||
return $this->hasPermission($user, 'users.create');
|
||||
}
|
||||
|
||||
public function update(User $current, User $toUpdate = null)
|
||||
{
|
||||
// user has proper permissions
|
||||
if ($this->hasPermission($current, 'users.update')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// no permissions and not trying to update his own model
|
||||
if (!$toUpdate || $current->id !== $toUpdate->id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// user should not be able to change his own permissions or roles
|
||||
if (
|
||||
$this->request->get('permissions') ||
|
||||
$this->request->get('roles')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function destroy(User $user, array $userIds)
|
||||
{
|
||||
$deletingOwnAccount = collect($userIds)->every(function (
|
||||
int $userId
|
||||
) use ($user) {
|
||||
return $userId === $user->id;
|
||||
});
|
||||
|
||||
return $deletingOwnAccount || $this->hasPermission($user, 'users.delete');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user