mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-23 09:16:54 +00:00
refactor: Replace UsersCubit with UsersBloc
This commit is contained in:
parent
e5f00f8770
commit
455b1ed7f9
|
@ -6,6 +6,7 @@ import 'package:selfprivacy/logic/bloc/devices/devices_bloc.dart';
|
|||
import 'package:selfprivacy/logic/bloc/recovery_key/recovery_key_bloc.dart';
|
||||
import 'package:selfprivacy/logic/bloc/server_jobs/server_jobs_bloc.dart';
|
||||
import 'package:selfprivacy/logic/bloc/services/services_bloc.dart';
|
||||
import 'package:selfprivacy/logic/bloc/users/users_bloc.dart';
|
||||
import 'package:selfprivacy/logic/bloc/volumes/volumes_bloc.dart';
|
||||
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
||||
|
@ -13,7 +14,6 @@ import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart';
|
|||
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/support_system/support_system_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
|
||||
|
||||
class BlocAndProviderConfig extends StatefulWidget {
|
||||
const BlocAndProviderConfig({super.key, this.child});
|
||||
|
@ -27,7 +27,7 @@ class BlocAndProviderConfig extends StatefulWidget {
|
|||
class BlocAndProviderConfigState extends State<BlocAndProviderConfig> {
|
||||
late final ServerInstallationCubit serverInstallationCubit;
|
||||
late final SupportSystemCubit supportSystemCubit;
|
||||
late final UsersCubit usersCubit;
|
||||
late final UsersBloc usersBloc;
|
||||
late final ServicesBloc servicesBloc;
|
||||
late final BackupsBloc backupsBloc;
|
||||
late final DnsRecordsCubit dnsRecordsCubit;
|
||||
|
@ -43,7 +43,7 @@ class BlocAndProviderConfigState extends State<BlocAndProviderConfig> {
|
|||
super.initState();
|
||||
serverInstallationCubit = ServerInstallationCubit()..load();
|
||||
supportSystemCubit = SupportSystemCubit();
|
||||
usersCubit = UsersCubit();
|
||||
usersBloc = UsersBloc();
|
||||
servicesBloc = ServicesBloc();
|
||||
backupsBloc = BackupsBloc();
|
||||
dnsRecordsCubit = DnsRecordsCubit();
|
||||
|
@ -77,7 +77,7 @@ class BlocAndProviderConfigState extends State<BlocAndProviderConfig> {
|
|||
lazy: false,
|
||||
),
|
||||
BlocProvider(
|
||||
create: (final _) => usersCubit,
|
||||
create: (final _) => usersBloc,
|
||||
lazy: false,
|
||||
),
|
||||
BlocProvider(
|
||||
|
@ -105,7 +105,6 @@ class BlocAndProviderConfigState extends State<BlocAndProviderConfig> {
|
|||
BlocProvider(create: (final _) => volumesBloc),
|
||||
BlocProvider(
|
||||
create: (final _) => JobsCubit(
|
||||
usersCubit: usersCubit,
|
||||
servicesBloc: servicesBloc,
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
|
@ -13,7 +15,11 @@ class ConnectionStatusBloc
|
|||
connectionStatus: ConnectionStatus.nonexistent,
|
||||
),
|
||||
) {
|
||||
on<ConnectionStatusChanged>((final event, final emit) {
|
||||
emit(ConnectionStatusState(connectionStatus: event.connectionStatus));
|
||||
});
|
||||
final apiConnectionRepository = getIt<ApiConnectionRepository>();
|
||||
_apiConnectionStatusSubscription =
|
||||
apiConnectionRepository.connectionStatusStream.listen(
|
||||
(final ConnectionStatus connectionStatus) {
|
||||
add(
|
||||
|
@ -21,8 +27,13 @@ class ConnectionStatusBloc
|
|||
);
|
||||
},
|
||||
);
|
||||
on<ConnectionStatusChanged>((final event, final emit) {
|
||||
emit(ConnectionStatusState(connectionStatus: event.connectionStatus));
|
||||
});
|
||||
}
|
||||
|
||||
StreamSubscription? _apiConnectionStatusSubscription;
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_apiConnectionStatusSubscription?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ part of 'devices_bloc.dart';
|
|||
sealed class DevicesState extends Equatable {
|
||||
DevicesState({
|
||||
required final List<ApiToken> devices,
|
||||
}) : _hashCode = devices.hashCode;
|
||||
}) : _hashCode = Object.hashAll(devices);
|
||||
|
||||
final int _hashCode;
|
||||
|
||||
|
|
105
lib/logic/bloc/users/users_bloc.dart
Normal file
105
lib/logic/bloc/users/users_bloc.dart
Normal file
|
@ -0,0 +1,105 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:bloc_concurrency/bloc_concurrency.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||
|
||||
part 'users_event.dart';
|
||||
part 'users_state.dart';
|
||||
|
||||
class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
UsersBloc() : super(UsersInitial()) {
|
||||
on<UsersListChanged>(
|
||||
_updateList,
|
||||
transformer: sequential(),
|
||||
);
|
||||
on<UsersListRefresh>(
|
||||
_reload,
|
||||
transformer: droppable(),
|
||||
);
|
||||
on<UsersConnectionStatusChanged>(
|
||||
_mapConnectionStatusChangedToState,
|
||||
transformer: sequential(),
|
||||
);
|
||||
|
||||
final apiConnectionRepository = getIt<ApiConnectionRepository>();
|
||||
_apiConnectionStatusSubscription =
|
||||
apiConnectionRepository.connectionStatusStream.listen(
|
||||
(final ConnectionStatus connectionStatus) {
|
||||
add(
|
||||
UsersConnectionStatusChanged(connectionStatus),
|
||||
);
|
||||
},
|
||||
);
|
||||
_apiDataSubscription = apiConnectionRepository.dataStream.listen(
|
||||
(final ApiData apiData) {
|
||||
add(
|
||||
UsersListChanged(apiData.users.data ?? []),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _updateList(
|
||||
final UsersListChanged event,
|
||||
final Emitter<UsersState> emit,
|
||||
) async {
|
||||
if (event.users.isEmpty) {
|
||||
emit(UsersInitial());
|
||||
return;
|
||||
}
|
||||
final newState = UsersLoaded(
|
||||
users: event.users,
|
||||
);
|
||||
emit(newState);
|
||||
}
|
||||
|
||||
Future<void> refresh() async {
|
||||
getIt<ApiConnectionRepository>().apiData.users.invalidate();
|
||||
await getIt<ApiConnectionRepository>().reload(null);
|
||||
}
|
||||
|
||||
Future<void> _reload(
|
||||
final UsersListRefresh event,
|
||||
final Emitter<UsersState> emit,
|
||||
) async {
|
||||
emit(UsersRefreshing(users: state.users));
|
||||
await refresh();
|
||||
}
|
||||
|
||||
Future<void> _mapConnectionStatusChangedToState(
|
||||
final UsersConnectionStatusChanged event,
|
||||
final Emitter<UsersState> emit,
|
||||
) async {
|
||||
switch (event.connectionStatus) {
|
||||
case ConnectionStatus.nonexistent:
|
||||
emit(UsersInitial());
|
||||
break;
|
||||
case ConnectionStatus.connected:
|
||||
if (state is! UsersLoaded) {
|
||||
emit(UsersRefreshing(users: state.users));
|
||||
}
|
||||
case ConnectionStatus.reconnecting:
|
||||
case ConnectionStatus.offline:
|
||||
case ConnectionStatus.unauthorized:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StreamSubscription? _apiDataSubscription;
|
||||
StreamSubscription? _apiConnectionStatusSubscription;
|
||||
|
||||
@override
|
||||
void onChange(final Change<UsersState> change) {
|
||||
super.onChange(change);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_apiDataSubscription?.cancel();
|
||||
_apiConnectionStatusSubscription?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
}
|
30
lib/logic/bloc/users/users_event.dart
Normal file
30
lib/logic/bloc/users/users_event.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
part of 'users_bloc.dart';
|
||||
|
||||
sealed class UsersEvent extends Equatable {
|
||||
const UsersEvent();
|
||||
}
|
||||
|
||||
class UsersListChanged extends UsersEvent {
|
||||
const UsersListChanged(this.users);
|
||||
|
||||
final List<User> users;
|
||||
|
||||
@override
|
||||
List<Object> get props => [users];
|
||||
}
|
||||
|
||||
class UsersListRefresh extends UsersEvent {
|
||||
const UsersListRefresh();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class UsersConnectionStatusChanged extends UsersEvent {
|
||||
const UsersConnectionStatusChanged(this.connectionStatus);
|
||||
|
||||
final ConnectionStatus connectionStatus;
|
||||
|
||||
@override
|
||||
List<Object> get props => [connectionStatus];
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
part of 'users_cubit.dart';
|
||||
part of 'users_bloc.dart';
|
||||
|
||||
class UsersState extends ServerInstallationDependendState {
|
||||
const UsersState(this.users, this.isLoading);
|
||||
sealed class UsersState extends Equatable {
|
||||
UsersState({
|
||||
required final List<User> users,
|
||||
}) : _hashCode = Object.hashAll(users);
|
||||
|
||||
final List<User> users;
|
||||
final bool isLoading;
|
||||
final int _hashCode;
|
||||
|
||||
List<User> get users =>
|
||||
getIt<ApiConnectionRepository>().apiData.users.data ?? const [];
|
||||
|
||||
User get rootUser =>
|
||||
users.firstWhere((final user) => user.type == UserType.root);
|
||||
|
@ -15,9 +19,6 @@ class UsersState extends ServerInstallationDependendState {
|
|||
List<User> get normalUsers =>
|
||||
users.where((final user) => user.type == UserType.normal).toList();
|
||||
|
||||
@override
|
||||
List<Object> get props => [users, isLoading];
|
||||
|
||||
/// Makes a copy of existing users list, but places 'primary'
|
||||
/// to the beginning and sorts the rest alphabetically
|
||||
///
|
||||
|
@ -44,17 +45,29 @@ class UsersState extends ServerInstallationDependendState {
|
|||
return primaryUser == null ? normalUsers : [primaryUser] + normalUsers;
|
||||
}
|
||||
|
||||
UsersState copyWith({
|
||||
final List<User>? users,
|
||||
final bool? isLoading,
|
||||
}) =>
|
||||
UsersState(
|
||||
users ?? this.users,
|
||||
isLoading ?? this.isLoading,
|
||||
);
|
||||
|
||||
bool isLoginRegistered(final String login) =>
|
||||
users.any((final User user) => user.login == login);
|
||||
|
||||
bool get isEmpty => users.isEmpty;
|
||||
}
|
||||
|
||||
class UsersInitial extends UsersState {
|
||||
UsersInitial() : super(users: const []);
|
||||
|
||||
@override
|
||||
List<Object> get props => [_hashCode];
|
||||
}
|
||||
|
||||
class UsersRefreshing extends UsersState {
|
||||
UsersRefreshing({required super.users});
|
||||
|
||||
@override
|
||||
List<Object> get props => [_hashCode];
|
||||
}
|
||||
|
||||
class UsersLoaded extends UsersState {
|
||||
UsersLoaded({required super.users});
|
||||
|
||||
@override
|
||||
List<Object> get props => [_hashCode];
|
||||
}
|
|
@ -6,7 +6,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart';
|
||||
import 'package:selfprivacy/logic/bloc/services/services_bloc.dart';
|
||||
import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/job.dart';
|
||||
|
||||
export 'package:provider/provider.dart';
|
||||
|
@ -15,12 +14,10 @@ part 'client_jobs_state.dart';
|
|||
|
||||
class JobsCubit extends Cubit<JobsState> {
|
||||
JobsCubit({
|
||||
required this.usersCubit,
|
||||
required this.servicesBloc,
|
||||
}) : super(JobsStateEmpty());
|
||||
|
||||
final ServerApi api = ServerApi();
|
||||
final UsersCubit usersCubit;
|
||||
final ServicesBloc servicesBloc;
|
||||
|
||||
void addJob(final ClientJob job) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:cubit_form/cubit_form.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/logic/bloc/users/users_bloc.dart';
|
||||
import 'package:selfprivacy/logic/cubit/forms/validations/validations.dart';
|
||||
import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
|
||||
|
||||
class FieldCubitFactory {
|
||||
FieldCubitFactory(this.context);
|
||||
|
@ -27,7 +27,7 @@ class FieldCubitFactory {
|
|||
),
|
||||
ValidationModel(
|
||||
(final String login) =>
|
||||
context.read<UsersCubit>().state.isLoginRegistered(login),
|
||||
context.read<UsersBloc>().state.isLoginRegistered(login),
|
||||
'validations.already_exist'.tr(),
|
||||
),
|
||||
RequiredStringValidation('validations.required'.tr()),
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
import 'package:selfprivacy/config/hive_config.dart';
|
||||
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_connection_dependent/server_connection_dependent_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||
|
||||
export 'package:provider/provider.dart';
|
||||
|
||||
part 'users_state.dart';
|
||||
|
||||
class UsersCubit extends ServerConnectionDependentCubit<UsersState> {
|
||||
UsersCubit()
|
||||
: super(
|
||||
const UsersState(
|
||||
<User>[],
|
||||
false,
|
||||
),
|
||||
);
|
||||
Box<User> box = Hive.box<User>(BNames.usersBox);
|
||||
Box serverInstallationBox = Hive.box(BNames.serverInstallationBox);
|
||||
|
||||
final ServerApi api = ServerApi();
|
||||
|
||||
@override
|
||||
Future<void> load() async {
|
||||
final List<User> loadedUsers = box.values.toList();
|
||||
if (loadedUsers.isNotEmpty) {
|
||||
emit(
|
||||
UsersState(
|
||||
loadedUsers,
|
||||
false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
unawaited(refresh());
|
||||
}
|
||||
|
||||
Future<void> refresh() async {
|
||||
if (getIt<ApiConnectionRepository>().connectionStatus ==
|
||||
ConnectionStatus.nonexistent) {
|
||||
return;
|
||||
}
|
||||
emit(state.copyWith(isLoading: true));
|
||||
final List<User> usersFromServer = await api.getAllUsers();
|
||||
if (usersFromServer.isNotEmpty) {
|
||||
emit(
|
||||
UsersState(
|
||||
usersFromServer,
|
||||
false,
|
||||
),
|
||||
);
|
||||
// Update the users it the box
|
||||
await box.clear();
|
||||
await box.addAll(usersFromServer);
|
||||
} else {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar('users.could_not_fetch_users'.tr());
|
||||
emit(state.copyWith(isLoading: false));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> createUser(final User user) async {
|
||||
// If user exists on server, do nothing
|
||||
if (state.users
|
||||
.any((final User u) => u.login == user.login && u.isFoundOnServer)) {
|
||||
return;
|
||||
}
|
||||
final String? password = user.password;
|
||||
if (password == null) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar('users.could_not_create_user'.tr());
|
||||
return;
|
||||
}
|
||||
// If API returned error, do nothing
|
||||
final GenericResult<User?> result =
|
||||
await api.createUser(user.login, password);
|
||||
if (result.data == null) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar(result.message ?? 'users.could_not_create_user'.tr());
|
||||
return;
|
||||
}
|
||||
|
||||
final List<User> loadedUsers = List<User>.from(state.users);
|
||||
loadedUsers.add(result.data!);
|
||||
await box.clear();
|
||||
await box.addAll(loadedUsers);
|
||||
emit(state.copyWith(users: loadedUsers));
|
||||
}
|
||||
|
||||
Future<void> deleteUser(final User user) async {
|
||||
// If user is primary or root, don't delete
|
||||
if (user.type != UserType.normal) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar('users.could_not_delete_user'.tr());
|
||||
return;
|
||||
}
|
||||
final List<User> loadedUsers = List<User>.from(state.users);
|
||||
final GenericResult result = await api.deleteUser(user.login);
|
||||
if (result.success && result.data) {
|
||||
loadedUsers.removeWhere((final User u) => u.login == user.login);
|
||||
await box.clear();
|
||||
await box.addAll(loadedUsers);
|
||||
emit(state.copyWith(users: loadedUsers));
|
||||
}
|
||||
|
||||
if (!result.success) {
|
||||
getIt<NavigationService>().showSnackBar('jobs.generic_error'.tr());
|
||||
}
|
||||
|
||||
if (!result.data) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar(result.message ?? 'jobs.generic_error'.tr());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> changeUserPassword(
|
||||
final User user,
|
||||
final String newPassword,
|
||||
) async {
|
||||
if (user.type == UserType.root) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar('users.could_not_change_password'.tr());
|
||||
return;
|
||||
}
|
||||
final GenericResult<User?> result =
|
||||
await api.updateUser(user.login, newPassword);
|
||||
if (result.data == null) {
|
||||
getIt<NavigationService>().showSnackBar(
|
||||
result.message ?? 'users.could_not_change_password'.tr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addSshKey(final User user, final String publicKey) async {
|
||||
final GenericResult<User?> result =
|
||||
await api.addSshKey(user.login, publicKey);
|
||||
if (result.data != null) {
|
||||
final User updatedUser = result.data!;
|
||||
final int index =
|
||||
state.users.indexWhere((final User u) => u.login == user.login);
|
||||
await box.putAt(index, updatedUser);
|
||||
emit(
|
||||
state.copyWith(
|
||||
users: box.values.toList(),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar(result.message ?? 'users.could_not_add_ssh_key'.tr());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteSshKey(final User user, final String publicKey) async {
|
||||
final GenericResult<User?> result =
|
||||
await api.removeSshKey(user.login, publicKey);
|
||||
if (result.data != null) {
|
||||
final User updatedUser = result.data!;
|
||||
final int index =
|
||||
state.users.indexWhere((final User u) => u.login == user.login);
|
||||
await box.putAt(index, updatedUser);
|
||||
emit(
|
||||
state.copyWith(
|
||||
users: box.values.toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void clear() async {
|
||||
emit(
|
||||
const UsersState(
|
||||
<User>[],
|
||||
false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
|
@ -8,6 +9,7 @@ import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.da
|
|||
import 'package:selfprivacy/logic/models/backup.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||
import 'package:selfprivacy/logic/models/json/api_token.dart';
|
||||
import 'package:selfprivacy/logic/models/json/recovery_token_status.dart';
|
||||
import 'package:selfprivacy/logic/models/json/server_disk_volume.dart';
|
||||
|
@ -68,6 +70,116 @@ class ApiConnectionRepository {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> createUser(final User user) async {
|
||||
final List<User>? loadedUsers = _apiData.users.data;
|
||||
if (loadedUsers == null) {
|
||||
return;
|
||||
}
|
||||
// If user exists on server, do nothing
|
||||
if (loadedUsers
|
||||
.any((final User u) => u.login == user.login && u.isFoundOnServer)) {
|
||||
return;
|
||||
}
|
||||
final String? password = user.password;
|
||||
if (password == null) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar('users.could_not_create_user'.tr());
|
||||
return;
|
||||
}
|
||||
// If API returned error, do nothing
|
||||
final GenericResult<User?> result =
|
||||
await api.createUser(user.login, password);
|
||||
if (result.data == null) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar(result.message ?? 'users.could_not_create_user'.tr());
|
||||
return;
|
||||
}
|
||||
|
||||
_apiData.users.data?.add(result.data!);
|
||||
_apiData.users.invalidate();
|
||||
}
|
||||
|
||||
Future<void> deleteUser(final User user) async {
|
||||
final List<User>? loadedUsers = _apiData.users.data;
|
||||
if (loadedUsers == null) {
|
||||
return;
|
||||
}
|
||||
// If user is primary or root, don't delete
|
||||
if (user.type != UserType.normal) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar('users.could_not_delete_user'.tr());
|
||||
return;
|
||||
}
|
||||
final GenericResult result = await api.deleteUser(user.login);
|
||||
if (result.success && result.data) {
|
||||
_apiData.users.data?.removeWhere((final User u) => u.login == user.login);
|
||||
_apiData.users.invalidate();
|
||||
}
|
||||
|
||||
if (!result.success || !result.data) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar(result.message ?? 'jobs.generic_error'.tr());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> changeUserPassword(
|
||||
final User user,
|
||||
final String newPassword,
|
||||
) async {
|
||||
if (user.type == UserType.root) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar('users.could_not_change_password'.tr());
|
||||
return;
|
||||
}
|
||||
final GenericResult<User?> result = await api.updateUser(
|
||||
user.login,
|
||||
newPassword,
|
||||
);
|
||||
if (result.data == null) {
|
||||
getIt<NavigationService>().showSnackBar(
|
||||
result.message ?? 'users.could_not_change_password'.tr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addSshKey(final User user, final String publicKey) async {
|
||||
final List<User>? loadedUsers = _apiData.users.data;
|
||||
if (loadedUsers == null) {
|
||||
return;
|
||||
}
|
||||
final GenericResult<User?> result =
|
||||
await api.addSshKey(user.login, publicKey);
|
||||
if (result.data != null) {
|
||||
final User updatedUser = result.data!;
|
||||
final int index =
|
||||
loadedUsers.indexWhere((final User u) => u.login == user.login);
|
||||
loadedUsers[index] = updatedUser;
|
||||
_apiData.users.invalidate();
|
||||
} else {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar(result.message ?? 'users.could_not_add_ssh_key'.tr());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteSshKey(final User user, final String publicKey) async {
|
||||
final List<User>? loadedUsers = _apiData.users.data;
|
||||
if (loadedUsers == null) {
|
||||
return;
|
||||
}
|
||||
final GenericResult<User?> result =
|
||||
await api.removeSshKey(user.login, publicKey);
|
||||
if (result.data != null) {
|
||||
final User updatedUser = result.data!;
|
||||
final int index =
|
||||
loadedUsers.indexWhere((final User u) => u.login == user.login);
|
||||
loadedUsers[index] = updatedUser;
|
||||
_apiData.users.invalidate();
|
||||
} else {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar(result.message ?? 'jobs.generic_error'.tr());
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_dataStream.close();
|
||||
_connectionStatusStream.close();
|
||||
|
@ -106,6 +218,7 @@ class ApiConnectionRepository {
|
|||
_apiData.recoveryKeyStatus.data =
|
||||
await _apiData.recoveryKeyStatus.fetchData();
|
||||
_apiData.devices.data = await _apiData.devices.fetchData();
|
||||
_apiData.users.data = await _apiData.users.fetchData();
|
||||
_dataStream.add(_apiData);
|
||||
|
||||
connectionStatus = ConnectionStatus.connected;
|
||||
|
@ -149,6 +262,7 @@ class ApiConnectionRepository {
|
|||
.refetchData(version, () => _dataStream.add(_apiData));
|
||||
await _apiData.devices
|
||||
.refetchData(version, () => _dataStream.add(_apiData));
|
||||
await _apiData.users.refetchData(version, () => _dataStream.add(_apiData));
|
||||
}
|
||||
|
||||
void emitData() {
|
||||
|
@ -188,6 +302,9 @@ class ApiData {
|
|||
),
|
||||
devices = ApiDataElement<List<ApiToken>>(
|
||||
fetchData: () async => (await api.getApiTokens()).data,
|
||||
),
|
||||
users = ApiDataElement<List<User>>(
|
||||
fetchData: () async => api.getAllUsers(),
|
||||
);
|
||||
|
||||
ApiDataElement<List<ServerJob>> serverJobs;
|
||||
|
@ -198,6 +315,7 @@ class ApiData {
|
|||
ApiDataElement<List<ServerDiskVolume>> volumes;
|
||||
ApiDataElement<RecoveryKeyStatus> recoveryKeyStatus;
|
||||
ApiDataElement<List<ApiToken>> devices;
|
||||
ApiDataElement<List<User>> users;
|
||||
}
|
||||
|
||||
enum ConnectionStatus {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||
import 'package:selfprivacy/logic/models/service.dart';
|
||||
|
@ -48,7 +49,7 @@ class CreateUserJob extends ClientJob {
|
|||
|
||||
@override
|
||||
void execute(final JobsCubit cubit) async {
|
||||
await cubit.usersCubit.createUser(user);
|
||||
await getIt<ApiConnectionRepository>().createUser(user);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -64,7 +65,8 @@ class ResetUserPasswordJob extends ClientJob {
|
|||
|
||||
@override
|
||||
void execute(final JobsCubit cubit) async {
|
||||
await cubit.usersCubit.changeUserPassword(user, user.password!);
|
||||
await getIt<ApiConnectionRepository>()
|
||||
.changeUserPassword(user, user.password!);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -85,7 +87,7 @@ class DeleteUserJob extends ClientJob {
|
|||
|
||||
@override
|
||||
void execute(final JobsCubit cubit) async {
|
||||
await cubit.usersCubit.deleteUser(user);
|
||||
await getIt<ApiConnectionRepository>().deleteUser(user);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -129,7 +131,7 @@ class CreateSSHKeyJob extends ClientJob {
|
|||
|
||||
@override
|
||||
void execute(final JobsCubit cubit) async {
|
||||
await cubit.usersCubit.addSshKey(user, publicKey);
|
||||
await getIt<ApiConnectionRepository>().addSshKey(user, publicKey);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -155,7 +157,7 @@ class DeleteSSHKeyJob extends ClientJob {
|
|||
|
||||
@override
|
||||
void execute(final JobsCubit cubit) async {
|
||||
await cubit.usersCubit.deleteSshKey(user, publicKey);
|
||||
await getIt<ApiConnectionRepository>().deleteSshKey(user, publicKey);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -16,7 +16,7 @@ class NewUserPage extends StatelessWidget {
|
|||
final jobCubit = context.read<JobsCubit>();
|
||||
final jobState = jobCubit.state;
|
||||
final users = <User>[];
|
||||
users.addAll(context.read<UsersCubit>().state.users);
|
||||
users.addAll(context.read<UsersBloc>().state.users);
|
||||
if (jobState is JobsStateWithJobs) {
|
||||
final jobs = jobState.clientJobList;
|
||||
for (final job in jobs) {
|
||||
|
|
|
@ -15,7 +15,7 @@ class UserDetailsPage extends StatelessWidget {
|
|||
|
||||
final String domainName = UiHelpers.getDomainName(config);
|
||||
|
||||
final User user = context.watch<UsersCubit>().state.users.firstWhere(
|
||||
final User user = context.watch<UsersBloc>().state.users.firstWhere(
|
||||
(final User user) => user.login == login,
|
||||
orElse: () => const User(
|
||||
type: UserType.normal,
|
||||
|
|
|
@ -4,12 +4,12 @@ import 'package:easy_localization/easy_localization.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/config/brand_theme.dart';
|
||||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
import 'package:selfprivacy/logic/bloc/users/users_bloc.dart';
|
||||
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
|
||||
import 'package:selfprivacy/logic/cubit/forms/user/ssh_form_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/forms/user/user_form_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||
import 'package:selfprivacy/logic/models/job.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
|
||||
|
@ -49,18 +49,18 @@ class UsersPage extends StatelessWidget {
|
|||
iconData: BrandIcons.users,
|
||||
);
|
||||
} else {
|
||||
child = BlocBuilder<UsersCubit, UsersState>(
|
||||
child = BlocBuilder<UsersBloc, UsersState>(
|
||||
builder: (final BuildContext context, final UsersState state) {
|
||||
final users = state.orderedUsers;
|
||||
if (users.isEmpty) {
|
||||
if (state.isLoading) {
|
||||
if (state is UsersRefreshing) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
await context.read<UsersCubit>().refresh();
|
||||
await context.read<UsersBloc>().refresh();
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
|
@ -76,7 +76,7 @@ class UsersPage extends StatelessWidget {
|
|||
const SizedBox(height: 18),
|
||||
BrandOutlinedButton(
|
||||
onPressed: () {
|
||||
context.read<UsersCubit>().refresh();
|
||||
context.read<UsersBloc>().refresh();
|
||||
},
|
||||
title: 'users.refresh_users'.tr(),
|
||||
),
|
||||
|
@ -88,7 +88,7 @@ class UsersPage extends StatelessWidget {
|
|||
}
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
await context.read<UsersCubit>().refresh();
|
||||
await context.read<UsersBloc>().refresh();
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
|
|
Loading…
Reference in a new issue