diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2MembersApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2MembersApiController.php index 46b7f398d..799517b15 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2MembersApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2MembersApiController.php @@ -501,6 +501,50 @@ public function addMyAffiliation() return $this->addAffiliation('me'); } + #[OA\Get( + path: '/api/v1/members/external/{external_id}', + operationId: 'getMemberByIdExternalId', + summary: 'Get member by external Id', + description: 'Returns a member profile by External Id', + tags: ['Members'], + x: [ + 'required-groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + security: [['members_oauth2' => [ + MemberScopes::ReadMemberData, + ]]], + parameters: [ + new OA\Parameter(name: 'external_id', in: 'path', required: true, description: 'Member External ID', schema: new OA\Schema(type: 'integer')), + new OA\Parameter(name: 'expand', in: 'query', required: false, description: 'Expand relationships', schema: new OA\Schema(type: 'string')), + ], + responses: [ + new OA\Response( + response: Response::HTTP_OK, + description: 'Successful operation', + content: new OA\JsonContent(ref: '#/components/schemas/Member') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: 'Unauthorized'), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: 'Member not found'), + ] + )] + public function getMemberByIdExternalId($external_id){ + return $this->processRequest(function() use($external_id){ + $member = $this->repository->getByExternalId($external_id); + if(is_null($member)) + throw new EntityNotFoundException("Member not found by external Id."); + return $this->ok(SerializerRegistry::getInstance()->getSerializer($member, SerializerRegistry::SerializerType_Private)->serialize + ( + SerializerUtils::getExpand(), + SerializerUtils::getFields(), + SerializerUtils::getRelations() + )); + }); + } + #[OA\Post( path: '/api/v1/members/{member_id}/affiliations', operationId: 'addMemberAffiliation', diff --git a/database/migrations/config/Version20260410172200.php b/database/migrations/config/Version20260410172200.php new file mode 100644 index 000000000..2690b7be0 --- /dev/null +++ b/database/migrations/config/Version20260410172200.php @@ -0,0 +1,94 @@ +addSql($this->insertEndpoint( + self::API_NAME, + self::ENDPOINT_NAME, + self::ENDPOINT_ROUTE, + 'GET' + )); + + // 2. Insert endpoint_api_scopes association + $this->addSql($this->insertEndpointScope(self::API_NAME, self::ENDPOINT_NAME, $scope)); + + // 3. Insert endpoint_api_authz_groups + $authzGroups = [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ]; + + foreach ($authzGroups as $groupSlug) { + $this->addSql($this->insertEndpointAuthzGroup(self::API_NAME, self::ENDPOINT_NAME, $groupSlug)); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema): void + { + $scope = MemberScopes::ReadMemberData; + + // Reverse order: authz groups → endpoint scopes → endpoint + $authzGroups = [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ]; + + foreach ($authzGroups as $groupSlug) { + $this->addSql($this->deleteEndpointAuthzGroup(self::API_NAME, self::ENDPOINT_NAME, $groupSlug)); + } + + $this->addSql($this->deleteScopesEndpoints(self::API_NAME, [$scope])); + $this->addSql($this->deleteEndpoint(self::API_NAME, self::ENDPOINT_NAME)); + } +} diff --git a/database/seeders/ApiEndpointsSeeder.php b/database/seeders/ApiEndpointsSeeder.php index 78e1f35f9..290b23188 100644 --- a/database/seeders/ApiEndpointsSeeder.php +++ b/database/seeders/ApiEndpointsSeeder.php @@ -9410,6 +9410,17 @@ private function seedMemberEndpoints() 'http_method' => 'GET', 'scopes' => [MemberScopes::ReadMemberData], ], + [ + 'name' => 'get-member-by-external-id', + 'route' => '/api/v1/members/external/{external_id}', + 'http_method' => 'GET', + 'scopes' => [MemberScopes::ReadMemberData], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], [ 'name' => 'get-my-member', 'route' => '/api/v1/members/me', diff --git a/routes/api_v1.php b/routes/api_v1.php index fa9ba05e7..bb18c179e 100644 --- a/routes/api_v1.php +++ b/routes/api_v1.php @@ -24,7 +24,11 @@ // members Route::group(['prefix' => 'members'], function () { Route::get('', 'OAuth2MembersApiController@getAll'); - + Route::group(['prefix' => 'external'], function () { + Route::group(['prefix' => '{external_id}'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2MembersApiController@getMemberByIdExternalId']); + }); + }); Route::group(['prefix' => 'me'], function () { // get my member info Route::get('', 'OAuth2MembersApiController@getMyMember');