Files
lotteryLaravel/app/Models/AdminUser.php

243 lines
7.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Models;
use App\Support\AdminPermissionBridge;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\DB;
use Laravel\Sanctum\HasApiTokens;
class AdminUser extends Authenticatable
{
use HasApiTokens;
use Notifiable;
public const ROLE_SUPER_ADMIN = 'super_admin';
protected $table = 'admin_users';
protected $fillable = [
'username',
'name',
'email',
'password',
'status',
];
protected $hidden = [
'password',
'remember_token',
];
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'last_login_at' => 'datetime',
'password' => 'hashed',
];
}
public static function defaultAdminSiteId(): int
{
static $cached = null;
if ($cached !== null) {
return $cached;
}
$id = DB::table('admin_sites')->where('is_default', true)->value('id');
if ($id === null) {
$id = DB::table('admin_sites')->orderBy('id')->value('id');
}
if ($id === null) {
throw new \RuntimeException('No admin_sites row found.');
}
$cached = (int) $id;
return $cached;
}
/**
* 用户在各站点上的角色(多站点 RBAC
*
* @return BelongsToMany<AdminRole, AdminUser>
*/
public function roles(): BelongsToMany
{
return $this->belongsToMany(
AdminRole::class,
'admin_user_site_roles',
'admin_user_id',
'role_id',
)->withPivot(['site_id', 'granted_at']);
}
/**
* 将用户在默认站点上的角色设为指定 slug 集合(全量替换该站点 pivot
*
* @param list<string> $slugs
*/
public function syncRoleSlugsForDefaultSite(array $slugs): void
{
$siteId = self::defaultAdminSiteId();
$slugs = array_values(array_unique($slugs));
$roleIds = DB::table('admin_roles')
->whereIn('slug', $slugs)
->pluck('id')
->all();
DB::transaction(function () use ($siteId, $roleIds): void {
DB::table('admin_user_site_roles')
->where('admin_user_id', $this->id)
->where('site_id', $siteId)
->delete();
$now = now();
foreach ($roleIds as $rid) {
DB::table('admin_user_site_roles')->insert([
'admin_user_id' => $this->id,
'site_id' => $siteId,
'role_id' => (int) $rid,
'granted_at' => $now,
]);
}
});
}
public function isSuperAdmin(): bool
{
if ($this->relationLoaded('roles')) {
return $this->roles->contains('slug', self::ROLE_SUPER_ADMIN);
}
return $this->roles()->where('admin_roles.slug', self::ROLE_SUPER_ADMIN)->exists();
}
/**
* 仅来自「直接授权」的 menu_action.permission_code默认站点含 site_id 为 null 的历史行)。
*
* @return list<string>
*/
public function directMenuActionPermissionCodes(): array
{
$siteId = self::defaultAdminSiteId();
$rows = DB::table('admin_user_menu_actions as uma')
->join('admin_menu_actions as ma', 'ma.id', '=', 'uma.menu_action_id')
->where('uma.admin_user_id', $this->id)
->where(function ($q) use ($siteId): void {
$q->where('uma.site_id', $siteId)->orWhereNull('uma.site_id');
})
->where('ma.status', 1)
->pluck('ma.permission_code')
->all();
$out = [];
foreach ($rows as $code) {
if (is_string($code) && $code !== '') {
$out[$code] = true;
}
}
return array_keys($out);
}
/**
* 直接授权对应的 `prd.*` 展示列表(与 {@see self::directMenuActionPermissionCodes()} 桥接)。
*
* @return list<string>
*/
public function directLegacyPermissionSlugs(): array
{
return AdminPermissionBridge::legacySlugsGrantedByMenuActionCodes($this->directMenuActionPermissionCodes());
}
/**
* 角色 + 直接授权合并后的 menu_action.permission_code。
*
* @return list<string>
*/
public function effectiveMenuActionPermissionCodes(): array
{
if ($this->isSuperAdmin()) {
$codes = DB::table('admin_menu_actions')->where('status', 1)->pluck('permission_code')->all();
$out = [];
foreach ($codes as $c) {
if (is_string($c) && $c !== '') {
$out[$c] = true;
}
}
return array_keys($out);
}
$fromRoles = DB::table('admin_user_site_roles as usr')
->join('admin_role_menu_actions as rma', 'rma.role_id', '=', 'usr.role_id')
->join('admin_menu_actions as ma', 'ma.id', '=', 'rma.menu_action_id')
->where('usr.admin_user_id', $this->id)
->where('ma.status', 1)
->pluck('ma.permission_code')
->all();
$merged = [];
foreach (array_merge($fromRoles, $this->directMenuActionPermissionCodes()) as $c) {
if (is_string($c) && $c !== '') {
$merged[$c] = true;
}
}
return array_keys($merged);
}
/** 是否具备指定权限:`prd.*` 走 legacy_map否则按 permission_code 精确匹配。含 `super_admin` 全放行。 */
public function hasAdminPermission(string $slug): bool
{
if ($this->isSuperAdmin()) {
return true;
}
$effective = $this->effectiveMenuActionPermissionCodes();
if ($slug !== '' && in_array($slug, $effective, true)) {
return true;
}
if (! str_starts_with($slug, 'prd.')) {
return false;
}
$needed = AdminPermissionBridge::menuActionCodesForLegacy($slug);
if ($needed === []) {
return false;
}
return count(array_intersect($needed, $effective)) > 0;
}
/**
* @return list<string> 与 Next 侧栏、`admin.permission` 中间件一致的 `prd.*` slug 列表
*/
public function adminPermissionSlugs(): array
{
if ($this->isSuperAdmin()) {
return AdminPermissionBridge::allLegacySlugs();
}
return AdminPermissionBridge::legacySlugsGrantedByMenuActionCodes($this->effectiveMenuActionPermissionCodes());
}
/**
* @return list<string>
*/
public function adminRoleSlugs(): array
{
$this->loadMissing('roles');
return $this->roles
->pluck('slug')
->filter(static fn ($slug): bool => is_string($slug) && $slug !== '')
->unique()
->values()
->all();
}
}