Skip to content

Commit

Permalink
add route to save user responses
Browse files Browse the repository at this point in the history
  • Loading branch information
AmonDeShir committed Aug 16, 2024
1 parent eee6908 commit 13b32a2
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 1 deletion.
23 changes: 23 additions & 0 deletions app/Http/Controllers/AnswerRecordController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\Answer;
use App\Models\AnswerRecord;
use Illuminate\Http\RedirectResponse;

use function redirect;

class AnswerRecordController extends Controller
{
public function answer(AnswerRecord $answerRecord, Answer $answer): RedirectResponse
{
$answerRecord->answer()->associate($answer)->save();

return redirect()
->back()
->with("success", "Answer updated");
}
}
4 changes: 4 additions & 0 deletions app/Models/AnswerRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class AnswerRecord extends Model
{
use HasFactory;

protected $fillable = [
"text",
];

public function quizSubmission(): BelongsTo
{
return $this->belongsTo(QuizSubmission::class);
Expand Down
2 changes: 1 addition & 1 deletion app/Models/QuizSubmission.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function answerRecords(): HasMany

public function isClosed(): Attribute
{
return Attribute::get(fn(): bool => $this->closed_at !== null);
return Attribute::get(fn(): bool => $this->closed_at !== null && $this->closed_at <= Carbon::now());
}

protected function casts(): array
Expand Down
19 changes: 19 additions & 0 deletions app/Policies/AnswerRecordPolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace App\Policies;

use App\Models\Answer;
use App\Models\AnswerRecord;
use App\Models\User;

class AnswerRecordPolicy
{
public function answer(User $user, AnswerRecord $answerRecord, Answer $answer): bool
{
$submission = $answerRecord->quizSubmission;

return !$submission->isClosed && $submission->user_id === $user->id && $answerRecord->question_id === $answer->question_id;
}
}
1 change: 1 addition & 0 deletions database/factories/QuizSubmissionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public function definition(): array
return [
"quiz_id" => Quiz::factory()->locked(),
"user_id" => User::factory(),
"closed_at" => Carbon::now()->addSeconds(3600),
];
}

Expand Down
2 changes: 2 additions & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

declare(strict_types=1);

use App\Http\Controllers\AnswerRecordController;
use App\Http\Controllers\QuestionAnswerController;
use App\Http\Controllers\QuizController;
use App\Http\Controllers\QuizQuestionController;
Expand Down Expand Up @@ -41,3 +42,4 @@

Route::post("/quizzes/{quiz}/start", [QuizController::class, "createSubmission"])->middleware(EnsureQuizIsNotAlreadyStarted::class)->can("submit,quiz");
Route::get("/submissions/{quizSubmission}/", [QuizSubmissionController::class, "show"])->can("view,quizSubmission");
Route::patch("/answers/{answerRecord}/{answer}", [AnswerRecordController::class, "answer"])->can("answer,answerRecord,answer");
125 changes: 125 additions & 0 deletions tests/Feature/AnswerRecordTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Models\Answer;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AnswerRecordTest extends TestCase
{
use RefreshDatabase;

protected User $user;

protected function setUp(): void
{
parent::setUp();

$this->user = User::factory()->create();
}

public function testUserCanAnswerQuestion(): void
{
$answer = Answer::factory()->locked()->create();
$submission = $answer->question->quiz->createSubmission($this->user);
$record = $submission->answerRecords[0];

$this->actingAs($this->user)
->from("/")
->patch("/answers/{$record->id}/{$answer->id}")
->assertRedirect("/");

$this->assertDatabaseHas("answer_records", [
"id" => $record->id,
"answer_id" => $answer->id,
]);
}

public function testUserCannotAnswerQuestionThatNotExisted(): void
{
$answer = Answer::factory()->locked()->create();

$this->actingAs($this->user)
->patch("/answers/0/{$answer->id}")
->assertStatus(404);
}

public function testUserCannotAnswerQuestionThatIsNotTheirs(): void
{
$user = User::factory()->create();
$answer = Answer::factory()->locked()->create();
$submission = $answer->question->quiz->createSubmission($user);
$record = $submission->answerRecords[0];

$this->actingAs($this->user)
->from("/")
->patch("/answers/{$record->id}/{$answer->id}")
->assertStatus(403);

$this->assertDatabaseMissing("answer_records", [
"id" => $record->id,
"answer_id" => $answer->id,
]);
}

public function testUserCannotAnswerQuestionThatBelongsToClosedSubmission(): void
{
$answer = Answer::factory()->locked()->create();
$submission = $answer->question->quiz->createSubmission($this->user);
$record = $submission->answerRecords[0];

$submission->closed_at = Carbon::now();
$submission->save();

$this->actingAs($this->user)
->from("/")
->patch("/answers/{$record->id}/{$answer->id}")
->assertStatus(403);

$this->assertDatabaseMissing("answer_records", [
"id" => $record->id,
"answer_id" => $answer->id,
]);
}

public function testUserCannotAnswerQuestionWithAnswerThatNotExist(): void
{
$answer = Answer::factory()->locked()->create();
$submission = $answer->question->quiz->createSubmission($this->user);
$record = $submission->answerRecords[0];

$this->actingAs($this->user)
->from("/")
->patch("/answers/{$record->id}/4")
->assertStatus(404);

$this->assertDatabaseMissing("answer_records", [
"id" => $record->id,
"answer_id" => $answer->id,
]);
}

public function testUserCannotAnswerQuestionWithAnswerNotAssignedToIt(): void
{
$answer = Answer::factory()->locked()->create();
$submission = $answer->question->quiz->createSubmission($this->user);
$record = $submission->answerRecords[0];

$answer1 = Answer::factory()->locked()->create();

$this->actingAs($this->user)
->from("/")
->patch("/answers/{$record->id}/{$answer1->id}")
->assertStatus(403);

$this->assertDatabaseMissing("answer_records", [
"id" => $record->id,
"answer_id" => $answer1->id,
]);
}
}

0 comments on commit 13b32a2

Please sign in to comment.