Commit 00307dc6 authored by Jacob Priddy's avatar Jacob Priddy 👌
Browse files

add unresponsive door count to dashboard

parent e389365f
...@@ -48,12 +48,12 @@ ...@@ -48,12 +48,12 @@
<div class="card-body"> <div class="card-body">
<div class="row no-gutters align-items-center"> <div class="row no-gutters align-items-center">
<div class="col mr-2"> <div class="col mr-2">
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">Earnings (Annual) <div class="text-xs font-weight-bold text-success text-uppercase mb-1">Unresponsive Doors
</div> </div>
<div class="h5 mb-0 font-weight-bold text-gray-800">$215,000</div> <div class="h5 mb-0 font-weight-bold text-gray-800">{{ $missingDoorCount }}</div>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<i class="fas fa-dollar-sign fa-2x text-gray-300"></i> <i class="fas fa-exclamation-triangle fa-2x text-gray-300"></i>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -7,6 +7,11 @@ use Carbon\Carbon; ...@@ -7,6 +7,11 @@ use Carbon\Carbon;
class Door class Door
{ {
/**
* A door is missing if it is AWOL for this much time.
*/
public const AWOL_TIME_SECONDS = 60 * 60 * 8;
/** /**
* @var int * @var int
*/ */
......
...@@ -197,4 +197,19 @@ class DatabaseDoorsRepository implements DoorsRepository ...@@ -197,4 +197,19 @@ class DatabaseDoorsRepository implements DoorsRepository
{ {
return (bool)$this->get($doorId); return (bool)$this->get($doorId);
} }
/**
* @inheritDoc
*/
public function awolFor(int $seconds): array
{
$doors = \App\Door::query()
->whereNotNull('last_seen_at')
->where('last_seen_at', '<', Carbon::now()->subRealSeconds($seconds))
->get();
return array_map(static function (\App\Door $door): Door {
return self::makeDoorFromDb($door);
}, $doors);
}
} }
...@@ -79,4 +79,12 @@ interface DoorsRepository ...@@ -79,4 +79,12 @@ interface DoorsRepository
* @return bool * @return bool
*/ */
public function exists(string $doorId): bool; public function exists(string $doorId): bool;
/**
* Retrieves doors who have not contacted the API in the last x seconds.
*
* @param int $seconds
* @return \Source\Entities\Door[]
*/
public function awolFor(int $seconds): array;
} }
...@@ -127,6 +127,7 @@ class InMemoryDoorsRepository implements DoorsRepository ...@@ -127,6 +127,7 @@ class InMemoryDoorsRepository implements DoorsRepository
$doors = 0; $doors = 0;
$this->doors = array_values(array_filter($this->doors, static function (Door $door) use ($doorId, &$doors) { $this->doors = array_values(array_filter($this->doors, static function (Door $door) use ($doorId, &$doors) {
$doors++; $doors++;
return !$door->hasIdOf($doorId); return !$door->hasIdOf($doorId);
})); }));
...@@ -140,4 +141,16 @@ class InMemoryDoorsRepository implements DoorsRepository ...@@ -140,4 +141,16 @@ class InMemoryDoorsRepository implements DoorsRepository
{ {
return (bool)$this->get($doorId); return (bool)$this->get($doorId);
} }
/**
* @inheritDoc
*/
public function awolFor(int $seconds): array
{
$compare = Carbon::now()->subRealSeconds($seconds);
return array_filter($this->doors, static function (Door $door) use ($compare) : bool {
return $door->getLastSeenAt() && $door->getLastSeenAt()->lessThan($compare);
});
}
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace Source\Gateways\Doors; namespace Source\Gateways\Doors;
use Carbon\Carbon;
use Source\Entities\Door; use Source\Entities\Door;
use Source\Entities\HashedSearchable; use Source\Entities\HashedSearchable;
...@@ -26,7 +27,10 @@ class LocalDoorsRepository extends InMemoryDoorsRepository ...@@ -26,7 +27,10 @@ class LocalDoorsRepository extends InMemoryDoorsRepository
'The Amazon', 'The Amazon',
'chicken izta door', 'chicken izta door',
HashedSearchable::hash($salt, 'door_1_api_token'), HashedSearchable::hash($salt, 'door_1_api_token'),
'door version here' 'door version here',
null,
null,
Carbon::now()->subWeek()
); );
} }
......
...@@ -18,6 +18,8 @@ class ResponseModel ...@@ -18,6 +18,8 @@ class ResponseModel
protected int $doorCount; protected int $doorCount;
protected int $missingDoorCount;
public function addFailureRate(DoorFailureRate $failureRate): void public function addFailureRate(DoorFailureRate $failureRate): void
{ {
$this->failureRates[] = $failureRate; $this->failureRates[] = $failureRate;
...@@ -38,6 +40,11 @@ class ResponseModel ...@@ -38,6 +40,11 @@ class ResponseModel
$this->doorCount = $count; $this->doorCount = $count;
} }
public function setMissingDoors(int $count): void
{
$this->missingDoorCount = $count;
}
public function getActiveUsers(): int public function getActiveUsers(): int
{ {
return $this->activeUsers; return $this->activeUsers;
...@@ -57,4 +64,9 @@ class ResponseModel ...@@ -57,4 +64,9 @@ class ResponseModel
{ {
return $this->doorCount; return $this->doorCount;
} }
public function getNumberOfMissingDoors(): int
{
return $this->missingDoorCount;
}
} }
...@@ -3,46 +3,30 @@ ...@@ -3,46 +3,30 @@
namespace Source\UseCases\Admin\Statistics; namespace Source\UseCases\Admin\Statistics;
use Carbon\Carbon; use Carbon\Carbon;
//use Source\Gateways\Entries\EntriesRepository; use Source\Entities\Door;
//use Source\Gateways\Attempts\AttemptsRepository;
use Source\Gateways\Doors\DoorsRepository; use Source\Gateways\Doors\DoorsRepository;
use Source\Gateways\Users\UsersRepository;
use Source\Gateways\Statistics\StatisticsRepository; use Source\Gateways\Statistics\StatisticsRepository;
class Statistics implements StatisticsUseCase class Statistics implements StatisticsUseCase
{ {
protected const STATISTIC_LIMIT = 10; protected const STATISTIC_LIMIT = 10;
/*
* Active users of the system (Number of unique users who have used a door in the past week)
* Graph of door usages
* bad doors
* bad keypads
* Top entry fialure by percentage of entered codes
*/
// /**
// * @var \Source\Gateways\Attempts\AttemptsRepository
// */
// protected AttemptsRepository $attempts;
//
// /**
// * @var \Source\Gateways\Entries\EntriesRepository
// */
// protected EntriesRepository $entries;
/** /**
* @var \Source\Gateways\Statistics\StatisticsRepository * @var \Source\Gateways\Statistics\StatisticsRepository
*/ */
protected StatisticsRepository $statistics; protected StatisticsRepository $statistics;
/**
* @var \Source\Gateways\Doors\DoorsRepository
*/
protected DoorsRepository $doors;
public function __construct( public function __construct(
// AttemptsRepository $attempts, StatisticsRepository $statistics,
// EntriesRepository $entries, DoorsRepository $doors
StatisticsRepository $statistics
) { ) {
// $this->attempts = $attempts;
// $this->entries = $entries;
$this->statistics = $statistics; $this->statistics = $statistics;
$this->doors = $doors;
} }
/** /**
...@@ -59,12 +43,16 @@ class Statistics implements StatisticsUseCase ...@@ -59,12 +43,16 @@ class Statistics implements StatisticsUseCase
$doors = $this->statistics->countDoors(); $doors = $this->statistics->countDoors();
$awolDoorCount = count($this->doors->awolFor(Door::AWOL_TIME_SECONDS));
$response = new ResponseModel(); $response = new ResponseModel();
$response->setActiveUsers($this->statistics->countActiveUsers($start, $date)); $response->setActiveUsers($this->statistics->countActiveUsers($start, $date));
$response->setDoorCount($doors); $response->setDoorCount($doors);
$response->setMissingDoors($awolDoorCount);
foreach ($usages as $usage) { foreach ($usages as $usage) {
$response->addMostUsedDoor($usage[1], $usage[0]); $response->addMostUsedDoor($usage[1], $usage[0]);
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace Source\UseCases\Admin\Statistics; namespace Source\UseCases\Admin\Statistics;
use Source\Gateways\Doors\DoorsRepository;
use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
...@@ -21,7 +22,10 @@ class StatisticsUseCaseServiceProvider extends ServiceProvider implements Deferr ...@@ -21,7 +22,10 @@ class StatisticsUseCaseServiceProvider extends ServiceProvider implements Deferr
public function register(): void public function register(): void
{ {
$this->app->bind(StatisticsUseCase::class, static function (Application $app) { $this->app->bind(StatisticsUseCase::class, static function (Application $app) {
return new Statistics($app->make(StatisticsRepository::class)); return new Statistics(
$app->make(StatisticsRepository::class),
$app->make(DoorsRepository::class)
);
}); });
} }
......
...@@ -17,6 +17,8 @@ class WebPresenter extends BasePresenter implements Presenter ...@@ -17,6 +17,8 @@ class WebPresenter extends BasePresenter implements Presenter
$this->viewModel['doorCount'] = $responseModel->getDoorCount(); $this->viewModel['doorCount'] = $responseModel->getDoorCount();
$this->viewModel['missingDoorCount'] = $responseModel->getNumberOfMissingDoors();
try { try {
$this->viewModel['failures']['labels'] = json_encode(array_map(static function (DoorFailureRate $rate) { $this->viewModel['failures']['labels'] = json_encode(array_map(static function (DoorFailureRate $rate) {
return $rate->getDoor()->getLocation(); return $rate->getDoor()->getLocation();
......
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