gestion addin

This commit is contained in:
mrKamoo
2026-10-01 13:38:01 +02:00
parent 28eba5e1e4
commit 1b91590cca
13 changed files with 769 additions and 48 deletions
@@ -0,0 +1,76 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Admin\Concerns\ScopedToTenant;
use App\Http\Controllers\Controller;
use App\Models\AuditLog;
use App\Models\EditableField;
use App\Models\UserOverride;
use App\Signature\ProfileService;
use App\Signature\VariableMap;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\View\View;
/** Choix des champs que les agents peuvent modifier eux-mêmes (add-in et portail). */
class EditableFieldController extends Controller
{
use ScopedToTenant;
/** L'adresse e-mail n'est jamais modifiable : elle doit rester celle de la boîte. */
private const EXCLUDED = ['email'];
public function index(): View
{
$tenant = $this->tenantId();
foreach (array_diff(array_keys(VariableMap::FIELDS), self::EXCLUDED) as $key) {
EditableField::firstOrCreate(
['tenant_id' => $tenant, 'field' => $key],
['label' => VariableMap::FIELDS[$key]['label'], 'enabled' => false, 'validation_rule' => in_array($key, ['telephone', 'mobile'], true) ? 'phone' : 'text'],
);
}
$usage = UserOverride::query()
->join('directory_users', 'directory_users.id', '=', 'user_overrides.directory_user_id')
->where('directory_users.tenant_id', $tenant)
->selectRaw('user_overrides.field, count(*) as n')->groupBy('user_overrides.field')->pluck('n', 'field');
return view('admin.fields.index', [
'fields' => EditableField::where('tenant_id', $tenant)->whereNotIn('field', self::EXCLUDED)
->get()->sortBy(fn ($f) => array_search($f->field, array_keys(VariableMap::FIELDS)))->values(),
'types' => ProfileService::TYPES,
'usage' => $usage,
]);
}
public function update(Request $request): RedirectResponse
{
$tenant = $this->tenantId();
$data = $request->validate([
'fields' => ['array'],
'fields.*.enabled' => ['nullable', 'boolean'],
'fields.*.label' => ['required', 'string', 'max:60'],
'fields.*.type' => ['required', Rule::in(array_keys(ProfileService::TYPES))],
]);
$changes = [];
foreach ($data['fields'] ?? [] as $key => $row) {
$field = EditableField::where('tenant_id', $tenant)->where('field', $key)->whereNotIn('field', self::EXCLUDED)->first();
if (! $field) {
continue;
}
$field->fill(['enabled' => (bool) ($row['enabled'] ?? false), 'label' => $row['label'], 'validation_rule' => $row['type']]);
if ($field->isDirty()) {
$changes[$key] = $field->getDirty();
$field->save();
}
}
if ($changes) {
AuditLog::record('admin', $this->actor(), 'fields.update', null, $changes, $tenant);
}
return back()->with('status', $changes ? 'Champs modifiables enregistrés : effet immédiat dans l\'add-in et le portail.' : 'Aucun changement.');
}
}
@@ -0,0 +1,46 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Signature\ProfileService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
/** Profil de l'agent pour le volet de l'add-in (jeton Entra NAA). */
class ProfileController extends Controller
{
public function show(Request $request, ProfileService $profiles): JsonResponse
{
return response()->json($profiles->profile($request->attributes->get('directory_user')))
->header('Cache-Control', 'private, no-store');
}
/**
* PUT { fields: { mobile: "06…" | null, … }, hidden: ["bureau"], reply_variant?: short|full|none|null }
* null = revenir à l'annuaire ; « hidden » = ne pas afficher le champ (les chaînes vides
* étant converties en null par Laravel, le masquage passe par cette liste explicite).
*/
public function update(Request $request, ProfileService $profiles): JsonResponse
{
$user = $request->attributes->get('directory_user');
$fields = $request->input('fields', []);
$hidden = $request->input('hidden', []);
abort_unless(is_array($fields) && is_array($hidden), 422, 'fields doit être un objet et hidden une liste.');
foreach ($hidden as $key) {
if (is_string($key)) {
$fields[$key] = '';
}
}
$profiles->update(
$user,
$fields,
$request->input('reply_variant'),
$request->exists('reply_variant'),
(string) ($user->mail ?? $user->user_principal_name),
);
return response()->json($profiles->profile($user->fresh()));
}
}
@@ -4,22 +4,53 @@ namespace App\Http\Controllers\Portal;
use App\Http\Controllers\Controller;
use App\Models\DirectoryUser;
use App\Signature\ProfileService;
use App\Signature\SignatureBuilder;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
/** Portail agent : aperçu de la signature. Champs modifiables et préférences arrivent au lot 2. */
/** Portail agent : aperçu de la signature et modification des champs ouverts par l'admin. */
class PortalController extends Controller
{
public function __invoke(Request $request, SignatureBuilder $builder): View
public function show(Request $request, SignatureBuilder $builder, ProfileService $profiles): View
{
$user = $request->user();
$agent = DirectoryUser::where('tenant_id', $user->tenant_id)->where('entra_oid', $user->entra_oid)->firstOrFail();
$agent = $this->agent($request);
return view('portal.home', [
'agent' => $agent,
'profile' => $profiles->profile($agent),
'full' => $builder->build($agent, 'new'),
'reply' => $builder->build($agent, 'reply'),
]);
}
public function update(Request $request, ProfileService $profiles): RedirectResponse
{
$agent = $this->agent($request);
$values = [];
foreach ((array) $request->input('fields', []) as $key => $row) {
$mode = $row['mode'] ?? 'directory';
$values[$key] = match ($mode) {
'custom' => (string) ($row['value'] ?? ''),
'hidden' => '',
default => null,
};
if ($mode === 'custom' && trim((string) ($row['value'] ?? '')) === '') {
$values[$key] = null; // valeur perso vide : on revient à l'annuaire
}
}
$reply = $request->input('reply_variant');
$profiles->update($agent, $values, $reply === 'default' ? null : $reply, $request->has('reply_variant'), (string) $agent->mail);
return back()->with('status', 'Vos informations sont enregistrées : elles s\'appliquent à vos prochains messages.');
}
private function agent(Request $request): DirectoryUser
{
$user = $request->user();
return DirectoryUser::where('tenant_id', $user->tenant_id)->where('entra_oid', $user->entra_oid)->firstOrFail();
}
}