128 lines
5.2 KiB
PHP
128 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace App\Signature;
|
|
|
|
use App\Models\AuditLog;
|
|
use App\Models\DirectoryUser;
|
|
use App\Models\EditableField;
|
|
use App\Models\UserOverride;
|
|
use App\Models\UserPreference;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Illuminate\Validation\Rule;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
/**
|
|
* Informations modifiables par l'agent lui-même (add-in et portail).
|
|
* - Seuls les champs ouverts par l'admin sont acceptés.
|
|
* - Une surcharge ne modifie que la signature : l'annuaire (AD / Entra) reste la référence.
|
|
* - Valeur null = revenir à la valeur de l'annuaire ; chaîne vide = ne pas afficher ce champ.
|
|
* - Publication immédiate, chaque modification est tracée dans le journal d'audit.
|
|
*/
|
|
final class ProfileService
|
|
{
|
|
public const TYPES = [
|
|
'text' => ['label' => 'Texte libre', 'rule' => ['string', 'max:120']],
|
|
'phone' => ['label' => 'Téléphone', 'rule' => ['string', 'max:25', 'regex:/^[0-9 +().\-]{6,25}$/']],
|
|
];
|
|
|
|
/** @return array{fields: array<int, array>, reply_variant: ?string, reply_variant_default: string} */
|
|
public function profile(DirectoryUser $user): array
|
|
{
|
|
$editable = $this->editableFields($user);
|
|
$overrides = $user->overrides()->pluck('value', 'field');
|
|
|
|
$fields = [];
|
|
foreach ($editable as $f) {
|
|
$column = VariableMap::FIELDS[$f->field]['column'] ?? null;
|
|
if (! $column) {
|
|
continue;
|
|
}
|
|
$fields[] = [
|
|
'key' => $f->field,
|
|
'label' => $f->label,
|
|
'type' => $f->validation_rule ?: 'text',
|
|
'directory_value' => $user->getAttribute($column),
|
|
'override' => $overrides->has($f->field) ? $overrides[$f->field] : null,
|
|
'overridden' => $overrides->has($f->field),
|
|
];
|
|
}
|
|
|
|
return [
|
|
'fields' => $fields,
|
|
'reply_variant' => $user->preference?->reply_variant,
|
|
'reply_variant_default' => config('signature.default_reply_variant', 'short'),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array<string, string|null> $values clé de variable => valeur (null = rétablir l'annuaire)
|
|
*
|
|
* @throws \Illuminate\Validation\ValidationException
|
|
*/
|
|
public function update(DirectoryUser $user, array $values, ?string $replyVariant, bool $replyVariantProvided, string $actor): void
|
|
{
|
|
$editable = $this->editableFields($user)->keyBy('field');
|
|
|
|
$forbidden = array_diff(array_keys($values), $editable->keys()->all());
|
|
if ($forbidden) {
|
|
throw ValidationException::withMessages(
|
|
collect($forbidden)->mapWithKeys(fn ($k) => ["fields.{$k}" => 'Ce champ n\'est pas modifiable.'])->all()
|
|
);
|
|
}
|
|
|
|
$rules = ['reply_variant' => ['nullable', Rule::in(['short', 'full', 'none'])]];
|
|
foreach (array_keys($values) as $key) {
|
|
$type = $editable[$key]->validation_rule ?: 'text';
|
|
$rules["fields.{$key}"] = array_merge(['nullable'], self::TYPES[$type]['rule'] ?? self::TYPES['text']['rule']);
|
|
}
|
|
// Chaîne vide = masquer le champ : rien à valider pour elle.
|
|
Validator::make(
|
|
['fields' => array_filter($values, fn ($v) => $v !== ''), 'reply_variant' => $replyVariant],
|
|
$rules,
|
|
['fields.*.regex' => 'Numéro invalide (chiffres, espaces, + . - ( ) uniquement).', 'fields.*.max' => 'Valeur trop longue.'],
|
|
)->validate();
|
|
|
|
DB::transaction(function () use ($user, $values, $replyVariant, $replyVariantProvided, $actor) {
|
|
$changes = [];
|
|
foreach ($values as $key => $value) {
|
|
$value = $value === null ? null : trim((string) $value);
|
|
$current = UserOverride::where('directory_user_id', $user->id)->where('field', $key)->first();
|
|
|
|
if ($value === null) {
|
|
if ($current) {
|
|
$changes[$key] = [$current->value, '(annuaire)'];
|
|
$current->delete();
|
|
}
|
|
continue;
|
|
}
|
|
if ($current?->value === $value) {
|
|
continue;
|
|
}
|
|
$changes[$key] = [$current?->value ?? '(annuaire)', $value === '' ? '(masqué)' : $value];
|
|
UserOverride::updateOrCreate(['directory_user_id' => $user->id, 'field' => $key], ['value' => $value]);
|
|
}
|
|
|
|
if ($replyVariantProvided) {
|
|
$pref = UserPreference::firstOrNew(['directory_user_id' => $user->id]);
|
|
if ($pref->reply_variant !== $replyVariant) {
|
|
$changes['reply_variant'] = [$pref->reply_variant ?? '(défaut)', $replyVariant ?? '(défaut)'];
|
|
$pref->reply_variant = $replyVariant;
|
|
$pref->save();
|
|
}
|
|
}
|
|
|
|
if ($changes) {
|
|
AuditLog::record('agent', $actor, 'profile.update', $user, $changes);
|
|
}
|
|
});
|
|
}
|
|
|
|
private function editableFields(DirectoryUser $user)
|
|
{
|
|
return EditableField::where('tenant_id', $user->tenant_id)->where('enabled', true)
|
|
->whereIn('field', array_keys(VariableMap::FIELDS))
|
|
->orderBy('id')->get();
|
|
}
|
|
}
|