feat: new feature
This commit is contained in:
@@ -20,7 +20,7 @@ use Catch\Base\CatchModel as Model;
|
||||
* @property $updated_at
|
||||
* @property $deleted_at
|
||||
*/
|
||||
class DepartmentsModel extends Model
|
||||
class Departments extends Model
|
||||
{
|
||||
protected $table = 'departments';
|
||||
|
||||
@@ -47,4 +47,25 @@ class DepartmentsModel extends Model
|
||||
];
|
||||
|
||||
protected bool $asTree = true;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param int|array $id
|
||||
* @return array
|
||||
*/
|
||||
public function findFollowDepartments(int|array $id): array
|
||||
{
|
||||
if (!is_array($id)) {
|
||||
$id = [$id];
|
||||
}
|
||||
|
||||
$followDepartmentIds = $this->whereIn($this->getParentIdColumn(), $id)->pluck('id')->toArray();
|
||||
|
||||
if (! empty($followDepartmentIds)) {
|
||||
$followDepartmentIds = array_merge($followDepartmentIds, $this->findFollowDepartments($followDepartmentIds));
|
||||
}
|
||||
|
||||
return $followDepartmentIds;
|
||||
}
|
||||
}
|
@@ -18,7 +18,7 @@ use Catch\Base\CatchModel as Model;
|
||||
* @property $updated_at
|
||||
* @property $deleted_at
|
||||
*/
|
||||
class JobsModel extends Model
|
||||
class Jobs extends Model
|
||||
{
|
||||
protected $table = 'jobs';
|
||||
|
@@ -1,121 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Permissions\Models;
|
||||
|
||||
use Catch\CatchAdmin;
|
||||
use Catch\Traits\DB\BaseOperate;
|
||||
use Catch\Traits\DB\ScopeTrait;
|
||||
use Catch\Traits\DB\Trans;
|
||||
use Illuminate\Contracts\Http\Kernel;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Modules\Permissions\Exceptions\PermissionForbidden;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class LogOperate extends Model
|
||||
{
|
||||
use BaseOperate, Trans, ScopeTrait;
|
||||
|
||||
protected $table = 'log_operate';
|
||||
|
||||
protected $fillable = [
|
||||
'id',
|
||||
'module',
|
||||
'operate',
|
||||
'route',
|
||||
'params',
|
||||
'ip',
|
||||
'http_method',
|
||||
'http_method',
|
||||
'start_at',
|
||||
'time_taken',
|
||||
'creator_id',
|
||||
'created_at',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @return void
|
||||
*/
|
||||
public function log(Request $request, Response $response): void
|
||||
{
|
||||
if (! $response->isOk() && $response->exception instanceof PermissionForbidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user = Auth::guard(getGuardName())->user();
|
||||
|
||||
$userModel = getAuthUserModel();
|
||||
|
||||
if (! $user instanceof $userModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
$user->getAttribute('permissions')->each(function ($permission) use ($user, $request, $response) {
|
||||
if ($permission->isAction()) {
|
||||
[$controller, $action] = explode('@', $permission->permission_mark);
|
||||
|
||||
if (! CatchAdmin::getModuleControllerNamespace($permission->module).$controller.'Controller@'.$action == Route::currentRouteAction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$requestStartAt = app(Kernel::class)->requestStartedAt()->timestamp;
|
||||
|
||||
$params = $request->all();
|
||||
// 如果参数过长则不记录
|
||||
if (!empty($params)) {
|
||||
if (strlen($encodeParams = \json_encode($params, JSON_UNESCAPED_UNICODE)) > 5000) {
|
||||
$params = [];
|
||||
}
|
||||
}
|
||||
|
||||
$this->storeBy([
|
||||
'module' => $permission->module,
|
||||
|
||||
'operate' => $permission->permission_name,
|
||||
|
||||
'route' => $permission->permission_mark,
|
||||
|
||||
'creator_id' => $user->id,
|
||||
|
||||
'http_method' => $request->method(),
|
||||
|
||||
'http_code' => $response->getStatusCode(),
|
||||
|
||||
'start_at' => $requestStartAt,
|
||||
|
||||
'time_taken' => time() - $requestStartAt,
|
||||
|
||||
'ip' => $request->ip(),
|
||||
|
||||
'params' => !empty($params) ? $encodeParams : '',
|
||||
|
||||
'created_at' => time()
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Attribute
|
||||
*/
|
||||
protected function timeTaken(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn($value) => $value . 's',
|
||||
);
|
||||
}
|
||||
}
|
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace Modules\Permissions\Models;
|
||||
|
||||
use Catch\Base\CatchModel as Model;
|
||||
use Catch\CatchAdmin;
|
||||
use Catch\Enums\Status;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Modules\Permissions\Enums\MenuStatus;
|
||||
@@ -29,7 +30,7 @@ use Modules\Permissions\Enums\MenuType;
|
||||
* @property $updated_at
|
||||
* @property $deleted_at
|
||||
*/
|
||||
class PermissionsModel extends Model
|
||||
class Permissions extends Model
|
||||
{
|
||||
protected $table = 'permissions';
|
||||
|
||||
@@ -58,6 +59,22 @@ class PermissionsModel extends Model
|
||||
|
||||
protected $hidden = ['pivot'];
|
||||
|
||||
/**
|
||||
* default permission actions
|
||||
*
|
||||
* @var array|string[]
|
||||
*/
|
||||
protected array $defaultActions = [
|
||||
'index' => '列表',
|
||||
'store' => '新增',
|
||||
'show' => '读取',
|
||||
'update' => '更新',
|
||||
'destroy' => '删除',
|
||||
'enable' => '禁用/启用',
|
||||
'import' => '导入',
|
||||
'export' => '导出',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
@@ -103,6 +120,16 @@ class PermissionsModel extends Model
|
||||
return $this->type == MenuType::Top;
|
||||
}
|
||||
|
||||
/**
|
||||
* is menu
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isMenu(): bool
|
||||
{
|
||||
return $this->type == MenuType::Menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* actions
|
||||
*
|
||||
@@ -117,29 +144,73 @@ class PermissionsModel extends Model
|
||||
*
|
||||
* @param array $data
|
||||
* @return bool
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function storeBy(array $data): bool
|
||||
{
|
||||
$model = $this->fill($data);
|
||||
if ($data['actions'] ?? false) {
|
||||
/* @var static $parentMenu */
|
||||
$parentMenu = $this->firstBy(value: $data['parent_id'], field: 'id');
|
||||
|
||||
if ($model->isAction()) {
|
||||
$parentMenu = $this->firstBy($model->parent_id, 'id');
|
||||
$model->setAttribute('module', $parentMenu->module);
|
||||
$model->setAttribute('permission_mark', $parentMenu->permission_mark . '@' . $data['permission_mark']);
|
||||
$model->setAttribute('route', '');
|
||||
$model->setAttribute('icon', '');
|
||||
$model->setAttribute('component', '');
|
||||
$model->setAttribute('redirect', '');
|
||||
return $model->setCreatorId()->save();
|
||||
}
|
||||
if (! $parentMenu->isMenu()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($model->isTopMenu()) {
|
||||
$data['route'] = '/' . trim($data['route'], '/');
|
||||
}
|
||||
$actions = CatchAdmin::getControllerActions($parentMenu->module, $parentMenu->permission_mark);
|
||||
foreach ($actions as $k => $action) {
|
||||
if (! isset($this->defaultActions[$action])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->addAction($this->newInstance([
|
||||
'type' => MenuType::Action->value(),
|
||||
'parent_id' => $data['parent_id'],
|
||||
'permission_name' => $this->defaultActions[$action],
|
||||
'permission_mark' => $action,
|
||||
'sort' => $k + 1
|
||||
]), $parentMenu);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$model = $this->fill($data);
|
||||
|
||||
if ($model->isAction()) {
|
||||
$parentMenu = $this->firstBy($model->parent_id, 'id');
|
||||
return $this->addAction($model, $parentMenu);
|
||||
}
|
||||
|
||||
if ($model->isTopMenu()) {
|
||||
$data['route'] = '/'.trim($data['route'], '/');
|
||||
}
|
||||
|
||||
return parent::storeBy($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* add action
|
||||
*
|
||||
* @param $model
|
||||
* @param Permissions $parent
|
||||
* @return mixed
|
||||
*/
|
||||
protected function addAction($model, mixed $parent): mixed
|
||||
{
|
||||
$model->setAttribute('module', $parent->module);
|
||||
$model->setAttribute('permission_mark', $parent->permission_mark. '@'. $model->permission_mark);
|
||||
$model->setAttribute('route', '');
|
||||
$model->setAttribute('icon', '');
|
||||
$model->setAttribute('component', '');
|
||||
$model->setAttribute('redirect', '');
|
||||
|
||||
if ($this->where('module', $model->getAttribute('module'))->where('permission_mark', $model->getAttribute('permission_mark'))->first()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $model->setCreatorId()->save();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* update data
|
||||
@@ -153,9 +224,9 @@ class PermissionsModel extends Model
|
||||
$model = $this->fill($data);
|
||||
|
||||
if ($model->isAction()) {
|
||||
/* @var PermissionsModel $parentMenu */
|
||||
$parentMenu = $this->firstBy($model->parent_id, 'id');
|
||||
$data['permission_mark'] = $parentMenu->permission_mark . '@' . $data['permission_mark'];
|
||||
/* @var Permissions $parentMenu */
|
||||
$parentMenu = $this->firstBy($model->parent_id, 'id');
|
||||
$data['permission_mark'] = $parentMenu->permission_mark.'@'.$data['permission_mark'];
|
||||
}
|
||||
|
||||
return parent::updateBy($id, $data);
|
@@ -6,6 +6,7 @@ namespace Modules\Permissions\Models;
|
||||
|
||||
use Catch\Base\CatchModel as Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Modules\Permissions\Models\Traits\DataRange;
|
||||
|
||||
/**
|
||||
* @property $role_name
|
||||
@@ -18,8 +19,10 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
* @property $updated_at
|
||||
* @property $deleted_at
|
||||
*/
|
||||
class RolesModel extends Model
|
||||
class Roles extends Model
|
||||
{
|
||||
use DataRange;
|
||||
|
||||
protected $table = 'roles';
|
||||
|
||||
protected $fillable = ['id', 'role_name', 'identify', 'parent_id', 'description', 'data_range', 'creator_id', 'created_at', 'updated_at', 'deleted_at'];
|
||||
@@ -59,6 +62,17 @@ class RolesModel extends Model
|
||||
*/
|
||||
public function permissions(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(PermissionsModel::class, 'role_has_permissions', 'role_id', 'permission_id');
|
||||
return $this->belongsToMany(Permissions::class, 'role_has_permissions', 'role_id', 'permission_id');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* departments
|
||||
*
|
||||
* @return BelongsToMany
|
||||
*/
|
||||
public function departments(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Departments::class, 'role_has_departments', 'role_id', 'department_id');
|
||||
}
|
||||
}
|
100
modules/Permissions/Models/Traits/DataRange.php
Normal file
100
modules/Permissions/Models/Traits/DataRange.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Permissions\Models\Traits;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Modules\Permissions\Models\Departments;
|
||||
use Modules\Permissions\Models\Roles;
|
||||
use Modules\Permissions\Enums\DataRange as DataRangeEnum;
|
||||
|
||||
trait DataRange
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @param $query
|
||||
* @param array|Collection $roles
|
||||
* @return mixed
|
||||
*/
|
||||
public function scopeDataRange($query, array|Collection $roles = []): mixed
|
||||
{
|
||||
$currenUser = Auth::guard(getGuardName())->user();
|
||||
|
||||
if ($currenUser->isSuperAdmin()) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
$userIds = $this->getDepartmentUserIdsBy($roles, $currenUser);
|
||||
|
||||
if (empty($userIds)) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
return $query->whereIn($this->aliasField('creator_id'), $userIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* get department ids
|
||||
*
|
||||
* @param array $roles
|
||||
* @param $currentUser
|
||||
* @return Collection
|
||||
*/
|
||||
public function getDepartmentUserIdsBy(array $roles, $currentUser): Collection
|
||||
{
|
||||
$userIds = Collection::make();
|
||||
|
||||
if (empty($roles)) {
|
||||
$roles = $currentUser->roles()->get();
|
||||
}
|
||||
|
||||
/* @var Roles $role */
|
||||
foreach ($roles as $role) {
|
||||
if (DataRangeEnum::All_Data->assert($role->data_range)) {
|
||||
return Collection::make();
|
||||
}
|
||||
|
||||
if (DataRangeEnum::Personal_Choose->assert($role->data_range)) {
|
||||
$userIds = $userIds->merge($this->getUserIdsByDepartmentId($role->departments()->pluck('id')));
|
||||
}
|
||||
|
||||
if (DataRangeEnum::Personal_Data->assert($role->data_range)) {
|
||||
$userIds = $userIds->push($currentUser->id);
|
||||
}
|
||||
|
||||
if (DataRangeEnum::Department_Data->assert($role->data_range)) {
|
||||
$userIds = $userIds->merge(
|
||||
$this->getUserIdsByDepartmentId([$currentUser->department_id])
|
||||
);
|
||||
}
|
||||
|
||||
if (DataRangeEnum::Department_DOWN_Data->assert($role->data_range)) {
|
||||
$departmentsId = [$currentUser->department_id];
|
||||
|
||||
$departmentModel = new Departments();
|
||||
|
||||
$departmentIds = $departmentModel->findFollowDepartments($departmentsId);
|
||||
|
||||
$userIds = $userIds->merge($this->getUserIdsByDepartmentId($departmentIds))->push($currentUser->id);
|
||||
}
|
||||
}
|
||||
|
||||
return $userIds->unique();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get user ids by department is
|
||||
*
|
||||
* @param array|Collection $departmentIds
|
||||
* @return Collection
|
||||
*/
|
||||
protected function getUserIdsByDepartmentId(array|Collection $departmentIds): Collection
|
||||
{
|
||||
$userModel = app(getAuthUserModel());
|
||||
|
||||
return $userModel->whereIn('department_id', $departmentIds)->pluck('id');
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user