QuickQuiz/tests/Feature/AdminPermissionTest.php

188 lines
6.6 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Feature;
use App\Models\Paper;
use App\Models\Permission;
use App\Models\QuestionBank;
use App\Models\User;
use App\Services\QuestionImportService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use Tymon\JWTAuth\Facades\JWTAuth;
final class AdminPermissionTest extends TestCase
{
use RefreshDatabase;
protected bool $seed = true;
public function test_user_without_admin_permission_cannot_access_admin_resources(): void
{
$user = User::factory()->create(['role' => 'user']);
$this->withToken(JWTAuth::fromUser($user))
->getJson('/api/admin/banks')
->assertForbidden()
->assertJsonPath('message', '权限不足');
}
public function test_teacher_only_lists_owned_questions(): void
{
$owner = User::factory()->create(['role' => 'teacher']);
$otherTeacher = User::factory()->create(['role' => 'teacher']);
$ownedBank = $this->bankFor($owner, '自己的题库');
$otherBank = $this->bankFor($otherTeacher, '别人的题库');
app(QuestionImportService::class)->importJsonText($ownedBank, $owner, file_get_contents(base_path('question.json')));
app(QuestionImportService::class)->importJsonText($otherBank, $otherTeacher, file_get_contents(base_path('question.json')));
$response = $this->withToken(JWTAuth::fromUser($owner))
->getJson('/api/admin/questions')
->assertOk();
$bankIds = collect($response->json('data.items'))->pluck('question_bank_id')->unique()->values()->all();
$this->assertSame([$ownedBank->id], $bankIds);
}
public function test_teacher_cannot_import_into_another_teachers_bank(): void
{
$owner = User::factory()->create(['role' => 'teacher']);
$otherTeacher = User::factory()->create(['role' => 'teacher']);
$otherBank = $this->bankFor($otherTeacher, '别人的题库');
$this->withToken(JWTAuth::fromUser($owner))
->postJson('/api/admin/questions', [
'question_bank_id' => $otherBank->id,
'content' => '不能越权新增',
'type' => 'single',
'options' => [
['text' => 'A', 'correct' => true],
['text' => 'B', 'correct' => false],
],
])
->assertForbidden();
}
public function test_teacher_without_user_permission_cannot_manage_users(): void
{
$teacher = User::factory()->create(['role' => 'teacher']);
$this->withToken(JWTAuth::fromUser($teacher))
->getJson('/api/admin/users')
->assertForbidden()
->assertJsonPath('message', '权限不足');
}
public function test_admin_can_update_user_status_and_password(): void
{
$admin = User::query()->where('role', 'admin')->firstOrFail();
$target = User::factory()->create(['role' => 'user', 'is_active' => true]);
$this->withToken(JWTAuth::fromUser($admin))
->putJson("/api/admin/users/{$target->id}", [
'name' => '新姓名',
'role' => 'teacher',
'is_active' => false,
'password' => 'newpass123',
])
->assertOk()
->assertJsonPath('data.name', '新姓名')
->assertJsonPath('data.role', 'teacher')
->assertJsonPath('data.is_active', false);
$this->assertDatabaseHas('users', [
'id' => $target->id,
'name' => '新姓名',
'role' => 'teacher',
'is_active' => false,
]);
}
public function test_admin_can_read_and_sync_role_permissions(): void
{
$admin = User::query()->where('role', 'admin')->firstOrFail();
$permission = Permission::query()->where('code', 'banks')->firstOrFail();
$token = JWTAuth::fromUser($admin);
$this->withToken($token)
->getJson('/api/admin/permissions')
->assertOk()
->assertJsonStructure(['data' => ['permissions', 'role_permissions']]);
$this->withToken($token)
->putJson('/api/admin/roles/user/permissions', [
'permission_ids' => [$permission->id],
])
->assertOk();
$this->assertDatabaseHas('role_permissions', [
'role' => 'user',
'permission_id' => $permission->id,
]);
$this->assertDatabaseHas('operation_logs', [
'action' => 'role.permissions_updated',
'target_type' => 'role',
]);
}
public function test_teacher_can_view_and_update_owned_paper_questions(): void
{
$teacher = User::factory()->create(['role' => 'teacher']);
$bank = $this->bankFor($teacher, '试卷题库');
app(QuestionImportService::class)->importJsonText($bank, $teacher, file_get_contents(base_path('question.json')));
$questions = $bank->questions()->take(2)->get();
$paper = Paper::create([
'owner_id' => $teacher->id,
'question_bank_id' => $bank->id,
'title' => '原试卷',
'is_active' => true,
]);
$paper->questions()->attach($questions[0]->id, ['score' => 3, 'sort' => 0]);
$token = JWTAuth::fromUser($teacher);
$this->withToken($token)
->getJson("/api/admin/papers/{$paper->id}")
->assertOk()
->assertJsonPath('data.questions.0.id', $questions[0]->id)
->assertJsonPath('data.questions.0.pivot.score', '3.00');
$this->withToken($token)
->putJson("/api/admin/papers/{$paper->id}", [
'title' => '更新试卷',
'is_active' => false,
'questions' => [
['id' => $questions[1]->id, 'score' => 4],
],
])
->assertOk()
->assertJsonPath('data.title', '更新试卷')
->assertJsonPath('data.is_active', false)
->assertJsonPath('data.questions_count', 1);
$this->assertDatabaseHas('paper_questions', [
'paper_id' => $paper->id,
'question_id' => $questions[1]->id,
'score' => 4,
]);
$this->assertDatabaseMissing('paper_questions', [
'paper_id' => $paper->id,
'question_id' => $questions[0]->id,
]);
}
private function bankFor(User $user, string $name): QuestionBank
{
return QuestionBank::create([
'owner_id' => $user->id,
'name' => $name,
'visibility' => 'private',
'is_active' => true,
]);
}
}