Commit 95157362 authored by Jacob Priddy's avatar Jacob Priddy 👌
Browse files

Make attempts and entries use shallow linking by location

so that they are not hard attached to doors. E.G. when a door gets
deleted the history sticks around, or if a door gets moved, it's tied to
location.

Also updated the authorizer to pass around a full door since it is there
anyway...
parent 5f489423
Pipeline #12511 passed with stages
in 2 minutes and 36 seconds
...@@ -3,17 +3,8 @@ ...@@ -3,17 +3,8 @@
namespace App; namespace App;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Attempt extends Model class Attempt extends Model
{ {
protected $fillable = ['door_id']; protected $fillable = ['door_location'];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function door(): BelongsTo
{
return $this->belongsTo(Door::class);
}
} }
...@@ -20,22 +20,6 @@ class Door extends Authenticatable ...@@ -20,22 +20,6 @@ class Door extends Authenticatable
return $this->belongsToMany(Group::class); return $this->belongsToMany(Group::class);
} }
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function entries(): HasMany
{
return $this->hasMany(Entry::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function attempts(): HasMany
{
return $this->hasMany(Attempt::class);
}
/** /**
* @return \Illuminate\Database\Eloquent\Relations\HasMany * @return \Illuminate\Database\Eloquent\Relations\HasMany
*/ */
...@@ -44,7 +28,7 @@ class Door extends Authenticatable ...@@ -44,7 +28,7 @@ class Door extends Authenticatable
return $this->hasMany(Override::class); return $this->hasMany(Override::class);
} }
public static function boot() public static function boot(): void
{ {
parent::boot(); parent::boot();
...@@ -52,18 +36,6 @@ class Door extends Authenticatable ...@@ -52,18 +36,6 @@ class Door extends Authenticatable
// Detach all groups // Detach all groups
$door->groups()->detach(); $door->groups()->detach();
// Delete all entries
/** @var \App\Entry $entry */
foreach ($door->entries() as $entry) {
$entry->delete();
}
// Delete all attempts
/** @var \App\Attempt $attempt */
foreach ($door->attempts() as $attempt) {
$attempt->delete();
}
// Delete all overrides // Delete all overrides
/** @var \App\Override $override */ /** @var \App\Override $override */
foreach ($door->overrides() as $override) { foreach ($door->overrides() as $override) {
......
...@@ -7,15 +7,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; ...@@ -7,15 +7,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Entry extends Model class Entry extends Model
{ {
protected $fillable = ['door_id', 'user_id', 'success']; protected $fillable = ['door_location', 'user_id', 'success'];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function door(): BelongsTo
{
return $this->belongsTo(Door::class);
}
/** /**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
......
...@@ -3,10 +3,12 @@ ...@@ -3,10 +3,12 @@
namespace App\Guards; namespace App\Guards;
use Source\Entities\Door;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Auth\GuardHelpers; use Illuminate\Auth\GuardHelpers;
use Illuminate\Contracts\Auth\Guard; use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable;
use Source\Gateways\Doors\DatabaseDoorsRepository;
use Source\UseCases\Door\Authenticate\AuthenticateUseCase; use Source\UseCases\Door\Authenticate\AuthenticateUseCase;
use Source\UseCases\Door\Authenticate\TranslationPresenter; use Source\UseCases\Door\Authenticate\TranslationPresenter;
...@@ -71,6 +73,21 @@ class DoorGuard implements Guard ...@@ -71,6 +73,21 @@ class DoorGuard implements Guard
return $this->user = $user; return $this->user = $user;
} }
/**
* @return \Source\Entities\Door|null
*/
public function getDoor(): ?Door
{
/** @var \App\Door|null $door */
$door = $this->user();
if ($door) {
return DatabaseDoorsRepository::makeDoorFromDb($door);
}
return null;
}
/** /**
* Get the token for the current request. * Get the token for the current request.
* *
......
...@@ -17,7 +17,7 @@ class AttemptsController extends ApiController ...@@ -17,7 +17,7 @@ class AttemptsController extends ApiController
/** /**
* Get Attempts * Get Attempts
* *
* This route filters attempts based off of starting date, ending date, or door id. * This route filters attempts based off of starting date, ending date, or door location.
* If only start is supplied, all attempts after the start date are given. If only end * If only start is supplied, all attempts after the start date are given. If only end
* is supplied, all attempts before the start date are given. If both dates are supplied, * is supplied, all attempts before the start date are given. If both dates are supplied,
* all attempts between the given dates are returned. This route is paginated. * all attempts between the given dates are returned. This route is paginated.
...@@ -26,9 +26,9 @@ class AttemptsController extends ApiController ...@@ -26,9 +26,9 @@ class AttemptsController extends ApiController
* @paginated * @paginated
* @queryParam start The beginning date to filter attempts by. Example: 2000-06-02 08:11:45 * @queryParam start The beginning date to filter attempts by. Example: 2000-06-02 08:11:45
* @queryParam end The ending date to filter attempts by. Example: 2920-06-02 08:11:45 * @queryParam end The ending date to filter attempts by. Example: 2920-06-02 08:11:45
* @queryParam door_id The door id to filter on. Example: 1 * @queryParam door_location The door location to filter on. Example: The Amazon
* *
* @response 422 {"message":"The given data was invalid.","errors":{"start":["The start is not a valid date."],"end":["The end is not a valid date."],"door_id":["The door id must be an integer."]}} * @response 422 {"message":"The given data was invalid.","errors":{"start":["The start is not a valid date."],"end":["The end is not a valid date."],"door_location":["The door location must be a string."]}}
* *
* @param \Source\UseCases\Attempts\GetAttempts\GetAttemptsUseCase $attempts * @param \Source\UseCases\Attempts\GetAttempts\GetAttemptsUseCase $attempts
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
...@@ -44,7 +44,7 @@ class AttemptsController extends ApiController ...@@ -44,7 +44,7 @@ class AttemptsController extends ApiController
$this->validate($this->request, [ $this->validate($this->request, [
'start' => 'nullable|date', 'start' => 'nullable|date',
'end' => 'nullable|date', 'end' => 'nullable|date',
'door_id' => 'nullable|integer', 'door_location' => 'nullable|string',
]); ]);
$presenter = new GetAttemptsAPIPresenter(); $presenter = new GetAttemptsAPIPresenter();
...@@ -52,7 +52,7 @@ class AttemptsController extends ApiController ...@@ -52,7 +52,7 @@ class AttemptsController extends ApiController
$attempts->getBetweenDates( $attempts->getBetweenDates(
$this->request->input('start'), $this->request->input('start'),
$this->request->input('end'), $this->request->input('end'),
$this->request->input('door_id'), $this->request->input('door_location'),
$presenter $presenter
); );
......
...@@ -93,7 +93,11 @@ class DoorController extends ApiController ...@@ -93,7 +93,11 @@ class DoorController extends ApiController
'doorcode' => 'required|string', 'doorcode' => 'required|string',
]); ]);
$access->protectUserDoorAccessAtTime($this->doorGuard->id(), $this->request->input('doorcode'), Carbon::now()); $access->protectUserDoorAccessAtTime(
$this->doorGuard->getDoor(),
$this->request->input('doorcode'),
Carbon::now()
);
return $this->respondStatus(); return $this->respondStatus();
} }
......
...@@ -25,10 +25,10 @@ class EntriesController extends ApiController ...@@ -25,10 +25,10 @@ class EntriesController extends ApiController
* @paginated * @paginated
* @queryParam start The beginning date to filter entries by. Example: 2000-06-02 08:11:45 * @queryParam start The beginning date to filter entries by. Example: 2000-06-02 08:11:45
* @queryParam end The ending date to filter entries by. Example: 2920-06-02 08:11:45 * @queryParam end The ending date to filter entries by. Example: 2920-06-02 08:11:45
* @queryParam door_id The door id to filter entries on. Example: 1 * @queryParam door_id The door id to filter entries on. Example: Amazon
* @queryParam user_id The user id to filter entries on. Example: 420 * @queryParam user_id The user id to filter entries on. Example: 420
* *
* @response 422 {"message":"The given data was invalid.","errors":{"start":["The start is not a valid date."],"end":["The end is not a valid date."],"door_id":["The door id must be an integer."],"user_id":["The user id must be an integer."]}} * @response 422 {"message":"The given data was invalid.","errors":{"start":["The start is not a valid date."],"end":["The end is not a valid date."],"door_location":["The door location must be a string."],"user_id":["The user id must be an integer."]}}
* *
* @param \Source\UseCases\Entries\GetEntries\GetEntriesUseCase $userEntries * @param \Source\UseCases\Entries\GetEntries\GetEntriesUseCase $userEntries
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
...@@ -43,7 +43,7 @@ class EntriesController extends ApiController ...@@ -43,7 +43,7 @@ class EntriesController extends ApiController
$this->validate($this->request, [ $this->validate($this->request, [
'start' => 'nullable|date', 'start' => 'nullable|date',
'end' => 'nullable|date', 'end' => 'nullable|date',
'door_id' => 'nullable|integer', 'door_location' => 'nullable|string',
'user_id' => 'nullable|integer', 'user_id' => 'nullable|integer',
]); ]);
...@@ -51,7 +51,7 @@ class EntriesController extends ApiController ...@@ -51,7 +51,7 @@ class EntriesController extends ApiController
$userEntries->getEntries( $userEntries->getEntries(
$this->request->input('user_id'), $this->request->input('user_id'),
$this->request->input('door_id'), $this->request->input('door_location'),
$this->request->input('start'), $this->request->input('start'),
$this->request->input('end'), $this->request->input('end'),
$presenter $presenter
......
...@@ -14,13 +14,14 @@ class AttemptsController extends Controller ...@@ -14,13 +14,14 @@ class AttemptsController extends Controller
* @param \Source\UseCases\Attempts\GetAttempts\GetAttemptsUseCase $attempts * @param \Source\UseCases\Attempts\GetAttempts\GetAttemptsUseCase $attempts
* @return \Illuminate\View\View * @return \Illuminate\View\View
* @throws \Illuminate\Validation\ValidationException * @throws \Illuminate\Validation\ValidationException
* @throws \Exception
*/ */
public function index(GetAttemptsUseCase $attempts): View public function index(GetAttemptsUseCase $attempts): View
{ {
$this->validate($this->request, [ $this->validate($this->request, [
'start' => 'nullable|date', 'start' => 'nullable|date',
'end' => 'nullable|date', 'end' => 'nullable|date',
'door_id' => 'nullable|integer', 'door_location' => 'nullable|string',
]); ]);
$start = $this->request->input('start'); $start = $this->request->input('start');
......
...@@ -22,7 +22,7 @@ class EntriesController extends Controller ...@@ -22,7 +22,7 @@ class EntriesController extends Controller
$this->validate($this->request, [ $this->validate($this->request, [
'start' => 'nullable|date', 'start' => 'nullable|date',
'end' => 'nullable|date', 'end' => 'nullable|date',
'door_id' => 'nullable|integer', 'door_location' => 'nullable|string',
'user_id' => 'nullable|integer', 'user_id' => 'nullable|integer',
]); ]);
...@@ -38,7 +38,7 @@ class EntriesController extends Controller ...@@ -38,7 +38,7 @@ class EntriesController extends Controller
$entries->getEntries( $entries->getEntries(
$this->request->input('user_id'), $this->request->input('user_id'),
$this->request->input('door_id'), $this->request->input('door_location'),
$start, $start,
$end, $end,
$presenter $presenter
......
...@@ -17,9 +17,8 @@ class CreateEntriesTable extends Migration ...@@ -17,9 +17,8 @@ class CreateEntriesTable extends Migration
Schema::create('entries', static function (Blueprint $table) { Schema::create('entries', static function (Blueprint $table) {
$table->id(); $table->id();
$table->unsignedBigInteger('user_id'); $table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('door_id'); $table->string('door_location');
$table->boolean('success'); $table->boolean('success');
$table->foreign('door_id')->references('id')->on('doors');
$table->foreign('user_id')->references('id')->on('users'); $table->foreign('user_id')->references('id')->on('users');
$table->timestamps(); $table->timestamps();
}); });
......
...@@ -15,8 +15,7 @@ class CreateAttemptsTable extends Migration ...@@ -15,8 +15,7 @@ class CreateAttemptsTable extends Migration
{ {
Schema::create('attempts', static function (Blueprint $table) { Schema::create('attempts', static function (Blueprint $table) {
$table->id(); $table->id();
$table->unsignedBigInteger('door_id'); $table->string('door_location');
$table->foreign('door_id')->references('id')->on('doors');
$table->timestamps(); $table->timestamps();
}); });
} }
......
...@@ -38,6 +38,12 @@ ...@@ -38,6 +38,12 @@
{{ door($row[$header])['name'] }} (ID: {{ $row[$header] }}) {{ door($row[$header])['name'] }} (ID: {{ $row[$header] }})
</a> </a>
</td> </td>
@elseif($header === 'door_shallow_link')
<td>
<a href="{{ route('web.admin.doors.index', ['query' => $row[$header]]) }}">
{{ $row[$header] }}
</a>
</td>
@elseif($header === 'schedule_id') @elseif($header === 'schedule_id')
<td> <td>
<a href="{{ route('web.admin.schedules.edit', ['scheduleId' => $row[$header]]) }}"> <a href="{{ route('web.admin.schedules.edit', ['scheduleId' => $row[$header]]) }}">
......
...@@ -15,7 +15,7 @@ class Attempt ...@@ -15,7 +15,7 @@ class Attempt
/** /**
* @var int * @var int
*/ */
protected int $doorId; protected string $doorLocation;
/** /**
* @var \Carbon\Carbon|null * @var \Carbon\Carbon|null
...@@ -29,12 +29,12 @@ class Attempt ...@@ -29,12 +29,12 @@ class Attempt
public function __construct( public function __construct(
int $id, int $id,
int $doorId, string $doorLocation,
?Carbon $createdAt = null, ?Carbon $createdAt = null,
?Carbon $updatedAt = null ?Carbon $updatedAt = null
) { ) {
$this->id = $id; $this->id = $id;
$this->doorId = $doorId; $this->doorLocation = $doorLocation;
$this->createdAt = $createdAt; $this->createdAt = $createdAt;
$this->updatedAt = $updatedAt; $this->updatedAt = $updatedAt;
} }
...@@ -48,11 +48,11 @@ class Attempt ...@@ -48,11 +48,11 @@ class Attempt
} }
/** /**
* @return int * @return string
*/ */
public function getDoorId(): int public function getDoorLocation(): string
{ {
return $this->doorId; return $this->doorLocation;
} }
/** /**
...@@ -94,15 +94,15 @@ class Attempt ...@@ -94,15 +94,15 @@ class Attempt
} }
/** /**
* @param string|null $doorId * @param string|null $doorLocation
* @return bool * @return bool
*/ */
public function hasDoorIdOf(?string $doorId): bool public function hasDoorLocationLike(?string $doorLocation): bool
{ {
if (!$doorId) { if (!$doorLocation) {
return false; return false;
} }
return $this->getDoorId() === (int)$doorId; return stripos($this->getDoorLocation(), $doorLocation) !== false;
} }
} }
...@@ -18,9 +18,9 @@ class Entry ...@@ -18,9 +18,9 @@ class Entry
protected int $userId; protected int $userId;
/** /**
* @var int * @var string
*/ */
protected int $doorId; protected string $doorLocation;
/** /**
* @var \Carbon\Carbon|null * @var \Carbon\Carbon|null
...@@ -40,14 +40,14 @@ class Entry ...@@ -40,14 +40,14 @@ class Entry
public function __construct( public function __construct(
int $id, int $id,
int $userId, int $userId,
int $doorId, string $doorLocation,
bool $success, bool $success,
?Carbon $createdAt = null, ?Carbon $createdAt = null,
?Carbon $updatedAt = null ?Carbon $updatedAt = null
) { ) {
$this->id = $id; $this->id = $id;
$this->userId = $userId; $this->userId = $userId;
$this->doorId = $doorId; $this->doorLocation = $doorLocation;
$this->success = $success; $this->success = $success;
$this->createdAt = $createdAt; $this->createdAt = $createdAt;
$this->updatedAt = $updatedAt; $this->updatedAt = $updatedAt;
...@@ -70,11 +70,11 @@ class Entry ...@@ -70,11 +70,11 @@ class Entry
} }
/** /**
* @return int * @return string
*/ */
public function getDoorId(): int public function getDoorLocation(): string
{ {
return $this->doorId; return $this->doorLocation;
} }
/** /**
...@@ -141,15 +141,15 @@ class Entry ...@@ -141,15 +141,15 @@ class Entry
} }
/** /**
* @param string|null $doorId * @param string|null $doorLocation
* @return bool * @return bool
*/ */
public function hasDoorIdOf(?string $doorId): bool public function hasDoorLocationLike(?string $doorLocation): bool
{ {
if (!$doorId) { if (!$doorLocation) {
return false; return false;
} }
return $this->getDoorId() === (int)$doorId; return stripos($this->getDoorLocation(), $doorLocation) !== false;
} }
} }
...@@ -17,8 +17,8 @@ interface AttemptsRepository ...@@ -17,8 +17,8 @@ interface AttemptsRepository
/** /**
* @param \Carbon\Carbon|null $begin * @param \Carbon\Carbon|null $begin
* @param \Carbon\Carbon|null $end * @param \Carbon\Carbon|null $end
* @param string|null $doorId * @param string|null $doorLocation
* @return \Source\Entities\Attempt[] * @return \Source\Entities\Attempt[]
*/ */
public function getBetween(?Carbon $begin = null, ?Carbon $end = null, ?string $doorId = null): array; public function getBetween(?Carbon $begin = null, ?Carbon $end = null, ?string $doorLocation = null): array;
} }
...@@ -19,7 +19,7 @@ class DatabaseAttemptsRepository implements AttemptsRepository ...@@ -19,7 +19,7 @@ class DatabaseAttemptsRepository implements AttemptsRepository
{ {
return new Attempt( return new Attempt(
$attempt->getAttribute('id'), $attempt->getAttribute('id'),
$attempt->getAttribute('door_id'), $attempt->getAttribute('door_location'),
$attempt->getAttribute('created_at'), $attempt->getAttribute('created_at'),
$attempt->getAttribute('updated_at') $attempt->getAttribute('updated_at')
); );
...@@ -28,12 +28,12 @@ class DatabaseAttemptsRepository implements AttemptsRepository ...@@ -28,12 +28,12 @@ class DatabaseAttemptsRepository implements AttemptsRepository
/** /**
* @inheritDoc * @inheritDoc