234 lines
5.8 KiB
PHP
234 lines
5.8 KiB
PHP
<?php
|
|
|
|
use App\Models\Forum;
|
|
use App\Models\Post;
|
|
use App\Models\PostThank;
|
|
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 makeThread(): Thread
|
|
{
|
|
$category = Forum::create([
|
|
'name' => 'Category',
|
|
'description' => null,
|
|
'type' => 'category',
|
|
'parent_id' => null,
|
|
'position' => 1,
|
|
]);
|
|
|
|
$forum = Forum::create([
|
|
'name' => 'Forum',
|
|
'description' => null,
|
|
'type' => 'forum',
|
|
'parent_id' => $category->id,
|
|
'position' => 1,
|
|
]);
|
|
|
|
return Thread::create([
|
|
'forum_id' => $forum->id,
|
|
'user_id' => null,
|
|
'title' => 'Thread Title',
|
|
'body' => 'Thread Body',
|
|
]);
|
|
}
|
|
|
|
it('creates a post in a thread', function (): void {
|
|
$user = User::factory()->create();
|
|
Sanctum::actingAs($user);
|
|
|
|
$thread = makeThread();
|
|
|
|
$response = $this->postJson('/api/posts', [
|
|
'body' => 'First reply',
|
|
'thread' => "/api/threads/{$thread->id}",
|
|
]);
|
|
|
|
$response->assertStatus(201);
|
|
$response->assertJsonFragment([
|
|
'body' => 'First reply',
|
|
'thread' => "/api/threads/{$thread->id}",
|
|
]);
|
|
|
|
$this->assertDatabaseHas('posts', [
|
|
'thread_id' => $thread->id,
|
|
'user_id' => $user->id,
|
|
'body' => 'First reply',
|
|
]);
|
|
});
|
|
|
|
it('validates required fields when creating posts', function (): void {
|
|
$user = User::factory()->create();
|
|
Sanctum::actingAs($user);
|
|
|
|
$response = $this->postJson('/api/posts', []);
|
|
|
|
$response->assertStatus(422);
|
|
$response->assertJsonValidationErrors(['body', 'thread']);
|
|
});
|
|
|
|
it('enforces post update permissions', function (): void {
|
|
$thread = makeThread();
|
|
$owner = User::factory()->create();
|
|
$other = User::factory()->create();
|
|
|
|
$post = Post::create([
|
|
'thread_id' => $thread->id,
|
|
'user_id' => $owner->id,
|
|
'body' => 'Original body',
|
|
]);
|
|
|
|
Sanctum::actingAs($other);
|
|
$response = $this->patchJson("/api/posts/{$post->id}", [
|
|
'body' => 'Hacked body',
|
|
]);
|
|
|
|
$response->assertStatus(403);
|
|
|
|
Sanctum::actingAs($owner);
|
|
$response = $this->patchJson("/api/posts/{$post->id}", [
|
|
'body' => 'Owner update',
|
|
]);
|
|
|
|
$response->assertOk();
|
|
$this->assertDatabaseHas('posts', [
|
|
'id' => $post->id,
|
|
'body' => 'Owner update',
|
|
]);
|
|
|
|
$admin = User::factory()->create();
|
|
$role = Role::create(['name' => 'ROLE_ADMIN', 'color' => '#111111']);
|
|
$admin->roles()->attach($role);
|
|
|
|
Sanctum::actingAs($admin);
|
|
$response = $this->patchJson("/api/posts/{$post->id}", [
|
|
'body' => 'Admin update',
|
|
]);
|
|
|
|
$response->assertOk();
|
|
$this->assertDatabaseHas('posts', [
|
|
'id' => $post->id,
|
|
'body' => 'Admin update',
|
|
]);
|
|
});
|
|
|
|
it('requires authentication to update a post', function (): void {
|
|
$thread = makeThread();
|
|
$post = Post::create([
|
|
'thread_id' => $thread->id,
|
|
'user_id' => null,
|
|
'body' => 'Original body',
|
|
]);
|
|
|
|
$response = $this->patchJson("/api/posts/{$post->id}", [
|
|
'body' => 'Updated body',
|
|
]);
|
|
|
|
$response->assertStatus(401);
|
|
});
|
|
|
|
it('deletes a post and tracks deleted_by', function (): void {
|
|
$thread = makeThread();
|
|
$user = User::factory()->create();
|
|
|
|
$post = Post::create([
|
|
'thread_id' => $thread->id,
|
|
'user_id' => $user->id,
|
|
'body' => 'To be deleted',
|
|
]);
|
|
|
|
Sanctum::actingAs($user);
|
|
$response = $this->deleteJson("/api/posts/{$post->id}");
|
|
|
|
$response->assertStatus(204);
|
|
|
|
$this->assertSoftDeleted('posts', [
|
|
'id' => $post->id,
|
|
]);
|
|
|
|
$this->assertDatabaseHas('posts', [
|
|
'id' => $post->id,
|
|
'deleted_by' => $user->id,
|
|
]);
|
|
});
|
|
|
|
it('filters posts by thread', function (): void {
|
|
$threadA = makeThread();
|
|
$threadB = makeThread();
|
|
|
|
$postA = Post::create([
|
|
'thread_id' => $threadA->id,
|
|
'user_id' => null,
|
|
'body' => 'Post A',
|
|
]);
|
|
|
|
Post::create([
|
|
'thread_id' => $threadB->id,
|
|
'user_id' => null,
|
|
'body' => 'Post B',
|
|
]);
|
|
|
|
$response = $this->getJson("/api/posts?thread=/api/threads/{$threadA->id}");
|
|
|
|
$response->assertOk();
|
|
$response->assertJsonCount(1);
|
|
$response->assertJsonFragment([
|
|
'id' => $postA->id,
|
|
'body' => 'Post A',
|
|
]);
|
|
});
|
|
|
|
it('allows users to thank and unthank posts', function (): void {
|
|
$thread = makeThread();
|
|
$author = User::factory()->create();
|
|
$thanker = User::factory()->create();
|
|
|
|
$post = Post::create([
|
|
'thread_id' => $thread->id,
|
|
'user_id' => $author->id,
|
|
'body' => 'Helpful answer',
|
|
]);
|
|
|
|
Sanctum::actingAs($thanker);
|
|
$response = $this->postJson("/api/posts/{$post->id}/thanks");
|
|
|
|
$response->assertStatus(201);
|
|
$this->assertDatabaseHas('post_thanks', [
|
|
'post_id' => $post->id,
|
|
'user_id' => $thanker->id,
|
|
]);
|
|
|
|
$response = $this->deleteJson("/api/posts/{$post->id}/thanks");
|
|
|
|
$response->assertStatus(204);
|
|
$this->assertDatabaseMissing('post_thanks', [
|
|
'post_id' => $post->id,
|
|
'user_id' => $thanker->id,
|
|
]);
|
|
});
|