Skip to content

Commit

Permalink
Merge pull request #1722 from bakaphp/abilities-module-template
Browse files Browse the repository at this point in the history
refactor: debug test
  • Loading branch information
FredPeal authored Jul 29, 2024
2 parents 7039f8b + d8f31d9 commit 8daa8fb
Show file tree
Hide file tree
Showing 15 changed files with 422 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
MEILISEARCH_HOST: http://localhost:7700
MEILISEARCH_KEY: masterKey
SCOUT_QUEUE: false
#APP_DEBUG: true
# APP_DEBUG: true

#third party integration
TEST_ZOHO_CLIENT_ID: ${{ secrets.TEST_ZOHO_CLIENT_ID }}
Expand Down
42 changes: 42 additions & 0 deletions app/Console/Commands/AccessControl/UpdateAbilitiesCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace App\Console\Commands\AccessControl;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
use Kanvas\AccessControlList\Actions\CreateAbilitiesByModule;
use Kanvas\Apps\Models\Apps;
use Kanvas\AccessControlList\Enums\ModuleEnum;
use Kanvas\AccessControlList\Repositories\RolesRepository;

class UpdateAbilitiesCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'kanvas:update-abilities {app?}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';

/**
* Execute the console command.
*/
public function handle()
{
if ($key = $this->argument('app')) {
$apps = Apps::where('key', $key)->get();
} else {
$apps = Apps::all();
}
foreach ($apps as $app) {
(new CreateAbilitiesByModule($app))->execute();
}
}
}
29 changes: 26 additions & 3 deletions app/GraphQL/Ecosystem/Mutations/Roles/RolesManagementMutation.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Baka\Support\Str;
use Bouncer;
use Illuminate\Support\Facades\Redis;
use Kanvas\AccessControlList\Actions\AssignRoleAction;
use Kanvas\AccessControlList\Actions\CreateRoleAction;
use Kanvas\AccessControlList\Actions\UpdateRoleAction;
Expand All @@ -14,6 +15,7 @@
use Kanvas\AccessControlList\Repositories\RolesRepository;
use Kanvas\Apps\Models\Apps;
use Kanvas\Exceptions\ValidationException;
use Kanvas\SystemModules\Repositories\SystemModulesRepository;
use Kanvas\Users\Repositories\UsersRepository;
use Nuwave\Lighthouse\Exceptions\AuthorizationException;
use Silber\Bouncer\Database\Role as SilberRole;
Expand Down Expand Up @@ -59,7 +61,7 @@ public function removeRoleFromUser(mixed $rootValue, array $request): bool

$role = RolesRepository::getByMixedParamFromCompany($request['role']);

if ($auth->isAppOwner()) {
if ($auth->isAdmin()) {
$user = UsersRepository::getUserOfAppById($userId, $app);
} else {
$user = UsersRepository::getUserOfCompanyById($company, $userId);
Expand All @@ -70,6 +72,28 @@ public function removeRoleFromUser(mixed $rootValue, array $request): bool
return true;
}

public function givePermissionToRole(mixed $rootValue, array $request): bool
{
$systemModule = SystemModulesRepository::getByModelName($request['systemModule'], app(Apps::class));
Bouncer::allow($request['role'])->to($request['permission'], $systemModule->model_name);

$roles = RolesRepository::getMapAbilityInModules($request['role']);
Redis::set(RolesEnums::KEY_MAP->value, $roles);

return true;
}

public function removePermissionToRole(mixed $rootValue, array $request): bool
{
$systemModule = SystemModulesRepository::getByModelName($request['systemModule'], app(Apps::class));
Bouncer::disallow($request['role'])->to($request['permission'], $systemModule->model_name);

$roles = RolesRepository::getMapAbilityInModules($request['role']);
Redis::set(RolesEnums::KEY_MAP->value, $roles);

return true;
}

/**
* givePermissionToUser.
*/
Expand All @@ -85,8 +109,7 @@ public function givePermissionToUser(mixed $rootValue, array $request): bool
} else {
$user = UsersRepository::getUserOfCompanyById($company, $userId);
}

