Skip to content

Commit 4a166c1

Browse files
authored
Merge pull request #31 from LibreCodeCoop/feat/email-field-type
feat(email): add email field type
2 parents 4d27486 + 1dfcd79 commit 4a166c1

26 files changed

+264
-26
lines changed
321 KB
Loading

lib/Enum/FieldType.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ enum FieldType: string {
1515
case BOOLEAN = 'boolean';
1616
case DATE = 'date';
1717
case URL = 'url';
18+
case EMAIL = 'email';
1819
case SELECT = 'select';
1920
case MULTISELECT = 'multiselect';
2021

@@ -28,6 +29,7 @@ public static function values(): array {
2829
self::BOOLEAN->value,
2930
self::DATE->value,
3031
self::URL->value,
32+
self::EMAIL->value,
3133
self::SELECT->value,
3234
self::MULTISELECT->value,
3335
];

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'|'url'|'select'|'multiselect'
13+
* @psalm-type ProfileFieldsType = 'text'|'number'|'boolean'|'date'|'url'|'email'|'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'|'url'|'select'|'multiselect',
72+
* type: 'text'|'number'|'boolean'|'date'|'url'|'email'|'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'|'url'|'select'|'multiselect',
151+
* type: 'text'|'number'|'boolean'|'date'|'url'|'email'|'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'|'url'|'select'|'multiselect',
251+
* type: 'text'|'number'|'boolean'|'date'|'url'|'email'|'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'|'url'|'select'|'multiselect',
32+
* type: 'text'|'number'|'boolean'|'date'|'url'|'email'|'select'|'multiselect',
3333
* edit_policy: 'admins'|'users',
3434
* exposure_policy: 'hidden'|'private'|'users'|'public',
3535
* sort_order: int,

lib/Service/FieldValueService.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ public function normalizeValue(FieldDefinition $definition, array|string|int|flo
109109
FieldType::BOOLEAN => $this->normalizeBooleanValue($rawValue),
110110
FieldType::DATE => $this->normalizeDateValue($rawValue),
111111
FieldType::URL => $this->normalizeUrlValue($rawValue),
112+
FieldType::EMAIL => $this->normalizeEmailValue($rawValue),
112113
FieldType::SELECT => $this->normalizeSelectValue($rawValue, $definition),
113114
FieldType::MULTISELECT => $this->normalizeMultiSelectValue($rawValue, $definition),
114115
};
@@ -367,6 +368,23 @@ private function normalizeUrlValue(array|string|int|float|bool $rawValue): array
367368
return ['value' => $value];
368369
}
369370

371+
/**
372+
* @param array<string, mixed>|scalar $rawValue
373+
* @return array{value: string}
374+
*/
375+
private function normalizeEmailValue(array|string|int|float|bool $rawValue): array {
376+
if (!is_string($rawValue)) {
377+
throw new InvalidArgumentException($this->l10n->t('Email fields require a valid email address.'));
378+
}
379+
380+
$value = trim($rawValue);
381+
if (filter_var($value, FILTER_VALIDATE_EMAIL) === false) {
382+
throw new InvalidArgumentException($this->l10n->t('Email fields require a valid email address.'));
383+
}
384+
385+
return ['value' => $value];
386+
}
387+
370388
/**
371389
* @param array<string, mixed> $value
372390
*/
@@ -429,8 +447,8 @@ private function normalizeSearchValue(FieldDefinition $definition, string $opera
429447
return $this->normalizeValue($definition, $rawValue);
430448
}
431449

