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
8a44c180
Commit
8a44c180
authored
Mar 01, 2020
by
Jacob Priddy
👌
Browse files
create groups endpoint
parent
8ffbbed6
Changes
21
Hide whitespace changes
Inline
Side-by-side
src/web/backend/app/Http/Controllers/ApiController.php
View file @
8a44c180
...
...
@@ -3,7 +3,9 @@
namespace
App\Http\Controllers
;
use
Illuminate\Http\Request
;
use
Illuminate\Http\JsonResponse
;
use
Source\Authorization\Authorizer
;
abstract
class
ApiController
extends
Controller
{
...
...
@@ -12,6 +14,22 @@ abstract class ApiController extends Controller
*/
protected
int
$status
=
200
;
/**
* @var \Illuminate\Http\Request
*/
protected
Request
$request
;
/**
* @var \Source\Authorization\Authorizer
*/
protected
Authorizer
$authorizer
;
public
function
__construct
(
Request
$request
,
Authorizer
$authorizer
)
{
$this
->
request
=
$request
;
$this
->
authorizer
=
$authorizer
;
}
/**
* @param int $code
*/
...
...
src/web/backend/app/Http/Controllers/GroupsController.php
0 → 100644
View file @
8a44c180
<?php
namespace
App\Http\Controllers
;
use
Illuminate\Http\JsonResponse
;
use
Source\Authorization\Permissions
;
use
Source\UseCases\Groups\CreateGroup\APIPresenter
as
CreateGroupAPIPresenter
;
use
Source\UseCases\Groups\CreateGroup\CreateGroupUseCase
;
class
GroupsController
extends
ApiController
{
/**
* @param \Source\UseCases\Groups\CreateGroup\CreateGroupUseCase $useCase
* @return \Illuminate\Http\JsonResponse
* @throws \Source\Exceptions\AuthorizationException
* @throws \Source\Exceptions\EntityNotFoundException
* @throws \Illuminate\Validation\ValidationException
* @throws \Source\Exceptions\EntityExistsException
*/
public
function
store
(
CreateGroupUseCase
$useCase
):
JsonResponse
{
$this
->
authorizer
->
protectAll
([
Permissions
::
MANAGE_GROUPS
]);
$this
->
validate
(
$this
->
request
,
[
'title'
=>
'required|string|max:255'
,
'description'
=>
'required|string'
]);
$presenter
=
new
CreateGroupAPIPresenter
();
$useCase
->
create
(
$this
->
request
->
all
(),
$presenter
);
return
$this
->
respondWithData
(
$presenter
->
getViewModel
());
}
}
src/web/backend/app/Http/Controllers/UsersController.php
View file @
8a44c180
...
...
@@ -3,9 +3,7 @@
namespace
App\Http\Controllers
;
use
Illuminate\Http\Request
;
use
Illuminate\Http\JsonResponse
;
use
Source\Authorization\Authorizer
;
use
Source\Authorization\Permissions
;
use
Source\UseCases\Users\GetUser\GetUserUseCase
;
use
Source\UseCases\Users\CreateUser\CreateUserUseCase
;
...
...
@@ -21,26 +19,6 @@ use Source\UseCases\Users\UpdateUser\APIPresenter as UpdateUserAPIPresenter;
class
UsersController
extends
ApiController
{
/**
* @var \Illuminate\Http\Request
*/
protected
Request
$request
;
/**
* @var \Source\Authorization\Authorizer
*/
protected
Authorizer
$authorizer
;
/**
* @param \Illuminate\Http\Request $request
* @param \Source\Authorization\Authorizer $authorizer
*/
public
function
__construct
(
Request
$request
,
Authorizer
$authorizer
)
{
$this
->
request
=
$request
;
$this
->
authorizer
=
$authorizer
;
}
/**
* @param \Source\UseCases\Users\GetAllUsers\GetAllUsersUseCase $getAllUsers
* @return \Illuminate\Http\JsonResponse
...
...
@@ -88,19 +66,16 @@ class UsersController extends ApiController
{
$this
->
authorizer
->
protectAll
([
Permissions
::
MANAGE_USERS
]);
$this
->
validate
(
$this
->
request
,
[
'first_name'
=>
'required|string|max:255'
,
'last_name'
=>
'required|string|max:255'
,
'display_name'
=>
'required|string|max:255'
,
'emplid'
=>
'nullable|string|max:7|min:6'
,
'email'
=>
'required|email|max:255'
,
'password'
=>
'nullable|string|min:15|max:255'
,
'doorcode'
=>
'required|string|numeric|digits_between:4,255'
,
'expires_at'
=>
'nullable|string|date|max:255'
,
]
);
$this
->
validate
(
$this
->
request
,
[
'first_name'
=>
'required|string|max:255'
,
'last_name'
=>
'required|string|max:255'
,
'display_name'
=>
'required|string|max:255'
,
'emplid'
=>
'nullable|string|max:7|min:6'
,
'email'
=>
'required|email|max:255'
,
'password'
=>
'nullable|string|min:15|max:255'
,
'doorcode'
=>
'required|string|numeric|digits_between:4,255'
,
'expires_at'
=>
'nullable|string|date|max:255'
,
]);
$presenter
=
new
CreateUserAPIPresenter
();
...
...
@@ -124,14 +99,14 @@ class UsersController extends ApiController
$this
->
validate
(
$this
->
request
,
[
'first_name'
=>
'required|string|max:255'
,
'last_name'
=>
'required|string|max:255'
,
'first_name'
=>
'required|string|max:255'
,
'last_name'
=>
'required|string|max:255'
,
'display_name'
=>
'required|string|max:255'
,
'emplid'
=>
'nullable|string|max:7|min:6'
,
'email'
=>
'required|email|max:255'
,
'password'
=>
'nullable|string|max:255'
,
'doorcode'
=>
'nullable|string|numeric|digits_between:4,255'
,
'expires_at'
=>
'nullable|string|date|max:255'
,
'emplid'
=>
'nullable|string|max:7|min:6'
,
'email'
=>
'required|email|max:255'
,
'password'
=>
'nullable|string|max:255'
,
'doorcode'
=>
'nullable|string|numeric|digits_between:4,255'
,
'expires_at'
=>
'nullable|string|date|max:255'
,
]
);
...
...
src/web/backend/app/Providers/AppServiceProvider.php
View file @
8a44c180
...
...
@@ -15,6 +15,7 @@ use Source\UseCases\Users\CreateUser\CreateUserUseCaseServiceProvider;
use
Source\UseCases\Users\DeleteUser\DeleteUserUseCaseServiceProvider
;
use
Source\UseCases\Users\UpdateUser\UpdateUserUseCaseServiceProvider
;
use
Source\UseCases\Users\GetAllUsers\GetAllUsersUseCaseServiceProvider
;
use
Source\UseCases\Groups\CreateGroup\CreateGroupUseCaseServiceProvider
;
use
Source\UseCases\Token\Authenticate\AuthenticateUseCaseServiceProvider
;
use
Source\UseCases\Doors\Authenticate\AuthenticateUseCaseServiceProvider
as
DoorAuthenticateUseCaseServiceProvider
;
use
Source\UseCases\Users\Authenticate\AuthenticateUseCaseServiceProvider
as
UserAuthenticateUseCaseServiceProvider
;
...
...
@@ -38,12 +39,17 @@ class AppServiceProvider extends ServiceProvider
* @var string[]
*/
protected
array
$useCaseProviders
=
[
// Users
GetUserUseCaseServiceProvider
::
class
,
DeleteUserUseCaseServiceProvider
::
class
,
UpdateUserUseCaseServiceProvider
::
class
,
CreateUserUseCaseServiceProvider
::
class
,
GetAllUsersUseCaseServiceProvider
::
class
,
// Groups
CreateGroupUseCaseServiceProvider
::
class
,
// Doors
AuthenticateUseCaseServiceProvider
::
class
,
DoorAuthenticateUseCaseServiceProvider
::
class
,
UserAuthenticateUseCaseServiceProvider
::
class
,
...
...
src/web/backend/routes/api.php
View file @
8a44c180
...
...
@@ -4,6 +4,7 @@ use Illuminate\Http\Request;
use
Illuminate\Support\Facades\Route
;
use
App\Http\Controllers\AuthController
;
use
App\Http\Controllers\UsersController
;
use
App\Http\Controllers\GroupsController
;
/*
|--------------------------------------------------------------------------
...
...
@@ -30,6 +31,16 @@ Route::group(['middleware' => 'auth:api'], static function () {
Route
::
delete
(
'{userId}'
,
[
UsersController
::
class
,
'delete'
]);
});
Route
::
group
([
'prefix'
=>
'groups'
,
],
static
function
()
{
Route
::
get
(
'/'
,
[
GroupsController
::
class
,
'index'
]);
Route
::
post
(
'/'
,
[
GroupsController
::
class
,
'store'
]);
Route
::
get
(
'{groupId}'
,
[
GroupsController
::
class
,
'get'
]);
Route
::
put
(
'{groupId}'
,
[
GroupsController
::
class
,
'update'
]);
Route
::
delete
(
'{groupId'
,
[
GroupsController
::
class
,
'delete'
]);
});
Route
::
get
(
'/user'
,
static
function
(
Request
$request
)
{
return
$request
->
user
();
});
...
...
src/web/backend/src/Authorization/Permissions.php
View file @
8a44c180
...
...
@@ -10,5 +10,6 @@ class Permissions
public
const
MANAGE_DOORS
=
'manage-doors'
;
public
const
MANAGE_TOKEN
=
'manage-token'
;
public
const
TOKEN_CREATE
=
'token-create'
;
public
const
MANAGE_GROUPS
=
'manage-groups'
;
public
const
CODE_QUERY
=
'code-query'
;
}
src/web/backend/src/Gateways/GroupUser/LocalGroupUserRepository.php
View file @
8a44c180
...
...
@@ -24,6 +24,7 @@ class LocalGroupUserRepository extends InMemoryGroupUserRepository
$this
->
addUserToGroup
(
LocalUsersRepository
::
getSemiPrivilegedUser
()
->
getId
(),
LocalGroupsRepository
::
getManageTokenGroup
()
->
getId
());
$this
->
addUserToGroup
(
LocalUsersRepository
::
getSemiPrivilegedUser
()
->
getId
(),
LocalGroupsRepository
::
getTokenCreateGroup
()
->
getId
());
$this
->
addUserToGroup
(
LocalUsersRepository
::
getSemiPrivilegedUser
()
->
getId
(),
LocalGroupsRepository
::
getCodeQueryGroup
()
->
getId
());
$this
->
addUserToGroup
(
LocalUsersRepository
::
getSemiPrivilegedUser
()
->
getId
(),
LocalGroupsRepository
::
getManageGroupsGroup
()
->
getId
());
$this
->
addUserToGroup
(
LocalUsersRepository
::
getComputerScienceStudent
()
->
getId
(),
...
...
src/web/backend/src/Gateways/Groups/LocalGroupsRepository.php
View file @
8a44c180
...
...
@@ -25,6 +25,8 @@ class LocalGroupsRepository extends InMemoryGroupsRepository
$this
->
create
(
static
::
getComputerScienceMajorGroup
());
$this
->
create
(
static
::
getEngineeringLabAccessGroup
());
$this
->
create
(
static
::
getManageGroupsGroup
());
}
/**
...
...
@@ -122,4 +124,13 @@ class LocalGroupsRepository extends InMemoryGroupsRepository
'Gives access to the Electrical Engineering Labs'
);
}
public
static
function
getManageGroupsGroup
():
Group
{
return
new
Group
(
9
,
Permissions
::
MANAGE_GROUPS
,
'Gives permission to manage stored groups'
);
}
}
src/web/backend/src/UseCases/BasePresenter.php
View file @
8a44c180
...
...
@@ -5,6 +5,7 @@ namespace Source\UseCases;
use
Carbon\Carbon
;
use
Source\Entities\User
;
use
Source\Entities\Group
;
abstract
class
BasePresenter
{
...
...
@@ -70,6 +71,17 @@ abstract class BasePresenter
];
}
public
function
formatGroup
(
Group
$group
):
array
{
return
[
'id'
=>
$group
->
getId
(),
'title'
=>
$group
->
getTitle
(),
'description'
=>
$group
->
getDescription
(),
'created_at'
=>
$this
->
formatDateTime
(
$group
->
getCreatedAt
()),
'updated_at'
=>
$this
->
formatDateTime
(
$group
->
getUpdatedAt
()),
];
}
/**
* @param Carbon|null $date
* @param string $format
...
...
src/web/backend/src/UseCases/Groups/CreateGroup/APIPresenter.php
0 → 100644
View file @
8a44c180
<?php
namespace
Source\UseCases\Groups\CreateGroup
;
use
Source\UseCases\BasePresenter
;
class
APIPresenter
extends
BasePresenter
implements
Presenter
{
protected
array
$viewModel
=
[];
/** @inheritDoc */
public
function
present
(
ResponseModel
$responseModel
):
void
{
$this
->
viewModel
[
'group'
]
=
$this
->
formatGroup
(
$responseModel
->
getGroup
());
}
/** @inheritDoc */
public
function
getViewModel
():
array
{
return
$this
->
viewModel
;
}
}
src/web/backend/src/UseCases/Groups/CreateGroup/CreateGroup.php
0 → 100644
View file @
8a44c180
<?php
namespace
Source\UseCases\Groups\CreateGroup
;
use
Source\Entities\Group
;
use
Source\Gateways\Groups\GroupsRepository
;
use
Source\Exceptions\EntityExistsException
;
class
CreateGroup
implements
CreateGroupUseCase
{
/**
* @var \Source\Gateways\Groups\GroupsRepository
*/
protected
GroupsRepository
$groups
;
public
function
__construct
(
GroupsRepository
$groups
)
{
$this
->
groups
=
$groups
;
}
/**
* @inheritDoc
*/
public
function
create
(
array
$attributes
,
Presenter
$presenter
):
void
{
$group
=
new
Group
(
0
,
$attributes
[
'title'
],
$attributes
[
'description'
]
);
if
(
!
(
$group
=
$this
->
groups
->
create
(
$group
)))
{
throw
new
EntityExistsException
();
}
$response
=
new
ResponseModel
(
$group
);
$presenter
->
present
(
$response
);
}
}
src/web/backend/src/UseCases/Groups/CreateGroup/CreateGroupUseCase.php
0 → 100644
View file @
8a44c180
<?php
namespace
Source\UseCases\Groups\CreateGroup
;
interface
CreateGroupUseCase
{
/**
* Required attributes:
* title
* description
*
* @param array $attributes
* @param \Source\UseCases\Groups\CreateGroup\Presenter $presenter
* @throws \Source\Exceptions\EntityExistsException
*/
public
function
create
(
array
$attributes
,
Presenter
$presenter
):
void
;
}
src/web/backend/src/UseCases/Groups/CreateGroup/CreateGroupUseCaseServiceProvider.php
0 → 100644
View file @
8a44c180
<?php
namespace
Source\UseCases\Groups\CreateGroup
;
use
Source\Gateways\Groups\GroupsRepository
;
use
Illuminate\Contracts\Foundation\Application
;
use
Illuminate\Contracts\Support\DeferrableProvider
;
use
Illuminate\Support\ServiceProvider
;
/**
* Service provider must be registered in AppServiceProvider
*/
class
CreateGroupUseCaseServiceProvider
extends
ServiceProvider
implements
DeferrableProvider
{
/**
* Register any application services.
*
* @return void
*/
public
function
register
()
{
$this
->
app
->
bind
(
CreateGroupUseCase
::
class
,
static
function
(
Application
$app
)
{
return
new
CreateGroup
(
$app
->
make
(
GroupsRepository
::
class
));
});
}
/**
* Bootstrap any application services.
*
* @return void
*/
public
function
boot
():
void
{
}
/**
* @return array
*/
public
function
provides
()
{
return
[
CreateGroupUseCase
::
class
];
}
}
src/web/backend/src/UseCases/Groups/CreateGroup/Presenter.php
0 → 100644
View file @
8a44c180
<?php
namespace
Source\UseCases\Groups\CreateGroup
;
interface
Presenter
{
/**
* @param ResponseModel $responseModel
* @return void
*/
public
function
present
(
ResponseModel
$responseModel
):
void
;
/**
* @return array
*/
public
function
getViewModel
():
array
;
}
src/web/backend/src/UseCases/Groups/CreateGroup/ResponseModel.php
0 → 100644
View file @
8a44c180
<?php
namespace
Source\UseCases\Groups\CreateGroup
;
use
Source\Entities\Group
;
class
ResponseModel
{
/**
* @var \Source\Entities\Group
*/
protected
Group
$group
;
/**
* @param \Source\Entities\Group $group
*/
public
function
__construct
(
Group
$group
)
{
$this
->
group
=
$group
;
}
/**
* @return \Source\Entities\Group
*/
public
function
getGroup
():
Group
{
return
$this
->
group
;
}
}
src/web/backend/src/UseCases/Users/CreateUser/CreateUser.php
View file @
8a44c180
...
...
@@ -49,12 +49,13 @@ class CreateUser implements CreateUserUseCase
null
,
);
$response
=
new
ResponseModel
(
$user
);
if
(
!
$this
->
usersRepository
->
create
(
$user
))
{
if
(
!
(
$user
=
$this
->
usersRepository
->
create
(
$user
))
)
{
throw
new
EntityExistsException
();
}
$response
=
new
ResponseModel
(
$user
);
$presenter
->
present
(
$response
);
}
}
src/web/backend/tests/Feature/Api/Groups/CreateGroupApiTest.php
0 → 100644
View file @
8a44c180
<?php
namespace
Tests\Feature\Api\Groups
;
use
Source\Entities\Group
;
use
Source\Gateways\Groups\GroupsRepository
;
use
Source\Exceptions\EntityNotFoundException
;
use
Illuminate\Foundation\Testing\TestResponse
;
use
Source\Gateways\Groups\InMemoryGroupsRepository
;
use
Tests\Feature\AuthenticatesWithApplicationTestCase
;
class
CreateGroupApiTest
extends
AuthenticatesWithApplicationTestCase
{
protected
TestResponse
$response
;
protected
InMemoryGroupsRepository
$groups
;
public
function
setUp
():
void
{
parent
::
setUp
();
$this
->
groups
=
$this
->
app
->
make
(
GroupsRepository
::
class
);
}
/**
* @param array $data
*/
protected
function
handleTest
(
array
$data
):
void
{
$this
->
response
=
$this
->
postJson
(
'/groups'
,
array_merge
(
[
'api_token'
=>
$this
->
authToken
],
$data
)
);
}
/**
* @test
*/
public
function
it_denies_unauthorized
():
void
{
$this
->
handleTest
([]);
$this
->
response
->
assertStatus
(
401
);
}
/**
* @test
* @throws \Source\Exceptions\EntityNotFoundException
*/
public
function
it_protects_the_route
():
void
{
$this
->
authorize
(
false
);
$this
->
handleTest
([]);
$this
->
response
->
assertStatus
(
403
);
}
public
function
invalidGroupProvider
():
array
{
$group
=
new
Group
(
0
,
'title'
,
'desc'
);
return
[
// Missing one of the required
[
[
'title'
=>
$group
->
getTitle
(),
],
[
'description'
=>
[
'The description field is required.'
]],
],
[
[
'description'
=>
$group
->
getDescription
(),
],
[
'title'
=>
[
'The title field is required.'
]],
],
];
}
/**
* @test
* @param array $data
* @param array $message
* @dataProvider invalidGroupProvider
* @throws EntityNotFoundException
*/
public
function
it_tests_the_validation_rules
(
array
$data
,
array
$message
):
void
{
$this
->
authenticate
();
$this
->
handleTest
(
$data
);
$this
->
response
->
assertJsonFragment
(
$message
);
}
/**
* @test
* @throws EntityNotFoundException
*/
public
function
it_creates_a_group
():
void
{
$this
->
authenticate
();
$this
->
handleTest
([
'title'
=>
'title'
,
'description'
=>
'desc'
,
]);
$this
->
response
->
assertStatus
(
200
);
$this
->
response
->
assertJsonFragment
([
'title'
=>
'title'
,
'description'
=>
'desc'
,
]);
$this
->
assertCount
(
1
,
$this
->
groups
->
all
());
}
}
src/web/backend/tests/Unit/Source/UseCases/Groups/CreateGroup/PresenterStub.php
0 → 100644
View file @
8a44c180
<?php
namespace
Tests\Unit\Source\UseCases\Groups\CreateGroup
;
use
Source\UseCases\Groups\CreateGroup\Presenter
;