Bouncer::allow($user)->to(Str::slug($request['permission']));
Bouncer::allow($user)->to(Str::simpleSlug($request['permission']));

return true;
}
Expand Down
19 changes: 17 additions & 2 deletions app/GraphQL/Ecosystem/Queries/Roles/RoleAbilitiesQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@

namespace App\GraphQL\Ecosystem\Queries\Roles;

use Illuminate\Support\Facades\Redis;
use Kanvas\AccessControlList\Repositories\RolesRepository;
use Kanvas\Companies\Repositories\CompaniesRepository;
use Kanvas\Users\Repositories\UsersRepository;
use Kanvas\AccessControlList\Enums\RolesEnums;

class RoleAbilitiesQuery
{
public function getAllAbilities(mixed $root, array $query): array
{
$company = $query['companyId'] ? CompaniesRepository::getById((int)$query['companyId']) : auth()->user()->getCurrentCompany();
$abilities = UsersRepository::getUserOfCompanyById(
auth()->user()->getCurrentCompany(),
$query['userId']
$company,
(int)$query['userId']
)->getAbilities();

$mapAbilities = $abilities->map(function ($ability) {
Expand All @@ -21,4 +26,14 @@ public function getAllAbilities(mixed $root, array $query): array

return $mapAbilities->all();
}

public function getAllAbilitiesByRoles(mixed $root, array $request): array
{
$roles = RolesRepository::getMapAbilityInModules($request['role']);
if ($map = Redis::get(RolesEnums::KEY_MAP->value)) {
return $map;
}
Redis::set(RolesEnums::KEY_MAP->value, $roles);
return $roles;
}
}
32 changes: 32 additions & 0 deletions database/migrations/2024_04_15_162222_abilities_modules_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class () extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('abilities_modules', function (Blueprint $table) {
$table->id();
$table->integer('system_modules_id')->index('system_modules_id');
$table->integer('apps_id')->index('apps_id');
$table->integer('abilities_id')->index('abilities_id');
$table->integer('module_id')->index('module_id');
$table->string('scope');
$table->integer('is_deleted')->default(0);
$table->timestamps();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('abilities_modules');
}
};
50 changes: 49 additions & 1 deletion graphql/schemas/Ecosystem/rolePermission.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,37 @@ type Role {
scope: String
userCount: Int!
abilitiesCount: Int!
abilities: [Module!]
systemRole: Boolean! @method(name: "isSystemRole")
}
type Abilities {
id: ID
name: String!
title: String
module: Module!
entity_type: String
roleId: ID
}
type RoleAbilities {
module: Module!
}
type RoleEntity {
name: String
abilities: [Abilities!]
}

type RolesModule {
name: AppModule
entities: [RoleEntity!]
}
enum AppModule {
ECOSYSTEM @enum(value: 1)
INVENTORY @enum(value: 2)
CRM @enum(value: 3)
SOCIAL @enum(value: 4)
WORKFLOW @enum(value: 5)
ACTION_ENGINE @enum(value: 6)
}
extend type Query @guard {
roles(
search: String @search
Expand All @@ -26,10 +54,14 @@ extend type Query @guard {
@field(
resolver: "App\\GraphQL\\Ecosystem\\Queries\\Roles\\RolePermissionQuery@can"
)
getAllAbilities(userId: ID!): [String]
getAllAbilities(userId: ID!, companyId: ID): [String]
@field(
resolver: "App\\GraphQL\\Ecosystem\\Queries\\Roles\\RoleAbilitiesQuery@getAllAbilities"
)
getRoleAbilities(role: String!): [RolesModule]
@field(
resolver: "App\\GraphQL\\Ecosystem\\Queries\\Roles\\RoleAbilitiesQuery@getAllAbilitiesByRoles"
)
}

extend type Mutation @guardByAdmin {
Expand Down Expand Up @@ -64,4 +96,20 @@ extend type Mutation @guardByAdmin {
@field(
resolver: "App\\GraphQL\\Ecosystem\\Mutations\\Roles\\RolesManagementMutation@removePermissionToUser"
)
givePermissionToRole(
role: String!
permission: String!
systemModule: String!
): Boolean
@field(
resolver: "App\\GraphQL\\Ecosystem\\Mutations\\Roles\\RolesManagementMutation@givePermissionToRole"
)
removePermissionToRole(
role: String!
permission: String!
systemModule: String!
): Boolean
@field(
resolver: "App\\GraphQL\\Ecosystem\\Mutations\\Roles\\RolesManagementMutation@givePermissionToRole"
)
}
55 changes: 55 additions & 0 deletions src/Kanvas/AccessControlList/Actions/CreateAbilitiesByModule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Kanvas\AccessControlList\Actions;

use Bouncer;
use Kanvas\AccessControlList\Enums\RolesEnums;
use Kanvas\AccessControlList\Models\Ability;
use Kanvas\AccessControlList\Models\AbilitiesModules;
use Kanvas\AccessControlList\Templates\ModulesRepositories;
use Kanvas\Apps\Models\Apps;
use Kanvas\SystemModules\Repositories\SystemModulesRepository;

class CreateAbilitiesByModule
{
public function __construct(protected ?Apps $app = null)
{
$this->app = $app ?? app(Apps::class);
}

/**
* Create abilities by module.
*
* @return void
*/
public function execute()
{
$scope = RolesEnums::getScope($this->app);
Bouncer::scope()->to($scope);
Bouncer::useAbilityModel(Ability::class);

foreach (ModulesRepositories::getAbilitiesByModule() as $module => $subModule) {
foreach ($subModule as $model => $abilities) {
$systemModule = SystemModulesRepository::getByModelName($model);
foreach ($abilities as $ability) {
$ability = Bouncer::ability()->firstOrCreate([
'name' => $ability,
'title' => ucfirst($ability),
'entity_type' => $model,
]);
AbilitiesModules::firstOrCreate(
[
'system_modules_id' => $systemModule->getId(),
'abilities_id' => $ability->id,
'scope' => $scope,
'module_id' => $module,
'apps_id' => $this->app->getId(),
]
);
}
}
}
}
}
2 changes: 2 additions & 0 deletions src/Kanvas/AccessControlList/Enums/RolesEnums.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ enum RolesEnums: string
case DEVELOPER = 'Developer';
case MANAGER = 'Managers';

case KEY_MAP = "roles:abilities";

/**
* Roles are scoped by app
* in the future companies may create there own roles
Expand Down
26 changes: 26 additions & 0 deletions src/Kanvas/AccessControlList/Models/AbilitiesModules.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Kanvas\AccessControlList\Models;

use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Kanvas\Models\BaseModel;
use Kanvas\SystemModules\Models\SystemModules;
use Silber\Bouncer\Database\Ability;

class AbilitiesModules extends BaseModel
{
protected $guarded = [];
protected $table = 'abilities_modules';

public function systemModule(): BelongsTo
{
return $this->belongsTo(SystemModules::class, 'system_modules_id');
}

public function ability(): BelongsTo
{
return $this->belongsTo(Ability::class, ['abilities_id', 'scope'], ['id', 'scope']);
}
}
16 changes: 16 additions & 0 deletions src/Kanvas/AccessControlList/Models/Ability.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Kanvas\AccessControlList\Models;

use Silber\Bouncer\Database\Ability as SilberAbility;

class Ability extends SilberAbility
{
protected $fillable = [
'name',
'title',
'entity_type',
];
}
12 changes: 12 additions & 0 deletions src/Kanvas/AccessControlList/Models/Role.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ public function getAbilitiesCountAttribute(): int
return (int)$count;
}

public function getModules(): array
{
$modules = [];
foreach ($this->abilities as $ability) {
$module = $ability->module;
if (! isset($modules[$module->id])) {
$modules[$module->id] = $module;
}
}
return $modules;
}

public function isAdmin(): bool
{
return $this->name === RolesEnums::ADMIN->value;
Expand Down
Loading

0 comments on commit 8daa8fb

Please sign in to comment.