From 34551e085aa7c231674785f7eaec49887237bafa Mon Sep 17 00:00:00 2001 From: AmonDeShir Date: Mon, 12 Aug 2024 12:36:26 +0200 Subject: [PATCH] add quiz cloning --- app/Http/Controllers/QuizController.php | 12 +++++++ app/Models/Quiz.php | 16 +++++++++ routes/web.php | 1 + tests/Feature/QuizTest.php | 48 +++++++++++++++++++++++++ 4 files changed, 77 insertions(+) diff --git a/app/Http/Controllers/QuizController.php b/app/Http/Controllers/QuizController.php index 111501dd..7fb67303 100644 --- a/app/Http/Controllers/QuizController.php +++ b/app/Http/Controllers/QuizController.php @@ -79,4 +79,16 @@ public function destroy(Quiz $quiz): RedirectResponse ->back() ->with("success", "Quiz deleted"); } + + /** + * @throws AuthorizationException + */ + public function clone(Quiz $quiz): RedirectResponse + { + $quiz->clone(); + + return redirect() + ->back() + ->with("success", "Quiz cloned"); + } } diff --git a/app/Models/Quiz.php b/app/Models/Quiz.php index c38b5bf3..7576f3bd 100644 --- a/app/Models/Quiz.php +++ b/app/Models/Quiz.php @@ -5,6 +5,7 @@ namespace App\Models; use Carbon\Carbon; +use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -47,6 +48,21 @@ public function isLocked(): Attribute return Attribute::get(fn(): bool => $this->locked_at !== null); } + /** + * @throws AuthorizationException + */ + public function clone(): self + { + $quizCopy = $this->replicate(); + $quizCopy->save(); + + foreach ($this->questions as $question) { + $question->cloneTo($quizCopy); + } + + return $quizCopy; + } + protected function casts(): array { return [ diff --git a/routes/web.php b/routes/web.php index c8a188e0..54d9c4c6 100644 --- a/routes/web.php +++ b/routes/web.php @@ -11,6 +11,7 @@ Route::get("/", fn(): Response => inertia("Welcome")); Route::post("/quizzes/{quiz}/lock", [QuizController::class, "lock"]); +Route::post("/quizzes/{quiz}/clone/", [QuizController::class, "clone"]); Route::post("/questions/{question}/clone/{quiz}", [QuizQuestionController::class, "clone"]); Route::post("/answers/{answer}/correct", [QuestionAnswerController::class, "markAsCorrect"]); Route::post("/answers/{answer}/invalid", [QuestionAnswerController::class, "markAsInvalid"]); diff --git a/tests/Feature/QuizTest.php b/tests/Feature/QuizTest.php index ef680a89..bacd41d7 100644 --- a/tests/Feature/QuizTest.php +++ b/tests/Feature/QuizTest.php @@ -227,4 +227,52 @@ public function testUserCannotDeleteQuestionThatNotExisted(): void ->delete("/quizzes/1") ->assertStatus(404); } + + public function testUserCanCopyQuiz(): void + { + $user = User::factory()->create(); + $quiz = Quiz::factory()->create(); + $questions = Question::factory()->count(2)->create(["quiz_id" => $quiz->id]); + + Answer::factory()->count(10)->create(["question_id" => $questions[0]->id]); + Answer::factory()->count(10)->create(["question_id" => $questions[1]->id]); + + $this->assertDatabaseCount("quizzes", 1); + $this->assertDatabaseCount("questions", 2); + $this->assertDatabaseCount("answers", 20); + + $this->actingAs($user) + ->from("/") + ->post("/quizzes/{$quiz->id}/clone") + ->assertRedirect("/"); + + $this->assertDatabaseCount("quizzes", 2); + $this->assertDatabaseCount("questions", 4); + $this->assertDatabaseCount("answers", 40); + } + + public function testUserCanCopyLockedQuiz(): void + { + $user = User::factory()->create(); + $quiz = Quiz::factory()->locked()->create(); + + $this->assertDatabaseCount("quizzes", 1); + + $this->actingAs($user) + ->from("/") + ->post("/quizzes/{$quiz->id}/clone") + ->assertRedirect("/"); + + $this->assertDatabaseCount("quizzes", 2); + } + + public function testUserCannotCopyQuizThatNotExisted(): void + { + $user = User::factory()->create(); + + $this->actingAs($user) + ->from("/") + ->post("/quizzes/2/clone") + ->assertStatus(404); + } }