Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Guardians of the Kretschmar Elock System
Doorcode
Commits
4641d0b2
Commit
4641d0b2
authored
May 27, 2020
by
Jacob Priddy
👌
Browse files
Paginate attempts
parent
cca55e29
Changes
21
Hide whitespace changes
Inline
Side-by-side
src/backend/app/Http/Controllers/AttemptsController.php
View file @
4641d0b2
...
...
@@ -5,9 +5,7 @@ namespace App\Http\Controllers;
use
Illuminate\Http\JsonResponse
;
use
Source\Authorization\Permissions
;
use
Source\UseCases\Attempts\GetAttempts\GetAttemptsUseCase
;
use
Source\UseCases\Attempts\GetAttemptsForDoor\GetAttemptsForDoorUseCase
;
use
Source\UseCases\Attempts\GetAttempts\APIPresenter
as
GetAttemptsAPIPresenter
;
use
Source\UseCases\Attempts\GetAttemptsForDoor\APIPresenter
as
GetAttemptsForDoorAPIPresenter
;
use
Source\UseCases\Attempts\APIPresenter
as
GetAttemptsAPIPresenter
;
class
AttemptsController
extends
ApiController
{
...
...
@@ -24,44 +22,20 @@ class AttemptsController extends ApiController
$this
->
authorizer
->
protect
(
Permissions
::
LOGS_READ
);
$this
->
validate
(
$this
->
request
,
[
'start'
=>
'required|date|before:end'
,
'end'
=>
'required|date|after:start'
,
'start'
=>
'date'
,
'end'
=>
'date'
,
'door_id'
=>
'integer'
,
]);
$presenter
=
new
GetAttemptsAPIPresenter
();
$attempts
->
getBetweenDates
(
$this
->
request
->
input
(
'start'
),
$this
->
request
->
input
(
'end'
),
$presenter
);
return
$this
->
respondWithData
(
$presenter
->
getViewModel
());
}
/**
* @param \Source\UseCases\Attempts\GetAttemptsForDoor\GetAttemptsForDoorUseCase $doorAttempts
* @param string $doorId
* @return \Illuminate\Http\JsonResponse
* @throws \Illuminate\Validation\ValidationException
* @throws \Source\Exceptions\AuthorizationException
* @throws \Source\Exceptions\EntityNotFoundException
* @throws \Exception
*/
public
function
doorAttempts
(
GetAttemptsForDoorUseCase
$doorAttempts
,
string
$doorId
):
JsonResponse
{
$this
->
authorizer
->
protect
(
Permissions
::
LOGS_READ
);
$this
->
validate
(
$this
->
request
,
[
'start'
=>
'required|date|before:end'
,
'end'
=>
'required|date|after:start'
,
]);
$presenter
=
new
GetAttemptsForDoorAPIPresenter
();
$doorAttempts
->
getAttemptsForDoorBetween
(
$doorId
,
$attempts
->
getBetweenDates
(
$this
->
request
->
input
(
'start'
),
$this
->
request
->
input
(
'end'
),
$this
->
request
->
input
(
'door_id'
),
$presenter
);
return
$this
->
respondWithData
(
$presenter
->
getViewModel
());
return
$this
->
respondWithData
(
$presenter
->
getViewModel
(
50
));
}
}
src/backend/app/Providers/AppServiceProvider.php
View file @
4641d0b2
...
...
@@ -63,7 +63,6 @@ use Source\UseCases\Doors\GenerateDoorToken\GenerateDoorTokenUseCaseServiceProvi
use
Source\UseCases\Entries\GetEntriesForDoor\GetEntriesForDoorUseCaseServiceProvider
;
use
Source\UseCases\Entries\GetEntriesForUser\GetEntriesForUserUseCaseServiceProvider
;
use
Source\UseCases\Overrides\OverridesForDoor\OverridesForDoorUseCaseServiceProvider
;
use
Source\UseCases\Attempts\GetAttemptsForDoor\GetAttemptsForDoorUseCaseServiceProvider
;
use
Source\UseCases\DoorGroup\RemoveDoorFromGroup\RemoveDoorFromGroupUseCaseServiceProvider
;
use
Source\UseCases\GroupSchedule\SchedulesForGroup\SchedulesForGroupUseCaseServiceProvider
;
use
Source\UseCases\GroupUser\RemoveUserFromGroup\RemoveUserFromGroupUseCaseServiceProvider
;
...
...
@@ -160,7 +159,6 @@ class AppServiceProvider extends ServiceProvider
// Attempts
GetAttemptsUseCaseServiceProvider
::
class
,
GetAttemptsForDoorUseCaseServiceProvider
::
class
,
// Entries
GetEntriesForDoorUseCaseServiceProvider
::
class
,
...
...
src/backend/routes/api.php
View file @
4641d0b2
...
...
@@ -72,7 +72,6 @@ Route::group(['middleware' => 'auth:api'], static function () {
Route
::
delete
(
'{doorId}'
,
[
DoorsController
::
class
,
'delete'
]);
Route
::
get
(
'{doorId}/entries'
,
[
EntriesController
::
class
,
'doorEntries'
]);
Route
::
get
(
'{doorId}/attempts'
,
[
AttemptsController
::
class
,
'doorAttempts'
]);
Route
::
get
(
'{doorId}/groups'
,
[
DoorsController
::
class
,
'getGroupsForDoor'
]);
Route
::
post
(
'{doorId}/group/{groupId}'
,
[
DoorsController
::
class
,
'addDoorToGroup'
]);
...
...
src/backend/src/Entities/Attempt.php
View file @
4641d0b2
...
...
@@ -76,9 +76,21 @@ class Attempt
* @param \Carbon\Carbon $end
* @return bool
*/
public
function
isBetween
(
Carbon
$begin
,
Carbon
$end
):
bool
public
function
isBetween
(
?
Carbon
$begin
,
?
Carbon
$end
):
bool
{
return
$this
->
createdAt
->
isBetween
(
$begin
,
$end
);
if
(
$begin
&&
$end
)
{
return
$this
->
createdAt
->
isBetween
(
$begin
,
$end
);
}
if
(
$begin
)
{
return
$this
->
createdAt
->
greaterThan
(
$begin
);
}
if
(
$end
)
{
return
$this
->
createdAt
->
lessThan
(
$end
);
}
return
true
;
}
/**
...
...
src/backend/src/Gateways/Attempts/AttemptsRepository.php
View file @
4641d0b2
...
...
@@ -15,17 +15,10 @@ interface AttemptsRepository
public
function
add
(
Attempt
$attempt
):
?Attempt
;
/**
* @param \Carbon\Carbon $begin
* @param \Carbon\Carbon $end
* @param \Carbon\Carbon|null $begin
* @param \Carbon\Carbon|null $end
* @param string|null $doorId
* @return \Source\Entities\Attempt[]
*/
public
function
getBetween
(
Carbon
$begin
,
Carbon
$end
):
array
;
/**
* @param string $doorId
* @param \Carbon\Carbon $begin
* @param \Carbon\Carbon $end
* @return \Source\Entities\Attempt[]
*/
public
function
getForDoorBetween
(
string
$doorId
,
Carbon
$begin
,
Carbon
$end
):
array
;
public
function
getBetween
(
?Carbon
$begin
=
null
,
?Carbon
$end
=
null
,
?string
$doorId
=
null
):
array
;
}
src/backend/src/Gateways/Attempts/DatabaseAttemptsRepository.php
View file @
4641d0b2
...
...
@@ -28,28 +28,25 @@ class DatabaseAttemptsRepository implements AttemptsRepository
/**
* @inheritDoc
*/
public
function
getBetween
(
Carbon
$begin
,
Carbon
$end
):
array
public
function
getBetween
(
?
Carbon
$begin
=
null
,
?
Carbon
$end
=
null
,
?string
$doorId
=
null
):
array
{
$attempts
=
\
App\Attempt
::
query
()
->
whereBetween
(
'created_at'
,
[
$begin
,
$end
])
->
get
()
->
values
()
->
all
();
$query
=
\
App\Attempt
::
query
()
->
orderByDesc
(
'created_at'
);
return
array_map
(
static
function
(
\
App\Attempt
$attempt
)
{
return
self
::
toAttempt
(
$attempt
);
},
$attempts
);
}
if
(
$doorId
)
{
$query
->
where
(
'door_id'
,
$this
->
castToInt
(
$doorId
));
}
/**
* @inheritDoc
*/
public
function
getForDoorBetween
(
string
$doorId
,
Carbon
$begin
,
Carbon
$end
):
array
{
$attempts
=
\
App\Attempt
::
query
()
->
where
(
'door_id'
,
$this
->
castToInt
(
$doorId
))
->
whereBetween
(
'created_at'
,
[
$begin
,
$end
])
->
get
()
->
values
()
->
all
();
if
(
$begin
&&
$end
)
{
$query
->
whereBetween
(
'created_at'
,
[
$begin
,
$end
]);
}
elseif
(
$begin
)
{
$query
->
where
(
'created_at'
,
'>'
,
$begin
);
}
elseif
(
$end
)
{
$query
->
where
(
'created_at'
,
'<'
,
$end
);
}
return
array_map
(
static
function
(
\
App\Attempt
$attempt
)
{
return
self
::
toAttempt
(
$attempt
);
},
$
attempts
);
},
$
query
->
get
()
->
values
()
->
all
()
);
}
/**
...
...
src/backend/src/Gateways/Attempts/InMemoryAttemptsRepository.php
View file @
4641d0b2
...
...
@@ -34,20 +34,13 @@ class InMemoryAttemptsRepository implements AttemptsRepository
/**
* @inheritDoc
*/
public
function
getBetween
(
Carbon
$begin
,
Carbon
$end
):
array
public
function
getBetween
(
?
Carbon
$begin
=
null
,
?
Carbon
$end
=
null
,
?string
$doorId
=
null
):
array
{
return
array_values
(
array_filter
(
$this
->
attempts
,
static
function
(
Attempt
$attempt
)
use
(
$begin
,
$end
)
{
return
array_values
(
array_filter
(
$this
->
attempts
,
static
function
(
Attempt
$attempt
)
use
(
$begin
,
$end
,
$doorId
)
{
if
(
$doorId
)
{
return
$attempt
->
isBetween
(
$begin
,
$end
)
&&
$attempt
->
hasDoorIdOf
(
$doorId
);
}
return
$attempt
->
isBetween
(
$begin
,
$end
);
}));
}
/**
* @inheritDoc
*/
public
function
getForDoorBetween
(
string
$doorId
,
Carbon
$begin
,
Carbon
$end
):
array
{
return
array_values
(
array_filter
(
$this
->
attempts
,
static
function
(
Attempt
$attempt
)
use
(
$doorId
,
$begin
,
$end
)
{
return
$attempt
->
isBetween
(
$begin
,
$end
)
&&
$attempt
->
hasDoorIdOf
(
$doorId
);
}));
}
}
src/backend/src/Sanitize/CastsTo.php
View file @
4641d0b2
...
...
@@ -7,11 +7,11 @@ use Carbon\Carbon;
trait
CastsTo
{
/**
* @param $date
* @param string $format
* @param
string|null
$date
* @param string
$format
* @return \Carbon\Carbon|null
*/
protected
function
castToCarbon
(
$date
,
$format
=
'Y-m-d H:i:s'
):
?Carbon
protected
function
castToCarbon
(
?string
$date
,
$format
=
'Y-m-d H:i:s'
):
?Carbon
{
if
(
empty
(
$date
))
{
return
null
;
...
...
@@ -20,6 +20,20 @@ trait CastsTo
return
Carbon
::
createFromFormat
(
$format
,
$date
);
}
/**
* @param string|null $date
* @return \Carbon\Carbon|null
* @throws \Exception
*/
protected
function
liberalCastToCarbon
(
?string
$date
):
?Carbon
{
if
(
empty
(
$date
))
{
return
null
;
}
return
new
Carbon
(
$date
);
}
/**
* @param string|null $int
* @return int|null
...
...
src/backend/src/Sanitize/Paginates.php
View file @
4641d0b2
...
...
@@ -6,60 +6,21 @@ use Illuminate\Pagination\LengthAwarePaginator;
trait
Paginates
{
protected
int
$perPage
=
50
;
protected
int
$page
=
1
;
protected
array
$appends
=
[];
protected
?LengthAwarePaginator
$paginator
;
/**
* @param int $perPage
*/
public
function
setPerPage
(
int
$perPage
):
void
{
$this
->
perPage
=
$perPage
;
}
/**
* @param int $page
*/
public
function
setPage
(
int
$page
):
void
{
$this
->
page
=
$page
;
}
/**
* @return array
*/
public
function
getItems
():
array
{
if
(
!
$this
->
paginator
)
{
return
[];
}
return
$this
->
paginator
->
toArray
();
}
/**
* @param array $items
* @param int $perPage
* @param array $appends
* @return array
*/
p
ublic
function
setItems
(
array
$items
):
void
p
rotected
function
paginate
(
array
$items
,
int
$perPage
=
50
,
array
$appends
=
[]):
array
{
$currentPage
=
LengthAwarePaginator
::
resolveCurrentPage
();
$currentItems
=
array_slice
(
$items
,
$
this
->
perPage
*
(
$currentPage
-
1
),
$
this
->
perPage
);
$currentItems
=
array_slice
(
$items
,
$perPage
*
(
$currentPage
-
1
),
$perPage
);
$this
->
paginator
=
new
LengthAwarePaginator
(
$currentItems
,
count
(
$items
),
$this
->
perPage
,
$currentPage
);
$this
->
paginator
->
appends
(
$this
->
appends
);
}
$paginator
=
new
LengthAwarePaginator
(
$currentItems
,
count
(
$items
),
$perPage
,
$currentPage
);
$paginator
->
appends
(
$appends
);
/**
* @param array $appends
*/
public
function
setAppends
(
array
$appends
):
void
{
$this
->
appends
=
$appends
;
return
$paginator
->
toArray
();
}
}
src/backend/src/UseCases/Attempts/
GetAttempts/
APIPresenter.php
→
src/backend/src/UseCases/Attempts/APIPresenter.php
View file @
4641d0b2
<?php
namespace
Source\UseCases\Attempts
\GetAttempts
;
namespace
Source\UseCases\Attempts
;
use
Source\Entities\Attempt
;
use
Source\Sanitize\Paginates
;
use
Source\UseCases\BasePresenter
;
class
APIPresenter
extends
BasePresenter
implements
Presenter
{
protected
array
$viewModel
=
[];
use
Paginates
;
protected
array
$attempts
=
[];
/** @inheritDoc */
public
function
present
(
ResponseModel
$responseModel
):
void
{
$this
->
viewModel
[
'
attempts
'
]
=
array_map
(
function
(
Attempt
$attempt
)
{
$this
->
attempts
=
array_map
(
function
(
Attempt
$attempt
)
{
return
$this
->
formatAttempt
(
$attempt
);
},
$responseModel
->
getAttempts
());
}
/** @inheritDoc */
public
function
getViewModel
():
array
public
function
getViewModel
(
int
$perPage
,
array
$appends
=
[]
):
array
{
return
$this
->
viewModel
;
return
$this
->
paginate
(
$this
->
attempts
,
$perPage
,
$appends
)
;
}
}
src/backend/src/UseCases/Attempts/GetAttempts/GetAttempts.php
View file @
4641d0b2
...
...
@@ -2,11 +2,15 @@
namespace
Source\UseCases\Attempts\GetAttempts
;
use
Carbon\Carbon
;
use
Source\Sanitize\CastsTo
;
use
Source\UseCases\Attempts\Presenter
;
use
Source\UseCases\Attempts\ResponseModel
;
use
Source\Gateways\Attempts\AttemptsRepository
;
class
GetAttempts
implements
GetAttemptsUseCase
{
use
CastsTo
;
/**
* @var \Source\Gateways\Attempts\AttemptsRepository
*/
...
...
@@ -20,11 +24,19 @@ class GetAttempts implements GetAttemptsUseCase
/**
* @inheritDoc
*/
public
function
getBetweenDates
(
string
$start
,
string
$end
,
Presenter
$presenter
):
void
public
function
getBetweenDates
(
?
string
$start
,
?
string
$end
,
?string
$doorId
,
Presenter
$presenter
):
void
{
$attempts
=
$this
->
attempts
->
getBetween
(
new
Carbon
(
$start
),
new
Carbon
(
$end
));
$attempts
=
$this
->
attempts
->
getBetween
(
$this
->
liberalCastToCarbon
(
$start
),
$this
->
liberalCastToCarbon
(
$end
),
$doorId
);
$response
=
new
ResponseModel
();
$response
=
new
ResponseModel
(
$attempts
);
foreach
(
$attempts
as
$attempt
)
{
$response
->
addAttempt
(
$attempt
);
}
$presenter
->
present
(
$response
);
}
...
...
src/backend/src/UseCases/Attempts/GetAttempts/GetAttemptsUseCase.php
View file @
4641d0b2
...
...
@@ -3,15 +3,18 @@
namespace
Source\UseCases\Attempts\GetAttempts
;
use
Source\UseCases\Attempts\Presenter
;
interface
GetAttemptsUseCase
{
/**
* the passed start and end dates must be parsable by datetime
*
* @param string $start
* @param string $end
* @param \Source\UseCases\Attempts\GetAttempts\Presenter $presenter
* @param string $start
* @param string $end
* @param string|null $doorId
* @param \Source\UseCases\Attempts\Presenter $presenter
* @throws \Exception
*/
public
function
getBetweenDates
(
string
$start
,
string
$end
,
Presenter
$presenter
):
void
;
public
function
getBetweenDates
(
?
string
$start
,
?
string
$end
,
?string
$doorId
,
Presenter
$presenter
):
void
;
}
src/backend/src/UseCases/Attempts/GetAttempts/Presenter.php
deleted
100644 → 0
View file @
cca55e29
<?php
namespace
Source\UseCases\Attempts\GetAttempts
;
interface
Presenter
{
/**
* @param ResponseModel $responseModel
* @return void
*/
public
function
present
(
ResponseModel
$responseModel
):
void
;
/**
* @return array
*/
public
function
getViewModel
():
array
;
}
src/backend/src/UseCases/Attempts/GetAttempts/ResponseModel.php
deleted
100644 → 0
View file @
cca55e29
<?php
namespace
Source\UseCases\Attempts\GetAttempts
;
class
ResponseModel
{
/**
* @var \Source\Entities\Attempt[]
*/
protected
array
$attempts
;
/**
* @var \Source\Entities\Attempt[]
*/
public
function
__construct
(
array
$attempts
)
{
$this
->
attempts
=
$attempts
;
}
/**
* @return \Source\Entities\Attempt[]
*/
public
function
getAttempts
():
array
{
return
$this
->
attempts
;
}
}
src/backend/src/UseCases/Attempts/GetAttemptsForDoor/APIPresenter.php
deleted
100644 → 0
View file @
cca55e29
<?php
namespace
Source\UseCases\Attempts\GetAttemptsForDoor
;
use
Source\Entities\Attempt
;
use
Source\UseCases\BasePresenter
;
class
APIPresenter
extends
BasePresenter
implements
Presenter
{
protected
array
$viewModel
=
[];
/** @inheritDoc */
public
function
present
(
ResponseModel
$responseModel
):
void
{
$this
->
viewModel
[
'attempts'
]
=
array_map
(
function
(
Attempt
$attempt
)
{
return
$this
->
formatAttempt
(
$attempt
);
},
$responseModel
->
getAttempts
());
}
/** @inheritDoc */
public
function
getViewModel
():
array
{
return
$this
->
viewModel
;
}
}
src/backend/src/UseCases/Attempts/GetAttemptsForDoor/GetAttemptsForDoor.php
deleted
100644 → 0
View file @
cca55e29
<?php
namespace
Source\UseCases\Attempts\GetAttemptsForDoor
;
use
Carbon\Carbon
;
use
Source\Gateways\Doors\DoorsRepository
;
use
Source\Exceptions\EntityNotFoundException
;
use
Source\Gateways\Attempts\AttemptsRepository
;
class
GetAttemptsForDoor
implements
GetAttemptsForDoorUseCase
{
/**
* @var \Source\Gateways\Attempts\AttemptsRepository
*/
protected
AttemptsRepository
$attempts
;
/**
* @var \Source\Gateways\Doors\DoorsRepository
*/
protected
DoorsRepository
$doors
;
public
function
__construct
(
AttemptsRepository
$attempts
,
DoorsRepository
$doors
)
{
$this
->
attempts
=
$attempts
;
$this
->
doors
=
$doors
;
}
/**
* @inheritDoc
*/
public
function
getAttemptsForDoorBetween
(
string
$doorId
,
string
$begin
,
string
$end
,
Presenter
$presenter
):
void
{
if
(
!
$this
->
doors
->
exists
(
$doorId
))
{
throw
new
EntityNotFoundException
();
}
$attempts
=
$this
->
attempts
->
getForDoorBetween
(
$doorId
,
new
Carbon
(
$begin
),
new
Carbon
(
$end
));
$response
=
new
ResponseModel
(
$attempts
);
$presenter
->
present
(
$response
);
}
}
src/backend/src/UseCases/Attempts/GetAttemptsForDoor/GetAttemptsForDoorUseCase.php
deleted
100644 → 0
View file @
cca55e29
<?php
namespace
Source\UseCases\Attempts\GetAttemptsForDoor
;
interface
GetAttemptsForDoorUseCase
{
/**
* Begin and end must be parsable by datetime
*
* @param string $doorId
* @param string $begin
* @param string $end
* @param \Source\UseCases\Attempts\GetAttemptsForDoor\Presenter $presenter
* @throws \Source\Exceptions\EntityNotFoundException
* @throws \Exception
*/
public
function
getAttemptsForDoorBetween
(
string
$doorId
,
string
$begin
,
string
$end
,
Presenter
$presenter
):
void
;
}
src/backend/src/UseCases/Attempts/GetAttemptsForDoor/GetAttemptsForDoorUseCaseServiceProvider.php
deleted
100644 → 0
View file @
cca55e29
<?php
namespace
Source\UseCases\Attempts\GetAttemptsForDoor
;
use
Illuminate\Support\ServiceProvider
;
use
Source\Gateways\Doors\DoorsRepository
;
use
Illuminate\Contracts\Foundation\Application
;
use
Source\Gateways\Attempts\AttemptsRepository
;
use
Illuminate\Contracts\Support\DeferrableProvider
;
/**
* Service provider must be registered in AppServiceProvider
*/
class
GetAttemptsForDoorUseCaseServiceProvider
extends
ServiceProvider
implements
DeferrableProvider
{
/**
* Register any application services.
*
* @return void
*/
public
function
register
()
{
$this
->
app
->
bind
(
GetAttemptsForDoorUseCase
::
class
,
static
function
(
Application
$app
)
{
return
new
GetAttemptsForDoor
(
$app
->
make
(
AttemptsRepository
::
class
),
$app
->
make
(
DoorsRepository
::
class
));
});
}
/**
* Bootstrap any application services.
*
* @return void
*/
public
function
boot
():
void
{
}
/**
* @return array
*/
public
function
provides