Commit 99e6157e authored by Jacob Priddy's avatar Jacob Priddy 👌
Browse files

integrate door version into crud

parent 800ddff3
Pipeline #9538 passed with stages
in 3 minutes and 4 seconds
......@@ -102,6 +102,11 @@ class DoorGuard implements Guard
return (bool)$this->retrieveByToken($credentials[$this->inputKey]);
}
protected function getDoorVersion(): ?string
{
return $this->request->header('Door-Controller-Version', null);
}
/**
* @param string|null $token
*
......@@ -111,7 +116,9 @@ class DoorGuard implements Guard
{
$presenter = new TranslationPresenter();
$this->authenticator->check($presenter, $token);
$version = $this->getDoorVersion();
$this->authenticator->check($presenter, $token, $version);
return $presenter->getViewModel();
}
......
......@@ -20,9 +20,9 @@ class CreateDoorsTable extends Migration
$table->string('name')->unique();
// hashed
$table->string('api_token')->unique();
$table->string('version')->nullable();
$table->string('version')->nullable()->default(null);
$table->timestamp('last_seen_at')->nullable()->default(null);
$table->timestamps();
$table->timestamp('last_seen_at')->nullable();
});
}
......
......@@ -42,11 +42,14 @@ class Door
*/
protected ?Carbon $lastSeenAt;
protected ?string $version;
/**
* @param int $id
* @param string $location
* @param string $name
* @param \Source\Entities\HashedSearchable $token
* @param string|null $version
* @param Carbon|null $createdAt
* @param Carbon|null $updatedAt
* @param \Carbon\Carbon|null $lastSeenAt
......@@ -56,6 +59,7 @@ class Door
string $location,
string $name,
HashedSearchable $token,
?string $version = null,
?Carbon $createdAt = null,
?Carbon $updatedAt = null,
?Carbon $lastSeenAt = null
......@@ -67,6 +71,15 @@ class Door
$this->createdAt = $createdAt;
$this->updatedAt = $updatedAt;
$this->lastSeenAt = $lastSeenAt;
$this->version = $version;
}
/**
* @return string|null
*/
public function getVersion(): ?string
{
return $this->version;
}
/**
......@@ -157,7 +170,7 @@ class Door
*/
public function hasIdOf(?string $id): bool
{
if (!$id) {
if ($id === null) {
return false;
}
......@@ -165,10 +178,26 @@ class Door
}
/**
* @param string $id
* @param int $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* @param \Carbon\Carbon|null $lastSeenAt
*/
public function setLastSeenAt(?Carbon $lastSeenAt): void
{
$this->lastSeenAt = $lastSeenAt;
}
/**
* @param string|null $version
*/
public function setVersion(?string $version): void
{
$this->version = $version;
}
}
......@@ -27,6 +27,8 @@ class DatabaseDoorsRepository implements DoorsRepository
$dbDoor->setAttribute('location', $door->getLocation());
$dbDoor->setAttribute('name', $door->getName());
$dbDoor->setAttribute('api_token', $door->getToken()->getHash());
$dbDoor->setAttribute('version', $door->getVersion());
$dbDoor->setAttribute('last_seen_at', $door->getLastSeenAt());
if (!$dbDoor->save()) {
return null;
......@@ -42,6 +44,7 @@ class DatabaseDoorsRepository implements DoorsRepository
$door->getAttribute('location'),
$door->getAttribute('name'),
new HashedSearchable($door->getAttribute('api_token')),
$door->getAttribute('version'),
$door->getAttribute('created_at'),
$door->getAttribute('updated_at'),
$door->getAttribute('last_seen_at')
......@@ -64,13 +67,26 @@ class DatabaseDoorsRepository implements DoorsRepository
return null;
}
// Anytime a door is matched update last_seen_at
$door->setAttribute('last_seen_at', Carbon::now());
$door->save();
return self::makeDoorFromDb($door);
}
/**
* @inheritDoc
*/
public function touch(string $doorId, Carbon $seen, ?string $version): void
{
$updated = [
'last_seen_at' => $seen,
];
// If we have a new version to set, set it.
if ($version) {
$updated['version'] = $version;
}
\App\Door::query()->where('id', $this->castToInt($doorId))->update($updated);
}
/**
* @inheritDoc
*/
......@@ -139,6 +155,8 @@ class DatabaseDoorsRepository implements DoorsRepository
$dbDoor->setAttribute('name', $door->getName());
$dbDoor->setAttribute('location', $door->getLocation());
$dbDoor->setAttribute('api_token', $door->getToken()->getHash());
$dbDoor->setAttribute('version', $door->getVersion());
$dbDoor->setAttribute('last_seen_at', $door->getLastSeenAt());
$dbDoor->save();
......
......@@ -3,6 +3,7 @@
namespace Source\Gateways\Doors;
use Carbon\Carbon;
use Source\Entities\Door;
use Source\Entities\HashedSearchable;
......@@ -32,6 +33,13 @@ interface DoorsRepository
*/
public function getByToken(?HashedSearchable $token): ?Door;
/**
* @param string $doorId
* @param \Carbon\Carbon $seen
* @param string|null $version
*/
public function touch(string $doorId, Carbon $seen, ?string $version): void;
/**
* Get a door by ID
*
......
......@@ -3,6 +3,7 @@
namespace Source\Gateways\Doors;
use Carbon\Carbon;
use Source\Entities\Door;
use Source\Entities\HashedSearchable;
use Source\Exceptions\EntityExistsException;
......@@ -40,6 +41,20 @@ class InMemoryDoorsRepository implements DoorsRepository
return null;
}
/**
* @inheritDoc
*/
public function touch(string $doorId, Carbon $seen, ?string $version): void
{
foreach ($this->doors as $door) {
if ($door->hasIdOf($doorId)) {
$door->setVersion($version);
$door->setLastSeenAt($seen);
return;
}
}
}
/**
* @inheritDoc
*/
......
......@@ -25,7 +25,8 @@ class LocalDoorsRepository extends InMemoryDoorsRepository
1,
'The Amazon',
'chicken izta door',
HashedSearchable::hash($salt, 'door_1_api_token')
HashedSearchable::hash($salt, 'door_1_api_token'),
'door version here'
);
}
......
......@@ -98,6 +98,7 @@ abstract class BasePresenter
'id' => $door->getId(),
'name' => $door->getName(),
'location' => $door->getLocation(),
'version' => $door->getVersion() ?? 'Unknown',
'created_at' => $this->formatDateTime($door->getCreatedAt()),
'updated_at' => $this->formatDateTime($door->getUpdatedAt()),
'last_seen_at' => $this->formatDateTime($door->getLastSeenAt()),
......
......@@ -2,6 +2,7 @@
namespace Source\UseCases\Door\Authenticate;
use Carbon\Carbon;
use Source\Entities\HashedSearchable;
use Source\Gateways\Doors\DoorsRepository;
......@@ -30,10 +31,14 @@ class Authenticate implements AuthenticateUseCase
/**
* @inheritDoc
*/
public function check(Presenter $presenter, ?string $token): void
public function check(Presenter $presenter, ?string $token, ?string $version): void
{
$found = $this->doors->getByToken(HashedSearchable::hash($this->salt, $token));
if ($found) {
$this->doors->touch($found->getId(), Carbon::now(), $version);
}
$response = new ResponseModel();
$response->setDoor($found);
......
......@@ -7,9 +7,11 @@ interface AuthenticateUseCase
{
/**
* Authenticates a door token
* Pass in the version to set it in the database.
*
* @param Presenter $presenter
* @param string|null $token
* @param string|null $version
*/
public function check(Presenter $presenter, ?string $token): void;
public function check(Presenter $presenter, ?string $token, ?string $version): void;
}
......@@ -47,6 +47,7 @@ class GenerateDoorToken implements GenerateDoorTokenUseCase
$door->getLocation(),
$door->getName(),
HashedSearchable::hash($this->salt, $token),
$door->getVersion(),
$door->getCreatedAt(),
$door->getUpdatedAt()
);
......
......@@ -13,6 +13,7 @@ interface GenerateDoorTokenUseCase
* @param string $doorId
* @param \Source\UseCases\Doors\CreateDoor\Presenter $presenter
* @throws \Source\Exceptions\EntityNotFoundException
* @throws \Source\Exceptions\EntityExistsException
*/
public function generate(string $doorId, Presenter $presenter): void;
}
......@@ -24,7 +24,7 @@ class UpdateDoor implements UpdateDoorUseCase
/**
* @inheritDoc
*/
public function update(string $doorId, array $attributes, Presenter $presenter)
public function update(string $doorId, array $attributes, Presenter $presenter): void
{
$door = $this->doors->get($doorId);
......
......@@ -13,8 +13,8 @@ interface UpdateDoorUseCase
* @param string $doorId
* @param array $attributes
* @param \Source\UseCases\Doors\UpdateDoor\Presenter $presenter
* @return mixed
* @throws \Source\Exceptions\EntityNotFoundException
* @throws \Source\Exceptions\EntityExistsException
*/
public function update(string $doorId, array $attributes, Presenter $presenter);
public function update(string $doorId, array $attributes, Presenter $presenter): void;
}
......@@ -3,6 +3,7 @@
namespace Tests\Database;
use Carbon\Carbon;
use Source\Entities\Door;
use Tests\DatabaseTestCase;
use Source\Entities\HashedSearchable;
......@@ -32,7 +33,6 @@ class DoorDatabaseTest extends DatabaseTestCase
$this->assertEquals('loc', $found->getLocation());
$this->assertEquals('name', $found->getName());
$this->assertNotNull($found->getLastSeenAt());
$this->assertNull($this->doors->getByToken(new HashedSearchable('i am autistic')));
$this->assertNotNull($this->doors->get($d->getId()));
......@@ -126,4 +126,32 @@ class DoorDatabaseTest extends DatabaseTestCase
$this->doors->create(new Door(0, 'loc', 'taken name', new HashedSearchable('token2')));
$this->doors->update($d->getId(), new Door(0, 'new loc', 'taken name', new HashedSearchable('new tok')));
}
/**
* @test
* @throws \Source\Exceptions\EntityExistsException
*/
public function it_touches_doors(): void
{
$now = new Carbon('2020-05-21 01:33:50');
$d = $this->doors->create(new Door(0, 'loc', 'name', new HashedSearchable('token1')));
$this->doors->touch($d->getId(), $now, 'version');
$actual = $this->doors->get($d->getId());
$this->assertEquals($now, $actual->getLastSeenAt());
$this->assertEquals('version', $actual->getVersion());
}
/**
* @test
* @throws \Source\Exceptions\EntityExistsException
*/
public function it_touches_doors_with_null_version(): void
{
$now = new Carbon('2020-05-21 01:33:50');
$d = $this->doors->create(new Door(0, 'loc', 'name', new HashedSearchable('token1'), 'version'));
$this->doors->touch($d->getId(), $now, null);
$actual = $this->doors->get($d->getId());
$this->assertEquals($now, $actual->getLastSeenAt());
$this->assertEquals('version', $actual->getVersion());
}
}
......@@ -23,7 +23,7 @@ class DoorAuthenticateUseCaseStub implements AuthenticateUseCase
/**
* @inheritDoc
*/
public function check(Presenter $presenter, ?string $token): void
public function check(Presenter $presenter, ?string $token, ?string $version): void
{
$response = new ResponseModel();
......
......@@ -40,10 +40,11 @@ class UseCaseTest extends TestCase
/**
* @param string|null $token
* @param string|null $version
*/
public function handleTest(?string $token): void
public function handleTest(?string $token, ?string $version = null): void
{
$this->useCase->check($this->presenter, $token);
$this->useCase->check($this->presenter, $token, $version);
$this->response = $this->presenter->response;
}
......@@ -89,4 +90,30 @@ class UseCaseTest extends TestCase
$this->assertNull($this->response->getDoor());
}
/**
* @test
* @throws \Source\Exceptions\EntityExistsException
*/
public function it_updates_the_version(): void
{
$this->doors->create(new Door(0, '', '', HashedSearchable::hash('', 'token')));
$this->handleTest('token', 'version');
$this->assertEquals('version', $this->response->getDoor()->getVersion());
}
/**
* @test
* @throws \Source\Exceptions\EntityExistsException
*/
public function it_updates_the_last_seen_at(): void
{
$this->doors->create(new Door(0, '', '', HashedSearchable::hash('', 'token')));
$this->handleTest('token', 'version');
$this->assertNotNull($this->response->getDoor()->getLastSeenAt());
}
}
......@@ -54,6 +54,7 @@ class PresenterTest extends TestCase
'location',
'nameeee yee haw',
new HashedSearchable('how are you'),
'the version',
new Carbon('2020-03-11 00:49:25'),
new Carbon('2020-03-11 00:49:29'),
new Carbon('2020-04-10 18:49:00')
......@@ -63,6 +64,32 @@ class PresenterTest extends TestCase
'id' => 69,
'location' => 'location',
'name' => 'nameeee yee haw',
'version' => 'the version',
'created_at' => '2020-03-11T00:49:25-07:00',
'updated_at' => '2020-03-11T00:49:29-07:00',
'last_seen_at' => '2020-04-10T18:49:00-07:00',
], $this->response['door']);
}
/** @test */
public function it_formats_a_door_with_no_version(): void
{
$this->handleTest(new Door(
69,
'location',
'nameeee yee haw',
new HashedSearchable('how are you'),
null,
new Carbon('2020-03-11 00:49:25'),
new Carbon('2020-03-11 00:49:29'),
new Carbon('2020-04-10 18:49:00')
));
$this->assertEquals([
'id' => 69,
'location' => 'location',
'name' => 'nameeee yee haw',
'version' => 'Unknown',
'created_at' => '2020-03-11T00:49:25-07:00',
'updated_at' => '2020-03-11T00:49:29-07:00',
'last_seen_at' => '2020-04-10T18:49:00-07:00',
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment