diff --git a/db/factories/SessionFactory.php b/db/factories/SessionFactory.php index 08768512..ee874341 100644 --- a/db/factories/SessionFactory.php +++ b/db/factories/SessionFactory.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Database\Factories\Engelsystem\Models; use Engelsystem\Models\Session; +use Engelsystem\Models\User\User; use Illuminate\Database\Eloquent\Factories\Factory; class SessionFactory extends Factory @@ -17,6 +18,7 @@ class SessionFactory extends Factory return [ 'id' => $this->faker->lexify('??????????'), 'payload' => $this->faker->text(100), + 'user_id' => $this->faker->optional()->passthrough(User::factory()), ]; } } diff --git a/db/migrations/2023_09_17_000000_add_user_to_sessions_table.php b/db/migrations/2023_09_17_000000_add_user_to_sessions_table.php new file mode 100644 index 00000000..935e5be9 --- /dev/null +++ b/db/migrations/2023_09_17_000000_add_user_to_sessions_table.php @@ -0,0 +1,34 @@ +schema->table('sessions', function (Blueprint $table): void { + $this->referencesUser($table)->nullable()->index()->after('payload'); + }); + } + + /** + * Reverse the migration + */ + public function down(): void + { + $this->schema->table('sessions', function (Blueprint $table): void { + $table->dropForeign('sessions_user_id_foreign'); + $table->dropColumn('user_id'); + }); + } +} diff --git a/src/Http/SessionHandlers/DatabaseHandler.php b/src/Http/SessionHandlers/DatabaseHandler.php index 1a7525d5..5851fa8b 100644 --- a/src/Http/SessionHandlers/DatabaseHandler.php +++ b/src/Http/SessionHandlers/DatabaseHandler.php @@ -33,6 +33,7 @@ class DatabaseHandler extends AbstractHandler $session->id = $id; $session->payload = $data; $session->last_activity = Carbon::now(); + $session->user_id = auth()->user()?->id; $session->save(); // The save return can't be used directly as it won't change if the second call is in the same second diff --git a/src/Models/Session.php b/src/Models/Session.php index 04a224f0..f91ca6af 100644 --- a/src/Models/Session.php +++ b/src/Models/Session.php @@ -5,14 +5,19 @@ declare(strict_types=1); namespace Engelsystem\Models; use Carbon\Carbon; +use Engelsystem\Models\User\User; +use Engelsystem\Models\User\UsesUserModel; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; /** * @property string $id * @property string $payload + * @property int|null $user_id * @property Carbon $last_activity * + * @property-read User|null $user + * * @method static Builder|Session whereId($value) * @method static Builder|Session wherePayload($value) * @method static Builder|Session whereLastActivity($value) @@ -20,6 +25,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; class Session extends BaseModel { use HasFactory; + use UsesUserModel; public $incrementing = false; // phpcs:ignore @@ -28,6 +34,7 @@ class Session extends BaseModel /** @var array default attributes */ protected $attributes = [ // phpcs:ignore 'payload' => '', + 'user_id' => null, ]; /** @var array */ @@ -39,5 +46,11 @@ class Session extends BaseModel protected $fillable = [ // phpcs:ignore 'id', 'payload', + 'user_id', + ]; + + /** @var array */ + protected $casts = [ // phpcs:ignore + 'user_id' => 'integer', ]; } diff --git a/src/Models/User/User.php b/src/Models/User/User.php index 25c21e5b..b218e3fe 100644 --- a/src/Models/User/User.php +++ b/src/Models/User/User.php @@ -14,6 +14,7 @@ use Engelsystem\Models\NewsComment; use Engelsystem\Models\OAuth; use Engelsystem\Models\Privilege; use Engelsystem\Models\Question; +use Engelsystem\Models\Session; use Engelsystem\Models\Shifts\Shift; use Engelsystem\Models\Shifts\ShiftEntry; use Engelsystem\Models\UserAngelType; @@ -52,6 +53,7 @@ use Illuminate\Support\Collection as SupportCollection; * @property-read Collection|AngelType[] $userAngelTypes * @property-read UserAngelType $pivot * @property-read Collection|ShiftEntry[] $shiftEntries + * @property-read Collection|Session[] $sessions * @property-read Collection|Worklog[] $worklogs * @property-read Collection|Worklog[] $worklogsCreated * @property-read Collection|Question[] $questionsAsked @@ -222,6 +224,11 @@ class User extends BaseModel return $this->hasMany(Worklog::class, 'creator_id'); } + public function sessions(): HasMany + { + return $this->hasMany(Session::class); + } + public function questionsAsked(): HasMany { return $this->hasMany(Question::class, 'user_id') diff --git a/tests/Unit/Http/SessionHandlers/DatabaseHandlerTest.php b/tests/Unit/Http/SessionHandlers/DatabaseHandlerTest.php index 9f6ed6b8..f76f99c4 100644 --- a/tests/Unit/Http/SessionHandlers/DatabaseHandlerTest.php +++ b/tests/Unit/Http/SessionHandlers/DatabaseHandlerTest.php @@ -5,8 +5,11 @@ declare(strict_types=1); namespace Engelsystem\Test\Unit\Http\SessionHandlers; use Engelsystem\Config\Config; +use Engelsystem\Helpers\Authenticator; use Engelsystem\Helpers\Carbon; use Engelsystem\Http\SessionHandlers\DatabaseHandler; +use Engelsystem\Models\Session; +use Engelsystem\Models\User\User; use Engelsystem\Test\Unit\HasDatabase; use Engelsystem\Test\Unit\TestCase; @@ -36,16 +39,34 @@ class DatabaseHandlerTest extends TestCase */ public function testWrite(): void { + $user = User::factory()->create(); + $auth = $this->createMock(Authenticator::class); + $auth->expects($this->exactly(2)) + ->method('user') + ->willReturnOnConsecutiveCalls(null, $user); + $this->app->instance('authenticator', $auth); + $handler = new DatabaseHandler($this->database); + $userExists = false; foreach (['Lorem Ipsum', 'Dolor Sit!'] as $data) { $this->assertTrue($handler->write('id-foo', $data)); $return = Session::whereId('id-foo')->get(); $this->assertCount(1, $return); - $return = $return->first(); - $this->assertEquals($data, $return->payload); + /** @var Session $session */ + $session = $return->first(); + $this->assertEquals($data, $session->payload); + + if ($userExists) { + $this->assertNotNull($session->user); + $this->assertEquals($user->id, $session->user->id); + } else { + $this->assertNull($session->user); + } + + $userExists = true; } } diff --git a/tests/Unit/Models/SessionTest.php b/tests/Unit/Models/SessionTest.php index d965d331..3055f84f 100644 --- a/tests/Unit/Models/SessionTest.php +++ b/tests/Unit/Models/SessionTest.php @@ -6,6 +6,7 @@ namespace Engelsystem\Test\Unit\Models; use Engelsystem\Helpers\Carbon; use Engelsystem\Models\Session; +use Engelsystem\Models\User\User; /** * This class provides tests for the Session model @@ -19,9 +20,11 @@ class SessionTest extends ModelTest */ public function testCreate(): void { + $user = User::factory()->create(); Session::create([ 'id' => 'foo', 'payload' => 'lorem ipsum', + 'user_id' => $user->id, 'last_activity' => Carbon::now(), ]); Session::create([ @@ -32,5 +35,9 @@ class SessionTest extends ModelTest $session = Session::find('foo'); $this->assertNotNull($session); $this->assertEquals('lorem ipsum', $session->payload); + $this->assertInstanceOf(User::class, $session->user); + + $session = Session::find('bar'); + $this->assertNull($session->user); } } diff --git a/tests/Unit/Models/User/UserTest.php b/tests/Unit/Models/User/UserTest.php index 8f2092ea..1cfe08ff 100644 --- a/tests/Unit/Models/User/UserTest.php +++ b/tests/Unit/Models/User/UserTest.php @@ -15,6 +15,7 @@ use Engelsystem\Models\NewsComment; use Engelsystem\Models\OAuth; use Engelsystem\Models\Privilege; use Engelsystem\Models\Question; +use Engelsystem\Models\Session; use Engelsystem\Models\Shifts\Shift; use Engelsystem\Models\Shifts\ShiftEntry; use Engelsystem\Models\User\Contact; @@ -375,6 +376,22 @@ class UserTest extends ModelTest $this->assertCount(2, $user->shiftEntries); } + /** + * @covers \Engelsystem\Models\User\User::sessions + */ + public function testSessions(): void + { + $user = new User($this->data); + $user->save(); + + Session::factory(2)->create(); + Session::factory(3)->create(['user_id' => $user->id]); + Session::factory(2)->create(); + Session::factory(4)->create(['user_id' => $user->id]); + + $this->assertCount(7, $user->sessions); + } + /** * @covers \Engelsystem\Models\User\User::worklogs */