Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
0b8d5a0
test(php): inject IL10N mock into FieldDefinitionServiceTest setUp
vitormattos Mar 20, 2026
1ed73dc
test(php): inject IL10N mock into FieldValueServiceTest setUp
vitormattos Mar 20, 2026
a7c4add
test(php): pass IL10N to FieldValueService in UserProfileFieldCheckTest
vitormattos Mar 20, 2026
0104829
test(php): pass IL10N to FieldValueService in LogProfileFieldChangeOp…
vitormattos Mar 20, 2026
4686c28
test(php): assert raw exception message in FieldDefinitionApiControll…
vitormattos Mar 20, 2026
2dcac3c
test(php): assert raw exception message in FieldValueAdminApiControll…
vitormattos Mar 20, 2026
e7f961b
test(php): assert raw exception message in FieldValueApiController ca…
vitormattos Mar 20, 2026
8f30b23
test(php): pass IL10N to FieldDefinitionApiController in integration …
vitormattos Mar 20, 2026
cb8cc4f
test(php): pass IL10N to FieldValueAdminApiController in integration …
vitormattos Mar 20, 2026
5c26937
test(php): pass IL10N to FieldValueApiController in integration test
vitormattos Mar 20, 2026
4ef29c1
refactor(php): inject IL10N into FieldDefinitionService and translate…
vitormattos Mar 20, 2026
009f128
refactor(php): inject IL10N into FieldValueService and translate thro…
vitormattos Mar 20, 2026
c5e184b
refactor(php): remove t() wrapping from catch blocks in FieldDefiniti…
vitormattos Mar 20, 2026
364cc7d
refactor(php): remove t() wrapping from catch blocks in FieldValueAdm…
vitormattos Mar 20, 2026
fc59d73
refactor(php): remove t() wrapping from catch blocks in FieldValueApi…
vitormattos Mar 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions lib/Controller/FieldDefinitionApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use OCP\AppFramework\Http\Attribute\ApiRoute;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IL10N;
use OCP\IRequest;

