Skip to content

Commit b1c1851

Browse files
committed
feat: add user to group endpoint
Signed-off-by: romanetar <roman_ag@hotmail.com>
1 parent 56325c7 commit b1c1851

12 files changed

Lines changed: 255 additions & 1 deletion

File tree

app/Http/Controllers/Api/OAuth2/OAuth2GroupApiController.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use App\Http\Controllers\GetAllTrait;
1616
use App\libs\Auth\Repositories\IGroupRepository;
1717
use App\ModelSerializers\SerializerRegistry;
18+
use App\Services\Auth\IGroupService;
1819
use OAuth2\IResourceServerContext;
1920
use Utils\Services\ILogService;
2021

@@ -26,21 +27,26 @@ final class OAuth2GroupApiController extends OAuth2ProtectedController
2627
{
2728
use GetAllTrait;
2829

30+
private IGroupService $service;
31+
2932
/**
3033
* OAuth2UserApiController constructor.
3134
* @param IGroupRepository $repository
35+
* @param IGroupService $service
3236
* @param IResourceServerContext $resource_server_context
3337
* @param ILogService $log_service
3438
*/
3539
public function __construct
3640
(
3741
IGroupRepository $repository,
42+
IGroupService $service,
3843
IResourceServerContext $resource_server_context,
3944
ILogService $log_service,
4045
)
4146
{
4247
parent::__construct($resource_server_context, $log_service);
4348
$this->repository = $repository;
49+
$this->service = $service;
4450
}
4551

4652
protected function getAllSerializerType(): string

app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,19 @@
1313
**/
1414

1515
use App\Http\Controllers\GetAllTrait;
16+
use App\Http\Controllers\Traits\RequestProcessor;
17+
use App\Http\Controllers\UserGroupsValidationRulesFactory;
1618
use App\Http\Controllers\UserValidationRulesFactory;
19+
use App\Http\Exceptions\HTTP403ForbiddenException;
1720
use App\Http\Utils\HTMLCleaner;
21+
use App\Jobs\AddUserAction;
1822
use App\ModelSerializers\SerializerRegistry;
23+
use App\Services\Auth\IGroupService;
24+
use Auth\Group;
1925
use Auth\Repositories\IUserRepository;
26+
use Illuminate\Http\JsonResponse;
2027
use Illuminate\Http\Request as LaravelRequest;
28+
use Illuminate\Support\Facades\App;
2129
use Illuminate\Support\Facades\Auth;
2230
use Illuminate\Support\Facades\Request;
2331
use Illuminate\Support\Facades\Log;
@@ -27,9 +35,11 @@
2735
use models\exceptions\ValidationException;
2836
use OAuth2\Builders\IdTokenBuilder;
2937
use OAuth2\IResourceServerContext;
38+
use OAuth2\Models\IClient;
3039
use OAuth2\Repositories\IClientRepository;
3140
use OAuth2\ResourceServer\IUserService;
3241
use Utils\Http\HttpContentType;
42+
use Utils\IPHelper;
3343
use Utils\Services\ILogService;
3444
use Exception;
3545
use OpenId\Services\IUserService as IOpenIdUserService;
@@ -41,6 +51,8 @@ final class OAuth2UserApiController extends OAuth2ProtectedController
4151
{
4252
use GetAllTrait;
4353

54+
use RequestProcessor;
55+
4456
protected function getAllSerializerType(): string
4557
{
4658
return SerializerRegistry::SerializerType_Private;
@@ -82,6 +94,11 @@ protected function getFilterValidatorRules(): array
8294
*/
8395
private $user_service;
8496

97+
/**
98+
* @var IGroupService
99+
*/
100+
private $group_service;
101+
85102
/**
86103
* @var IClientRepository
87104
*/
@@ -112,6 +129,7 @@ public function __construct
112129
(
113130
IUserRepository $repository,
114131
IUserService $user_service,
132+
IGroupService $group_service,
115133
IResourceServerContext $resource_server_context,
116134
ILogService $log_service,
117135
IOpenIdUserService $openid_user_service,
@@ -122,6 +140,7 @@ public function __construct
122140
parent::__construct($resource_server_context, $log_service);
123141
$this->repository = $repository;
124142
$this->user_service = $user_service;
143+
$this->group_service = $group_service;
125144
$this->client_repository = $client_repository;
126145
$this->id_token_builder = $id_token_builder;
127146
$this->openid_user_service = $openid_user_service;
@@ -324,4 +343,31 @@ public function get($id)
324343
}
325344
}
326345

346+
/**
347+
* @param $user_id
348+
* @return JsonResponse|mixed
349+
*/
350+
public function addUserToGroup($user_id): mixed
351+
{
352+
return $this->processRequest(function() use($user_id) {
353+
//check if it's a service app
354+
$app_type = $this->resource_server_context->getApplicationType();
355+
if (App::environment() != "testing" && !empty($app_type) && $app_type != IClient::ApplicationType_Service) {
356+
throw new HTTP403ForbiddenException("You are not allowed to perform this action.");
357+
}
358+
359+
if(!Request::isJson()) return $this->error400();
360+
361+
$payload = Request::json()->all();
362+
// Creates a Validator instance and validates the data.
363+
$validation = Validator::make($payload, UserGroupsValidationRulesFactory::build($payload));
364+
if ($validation->fails()) {
365+
$ex = new ValidationException();
366+
throw $ex->setMessages($validation->messages()->toArray());
367+
}
368+
$this->group_service->addUser2Groups(intval($user_id), $payload['groups']);
369+
return $this->updated();
370+
});
371+
}
372+
327373
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php namespace App\Http\Controllers;
2+
/**
3+
* Copyright 2025 OpenStack Foundation
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
**/
14+
use Auth\User;
15+
/**
16+
* Class UserGroupsValidationRulesFactory
17+
* @package App\Http\Controllers
18+
*/
19+
final class UserGroupsValidationRulesFactory
20+
{
21+
/**
22+
* @param array $data
23+
* @param false $update
24+
* @param User|null $currentUser
25+
* @return string[]
26+
*/
27+
public static function build(array $data, $update = false, ?User $currentUser = null){
28+
29+
if($update){
30+
return [
31+
'groups' => 'sometimes|int_array',
32+
];
33+
}
34+
35+
return [
36+
'groups' => 'required|int_array',
37+
];
38+
}
39+
}

app/Services/Auth/GroupService.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,30 @@ public function addUser2Group(Group $group, int $user_id): void
164164
}
165165
}
166166

