273 lines
6.9 KiB
PHP
273 lines
6.9 KiB
PHP
<?php
|
|
|
|
use App\Models\Forum;
|
|
use App\Models\Role;
|
|
use App\Models\Thread;
|
|
use App\Models\User;
|
|
use Laravel\Sanctum\Sanctum;
|
|
|
|
beforeEach(function (): void {
|
|
$parserProp = new ReflectionProperty(\App\Actions\BbcodeFormatter::class, 'parser');
|
|
$parserProp->setAccessible(true);
|
|
$parserProp->setValue(
|
|
\Mockery::mock(\s9e\TextFormatter\Parser::class)
|
|
->shouldReceive('parse')
|
|
->andReturn('<r/>')
|
|
->getMock()
|
|
);
|
|
|
|
$rendererProp = new ReflectionProperty(\App\Actions\BbcodeFormatter::class, 'renderer');
|
|
$rendererProp->setAccessible(true);
|
|
$rendererProp->setValue(
|
|
\Mockery::mock(\s9e\TextFormatter\Renderer::class)
|
|
->shouldReceive('render')
|
|
->andReturn('<p></p>')
|
|
->getMock()
|
|
);
|
|
});
|
|
|
|
afterEach(function (): void {
|
|
\Mockery::close();
|
|
});
|
|
|
|
function makeForum(): Forum
|
|
{
|
|
$category = Forum::create([
|
|
'name' => 'Category',
|
|
'description' => null,
|
|
'type' => 'category',
|
|
'parent_id' => null,
|
|
'position' => 1,
|
|
]);
|
|
|
|
return Forum::create([
|
|
'name' => 'Forum',
|
|
'description' => null,
|
|
'type' => 'forum',
|
|
'parent_id' => $category->id,
|
|
'position' => 1,
|
|
]);
|
|
}
|
|
|
|
it('creates a thread inside a forum', function (): void {
|
|
$user = User::factory()->create();
|
|
Sanctum::actingAs($user);
|
|
|
|
$forum = makeForum();
|
|
|
|
$response = $this->postJson('/api/threads', [
|
|
'title' => 'First Thread',
|
|
'body' => 'Hello world',
|
|
'forum' => "/api/forums/{$forum->id}",
|
|
]);
|
|
|
|
$response->assertStatus(201);
|
|
$response->assertJsonFragment([
|
|
'title' => 'First Thread',
|
|
'forum' => "/api/forums/{$forum->id}",
|
|
]);
|
|
|
|
$this->assertDatabaseHas('threads', [
|
|
'forum_id' => $forum->id,
|
|
'user_id' => $user->id,
|
|
'title' => 'First Thread',
|
|
]);
|
|
});
|
|
|
|
it('rejects creating threads in a category', function (): void {
|
|
$user = User::factory()->create();
|
|
Sanctum::actingAs($user);
|
|
|
|
$category = Forum::create([
|
|
'name' => 'Category Only',
|
|
'description' => null,
|
|
'type' => 'category',
|
|
'parent_id' => null,
|
|
'position' => 1,
|
|
]);
|
|
|
|
$response = $this->postJson('/api/threads', [
|
|
'title' => 'Nope',
|
|
'body' => 'Not allowed',
|
|
'forum' => "/api/forums/{$category->id}",
|
|
]);
|
|
|
|
$response->assertStatus(422);
|
|
$response->assertJsonFragment(['message' => 'Threads can only be created inside forums.']);
|
|
});
|
|
|
|
it('requires authentication to update a thread', function (): void {
|
|
$forum = makeForum();
|
|
$owner = User::factory()->create();
|
|
|
|
$thread = Thread::create([
|
|
'forum_id' => $forum->id,
|
|
'user_id' => $owner->id,
|
|
'title' => 'Original',
|
|
'body' => '',
|
|
]);
|
|
|
|
$response = $this->patchJson("/api/threads/{$thread->id}", [
|
|
'title' => 'Updated',
|
|
'body' => 'Updated body',
|
|
]);
|
|
|
|
$response->assertStatus(401);
|
|
});
|
|
|
|
it('enforces thread update permissions', function (): void {
|
|
$forum = makeForum();
|
|
$owner = User::factory()->create();
|
|
$other = User::factory()->create();
|
|
|
|
$thread = Thread::create([
|
|
'forum_id' => $forum->id,
|
|
'user_id' => $owner->id,
|
|
'title' => 'Original',
|
|
'body' => '',
|
|
]);
|
|
|
|
Sanctum::actingAs($other);
|
|
$response = $this->patchJson("/api/threads/{$thread->id}", [
|
|
'title' => 'Updated',
|
|
'body' => 'Updated body',
|
|
]);
|
|
|
|
$response->assertStatus(403);
|
|
|
|
Sanctum::actingAs($owner);
|
|
$response = $this->patchJson("/api/threads/{$thread->id}", [
|
|
'title' => 'Owner Update',
|
|
'body' => 'Owner body',
|
|
]);
|
|
|
|
$response->assertOk();
|
|
$this->assertDatabaseHas('threads', [
|
|
'id' => $thread->id,
|
|
'title' => 'Owner Update',
|
|
'body' => 'Owner body',
|
|
]);
|
|
|
|
$admin = User::factory()->create();
|
|
$role = Role::create(['name' => 'ROLE_ADMIN', 'color' => '#111111']);
|
|
$admin->roles()->attach($role);
|
|
|
|
Sanctum::actingAs($admin);
|
|
$response = $this->patchJson("/api/threads/{$thread->id}", [
|
|
'title' => 'Admin Update',
|
|
'body' => 'Admin body',
|
|
]);
|
|
|
|
$response->assertOk();
|
|
$this->assertDatabaseHas('threads', [
|
|
'id' => $thread->id,
|
|
'title' => 'Admin Update',
|
|
'body' => 'Admin body',
|
|
]);
|
|
});
|
|
|
|
it('enforces solved status permissions', function (): void {
|
|
$forum = makeForum();
|
|
$owner = User::factory()->create();
|
|
$other = User::factory()->create();
|
|
|
|
$thread = Thread::create([
|
|
'forum_id' => $forum->id,
|
|
'user_id' => $owner->id,
|
|
'title' => 'Original',
|
|
'body' => '',
|
|
'solved' => false,
|
|
]);
|
|
|
|
Sanctum::actingAs($other);
|
|
$response = $this->patchJson("/api/threads/{$thread->id}/solved", [
|
|
'solved' => true,
|
|
]);
|
|
|
|
$response->assertStatus(403);
|
|
|
|
Sanctum::actingAs($owner);
|
|
$response = $this->patchJson("/api/threads/{$thread->id}/solved", [
|
|
'solved' => true,
|
|
]);
|
|
|
|
$response->assertOk();
|
|
$this->assertDatabaseHas('threads', [
|
|
'id' => $thread->id,
|
|
'solved' => 1,
|
|
]);
|
|
});
|
|
|
|
it('filters threads by forum', function (): void {
|
|
$forumA = makeForum();
|
|
$forumB = makeForum();
|
|
|
|
$threadA = Thread::create([
|
|
'forum_id' => $forumA->id,
|
|
'user_id' => null,
|
|
'title' => 'Thread A',
|
|
'body' => '',
|
|
]);
|
|
|
|
Thread::create([
|
|
'forum_id' => $forumB->id,
|
|
'user_id' => null,
|
|
'title' => 'Thread B',
|
|
'body' => '',
|
|
]);
|
|
|
|
$response = $this->getJson("/api/threads?forum=/api/forums/{$forumA->id}");
|
|
|
|
$response->assertOk();
|
|
$response->assertJsonCount(1);
|
|
$response->assertJsonFragment([
|
|
'id' => $threadA->id,
|
|
'title' => 'Thread A',
|
|
]);
|
|
});
|
|
|
|
it('increments views count when showing a thread', function (): void {
|
|
$forum = makeForum();
|
|
$thread = Thread::create([
|
|
'forum_id' => $forum->id,
|
|
'user_id' => null,
|
|
'title' => 'Viewed Thread',
|
|
'body' => '',
|
|
'views_count' => 0,
|
|
]);
|
|
|
|
$response = $this->getJson("/api/threads/{$thread->id}");
|
|
|
|
$response->assertOk();
|
|
$response->assertJsonFragment([
|
|
'id' => $thread->id,
|
|
'views_count' => 1,
|
|
]);
|
|
|
|
$thread->refresh();
|
|
expect($thread->views_count)->toBe(1);
|
|
});
|
|
|
|
it('soft deletes a thread and tracks deleted_by', function (): void {
|
|
$forum = makeForum();
|
|
$user = User::factory()->create();
|
|
$thread = Thread::create([
|
|
'forum_id' => $forum->id,
|
|
'user_id' => $user->id,
|
|
'title' => 'Delete Me',
|
|
'body' => 'Body',
|
|
]);
|
|
|
|
Sanctum::actingAs($user);
|
|
$response = $this->deleteJson("/api/threads/{$thread->id}");
|
|
|
|
$response->assertStatus(204);
|
|
$this->assertSoftDeleted('threads', [
|
|
'id' => $thread->id,
|
|
]);
|
|
$this->assertDatabaseHas('threads', [
|
|
'id' => $thread->id,
|
|
'deleted_by' => $user->id,
|
|
]);
|
|
});
|