Skip to content

Commit 83eaa4a

Browse files
authored
Feature/add expands fields relations to get user by id v2 (#148)
* feat: add fields/relations passthrough to GET /api/v1|v2/users/{id} Wires SerializerUtils::getExpand()/getFields()/getRelations() into both by-ID user endpoints (matching the ParametrizedGetAll pattern already used by list endpoints), and makes PrivateUserSerializer treat `groups` as a gated relation (mirroring ApiScopeGroupSerializer) instead of appending it unconditionally. Unblocks ftn-docsnsklz PR #76 (SDS ftn-attendee-native-realtime-comms.md, D38): attendee-networking-api's IDP user_updated consumer needs to fetch exactly fields=public_profile_allow_chat_with_me,first_name,last_name,pic without pulling the rest of the private profile. v1 get() also migrated from manual try/catch to the shared processRequest() wrapper for consistent error handling with getV2(). Also fixes an unrelated pre-existing bug in UserLoginTurnstileTest where $testEmail/$testPassword being typed as non-nullable string caused a TypeError before the test's own markTestSkipped() logic could run when TEST_USER_EMAIL/TEST_USER_PASSWORD are unset. 9 new tests added to OAuth2UserApiTest; full suite green (180 tests, 0 failures, 7 legitimate skips). * docs(plan): mark spec as VERIFIED * chore: untrack plan file — plan docs are working artifacts, not committed * fix: document v1 expand param and add v1 default-shape regression test Address deep-review findings on PR #148: - OA\Get annotation for GET /api/v1/users/{id} was missing the `expand` parameter even though get() already passed SerializerUtils::getExpand() into serialize() -- the capability was live but undocumented. - v1 lacked a default-shape regression test symmetric with testGetUserByIdV2WithNoParamsReturnsSameShapeAsBefore, so the fields/relations passthrough's backward compatibility on v1 was only exercised incidentally.
1 parent 24c00ca commit 83eaa4a

4 files changed

Lines changed: 346 additions & 21 deletions

File tree

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

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use App\Http\Exceptions\HTTP403ForbiddenException;
2121
use App\Http\Utils\HTMLCleaner;
2222
use App\ModelSerializers\SerializerRegistry;
23+
use App\ModelSerializers\SerializerUtils;
2324
use Auth\Repositories\IUserRepository;
2425
use Illuminate\Http\JsonResponse;
2526
use Illuminate\Http\Request as LaravelRequest;
@@ -640,6 +641,27 @@ public function userInfo()
640641
required: true,
641642
schema: new OA\Schema(type: 'integer')
642643
),
644+
new OA\Parameter(
645+
name: 'expand',
646+
description: 'Expand relations: groups',
647+
in: 'query',
648+
required: false,
649+
schema: new OA\Schema(type: 'string')
650+
),
651+
new OA\Parameter(
652+
name: 'fields',
653+
description: 'Comma-separated list of scalar fields to return, e.g. first_name,last_name,pic,public_profile_allow_chat_with_me',
654+
in: 'query',
655+
required: false,
656+
schema: new OA\Schema(type: 'string')
657+
),
658+
new OA\Parameter(
659+
name: 'relations',
660+
description: 'Comma-separated list of relations to include (supported: groups)',
661+
in: 'query',
662+
required: false,
663+
schema: new OA\Schema(type: 'string')
664+
),
643665
],
644666
responses: [
645667
new OA\Response(
@@ -663,22 +685,19 @@ public function userInfo()
663685
)]
664686
public function get($id)
665687
{
666-
try {
688+
return $this->processRequest(function () use ($id) {
667689
$user = $this->repository->getById(intval($id));
668690
if (is_null($user)) {
669691
throw new EntityNotFoundException();
670692
}
671-
return $this->ok(SerializerRegistry::getInstance()->getSerializer($user, SerializerRegistry::SerializerType_Private)->serialize());
672-
} catch (ValidationException $ex1) {
673-
Log::warning($ex1);
674-
return $this->error412($ex1->getMessages());
675-
} catch (EntityNotFoundException $ex2) {
676-
Log::warning($ex2);
677-
return $this->error404(['message' => $ex2->getMessage()]);
678-
} catch (Exception $ex) {
679-
Log::error($ex);
680-
return $this->error500($ex);
681-
}
693+
return $this->ok(SerializerRegistry::getInstance()
694+
->getSerializer($user, SerializerRegistry::SerializerType_Private)
695+
->serialize(
696+
SerializerUtils::getExpand(),
697+
SerializerUtils::getFields(),
698+
SerializerUtils::getRelations()
699+
));
700+
});
682701
}
683702

684703
/**
@@ -716,6 +735,20 @@ public function get($id)
716735
required: false,
717736
schema: new OA\Schema(type: 'string')
718737
),
738+
new OA\Parameter(
739+
name: 'fields',
740+
description: 'Comma-separated list of scalar fields to return, e.g. first_name,last_name,pic,public_profile_allow_chat_with_me',
741+
in: 'query',
742+
required: false,
743+
schema: new OA\Schema(type: 'string')
744+
),
745+
new OA\Parameter(
746+
name: 'relations',
747+
description: 'Comma-separated list of relations to include (supported: groups)',
748+
in: 'query',
749+
required: false,
750+
schema: new OA\Schema(type: 'string')
751+
),
719752
],
720753
responses: [
721754
new OA\Response(
@@ -747,7 +780,9 @@ public function getV2($id)
747780
return $this->ok(SerializerRegistry::getInstance()
748781
->getSerializer($user, SerializerRegistry::SerializerType_Private)
749782
->serialize(
750-
Request::input("expand", '')
783+
SerializerUtils::getExpand(),
784+
SerializerUtils::getFields(),
785+
SerializerUtils::getRelations()
751786
));
752787
});
753788
}

app/ModelSerializers/Auth/UserSerializer.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ final class PublicUserSerializer extends BaseUserSerializer
4646
final class PrivateUserSerializer extends BaseUserSerializer
4747
{
4848

49+
protected static $allowed_relations = [
50+
'groups',
51+
];
52+
4953
protected static $array_mappings = [
5054
'Email' => 'email:json_string',
5155
'Identifier' => 'identifier:json_string',
@@ -96,15 +100,19 @@ public function serialize($expand = null, array $fields = [], array $relations =
96100
$user = $this->object;
97101
if (!$user instanceof User) return [];
98102

103+
if (!count($relations)) $relations = $this->getAllowedRelations();
104+
99105
$values = parent::serialize($expand, $fields, $relations, $params);
100106

101-
$groups = [];
102-
foreach ($user->getGroups() as $group) {
103-
if (!$group instanceof Group) continue;
104-
$groups[] = $group->getSlug();
105-
}
107+
if (in_array('groups', $relations)) {
108+
$groups = [];
109+
foreach ($user->getGroups() as $group) {
110+
if (!$group instanceof Group) continue;
111+
$groups[] = $group->getSlug();
112+
}
106113

107-
$values['groups'] = $groups;
114+
$values['groups'] = $groups;
115+
}
108116

109117
if (!empty($expand)) {
110118
$exp_expand = explode(',', $expand);

0 commit comments

Comments
 (0)