167+
/**
168+
* @param int $user_id
169+
* @param array $group_ids
170+
* @throw ValidationException
171+
* @throws \Exception
172+
*/
173+
public function addUser2Groups(int $user_id, array $group_ids): void
174+
{
175+
$this->tx_service->transaction(function() use($group_ids, $user_id){
176+
$user = $this->user_repository->getById($user_id);
177+
if(is_null($user))
178+
throw new EntityNotFoundException();
179+
180+
foreach($group_ids as $group_id){
181+
$group = $this->group_repository->getById(intval($group_id));
182+
if(is_null($group) || !$group instanceof Group)
183+
throw new EntityNotFoundException("group $group_id not found");
184+
185+
if (!$user->belongToGroup($group->getSlug()))
186+
$user->addToGroup($group);
187+
}
188+
});
189+
}
190+
167191
/**
168192
* @param Group $group
169193
* @param int $user_id

app/Services/Auth/IGroupService.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ interface IGroupService extends IBaseService
2828
*/
2929
public function addUser2Group(Group $group,int $user_id):void;
3030

31+
/**
32+
* @param int $user_id
33+
* @param array $group_ids
34+
* @throw ValidationException
35+
* @throws \Exception
36+
*/
37+
public function addUser2Groups(int $user_id, array $group_ids):void;
38+
3139
/**
3240
* @param Group $group
3341
* @param int $user_id

app/libs/OAuth2/IUserScopes.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ interface IUserScopes
2929
const MeRead = 'me/read';
3030
const MeWrite = 'me/write';
3131
const Write = 'users/write';
32+
const UserGroupWrite = 'users/groups/write';
3233
}

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
"Database\\Seeders\\": "database/seeders/"
9090
},
9191
"files": [
92+
"app/Utils/helpers.php",
9293
"app/libs/Utils/Html/HtmlHelpers.php"
9394
]
9495
},
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php namespace Database\Migrations;
2+
/**
3+
* Copyright 2025 OpenStack Foundation
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
**/
14+
15+
use App\libs\OAuth2\IUserScopes;
16+
use Database\Seeders\SeedUtils;
17+
use Doctrine\Migrations\AbstractMigration;
18+
use Doctrine\DBAL\Schema\Schema as Schema;
19+
/**
20+
* Class Version20250805084926
21+
* @package Database\Migrations
22+
*/
23+
class Version20250805084926 extends AbstractMigration
24+
{
25+
/**
26+
* @param Schema $schema
27+
*/
28+
public function up(Schema $schema):void
29+
{
30+
SeedUtils::seedScopes([
31+
[
32+
'name' => IUserScopes::UserGroupWrite,
33+
'short_description' => 'Allows associate Users to Groups.',
34+
'description' => 'Allows associate Users to Groups.',
35+
'system' => false,
36+
'default' => false,
37+
'groups' => false,
38+
]
39+
], 'users');
40+
41+
SeedUtils::seedApiEndpoints('users', [
42+
[
43+
'name' => 'add-user-to-groups',
44+
'active' => true,
45+
'route' => '/api/v1/users/{id}/groups',
46+
'http_method' => 'PUT',
47+
'scopes' => [
48+
IUserScopes::UserGroupWrite
49+
],
50+
],
51+
]);
52+
}
53+
54+
/**
55+
* @param Schema $schema
56+
*/
57+
public function down(Schema $schema):void
58+
{
59+
60+
}
61+
}

database/seeds/ApiEndpointSeeder.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
* See the License for the specific language governing permissions and
1212
* limitations under the License.
1313
**/
14+
15+
use App\libs\OAuth2\IUserScopes;
1416
use Illuminate\Database\Seeder;
1517
use Illuminate\Support\Facades\DB;
1618
/**
@@ -119,6 +121,15 @@ private function seedUsersEndpoints()
119121
\App\libs\OAuth2\IUserScopes::MeWrite
120122
],
121123
],
124+
[
125+
'name' => 'add-user-to-groups',
126+
'active' => true,
127+
'route' => '/api/v1/users/{id}/groups',
128+
'http_method' => 'PUT',
129+
'scopes' => [
130+
\App\libs\OAuth2\IUserScopes::UserGroupWrite
131+
],
132+
],
122133
]
123134
);
124135
}

database/seeds/ApiScopeSeeder.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ private function seedUsersScopes(){
9191
'system' => false,
9292
'default' => false,
9393
'groups' => false,
94+
],
95+
[
96+
'name' => IUserScopes::UserGroupWrite,
97+
'short_description' => 'Allows associate Users to Groups',
98+
'description' => 'Allows associate Users to Groups',
99+
'system' => false,
100+
'default' => false,
101+
'groups' => false,
94102
]
95103
], 'users');
96104

0 commit comments

Comments
 (0)