fix(#96): protéger le super admin en édition et suppression
Empêche la suppression d'un super administrateur et fige son identité (nom/prénom) côté API, avec alignement de la modale frontend pour masquer la suppression et verrouiller ces champs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -39,6 +39,10 @@ class _AdminUserFormDialogState extends State<AdminUserFormDialog> {
|
||||
List<RelaisModel> _relais = [];
|
||||
String? _selectedRelaisId;
|
||||
bool get _isEditMode => widget.initialUser != null;
|
||||
bool get _isSuperAdminTarget =>
|
||||
widget.initialUser?.role.toLowerCase() == 'super_admin';
|
||||
bool get _isLockedAdminIdentity =>
|
||||
_isEditMode && widget.adminMode && _isSuperAdminTarget;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -212,10 +216,12 @@ class _AdminUserFormDialogState extends State<AdminUserFormDialog> {
|
||||
|
||||
if (_isEditMode) {
|
||||
if (widget.adminMode) {
|
||||
final lockedNom = _toTitleCase(widget.initialUser!.nom ?? '');
|
||||
final lockedPrenom = _toTitleCase(widget.initialUser!.prenom ?? '');
|
||||
await UserService.updateAdministrateur(
|
||||
adminId: widget.initialUser!.id,
|
||||
nom: normalizedNom,
|
||||
prenom: normalizedPrenom,
|
||||
nom: _isLockedAdminIdentity ? lockedNom : normalizedNom,
|
||||
prenom: _isLockedAdminIdentity ? lockedPrenom : normalizedPrenom,
|
||||
email: _emailController.text.trim(),
|
||||
telephone: normalizedPhone.isEmpty
|
||||
? _normalizePhone(widget.initialUser!.telephone ?? '')
|
||||
@@ -308,6 +314,7 @@ class _AdminUserFormDialogState extends State<AdminUserFormDialog> {
|
||||
|
||||
Future<void> _delete() async {
|
||||
if (widget.readOnly) return;
|
||||
if (_isSuperAdminTarget) return;
|
||||
if (!_isEditMode || _isSubmitting) return;
|
||||
|
||||
final confirmed = await showDialog<bool>(
|
||||
@@ -430,11 +437,12 @@ class _AdminUserFormDialogState extends State<AdminUserFormDialog> {
|
||||
child: const Text('Fermer'),
|
||||
),
|
||||
] else if (_isEditMode) ...[
|
||||
OutlinedButton(
|
||||
onPressed: _isSubmitting ? null : _delete,
|
||||
style: OutlinedButton.styleFrom(foregroundColor: Colors.red.shade700),
|
||||
child: const Text('Supprimer'),
|
||||
),
|
||||
if (!_isSuperAdminTarget)
|
||||
OutlinedButton(
|
||||
onPressed: _isSubmitting ? null : _delete,
|
||||
style: OutlinedButton.styleFrom(foregroundColor: Colors.red.shade700),
|
||||
child: const Text('Supprimer'),
|
||||
),
|
||||
FilledButton.icon(
|
||||
onPressed: _isSubmitting ? null : _submit,
|
||||
icon: _isSubmitting
|
||||
@@ -471,26 +479,30 @@ class _AdminUserFormDialogState extends State<AdminUserFormDialog> {
|
||||
Widget _buildNomField() {
|
||||
return TextFormField(
|
||||
controller: _nomController,
|
||||
readOnly: widget.readOnly,
|
||||
readOnly: widget.readOnly || _isLockedAdminIdentity,
|
||||
textCapitalization: TextCapitalization.words,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Nom',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
validator: widget.readOnly ? null : (v) => _required(v, 'Nom'),
|
||||
validator: (widget.readOnly || _isLockedAdminIdentity)
|
||||
? null
|
||||
: (v) => _required(v, 'Nom'),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPrenomField() {
|
||||
return TextFormField(
|
||||
controller: _prenomController,
|
||||
readOnly: widget.readOnly,
|
||||
readOnly: widget.readOnly || _isLockedAdminIdentity,
|
||||
textCapitalization: TextCapitalization.words,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Prénom',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
validator: widget.readOnly ? null : (v) => _required(v, 'Prénom'),
|
||||
validator: (widget.readOnly || _isLockedAdminIdentity)
|
||||
? null
|
||||
: (v) => _required(v, 'Prénom'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user