Skip to content

Commit 4d27486

Browse files
authored
Merge pull request #30 from LibreCodeCoop/feat/url-field-type
feat(url): add URL field type
2 parents a376e5c + 6d14253 commit 4d27486

26 files changed

Lines changed: 267 additions & 18 deletions
29 KB
Loading

lib/Enum/FieldType.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ enum FieldType: string {
1414
case NUMBER = 'number';
1515
case BOOLEAN = 'boolean';
1616
case DATE = 'date';
17+
case URL = 'url';
1718
case SELECT = 'select';
1819
case MULTISELECT = 'multiselect';
1920

@@ -26,6 +27,7 @@ public static function values(): array {
2627
self::NUMBER->value,
2728
self::BOOLEAN->value,
2829
self::DATE->value,
30+
self::URL->value,
2931
self::SELECT->value,
3032
self::MULTISELECT->value,
3133
];

lib/ResponseDefinitions.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
namespace OCA\ProfileFields;
1111

1212
/**
13-
* @psalm-type ProfileFieldsType = 'text'|'number'|'boolean'|'date'|'select'|'multiselect'
13+
* @psalm-type ProfileFieldsType = 'text'|'number'|'boolean'|'date'|'url'|'select'|'multiselect'
1414
* @psalm-type ProfileFieldsVisibility = 'private'|'users'|'public'
1515
* @psalm-type ProfileFieldsEditPolicy = 'admins'|'users'
1616
* @psalm-type ProfileFieldsExposurePolicy = 'hidden'|'private'|'users'|'public'

lib/Service/DataImportService.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public function import(array $payload, bool $dryRun = false): array {
6969
* @param list<array{
7070
* field_key: non-empty-string,
7171
* label: non-empty-string,
72-
* type: 'text'|'number'|'boolean'|'date'|'select'|'multiselect',
72+
* type: 'text'|'number'|'boolean'|'date'|'url'|'select'|'multiselect',
7373
* edit_policy: 'admins'|'users',
7474
* exposure_policy: 'hidden'|'private'|'users'|'public',
7575
* sort_order: int,
@@ -148,7 +148,7 @@ private function collectValueSummary(array $values, array &$summary): void {
148148
* @param list<array{
149149
* field_key: non-empty-string,
150150
* label: non-empty-string,
151-
* type: 'text'|'number'|'boolean'|'date'|'select'|'multiselect',
151+
* type: 'text'|'number'|'boolean'|'date'|'url'|'select'|'multiselect',
152152
* edit_policy: 'admins'|'users',
153153
* exposure_policy: 'hidden'|'private'|'users'|'public',
154154
* sort_order: int,
@@ -248,7 +248,7 @@ private function persistValues(array $values, array $definitionsByFieldKey, arra
248248
* @param array{
249249
* field_key: non-empty-string,
250250
* label: non-empty-string,
251-
* type: 'text'|'number'|'boolean'|'date'|'select'|'multiselect',
251+
* type: 'text'|'number'|'boolean'|'date'|'url'|'select'|'multiselect',
252252
* edit_policy: 'admins'|'users',
253253
* exposure_policy: 'hidden'|'private'|'users'|'public',
254254
* sort_order: int,

lib/Service/FieldDefinitionValidator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class FieldDefinitionValidator {
2929
* @return array{
3030
* field_key: non-empty-string,
3131
* label: non-empty-string,
32-
* type: 'text'|'number'|'boolean'|'date'|'select'|'multiselect',
32+
* type: 'text'|'number'|'boolean'|'date'|'url'|'select'|'multiselect',
3333
* edit_policy: 'admins'|'users',
3434
* exposure_policy: 'hidden'|'private'|'users'|'public',
3535
* sort_order: int,

lib/Service/FieldValueService.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ public function normalizeValue(FieldDefinition $definition, array|string|int|flo
108108
FieldType::NUMBER => $this->normalizeNumberValue($rawValue),
109109
FieldType::BOOLEAN => $this->normalizeBooleanValue($rawValue),
110110
FieldType::DATE => $this->normalizeDateValue($rawValue),
111+
FieldType::URL => $this->normalizeUrlValue($rawValue),
111112
FieldType::SELECT => $this->normalizeSelectValue($rawValue, $definition),
112113
FieldType::MULTISELECT => $this->normalizeMultiSelectValue($rawValue, $definition),
113114
};
@@ -349,6 +350,23 @@ private function normalizeDateValue(array|string|int|float|bool $rawValue): arra
349350
return ['value' => $value];
350351
}
351352

353+
/**
354+
* @param array<string, mixed>|scalar $rawValue
355+
* @return array{value: string}
356+
*/
357+
private function normalizeUrlValue(array|string|int|float|bool $rawValue): array {
358+
if (!is_string($rawValue)) {
359+
throw new InvalidArgumentException($this->l10n->t('URL fields require a valid URL.'));
360+
}
361+
362+
$value = trim($rawValue);
363+
if (filter_var($value, FILTER_VALIDATE_URL) === false) {
364+
throw new InvalidArgumentException($this->l10n->t('URL fields require a valid URL.'));
365+
}
366+
367+
return ['value' => $value];
368+
}
369+
352370
/**
353371
* @param array<string, mixed> $value
354372
*/

lib/Service/ImportPayloadValidator.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function __construct(
3232
* definitions: list<array{
3333
* field_key: non-empty-string,
3434
* label: non-empty-string,
35-
* type: 'text'|'number'|'boolean'|'date'|'select'|'multiselect',
35+
* type: 'text'|'number'|'boolean'|'date'|'url'|'select'|'multiselect',
3636
* edit_policy: 'admins'|'users',
3737
* exposure_policy: 'hidden'|'private'|'users'|'public',
3838
* sort_order: int,
@@ -71,7 +71,7 @@ public function validate(array $payload): array {
7171
* @return array<non-empty-string, array{
7272
* field_key: non-empty-string,
7373
* label: non-empty-string,
74-
* type: 'text'|'number'|'boolean'|'date'|'select'|'multiselect',
74+
* type: 'text'|'number'|'boolean'|'date'|'url'|'select'|'multiselect',
7575
* edit_policy: 'admins'|'users',
7676
* exposure_policy: 'hidden'|'private'|'users'|'public',
7777
* sort_order: int,
@@ -119,7 +119,7 @@ private function validateDefinitions(array $definitions): array {
119119
* @param array<non-empty-string, array{
120120
* field_key: non-empty-string,
121121
* label: non-empty-string,
122-
* type: 'text'|'number'|'boolean'|'date'|'select'|'multiselect',
122+
* type: 'text'|'number'|'boolean'|'date'|'url'|'select'|'multiselect',
123123
* edit_policy: 'admins'|'users',
124124
* exposure_policy: 'hidden'|'private'|'users'|'public',
125125
* sort_order: int,
@@ -255,7 +255,7 @@ private function normalizeOptionalDate(array $payload, string $key, string $mess
255255
* @param array{
256256
* field_key: non-empty-string,
257257
* label: non-empty-string,
258-
* type: 'text'|'number'|'boolean'|'date'|'select'|'multiselect',
258+
* type: 'text'|'number'|'boolean'|'date'|'url'|'select'|'multiselect',
259259
* edit_policy: 'admins'|'users',
260260
* exposure_policy: 'hidden'|'private'|'users'|'public',
261261
* sort_order: int,

lib/Workflow/UserProfileFieldCheck.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ class UserProfileFieldCheck implements ICheck {
5959
'is',
6060
'!is',
6161
];
62+
private const URL_OPERATORS = [
63+
self::OPERATOR_IS_SET,
64+
self::OPERATOR_IS_NOT_SET,
65+
'is',
66+
'!is',
67+
'contains',
68+
'!contains',
69+
];
6270
private const SELECT_OPERATORS = [
6371
self::OPERATOR_IS_SET,
6472
self::OPERATOR_IS_NOT_SET,
@@ -122,8 +130,11 @@ public function validateCheck($operator, $value) {
122130

123131
if ($this->operatorRequiresValue((string)$operator)) {
124132
try {
125-
if (FieldType::from($definition->getType()) === FieldType::MULTISELECT) {
133+
$fieldType = FieldType::from($definition->getType());
134+
if ($fieldType === FieldType::MULTISELECT) {
126135
$this->normalizeExpectedMultiSelectOperand($definition, $config['value']);
136+
} elseif ($fieldType === FieldType::URL && ((string)$operator === 'contains' || (string)$operator === '!contains')) {
137+
// URL contains search terms are plain substrings — no URL validation needed.
127138
} else {
128139
$this->fieldValueService->normalizeValue($definition, $config['value']);
129140
}
@@ -184,6 +195,7 @@ private function isOperatorSupported(FieldDefinition $definition, string $operat
184195
FieldType::NUMBER => self::NUMBER_OPERATORS,
185196
FieldType::BOOLEAN => self::BOOLEAN_OPERATORS,
186197
FieldType::DATE => self::DATE_OPERATORS,
198+
FieldType::URL => self::URL_OPERATORS,
187199
FieldType::SELECT => self::SELECT_OPERATORS,
188200
FieldType::MULTISELECT => self::SELECT_OPERATORS,
189201
};
@@ -249,11 +261,16 @@ private function evaluate(FieldDefinition $definition, string $operator, string|
249261
return $this->evaluateMultiSelectOperator($operator, $expectedValue, $actualValue);
250262
}
251263

264+
if ($fieldType === FieldType::URL && ($operator === 'contains' || $operator === '!contains')) {
265+
return $this->evaluateTextOperator($operator, trim((string)$expectedRawValue), (string)$actualValue);
266+
}
267+
252268
$normalizedExpected = $this->fieldValueService->normalizeValue($definition, $expectedRawValue);
253269
$expectedValue = $normalizedExpected['value'] ?? null;
254270

255271
return match ($fieldType) {
256272
FieldType::TEXT,
273+
FieldType::URL,
257274
FieldType::SELECT => $this->evaluateTextOperator($operator, (string)$expectedValue, (string)$actualValue),
258275
FieldType::BOOLEAN => $this->evaluateBooleanOperator(
259276
$operator,

openapi-administration.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@
200200
"number",
201201
"boolean",
202202
"date",
203+
"url",
203204
"select",
204205
"multiselect"
205206
]

openapi-full.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@
275275
"number",
276276
"boolean",
277277
"date",
278+
"url",
278279
"select",
279280
"multiselect"
280281
]

0 commit comments

Comments
 (0)