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
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)
|
|
);
|
|
}
|
|
}
|