You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

182 lines
4.9 KiB

<?php
namespace App\Services;
use App\Models\AdminUser;
use App\Models\ResearchDirection;
use App\Models\Teacher;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Request;
class GridMemberScopeService
{
public function isSuperAdmin(AdminUser $user): bool
{
return $user->isSuperAdmin();
}
public function isGridMember(AdminUser $user): bool
{
if ($this->isSuperAdmin($user)) {
return false;
}
return $user->roles()->where('code', 'grid_member')->exists();
}
public function hasScope(AdminUser $user): bool
{
if ($this->isSuperAdmin($user)) {
return false;
}
if (! $this->isGridMember($user)) {
return false;
}
return $this->universityIds($user) !== [] || $this->researchDirectionNames($user) !== [];
}
/**
* @return array<int>
*/
public function universityIds(AdminUser $user): array
{
return $user->universities()->pluck('universities.id')->map(fn ($id) => (int) $id)->all();
}
/**
* @return array<int>
*/
public function researchDirectionIds(AdminUser $user): array
{
return $user->researchDirections()
->where('research_directions.status', 1)
->pluck('research_directions.id')
->map(fn ($id) => (int) $id)
->all();
}
/**
* @return array<int, string>
*/
public function researchDirectionNames(AdminUser $user): array
{
return $user->researchDirections()
->where('research_directions.status', 1)
->orderBy('research_directions.sort')
->pluck('research_directions.name')
->all();
}
/**
* @return array{university_ids: int[], research_direction_ids: int[], research_direction_names: string[]}
*/
public function scopePayload(AdminUser $user): array
{
return [
'university_ids' => $this->universityIds($user),
'research_direction_ids' => $this->researchDirectionIds($user),
'research_direction_names' => $this->researchDirectionNames($user),
];
}
public function applyTeacherScope(Builder $query, AdminUser $user): void
{
if (! $this->isGridMember($user)) {
return;
}
$uniIds = $this->universityIds($user);
$dirIds = $this->researchDirectionIds($user);
if ($uniIds === [] || $dirIds === []) {
$query->whereRaw('1 = 0');
return;
}
$query->whereIn('university_id', $uniIds)
->whereHas('researchDirections', fn ($q) => $q->whereIn('research_directions.id', $dirIds));
}
public function assertTeacherAccessible(AdminUser $user, Teacher $teacher): void
{
if (! $this->isGridMember($user)) {
return;
}
$uniIds = $this->universityIds($user);
$dirIds = $this->researchDirectionIds($user);
if ($uniIds === [] || $dirIds === []) {
$this->deny();
}
if (! in_array((int) $teacher->university_id, $uniIds, true)) {
$this->deny();
}
$teacher->loadMissing('researchDirections');
$overlap = $teacher->researchDirections->pluck('id')->intersect($dirIds);
if ($overlap->isEmpty()) {
$this->deny();
}
}
public function assertCanMutateTeachers(AdminUser $user): void
{
if ($this->isGridMember($user)) {
$this->deny('网格员仅可编辑与跟进已配置范围内的老师');
}
}
/**
* @param array<string, mixed> $data
*/
public function assertTeacherDataInScope(AdminUser $user, array $data, ?Teacher $existing = null): void
{
if (! $this->isGridMember($user)) {
return;
}
$uniIds = $this->universityIds($user);
$dirIds = $this->researchDirectionIds($user);
if (isset($data['university_id']) && ! in_array((int) $data['university_id'], $uniIds, true)) {
$this->deny('所选高校不在您的负责范围内');
}
if (isset($data['research_direction_ids'])) {
foreach ($data['research_direction_ids'] as $dirId) {
if (! in_array((int) $dirId, $dirIds, true)) {
$this->deny('所选研究方向不在您的负责范围内');
}
}
}
if ($existing) {
$this->assertTeacherAccessible($user, $existing);
}
}
public function userFromRequest(Request $request): AdminUser
{
/** @var AdminUser $user */
$user = $request->user();
return $user;
}
protected function deny(string $message = '无权访问该老师'): void
{
throw new HttpResponseException(
response()->json([
'message' => $message,
'data' => null,
], 403)
);
}
}