diff --git a/app/Jobs/UserCreateJob.php b/app/Jobs/UserCreateJob.php index 42c0742a..e875eda5 100644 --- a/app/Jobs/UserCreateJob.php +++ b/app/Jobs/UserCreateJob.php @@ -33,7 +33,7 @@ public function handle() { 'verified' => $this->verified, ]); - $latest = TermsOfUseVersion::latestActiveVersion(); + $latest = TermsOfUseVersion::getActiveVersion(); if ($latest) { UserTermsOfUseAcceptance::create([ 'user_id' => $user->id, diff --git a/app/Jobs/UserTouAcceptanceJob.php b/app/Jobs/UserTouAcceptanceJob.php index 964d3ff4..6bdcff45 100644 --- a/app/Jobs/UserTouAcceptanceJob.php +++ b/app/Jobs/UserTouAcceptanceJob.php @@ -28,7 +28,7 @@ public function handle(): void { try { UserTermsOfUseAcceptance::create([ 'user_id' => $user->id, - 'tou_version' => TermsOfUseVersion::latestActiveVersion()->version, + 'tou_version' => TermsOfUseVersion::getActiveVersion()->version, 'tou_accepted_at' => $user->created_at, ]); } catch (Throwable $exception) { diff --git a/app/TermsOfUseVersion.php b/app/TermsOfUseVersion.php index e4472407..ada1b1f6 100644 --- a/app/TermsOfUseVersion.php +++ b/app/TermsOfUseVersion.php @@ -29,7 +29,26 @@ class TermsOfUseVersion extends Model { 'active' => 'boolean', ]; - public static function latestActiveVersion(): ?self { - return self::query()->where('active', true)->latest()->first(); + /** + * Get the active ToU version. + */ + public static function getActiveVersion(): ?self { + return self::query()->where('active', true)->first(); + } + + /** + * Ensure only one ToU version remains active after any save operation. + */ + protected static function booted(): void { + static::saving(function (self $model): void { + if (!$model->active) { + return; + } + + self::query() + ->where('version', '!=', $model->version) + ->where('active', true) + ->update(['active' => false]); + }); } } diff --git a/tests/Jobs/UserTermsOfUseAcceptanceTest.php b/tests/Jobs/UserTermsOfUseAcceptanceTest.php index ddbf70ec..cc431d8b 100644 --- a/tests/Jobs/UserTermsOfUseAcceptanceTest.php +++ b/tests/Jobs/UserTermsOfUseAcceptanceTest.php @@ -19,14 +19,14 @@ public function testUserCreationCreatesTouAcceptance(): void { $this->assertDatabaseHas('tou_acceptances', [ 'user_id' => $user->id, - 'tou_version' => TermsOfUseVersion::latestActiveVersion()->version, + 'tou_version' => TermsOfUseVersion::getActiveVersion()->version, ]); $rows = UserTermsOfUseAcceptance::where('user_id', $user->id)->get(); $this->assertCount(1, $rows); $acceptance = $rows->first(); - $this->assertSame(TermsOfUseVersion::latestActiveVersion()->version, $acceptance->tou_version); + $this->assertSame(TermsOfUseVersion::getActiveVersion()->version, $acceptance->tou_version); $this->assertNotNull($acceptance->tou_accepted_at); } } diff --git a/tests/Jobs/UserTouAcceptanceJobTest.php b/tests/Jobs/UserTouAcceptanceJobTest.php index 5f804ca5..e7a846e5 100644 --- a/tests/Jobs/UserTouAcceptanceJobTest.php +++ b/tests/Jobs/UserTouAcceptanceJobTest.php @@ -26,7 +26,7 @@ public function testTouAcceptanceJob(): void { (new CreateFirstTermsOfUseVersionJob)->handle(); (new UserTouAcceptanceJob)->handle(); - $latest = TermsOfUseVersion::latestActiveVersion()->version; + $latest = TermsOfUseVersion::getActiveVersion()->version; $this->assertDatabaseHas('tou_acceptances', ['user_id' => $u1->id, 'tou_version' => $latest]); $this->assertDatabaseHas('tou_acceptances', ['user_id' => $u2->id, 'tou_version' => $latest]); diff --git a/tests/Models/TermsOfUseVersionTest.php b/tests/Models/TermsOfUseVersionTest.php new file mode 100644 index 00000000..bba866e4 --- /dev/null +++ b/tests/Models/TermsOfUseVersionTest.php @@ -0,0 +1,40 @@ + '2024-01-01', + 'active' => true, + ]); + + $second = TermsOfUseVersion::create([ + 'version' => '2025-01-01', + 'active' => true, + ]); + + $this->assertFalse($first->fresh()->active); + $this->assertTrue($second->fresh()->active); + } + + public function testSavingInactiveVersionDoesNotAffectExistingActiveVersion(): void { + $active = TermsOfUseVersion::create([ + 'version' => '2024-03-01', + 'active' => true, + ]); + + TermsOfUseVersion::create([ + 'version' => '2024-04-01', + 'active' => false, + ]); + + $this->assertTrue($active->fresh()->active); + } +}