diff --git a/assets/translations/ru.json b/assets/translations/ru.json index 6ceb70a4..4c92f22c 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -483,7 +483,8 @@ "rebootServer": "Перезагрузить сервер", "create_ssh_key": "Создать SSH ключ для {}", "delete_ssh_key": "Удалить SSH ключ для {}", - "server_jobs": "Задачи на сервере" + "server_jobs": "Задачи на сервере", + "resetUserPassword": "Сбросить пароль пользователя" }, "validations": { "required": "Обязательное поле.", diff --git a/lib/logic/cubit/client_jobs/client_jobs_cubit.dart b/lib/logic/cubit/client_jobs/client_jobs_cubit.dart index 7461a6df..49b856ff 100644 --- a/lib/logic/cubit/client_jobs/client_jobs_cubit.dart +++ b/lib/logic/cubit/client_jobs/client_jobs_cubit.dart @@ -121,6 +121,9 @@ class JobsCubit extends Cubit { if (job is DeleteSSHKeyJob) { await usersCubit.deleteSshKey(job.user, job.publicKey); } + if (job is ResetUserPasswordJob) { + await usersCubit.changeUserPassword(job.user, job.user.password!); + } } await api.pullConfigurationUpdate(); diff --git a/lib/logic/cubit/forms/user/user_form_cubit.dart b/lib/logic/cubit/forms/user/user_form_cubit.dart index d745b5f5..c60fef9e 100644 --- a/lib/logic/cubit/forms/user/user_form_cubit.dart +++ b/lib/logic/cubit/forms/user/user_form_cubit.dart @@ -11,28 +11,50 @@ class UserFormCubit extends FormCubit { UserFormCubit({ required this.jobsCubit, required final FieldCubitFactory fieldFactory, - final User? user, + final this.initialUser, }) { - final bool isEdit = user != null; + if (initialUser == null) { + login = fieldFactory.createUserLoginField(); + login.setValue(''); + password = fieldFactory.createUserPasswordField(); + password.setValue( + StringGenerators.userPassword(), + ); - login = fieldFactory.createUserLoginField(); - login.setValue(isEdit ? user.login : ''); - password = fieldFactory.createUserPasswordField(); - password.setValue( - isEdit ? (user.password ?? '') : StringGenerators.userPassword(), - ); + super.addFields([login, password]); + } else { + login = fieldFactory.createRequiredStringField(); + login.setValue(initialUser!.login); + password = fieldFactory.createUserPasswordField(); + password.setValue( + initialUser?.password ?? '', + ); - super.addFields([login, password]); + super.addFields([login, password]); + } } @override FutureOr onSubmit() { - final User user = User( - login: login.state.value, - type: UserType.normal, - password: password.state.value, - ); - jobsCubit.addJob(CreateUserJob(user: user)); + print('onSubmit'); + print('initialUser: $initialUser'); + print('login: ${login.state.value}'); + print('password: ${password.state.value}'); + if (initialUser == null) { + final User user = User( + login: login.state.value, + type: UserType.normal, + password: password.state.value, + ); + jobsCubit.addJob(CreateUserJob(user: user)); + } else { + final User user = User( + login: initialUser?.login ?? login.state.value, + type: initialUser?.type ?? UserType.normal, + password: password.state.value, + ); + jobsCubit.addJob(ResetUserPasswordJob(user: user)); + } } late FieldCubit login; @@ -43,4 +65,5 @@ class UserFormCubit extends FormCubit { } final JobsCubit jobsCubit; + final User? initialUser; } diff --git a/lib/logic/models/job.dart b/lib/logic/models/job.dart index 6ea31588..2d62a305 100644 --- a/lib/logic/models/job.dart +++ b/lib/logic/models/job.dart @@ -31,6 +31,17 @@ class CreateUserJob extends ClientJob { List get props => [id, title, user]; } +class ResetUserPasswordJob extends ClientJob { + ResetUserPasswordJob({ + required this.user, + }) : super(title: '${"jobs.resetUserPassword".tr()} ${user.login}'); + + final User user; + + @override + List get props => [id, title, user]; +} + class DeleteUserJob extends ClientJob { DeleteUserJob({ required this.user, diff --git a/lib/ui/pages/users/reset_password.dart b/lib/ui/pages/users/reset_password.dart new file mode 100644 index 00000000..841a9353 --- /dev/null +++ b/lib/ui/pages/users/reset_password.dart @@ -0,0 +1,84 @@ +part of 'users.dart'; + +class ResetPassword extends StatelessWidget { + const ResetPassword({ + required this.user, + final super.key, + }); + + final User user; + + @override + Widget build(final BuildContext context) => BrandBottomSheet( + child: BlocProvider( + create: (final BuildContext context) => UserFormCubit( + jobsCubit: context.read(), + fieldFactory: FieldCubitFactory(context), + initialUser: user, + ), + child: Builder( + builder: (final BuildContext context) { + final FormCubitState formCubitState = + context.watch().state; + + return BlocListener( + listener: + (final BuildContext context, final FormCubitState state) { + if (state.isSubmitted) { + Navigator.pop(context); + } + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + BrandHeader( + title: 'users.reset_password'.tr(), + ), + const SizedBox(width: 14), + Padding( + padding: paddingH15V0, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + CubitFormTextField( + formFieldCubit: + context.read().password, + decoration: InputDecoration( + alignLabelWithHint: false, + labelText: 'basis.password'.tr(), + suffixIcon: Padding( + padding: const EdgeInsets.only(right: 8), + child: IconButton( + icon: Icon( + BrandIcons.refresh, + color: + Theme.of(context).colorScheme.secondary, + ), + onPressed: context + .read() + .genNewPassword, + ), + ), + ), + ), + const SizedBox(height: 30), + BrandButton.rised( + onPressed: formCubitState.isSubmitting + ? null + : () => + context.read().trySubmit(), + text: 'basis.apply'.tr(), + ), + const SizedBox(height: 30), + ], + ), + ), + ], + ), + ); + }, + ), + ), + ); +} diff --git a/lib/ui/pages/users/user_details.dart b/lib/ui/pages/users/user_details.dart index 24f2457f..86a9e3d7 100644 --- a/lib/ui/pages/users/user_details.dart +++ b/lib/ui/pages/users/user_details.dart @@ -43,7 +43,17 @@ class UserDetails extends StatelessWidget { const SizedBox(height: 8), ListTile( iconColor: Theme.of(context).colorScheme.onBackground, - onTap: () => {}, + onTap: () => { + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (final BuildContext context) => Padding( + padding: MediaQuery.of(context).viewInsets, + child: ResetPassword(user: user), + ), + ), + }, leading: const Icon(Icons.lock_reset_outlined), title: Text( 'users.reset_password'.tr(), diff --git a/lib/ui/pages/users/users.dart b/lib/ui/pages/users/users.dart index 7e255935..40443a9c 100644 --- a/lib/ui/pages/users/users.dart +++ b/lib/ui/pages/users/users.dart @@ -31,6 +31,7 @@ part 'new_user.dart'; part 'user.dart'; part 'user_details.dart'; part 'add_user_fab.dart'; +part 'reset_password.dart'; class UsersPage extends StatelessWidget { const UsersPage({final super.key});