Add /subusers and /subusers/{id} endpoints for subuser management with permission-based visibility
- Implement routes to list and retrieve subusers based on grant visibility tied to the authenticated user's customer number. - Extend OpenAPI documentation with detailed descriptions, parameters, and response schemas for the new endpoints.
This commit is contained in:
+137
@@ -78,6 +78,81 @@ tags:
|
||||
paths:
|
||||
# Subusers (public registration + setup)
|
||||
/subusers:
|
||||
get:
|
||||
tags:
|
||||
- Subusers
|
||||
summary: List subusers visible to the authenticated user
|
||||
description: |
|
||||
Returns a paginated list of subusers (drivers) that have enabled grants tied to the
|
||||
authenticated user's customer number. Only subusers with at least one enabled, non-deleted
|
||||
grant for the caller's customer are returned.
|
||||
operationId: listSubusers
|
||||
parameters:
|
||||
- name: page
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
- name: limit
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 1000
|
||||
- name: search
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: List of visible subusers
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
username:
|
||||
type: string
|
||||
nullable: true
|
||||
name:
|
||||
type: string
|
||||
nullable: true
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
nullable: true
|
||||
phone_country_code:
|
||||
type: integer
|
||||
nullable: true
|
||||
phone:
|
||||
type: integer
|
||||
nullable: true
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
suspended_at:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
permissions:
|
||||
type: array
|
||||
description: Aggregated permission keys granted for the caller's customer
|
||||
items:
|
||||
type: string
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||||
post:
|
||||
tags:
|
||||
- Subusers
|
||||
@@ -130,6 +205,68 @@ paths:
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||||
|
||||
/subusers/{id}:
|
||||
get:
|
||||
tags:
|
||||
- Subusers
|
||||
summary: Get a subuser by ID (visible by grant)
|
||||
description: |
|
||||
Returns the subuser if the authenticated user has at least one enabled, non-deleted grant
|
||||
for their customer number to this subuser. Otherwise returns 404.
|
||||
operationId: getSubuser
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: Subuser details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
username:
|
||||
type: string
|
||||
nullable: true
|
||||
name:
|
||||
type: string
|
||||
nullable: true
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
nullable: true
|
||||
phone_country_code:
|
||||
type: integer
|
||||
nullable: true
|
||||
phone:
|
||||
type: integer
|
||||
nullable: true
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
suspended_at:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
permissions:
|
||||
type: array
|
||||
description: Aggregated permission keys granted for the caller's customer
|
||||
items:
|
||||
type: string
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||||
|
||||
/subusers/setup:
|
||||
get:
|
||||
tags:
|
||||
|
||||
@@ -429,5 +429,88 @@ class subusersRoute
|
||||
$response->error($e->getMessage(), 500);
|
||||
}
|
||||
});
|
||||
|
||||
// =============================
|
||||
// Subusers - List & Get (with grant visibility)
|
||||
// =============================
|
||||
$this->get('/subusers', function () {
|
||||
global $response;
|
||||
// Require authenticated user
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user === false) {
|
||||
$response->error('Unauthorized', 401);
|
||||
}
|
||||
$customerNumber = (int)$user->customer_number->value();
|
||||
if ($customerNumber === 0) {
|
||||
$response->error('Unauthorized', 401);
|
||||
}
|
||||
|
||||
// Only list subusers that have an enabled grant for the caller's customer number
|
||||
$existsClause = sprintf(
|
||||
"EXISTS (SELECT 1 FROM `subuser_grants` sg WHERE sg.`subuser` = `subusers`.`id` AND sg.`enabled` = 1 AND sg.`deleted_at` IS NULL AND sg.`billing_customer_number` = %d)",
|
||||
$customerNumber
|
||||
);
|
||||
|
||||
// Use pagination helper with additional where
|
||||
$objects = (new subusers_o())
|
||||
->listObjectsWithPaginationIfSet(function ($o) use ($customerNumber) {
|
||||
$o = (object)$o;
|
||||
$permissions = (new subuser_grants_o())
|
||||
->getGrantsForSubuserAndCustomer((int)$o->id, $customerNumber);
|
||||
return [
|
||||
'id' => (int)$o->id,
|
||||
'username' => $o->username,
|
||||
'name' => $o->name,
|
||||
'email' => $o->email,
|
||||
'phone_country_code' => isset($o->phone_country_code) ? (int)$o->phone_country_code : null,
|
||||
'phone' => isset($o->phone) ? (int)$o->phone : null,
|
||||
'created_at' => $o->created_at ?? null,
|
||||
'updated_at' => $o->updated_at ?? null,
|
||||
'suspended_at' => $o->suspended_at ?? null,
|
||||
'permissions' => $permissions,
|
||||
];
|
||||
}, null, [], $existsClause);
|
||||
|
||||
$response->success($objects);
|
||||
}, []);
|
||||
|
||||
$this->get('/subusers/{id}', function () {
|
||||
global $response;
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user === false) {
|
||||
$response->error('Unauthorized', 401);
|
||||
}
|
||||
$customerNumber = (int)$user->customer_number->value();
|
||||
if ($customerNumber === 0) {
|
||||
$response->error('Unauthorized', 401);
|
||||
}
|
||||
$id = (int)self::fromRoute('id');
|
||||
self::requireType($id, self::type_int());
|
||||
|
||||
$subuser = (new subusers_o())->select($id);
|
||||
if (!$subuser->exists()) {
|
||||
$response->error('Subuser not found', 404);
|
||||
}
|
||||
|
||||
// Check visibility via grants
|
||||
$permissions = (new subuser_grants_o())->getGrantsForSubuserAndCustomer($id, $customerNumber);
|
||||
if (empty($permissions)) {
|
||||
// Hide existence if not visible
|
||||
$response->error('Subuser not found', 404);
|
||||
}
|
||||
|
||||
$response->success([
|
||||
'id' => (int)$subuser->id,
|
||||
'username' => $subuser->username->value(),
|
||||
'name' => $subuser->name->value(),
|
||||
'email' => $subuser->email->value(),
|
||||
'phone_country_code' => (int)$subuser->phone_country_code->value(),
|
||||
'phone' => (int)$subuser->phone->value(),
|
||||
'created_at' => $subuser->created_at->value(),
|
||||
'updated_at' => $subuser->updated_at->value(),
|
||||
'suspended_at' => $subuser->suspended_at->value(),
|
||||
'permissions' => $permissions,
|
||||
]);
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user