432-
if (FieldType::from($definition->getType()) !== FieldType::TEXT) {
433-
throw new InvalidArgumentException($this->l10n->t('The "contains" operator is only available for text fields.'));
450+
if (!in_array(FieldType::from($definition->getType()), [FieldType::TEXT, FieldType::EMAIL], true)) {
451+
throw new InvalidArgumentException($this->l10n->t('The "contains" operator is only available for text and email fields.'));
434452
}
435453

436454
$normalized = $this->normalizeValue($definition, $rawValue);
@@ -451,7 +469,7 @@ private function matchesSearchOperator(FieldType $fieldType, array $candidateVal
451469
return ($candidateValue['value'] ?? null) === ($searchValue['value'] ?? null);
452470
}
453471

454-
if ($fieldType !== FieldType::TEXT) {
472+
if (!in_array($fieldType, [FieldType::TEXT, FieldType::EMAIL], true)) {
455473
return false;
456474
}
457475

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'|'url'|'select'|'multiselect',
35+
* type: 'text'|'number'|'boolean'|'date'|'url'|'email'|'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'|'url'|'select'|'multiselect',
74+
* type: 'text'|'number'|'boolean'|'date'|'url'|'email'|'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'|'url'|'select'|'multiselect',
122+
* type: 'text'|'number'|'boolean'|'date'|'url'|'email'|'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'|'url'|'select'|'multiselect',
258+
* type: 'text'|'number'|'boolean'|'date'|'url'|'email'|'select'|'multiselect',
259259
* edit_policy: 'admins'|'users',
260260
* exposure_policy: 'hidden'|'private'|'users'|'public',
261261
* sort_order: int,

lib/Workflow/UserProfileFieldCheck.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ class UserProfileFieldCheck implements ICheck {
6767
'contains',
6868
'!contains',
6969
];
70+
private const EMAIL_OPERATORS = [
71+
self::OPERATOR_IS_SET,
72+
self::OPERATOR_IS_NOT_SET,
73+
'is',
74+
'!is',
75+
'contains',
76+
'!contains',
77+
];
7078
private const SELECT_OPERATORS = [
7179
self::OPERATOR_IS_SET,
7280
self::OPERATOR_IS_NOT_SET,
@@ -133,8 +141,11 @@ public function validateCheck($operator, $value) {
133141
$fieldType = FieldType::from($definition->getType());
134142
if ($fieldType === FieldType::MULTISELECT) {
135143
$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.
144+
} elseif (
145+
($fieldType === FieldType::URL || $fieldType === FieldType::EMAIL)
146+
&& ((string)$operator === 'contains' || (string)$operator === '!contains')
147+
) {
148+
// URL/email contains search terms are plain substrings — no strict value validation needed.
138149
} else {
139150
$this->fieldValueService->normalizeValue($definition, $config['value']);
140151
}
@@ -196,6 +207,7 @@ private function isOperatorSupported(FieldDefinition $definition, string $operat
196207
FieldType::BOOLEAN => self::BOOLEAN_OPERATORS,
197208
FieldType::DATE => self::DATE_OPERATORS,
198209
FieldType::URL => self::URL_OPERATORS,
210+
FieldType::EMAIL => self::EMAIL_OPERATORS,
199211
FieldType::SELECT => self::SELECT_OPERATORS,
200212
FieldType::MULTISELECT => self::SELECT_OPERATORS,
201213
};
@@ -261,7 +273,7 @@ private function evaluate(FieldDefinition $definition, string $operator, string|
261273
return $this->evaluateMultiSelectOperator($operator, $expectedValue, $actualValue);
262274
}
263275

264-
if ($fieldType === FieldType::URL && ($operator === 'contains' || $operator === '!contains')) {
276+
if (($fieldType === FieldType::URL || $fieldType === FieldType::EMAIL) && ($operator === 'contains' || $operator === '!contains')) {
265277
return $this->evaluateTextOperator($operator, trim((string)$expectedRawValue), (string)$actualValue);
266278
}
267279

@@ -271,6 +283,7 @@ private function evaluate(FieldDefinition $definition, string $operator, string|
271283
return match ($fieldType) {
272284
FieldType::TEXT,
273285
FieldType::URL,
286+
FieldType::EMAIL,
274287
FieldType::SELECT => $this->evaluateTextOperator($operator, (string)$expectedValue, (string)$actualValue),
275288
FieldType::BOOLEAN => $this->evaluateBooleanOperator(
276289
$operator,

openapi-administration.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@
201201
"boolean",
202202
"date",
203203
"url",
204+
"email",
204205
"select",
205206
"multiselect"
206207
]

openapi-full.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@
276276
"boolean",
277277
"date",
278278
"url",
279+
"email",
279280
"select",
280281
"multiselect"
281282
]

0 commit comments

Comments
 (0)