/**
Expand All @@ -26,6 +27,7 @@ class FieldDefinitionApiController extends OCSController {
public function __construct(
IRequest $request,
private FieldDefinitionService $fieldDefinitionService,
private IL10N $l10n,
) {
parent::__construct(Application::APP_ID, $request);
}
Expand Down Expand Up @@ -129,7 +131,7 @@ public function update(
): DataResponse {
$existing = $this->fieldDefinitionService->findById($id);
if ($existing === null) {
return new DataResponse(['message' => 'Field definition not found'], Http::STATUS_NOT_FOUND);
return new DataResponse(['message' => $this->l10n->t('Field definition not found')], Http::STATUS_NOT_FOUND);
}

try {
Expand Down Expand Up @@ -167,7 +169,7 @@ public function update(
public function delete(int $id): DataResponse {
$definition = $this->fieldDefinitionService->delete($id);
if ($definition === null) {
return new DataResponse(['message' => 'Field definition not found'], Http::STATUS_NOT_FOUND);
return new DataResponse(['message' => $this->l10n->t('Field definition not found')], Http::STATUS_NOT_FOUND);
}

return new DataResponse($definition->jsonSerialize(), Http::STATUS_OK);
Expand Down
18 changes: 10 additions & 8 deletions lib/Controller/FieldValueAdminApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use OCP\AppFramework\Http\Attribute\ApiRoute;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IL10N;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserManager;
Expand All @@ -35,6 +36,7 @@ public function __construct(
private FieldDefinitionService $fieldDefinitionService,
private FieldValueService $fieldValueService,
private IUserManager $userManager,
private IL10N $l10n,
private ?string $userId,
) {
parent::__construct(Application::APP_ID, $request);
Expand Down Expand Up @@ -82,12 +84,12 @@ public function upsert(
?string $currentVisibility = null,
): DataResponse {
if ($this->userId === null) {
return new DataResponse(['message' => 'Authenticated admin user is required'], Http::STATUS_UNAUTHORIZED);
return new DataResponse(['message' => $this->l10n->t('Authenticated admin user is required')], Http::STATUS_UNAUTHORIZED);
}

$definition = $this->fieldDefinitionService->findById($fieldDefinitionId);
if ($definition === null || !$definition->getActive()) {
return new DataResponse(['message' => 'Field definition not found'], Http::STATUS_NOT_FOUND);
return new DataResponse(['message' => $this->l10n->t('Field definition not found')], Http::STATUS_NOT_FOUND);
}

try {
Expand Down Expand Up @@ -122,12 +124,12 @@ public function lookup(
array|string|int|float|bool|null $fieldValue = null,
): DataResponse {
if ($this->userId === null) {
return new DataResponse(['message' => 'Authenticated admin user is required'], Http::STATUS_UNAUTHORIZED);
return new DataResponse(['message' => $this->l10n->t('Authenticated admin user is required')], Http::STATUS_UNAUTHORIZED);
}

$definition = $this->fieldDefinitionService->findByFieldKey($fieldKey);
if ($definition === null || !$definition->getActive()) {
return new DataResponse(['message' => 'Lookup field definition not found'], Http::STATUS_NOT_FOUND);
return new DataResponse(['message' => $this->l10n->t('Lookup field definition not found')], Http::STATUS_NOT_FOUND);
}

try {
Expand All @@ -137,11 +139,11 @@ public function lookup(
}

if ($matches === []) {
return new DataResponse(['message' => 'User not found for lookup field value'], Http::STATUS_NOT_FOUND);
return new DataResponse(['message' => $this->l10n->t('User not found for lookup field value')], Http::STATUS_NOT_FOUND);
}

if (count($matches) > 1) {
return new DataResponse(['message' => 'Multiple users match the lookup field value'], Http::STATUS_CONFLICT);
return new DataResponse(['message' => $this->l10n->t('Multiple users match the lookup field value')], Http::STATUS_CONFLICT);
}

return new DataResponse($this->serializeLookupResult($definition, $matches[0]), Http::STATUS_OK);
Expand Down Expand Up @@ -174,12 +176,12 @@ public function search(
int $offset = 0,
): DataResponse {
if ($this->userId === null) {
return new DataResponse(['message' => 'Authenticated admin user is required'], Http::STATUS_UNAUTHORIZED);
return new DataResponse(['message' => $this->l10n->t('Authenticated admin user is required')], Http::STATUS_UNAUTHORIZED);
}

$definition = $this->fieldDefinitionService->findByFieldKey($fieldKey);
if ($definition === null || !$definition->getActive()) {
return new DataResponse(['message' => 'Search field definition not found'], Http::STATUS_NOT_FOUND);
return new DataResponse(['message' => $this->l10n->t('Search field definition not found')], Http::STATUS_NOT_FOUND);
}

try {
Expand Down
20 changes: 11 additions & 9 deletions lib/Controller/FieldValueApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IL10N;
use OCP\IRequest;

/**
Expand All @@ -32,6 +33,7 @@ public function __construct(
private FieldDefinitionService $fieldDefinitionService,
private FieldValueService $fieldValueService,
private FieldAccessService $fieldAccessService,
private IL10N $l10n,
private ?string $userId,
) {
parent::__construct(Application::APP_ID, $request);
Expand All @@ -52,7 +54,7 @@ public function __construct(
#[ApiRoute(verb: 'GET', url: '/api/v1/me/values')]
public function index(): DataResponse {
if ($this->userId === null) {
return new DataResponse(['message' => 'Authenticated user is required'], 401);
return new DataResponse(['message' => $this->l10n->t('Authenticated user is required')], 401);
}

$definitions = $this->fieldDefinitionService->findActiveOrdered();
Expand Down Expand Up @@ -113,20 +115,20 @@ public function upsert(
?string $currentVisibility = null,
): DataResponse {
if ($this->userId === null) {
return new DataResponse(['message' => 'Authenticated user is required'], 401);
return new DataResponse(['message' => $this->l10n->t('Authenticated user is required')], 401);
}

$definition = $this->fieldDefinitionService->findById($fieldDefinitionId);
if ($definition === null || !$definition->getActive()) {
return new DataResponse(['message' => 'Field definition not found'], 404);
return new DataResponse(['message' => $this->l10n->t('Field definition not found')], 404);
}

if (!$this->fieldAccessService->canEditValue($this->userId, $this->userId, $definition, false)) {
return new DataResponse(['message' => 'Field cannot be edited by the user'], 403);
return new DataResponse(['message' => $this->l10n->t('Field cannot be edited by the user')], 403);
}

if ($currentVisibility !== null && !$this->fieldAccessService->canChangeVisibility($this->userId, $this->userId, false)) {
return new DataResponse(['message' => 'Field visibility cannot be changed by the user'], 403);
return new DataResponse(['message' => $this->l10n->t('Field visibility cannot be changed by the user')], 403);
}

try {
Expand Down Expand Up @@ -160,20 +162,20 @@ public function updateVisibility(
string $currentVisibility,
): DataResponse {
if ($this->userId === null) {
return new DataResponse(['message' => 'Authenticated user is required'], 401);
return new DataResponse(['message' => $this->l10n->t('Authenticated user is required')], 401);
}

$definition = $this->fieldDefinitionService->findById($fieldDefinitionId);
if ($definition === null || !$definition->getActive()) {
return new DataResponse(['message' => 'Field definition not found'], 404);
return new DataResponse(['message' => $this->l10n->t('Field definition not found')], 404);
}

if (!$this->fieldAccessService->canEditValue($this->userId, $this->userId, $definition, false)) {
return new DataResponse(['message' => 'Field cannot be edited by the user'], 403);
return new DataResponse(['message' => $this->l10n->t('Field cannot be edited by the user')], 403);
}

if (!$this->fieldAccessService->canChangeVisibility($this->userId, $this->userId, false)) {
return new DataResponse(['message' => 'Field visibility cannot be changed by the user'], 403);
return new DataResponse(['message' => $this->l10n->t('Field visibility cannot be changed by the user')], 403);
}

try {
Expand Down
12 changes: 7 additions & 5 deletions lib/Service/FieldDefinitionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
use OCA\ProfileFields\Db\FieldDefinition;
use OCA\ProfileFields\Db\FieldDefinitionMapper;
use OCA\ProfileFields\Db\FieldValueMapper;
use OCP\IL10N;

class FieldDefinitionService {
public function __construct(
private FieldDefinitionMapper $fieldDefinitionMapper,
private FieldValueMapper $fieldValueMapper,
private FieldDefinitionValidator $validator,
private IL10N $l10n,
) {
}

Expand All @@ -30,7 +32,7 @@ public function __construct(
public function create(array $definition): FieldDefinition {
$validated = $this->validator->validate($definition);
if ($this->fieldDefinitionMapper->findByFieldKey($validated['field_key']) !== null) {
throw new InvalidArgumentException('field_key already exists');
throw new InvalidArgumentException($this->l10n->t('field_key already exists'));
}

$createdAt = $this->parseImportedDate($definition['created_at'] ?? null) ?? new DateTime();
Expand All @@ -46,7 +48,7 @@ public function create(array $definition): FieldDefinition {
try {
$entity->setOptions(isset($validated['options']) ? json_encode($validated['options'], JSON_THROW_ON_ERROR) : null);
} catch (JsonException $e) {
throw new InvalidArgumentException('options could not be encoded: ' . $e->getMessage(), 0, $e);
throw new InvalidArgumentException($this->l10n->t('options could not be encoded: %s', [$e->getMessage()]), 0, $e);
}
$entity->setCreatedAt($createdAt);
$entity->setUpdatedAt($updatedAt);
Expand All @@ -60,11 +62,11 @@ public function create(array $definition): FieldDefinition {
public function update(FieldDefinition $existing, array $definition): FieldDefinition {
$validated = $this->validator->validate($definition + ['field_key' => $existing->getFieldKey()]);
if (($definition['field_key'] ?? $existing->getFieldKey()) !== $existing->getFieldKey()) {
throw new InvalidArgumentException('field_key cannot be changed');
throw new InvalidArgumentException($this->l10n->t('field_key cannot be changed'));
}

if ($validated['type'] !== $existing->getType() && $this->fieldValueMapper->hasValuesForFieldDefinitionId($existing->getId())) {
throw new InvalidArgumentException('type cannot be changed after values exist');
throw new InvalidArgumentException($this->l10n->t('type cannot be changed after values exist'));
}

$existing->setLabel($validated['label']);
Expand All @@ -76,7 +78,7 @@ public function update(FieldDefinition $existing, array $definition): FieldDefin
try {
$existing->setOptions(isset($validated['options']) ? json_encode($validated['options'], JSON_THROW_ON_ERROR) : null);
} catch (JsonException $e) {
throw new InvalidArgumentException('options could not be encoded: ' . $e->getMessage(), 0, $e);
throw new InvalidArgumentException($this->l10n->t('options could not be encoded: %s', [$e->getMessage()]), 0, $e);
}
$existing->setUpdatedAt($this->parseImportedDate($definition['updated_at'] ?? null) ?? new DateTime());

Expand Down
32 changes: 17 additions & 15 deletions lib/Service/FieldValueService.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use OCA\ProfileFields\Workflow\Event\ProfileFieldVisibilityUpdatedEvent;
use OCA\ProfileFields\Workflow\ProfileFieldValueWorkflowSubject;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IL10N;

class FieldValueService {
private const SEARCH_OPERATOR_EQ = 'eq';
Expand All @@ -33,6 +34,7 @@ class FieldValueService {
public function __construct(
private FieldValueMapper $fieldValueMapper,
private IEventDispatcher $eventDispatcher,
private IL10N $l10n,
) {
}

Expand All @@ -51,7 +53,7 @@ public function upsert(
$valueJson = $this->encodeValue($normalizedValue);
$visibility = $currentVisibility ?? FieldExposurePolicy::from($definition->getExposurePolicy())->initialVisibility()->value;
if (!FieldVisibility::isValid($visibility)) {
throw new InvalidArgumentException('current_visibility is not supported');
throw new InvalidArgumentException($this->l10n->t('current_visibility is not supported'));
}

$entity = $this->fieldValueMapper->findByFieldDefinitionIdAndUserUid($definition->getId(), $userUid) ?? new FieldValue();
Expand Down Expand Up @@ -143,16 +145,16 @@ public function searchByDefinition(
int $offset,
): array {
if ($limit < 1 || $limit > self::SEARCH_MAX_LIMIT) {
throw new InvalidArgumentException(sprintf('limit must be between 1 and %d', self::SEARCH_MAX_LIMIT));
throw new InvalidArgumentException($this->l10n->t('limit must be between 1 and %d', [self::SEARCH_MAX_LIMIT]));
}

if ($offset < 0) {
throw new InvalidArgumentException('offset must be greater than or equal to 0');
throw new InvalidArgumentException($this->l10n->t('offset must be greater than or equal to 0'));
}

$normalizedOperator = strtolower(trim($operator));
if (!in_array($normalizedOperator, [self::SEARCH_OPERATOR_EQ, self::SEARCH_OPERATOR_CONTAINS], true)) {
throw new InvalidArgumentException('search operator is not supported');
throw new InvalidArgumentException($this->l10n->t('search operator is not supported'));
}

$searchValue = $this->normalizeSearchValue($definition, $normalizedOperator, $rawValue);
Expand All @@ -175,12 +177,12 @@ public function searchByDefinition(

public function updateVisibility(FieldDefinition $definition, string $userUid, string $updatedByUid, string $currentVisibility): FieldValue {
if (!FieldVisibility::isValid($currentVisibility)) {
throw new InvalidArgumentException('current_visibility is not supported');
throw new InvalidArgumentException($this->l10n->t('current_visibility is not supported'));
}

$entity = $this->fieldValueMapper->findByFieldDefinitionIdAndUserUid($definition->getId(), $userUid);
if ($entity === null) {
throw new InvalidArgumentException('field value not found');
throw new InvalidArgumentException($this->l10n->t('field value not found'));
}

$previousValue = $this->extractScalarValue($entity->getValueJson());
Expand Down Expand Up @@ -227,7 +229,7 @@ public function serializeForResponse(FieldValue $value): array {
*/
private function normalizeTextValue(array|string|int|float|bool $rawValue): array {
if (is_array($rawValue)) {
throw new InvalidArgumentException('text fields expect a scalar value');
throw new InvalidArgumentException($this->l10n->t('text fields expect a scalar value'));
}

return ['value' => trim((string)$rawValue)];
Expand All @@ -239,13 +241,13 @@ private function normalizeTextValue(array|string|int|float|bool $rawValue): arra
*/
private function normalizeSelectValue(array|string|int|float|bool $rawValue, FieldDefinition $definition): array {
if (!is_string($rawValue)) {
throw new InvalidArgumentException('select fields expect a string value');
throw new InvalidArgumentException($this->l10n->t('select fields expect a string value'));
}

$value = trim($rawValue);
$options = json_decode($definition->getOptions() ?? '[]', true);
if (!in_array($value, $options, true)) {
throw new InvalidArgumentException(sprintf('"%s" is not a valid option for this field', $value));
throw new InvalidArgumentException($this->l10n->t('"%s" is not a valid option for this field', [$value]));
}

return ['value' => $value];
Expand All @@ -257,7 +259,7 @@ private function normalizeSelectValue(array|string|int|float|bool $rawValue, Fie
*/
private function normalizeNumberValue(array|string|int|float|bool $rawValue): array {
if (is_array($rawValue) || is_bool($rawValue) || !is_numeric($rawValue)) {
throw new InvalidArgumentException('number fields expect a numeric value');
throw new InvalidArgumentException($this->l10n->t('number fields expect a numeric value'));
}

return ['value' => str_contains((string)$rawValue, '.') ? (float)$rawValue : (int)$rawValue];
Expand All @@ -270,7 +272,7 @@ private function encodeValue(array $value): string {
try {
return json_encode($value, JSON_THROW_ON_ERROR);
} catch (JsonException $exception) {
throw new InvalidArgumentException('value_json could not be encoded', 0, $exception);
throw new InvalidArgumentException($this->l10n->t('value_json could not be encoded'), 0, $exception);
}
}

Expand All @@ -281,11 +283,11 @@ private function decodeValue(string $valueJson): array {
try {
$decoded = json_decode($valueJson, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $exception) {
throw new InvalidArgumentException('value_json could not be decoded', 0, $exception);
throw new InvalidArgumentException($this->l10n->t('value_json could not be decoded'), 0, $exception);
}

if (!is_array($decoded)) {
throw new InvalidArgumentException('value_json must decode to an object payload');
throw new InvalidArgumentException($this->l10n->t('value_json must decode to an object payload'));
}

return $decoded;
Expand Down Expand Up @@ -326,13 +328,13 @@ private function normalizeSearchValue(FieldDefinition $definition, string $opera
}

if (FieldType::from($definition->getType()) !== FieldType::TEXT) {
throw new InvalidArgumentException('contains operator is only supported for text fields');
throw new InvalidArgumentException($this->l10n->t('contains operator is only supported for text fields'));
}

$normalized = $this->normalizeValue($definition, $rawValue);
$value = $normalized['value'] ?? null;
if (!is_string($value) || $value === '') {
throw new InvalidArgumentException('contains operator requires a non-empty text value');
throw new InvalidArgumentException($this->l10n->t('contains operator requires a non-empty text value'));
}

return ['value' => $value];
Expand Down
Loading
Loading