mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
[client]: fix restore & delete all bugs
This commit is contained in:
parent
4f0f4221fc
commit
3f83e7ee06
@ -13,8 +13,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
part 'menu_bloc.freezed.dart';
|
part 'menu_bloc.freezed.dart';
|
||||||
|
|
||||||
class MenuBloc extends Bloc<MenuEvent, MenuState> {
|
class MenuBloc extends Bloc<MenuEvent, MenuState> {
|
||||||
final IWorkspace workspace;
|
final IWorkspace workspaceManager;
|
||||||
MenuBloc(this.workspace) : super(MenuState.initial());
|
MenuBloc(this.workspaceManager) : super(MenuState.initial());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<MenuState> mapEventToState(
|
Stream<MenuState> mapEventToState(
|
||||||
@ -42,7 +42,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Stream<MenuState> _performActionOnCreateApp(CreateApp event) async* {
|
Stream<MenuState> _performActionOnCreateApp(CreateApp event) async* {
|
||||||
final result = await workspace.createApp(name: event.name, desc: event.desc);
|
final result = await workspaceManager.createApp(name: event.name, desc: event.desc);
|
||||||
yield result.fold(
|
yield result.fold(
|
||||||
(app) => state.copyWith(apps: some([app])),
|
(app) => state.copyWith(apps: some([app])),
|
||||||
(error) {
|
(error) {
|
||||||
@ -54,7 +54,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
|
|||||||
|
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
Stream<MenuState> _fetchApps() async* {
|
Stream<MenuState> _fetchApps() async* {
|
||||||
final appsOrFail = await workspace.getApps();
|
final appsOrFail = await workspaceManager.getApps();
|
||||||
yield appsOrFail.fold(
|
yield appsOrFail.fold(
|
||||||
(apps) => state.copyWith(apps: some(apps)),
|
(apps) => state.copyWith(apps: some(apps)),
|
||||||
(error) {
|
(error) {
|
||||||
|
@ -10,10 +10,10 @@ import 'package:dartz/dartz.dart';
|
|||||||
part 'menu_user_bloc.freezed.dart';
|
part 'menu_user_bloc.freezed.dart';
|
||||||
|
|
||||||
class MenuUserBloc extends Bloc<MenuUserEvent, MenuUserState> {
|
class MenuUserBloc extends Bloc<MenuUserEvent, MenuUserState> {
|
||||||
final IUser iUserImpl;
|
final IUser userManager;
|
||||||
final IUserListener listener;
|
final IUserListener listener;
|
||||||
|
|
||||||
MenuUserBloc(this.iUserImpl, this.listener) : super(MenuUserState.initial(iUserImpl.user));
|
MenuUserBloc(this.userManager, this.listener) : super(MenuUserState.initial(userManager.user));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<MenuUserState> mapEventToState(MenuUserEvent event) async* {
|
Stream<MenuUserState> mapEventToState(MenuUserEvent event) async* {
|
||||||
@ -36,7 +36,7 @@ class MenuUserBloc extends Bloc<MenuUserEvent, MenuUserState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _initUser() async {
|
Future<void> _initUser() async {
|
||||||
final result = await iUserImpl.initUser();
|
final result = await userManager.initUser();
|
||||||
result.fold((l) => null, (error) => Log.error(error));
|
result.fold((l) => null, (error) => Log.error(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,16 +8,16 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
|||||||
part 'trash_bloc.freezed.dart';
|
part 'trash_bloc.freezed.dart';
|
||||||
|
|
||||||
class TrashBloc extends Bloc<TrashEvent, TrashState> {
|
class TrashBloc extends Bloc<TrashEvent, TrashState> {
|
||||||
final ITrash iTrash;
|
final ITrash trasnManager;
|
||||||
final ITrashListener listener;
|
final ITrashListener listener;
|
||||||
TrashBloc({required this.iTrash, required this.listener}) : super(TrashState.init());
|
TrashBloc({required this.trasnManager, required this.listener}) : super(TrashState.init());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<TrashState> mapEventToState(TrashEvent event) async* {
|
Stream<TrashState> mapEventToState(TrashEvent event) async* {
|
||||||
yield* event.map(
|
yield* event.map(
|
||||||
initial: (e) async* {
|
initial: (e) async* {
|
||||||
listener.start(_listenTrashUpdated);
|
listener.start(_listenTrashUpdated);
|
||||||
final result = await iTrash.readTrash();
|
final result = await trasnManager.readTrash();
|
||||||
yield result.fold(
|
yield result.fold(
|
||||||
(objects) => state.copyWith(objects: objects, successOrFailure: left(unit)),
|
(objects) => state.copyWith(objects: objects, successOrFailure: left(unit)),
|
||||||
(error) => state.copyWith(successOrFailure: right(error)),
|
(error) => state.copyWith(successOrFailure: right(error)),
|
||||||
@ -27,18 +27,21 @@ class TrashBloc extends Bloc<TrashEvent, TrashState> {
|
|||||||
yield state.copyWith(objects: e.trash);
|
yield state.copyWith(objects: e.trash);
|
||||||
},
|
},
|
||||||
putback: (e) async* {
|
putback: (e) async* {
|
||||||
final result = await iTrash.putback(e.trashId);
|
final result = await trasnManager.putback(e.trashId);
|
||||||
yield* _handleResult(result);
|
yield* _handleResult(result);
|
||||||
},
|
},
|
||||||
delete: (e) async* {
|
delete: (e) async* {
|
||||||
final result = await iTrash.deleteViews([e.trashId]);
|
final result = await trasnManager.deleteViews([e.trashId]);
|
||||||
yield* _handleResult(result);
|
yield* _handleResult(result);
|
||||||
},
|
},
|
||||||
deleteAll: (e) async* {
|
deleteAll: (e) async* {
|
||||||
final result = await iTrash.deleteAll();
|
final result = await trasnManager.deleteAll();
|
||||||
|
yield* _handleResult(result);
|
||||||
|
},
|
||||||
|
restoreAll: (e) async* {
|
||||||
|
final result = await trasnManager.restoreAll();
|
||||||
yield* _handleResult(result);
|
yield* _handleResult(result);
|
||||||
},
|
},
|
||||||
restoreAll: (e) async* {},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,13 +8,13 @@ import 'package:app_flowy/workspace/domain/i_view.dart';
|
|||||||
part 'view_bloc.freezed.dart';
|
part 'view_bloc.freezed.dart';
|
||||||
|
|
||||||
class ViewBloc extends Bloc<ViewEvent, ViewState> {
|
class ViewBloc extends Bloc<ViewEvent, ViewState> {
|
||||||
final IView iViewImpl;
|
final IView viewManager;
|
||||||
final IViewListener listener;
|
final IViewListener listener;
|
||||||
|
|
||||||
ViewBloc({
|
ViewBloc({
|
||||||
required this.iViewImpl,
|
required this.viewManager,
|
||||||
required this.listener,
|
required this.listener,
|
||||||
}) : super(ViewState.init(iViewImpl.view));
|
}) : super(ViewState.init(viewManager.view));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<ViewState> mapEventToState(ViewEvent event) async* {
|
Stream<ViewState> mapEventToState(ViewEvent event) async* {
|
||||||
@ -26,13 +26,13 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
|
|||||||
}, viewDidUpdate: (e) async* {
|
}, viewDidUpdate: (e) async* {
|
||||||
yield* _handleViewDidUpdate(e.result);
|
yield* _handleViewDidUpdate(e.result);
|
||||||
}, rename: (e) async* {
|
}, rename: (e) async* {
|
||||||
final result = await iViewImpl.rename(e.newName);
|
final result = await viewManager.rename(e.newName);
|
||||||
yield result.fold(
|
yield result.fold(
|
||||||
(l) => state.copyWith(successOrFailure: left(unit)),
|
(l) => state.copyWith(successOrFailure: left(unit)),
|
||||||
(error) => state.copyWith(successOrFailure: right(error)),
|
(error) => state.copyWith(successOrFailure: right(error)),
|
||||||
);
|
);
|
||||||
}, delete: (e) async* {
|
}, delete: (e) async* {
|
||||||
final result = await iViewImpl.delete();
|
final result = await viewManager.delete();
|
||||||
yield result.fold(
|
yield result.fold(
|
||||||
(l) => state.copyWith(successOrFailure: left(unit)),
|
(l) => state.copyWith(successOrFailure: left(unit)),
|
||||||
(error) => state.copyWith(successOrFailure: right(error)),
|
(error) => state.copyWith(successOrFailure: right(error)),
|
||||||
|
@ -11,16 +11,16 @@ part 'welcome_bloc.freezed.dart';
|
|||||||
|
|
||||||
class WelcomeBloc extends Bloc<WelcomeEvent, WelcomeState> {
|
class WelcomeBloc extends Bloc<WelcomeEvent, WelcomeState> {
|
||||||
final UserRepo repo;
|
final UserRepo repo;
|
||||||
final IUserListener watch;
|
final IUserListener listener;
|
||||||
WelcomeBloc({required this.repo, required this.watch}) : super(WelcomeState.initial());
|
WelcomeBloc({required this.repo, required this.listener}) : super(WelcomeState.initial());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<WelcomeState> mapEventToState(
|
Stream<WelcomeState> mapEventToState(
|
||||||
WelcomeEvent event,
|
WelcomeEvent event,
|
||||||
) async* {
|
) async* {
|
||||||
yield* event.map(initial: (e) async* {
|
yield* event.map(initial: (e) async* {
|
||||||
watch.setWorkspacesCallback(_workspacesUpdated);
|
listener.setWorkspacesCallback(_workspacesUpdated);
|
||||||
watch.start();
|
listener.start();
|
||||||
//
|
//
|
||||||
yield* _fetchWorkspaces();
|
yield* _fetchWorkspaces();
|
||||||
}, openWorkspace: (e) async* {
|
}, openWorkspace: (e) async* {
|
||||||
@ -37,7 +37,7 @@ class WelcomeBloc extends Bloc<WelcomeEvent, WelcomeState> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
await watch.stop();
|
await listener.stop();
|
||||||
super.close();
|
super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,6 @@ class WelcomeBloc extends Bloc<WelcomeEvent, WelcomeState> {
|
|||||||
final result = await repo.createWorkspace(name, desc);
|
final result = await repo.createWorkspace(name, desc);
|
||||||
yield result.fold(
|
yield result.fold(
|
||||||
(workspace) {
|
(workspace) {
|
||||||
// add(const WelcomeEvent.fetchWorkspaces());
|
|
||||||
return state.copyWith(successOrFailure: left(unit));
|
return state.copyWith(successOrFailure: left(unit));
|
||||||
},
|
},
|
||||||
(error) {
|
(error) {
|
||||||
@ -88,7 +87,6 @@ class WelcomeEvent with _$WelcomeEvent {
|
|||||||
// const factory WelcomeEvent.fetchWorkspaces() = FetchWorkspace;
|
// const factory WelcomeEvent.fetchWorkspaces() = FetchWorkspace;
|
||||||
const factory WelcomeEvent.createWorkspace(String name, String desc) = CreateWorkspace;
|
const factory WelcomeEvent.createWorkspace(String name, String desc) = CreateWorkspace;
|
||||||
const factory WelcomeEvent.openWorkspace(Workspace workspace) = OpenWorkspace;
|
const factory WelcomeEvent.openWorkspace(Workspace workspace) = OpenWorkspace;
|
||||||
|
|
||||||
const factory WelcomeEvent.workspacesReveived(Either<List<Workspace>, WorkspaceError> workspacesOrFail) =
|
const factory WelcomeEvent.workspacesReveived(Either<List<Workspace>, WorkspaceError> workspacesOrFail) =
|
||||||
WorkspacesReceived;
|
WorkspacesReceived;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ class HomeDepsResolver {
|
|||||||
getIt.registerFactoryParam<WelcomeBloc, UserProfile, void>(
|
getIt.registerFactoryParam<WelcomeBloc, UserProfile, void>(
|
||||||
(user, _) => WelcomeBloc(
|
(user, _) => WelcomeBloc(
|
||||||
repo: UserRepo(user: user),
|
repo: UserRepo(user: user),
|
||||||
watch: getIt<IUserListener>(param1: user),
|
listener: getIt<IUserListener>(param1: user),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -53,21 +53,27 @@ class _TrashStackPageState extends State<TrashStackPage> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = context.watch<AppTheme>();
|
final theme = context.watch<AppTheme>();
|
||||||
const horizontalPadding = 80.0;
|
const horizontalPadding = 80.0;
|
||||||
return SizedBox.expand(
|
return BlocProvider(
|
||||||
child: Column(
|
create: (context) => getIt<TrashBloc>()..add(const TrashEvent.initial()),
|
||||||
children: [
|
child: BlocBuilder<TrashBloc, TrashState>(
|
||||||
_renderTopBar(theme),
|
builder: (context, state) {
|
||||||
const VSpace(32),
|
return SizedBox.expand(
|
||||||
_renderTrashList(context),
|
child: Column(
|
||||||
],
|
children: [
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
_renderTopBar(context, theme, state),
|
||||||
).padding(horizontal: horizontalPadding, vertical: 48),
|
const VSpace(32),
|
||||||
|
_renderTrashList(context, state),
|
||||||
|
],
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
).padding(horizontal: horizontalPadding, vertical: 48),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _renderTrashList(BuildContext context) {
|
Widget _renderTrashList(BuildContext context, TrashState state) {
|
||||||
const barSize = 6.0;
|
const barSize = 6.0;
|
||||||
|
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: ScrollbarListStack(
|
child: ScrollbarListStack(
|
||||||
axis: Axis.vertical,
|
axis: Axis.vertical,
|
||||||
@ -86,8 +92,8 @@ class _TrashStackPageState extends State<TrashStackPage> {
|
|||||||
physics: StyledScrollPhysics(),
|
physics: StyledScrollPhysics(),
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
slivers: [
|
slivers: [
|
||||||
_renderListHeader(context),
|
_renderListHeader(context, state),
|
||||||
_renderListBody(context),
|
_renderListBody(context, state),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -97,7 +103,7 @@ class _TrashStackPageState extends State<TrashStackPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _renderTopBar(AppTheme theme) {
|
Widget _renderTopBar(BuildContext context, AppTheme theme, TrashState state) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: 36,
|
height: 36,
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -128,7 +134,7 @@ class _TrashStackPageState extends State<TrashStackPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _renderListHeader(BuildContext context) {
|
Widget _renderListHeader(BuildContext context, TrashState state) {
|
||||||
return SliverPersistentHeader(
|
return SliverPersistentHeader(
|
||||||
delegate: TrashHeaderDelegate(),
|
delegate: TrashHeaderDelegate(),
|
||||||
floating: true,
|
floating: true,
|
||||||
@ -136,31 +142,24 @@ class _TrashStackPageState extends State<TrashStackPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _renderListBody(BuildContext context) {
|
Widget _renderListBody(BuildContext context, TrashState state) {
|
||||||
return BlocProvider(
|
return SliverList(
|
||||||
create: (context) => getIt<TrashBloc>()..add(const TrashEvent.initial()),
|
delegate: SliverChildBuilderDelegate(
|
||||||
child: BlocBuilder<TrashBloc, TrashState>(
|
(BuildContext context, int index) {
|
||||||
builder: (context, state) {
|
final object = state.objects[index];
|
||||||
return SliverList(
|
return SizedBox(
|
||||||
delegate: SliverChildBuilderDelegate(
|
height: 42,
|
||||||
(BuildContext context, int index) {
|
child: TrashCell(
|
||||||
final object = state.objects[index];
|
object: object,
|
||||||
return SizedBox(
|
onRestore: () {
|
||||||
height: 42,
|
context.read<TrashBloc>().add(TrashEvent.putback(object.id));
|
||||||
child: TrashCell(
|
|
||||||
object: object,
|
|
||||||
onRestore: () {
|
|
||||||
context.read<TrashBloc>().add(TrashEvent.putback(object.id));
|
|
||||||
},
|
|
||||||
onDelete: () => context.read<TrashBloc>().add(TrashEvent.delete(object.id)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
childCount: state.objects.length,
|
onDelete: () => context.read<TrashBloc>().add(TrashEvent.delete(object.id)),
|
||||||
addAutomaticKeepAlives: false,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
childCount: state.objects.length,
|
||||||
|
addAutomaticKeepAlives: false,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -17,17 +17,22 @@ export 'trash_create.pbenum.dart';
|
|||||||
class TrashIdentifiers extends $pb.GeneratedMessage {
|
class TrashIdentifiers extends $pb.GeneratedMessage {
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TrashIdentifiers', createEmptyInstance: create)
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TrashIdentifiers', createEmptyInstance: create)
|
||||||
..pc<TrashIdentifier>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: TrashIdentifier.create)
|
..pc<TrashIdentifier>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: TrashIdentifier.create)
|
||||||
|
..aOB(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deleteAll')
|
||||||
..hasRequiredFields = false
|
..hasRequiredFields = false
|
||||||
;
|
;
|
||||||
|
|
||||||
TrashIdentifiers._() : super();
|
TrashIdentifiers._() : super();
|
||||||
factory TrashIdentifiers({
|
factory TrashIdentifiers({
|
||||||
$core.Iterable<TrashIdentifier>? items,
|
$core.Iterable<TrashIdentifier>? items,
|
||||||
|
$core.bool? deleteAll,
|
||||||
}) {
|
}) {
|
||||||
final _result = create();
|
final _result = create();
|
||||||
if (items != null) {
|
if (items != null) {
|
||||||
_result.items.addAll(items);
|
_result.items.addAll(items);
|
||||||
}
|
}
|
||||||
|
if (deleteAll != null) {
|
||||||
|
_result.deleteAll = deleteAll;
|
||||||
|
}
|
||||||
return _result;
|
return _result;
|
||||||
}
|
}
|
||||||
factory TrashIdentifiers.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
factory TrashIdentifiers.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||||
@ -53,6 +58,15 @@ class TrashIdentifiers extends $pb.GeneratedMessage {
|
|||||||
|
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
$core.List<TrashIdentifier> get items => $_getList(0);
|
$core.List<TrashIdentifier> get items => $_getList(0);
|
||||||
|
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.bool get deleteAll => $_getBF(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
set deleteAll($core.bool v) { $_setBool(1, v); }
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.bool hasDeleteAll() => $_has(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
void clearDeleteAll() => clearField(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrashIdentifier extends $pb.GeneratedMessage {
|
class TrashIdentifier extends $pb.GeneratedMessage {
|
||||||
|
@ -24,11 +24,12 @@ const TrashIdentifiers$json = const {
|
|||||||
'1': 'TrashIdentifiers',
|
'1': 'TrashIdentifiers',
|
||||||
'2': const [
|
'2': const [
|
||||||
const {'1': 'items', '3': 1, '4': 3, '5': 11, '6': '.TrashIdentifier', '10': 'items'},
|
const {'1': 'items', '3': 1, '4': 3, '5': 11, '6': '.TrashIdentifier', '10': 'items'},
|
||||||
|
const {'1': 'delete_all', '3': 2, '4': 1, '5': 8, '10': 'deleteAll'},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `TrashIdentifiers`. Decode as a `google.protobuf.DescriptorProto`.
|
/// Descriptor for `TrashIdentifiers`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
final $typed_data.Uint8List trashIdentifiersDescriptor = $convert.base64Decode('ChBUcmFzaElkZW50aWZpZXJzEiYKBWl0ZW1zGAEgAygLMhAuVHJhc2hJZGVudGlmaWVyUgVpdGVtcw==');
|
final $typed_data.Uint8List trashIdentifiersDescriptor = $convert.base64Decode('ChBUcmFzaElkZW50aWZpZXJzEiYKBWl0ZW1zGAEgAygLMhAuVHJhc2hJZGVudGlmaWVyUgVpdGVtcxIdCgpkZWxldGVfYWxsGAIgASgIUglkZWxldGVBbGw=');
|
||||||
@$core.Deprecated('Use trashIdentifierDescriptor instead')
|
@$core.Deprecated('Use trashIdentifierDescriptor instead')
|
||||||
const TrashIdentifier$json = const {
|
const TrashIdentifier$json = const {
|
||||||
'1': 'TrashIdentifier',
|
'1': 'TrashIdentifier',
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::service::{
|
use crate::service::{
|
||||||
trash::{create_trash, delete_trash, read_trash},
|
trash::{create_trash, delete_all_trash, delete_trash, read_trash},
|
||||||
user::LoggedUser,
|
user::LoggedUser,
|
||||||
util::parse_from_payload,
|
util::parse_from_payload,
|
||||||
};
|
};
|
||||||
@ -42,6 +42,7 @@ pub async fn create_handler(
|
|||||||
Ok(FlowyResponse::success().into())
|
Ok(FlowyResponse::success().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(payload, pool, logged_user), fields(delete_trash), err)]
|
||||||
pub async fn delete_handler(
|
pub async fn delete_handler(
|
||||||
payload: Payload,
|
payload: Payload,
|
||||||
pool: Data<PgPool>,
|
pool: Data<PgPool>,
|
||||||
@ -53,7 +54,14 @@ pub async fn delete_handler(
|
|||||||
.await
|
.await
|
||||||
.context("Failed to acquire a Postgres connection to delete trash")?;
|
.context("Failed to acquire a Postgres connection to delete trash")?;
|
||||||
|
|
||||||
let _ = delete_trash(&mut transaction, make_records(params)?, &logged_user).await?;
|
if params.delete_all {
|
||||||
|
tracing::Span::current().record("delete_trash", &"all");
|
||||||
|
let _ = delete_all_trash(&mut transaction, &logged_user).await?;
|
||||||
|
} else {
|
||||||
|
let records = make_records(params)?;
|
||||||
|
let _ = delete_trash(&mut transaction, records, &logged_user).await?;
|
||||||
|
}
|
||||||
|
|
||||||
transaction
|
transaction
|
||||||
.commit()
|
.commit()
|
||||||
.await
|
.await
|
||||||
|
@ -33,6 +33,22 @@ pub(crate) async fn create_trash(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn delete_all_trash(
|
||||||
|
transaction: &mut DBTransaction<'_>,
|
||||||
|
user: &LoggedUser,
|
||||||
|
) -> Result<(), ServerError> {
|
||||||
|
let (sql, args) = SqlBuilder::delete(TRASH_TABLE)
|
||||||
|
.and_where_eq("user_id", &user.user_id)
|
||||||
|
.build()?;
|
||||||
|
let result = sqlx::query_with(&sql, args)
|
||||||
|
.execute(transaction as &mut DBTransaction<'_>)
|
||||||
|
.await
|
||||||
|
.map_err(map_sqlx_error)?;
|
||||||
|
|
||||||
|
tracing::Span::current().record("affected_row", &result.rows_affected());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn delete_trash(
|
pub(crate) async fn delete_trash(
|
||||||
transaction: &mut DBTransaction<'_>,
|
transaction: &mut DBTransaction<'_>,
|
||||||
records: Vec<(Uuid, i32)>,
|
records: Vec<(Uuid, i32)>,
|
||||||
|
@ -45,7 +45,7 @@ impl DocError {
|
|||||||
|
|
||||||
static_doc_error!(id_invalid, ErrorCode::DocIdInvalid);
|
static_doc_error!(id_invalid, ErrorCode::DocIdInvalid);
|
||||||
static_doc_error!(internal, ErrorCode::InternalError);
|
static_doc_error!(internal, ErrorCode::InternalError);
|
||||||
static_doc_error!(not_found, ErrorCode::DocNotfound);
|
static_doc_error!(record_not_found, ErrorCode::DocNotfound);
|
||||||
static_doc_error!(unauthorized, ErrorCode::UserUnauthorized);
|
static_doc_error!(unauthorized, ErrorCode::UserUnauthorized);
|
||||||
static_doc_error!(ws, ErrorCode::WsConnectError);
|
static_doc_error!(ws, ErrorCode::WsConnectError);
|
||||||
static_doc_error!(undo, ErrorCode::UndoFail);
|
static_doc_error!(undo, ErrorCode::UndoFail);
|
||||||
@ -97,7 +97,7 @@ impl std::default::Default for ErrorCode {
|
|||||||
impl std::convert::From<flowy_database::Error> for DocError {
|
impl std::convert::From<flowy_database::Error> for DocError {
|
||||||
fn from(error: flowy_database::Error) -> Self {
|
fn from(error: flowy_database::Error) -> Self {
|
||||||
match error {
|
match error {
|
||||||
flowy_database::Error::NotFound => DocError::not_found().context(error),
|
flowy_database::Error::NotFound => DocError::record_not_found().context(error),
|
||||||
_ => DocError::internal().context(error),
|
_ => DocError::internal().context(error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,11 +37,6 @@ impl FlowyDocument {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(&self, params: CreateDocParams) -> Result<(), DocError> {
|
|
||||||
let _ = self.doc_ctrl.create(params)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delete(&self, params: DocIdentifier) -> Result<(), DocError> {
|
pub fn delete(&self, params: DocIdentifier) -> Result<(), DocError> {
|
||||||
let _ = self.doc_ctrl.delete(params)?;
|
let _ = self.doc_ctrl.delete(params)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -46,4 +46,4 @@ impl DocCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn doc_not_found() -> DocError { DocError::not_found().context("Doc is close or you should call open first") }
|
fn doc_not_found() -> DocError { DocError::record_not_found().context("Doc is close or you should call open first") }
|
||||||
|
@ -45,17 +45,6 @@ impl DocController {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self), err)]
|
|
||||||
pub(crate) fn create(&self, params: CreateDocParams) -> Result<(), DocError> {
|
|
||||||
// let _doc = Doc {
|
|
||||||
// id: params.id,
|
|
||||||
// data: params.data,
|
|
||||||
// rev_id: 0,
|
|
||||||
// };
|
|
||||||
// let _ = self.doc_sql.create_doc_table(DocTable::new(doc), conn)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self, pool), err)]
|
#[tracing::instrument(level = "debug", skip(self, pool), err)]
|
||||||
pub(crate) async fn open(
|
pub(crate) async fn open(
|
||||||
&self,
|
&self,
|
||||||
@ -82,7 +71,6 @@ impl DocController {
|
|||||||
let doc_id = ¶ms.doc_id;
|
let doc_id = ¶ms.doc_id;
|
||||||
self.cache.remove(doc_id);
|
self.cache.remove(doc_id);
|
||||||
self.ws_manager.remove_handler(doc_id);
|
self.ws_manager.remove_handler(doc_id);
|
||||||
let _ = self.delete_doc_on_server(params)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,22 +83,6 @@ impl DocController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DocController {
|
impl DocController {
|
||||||
#[tracing::instrument(level = "debug", skip(self), err)]
|
|
||||||
fn delete_doc_on_server(&self, params: DocIdentifier) -> Result<(), DocError> {
|
|
||||||
let token = self.user.token()?;
|
|
||||||
let server = self.server.clone();
|
|
||||||
tokio::spawn(async move {
|
|
||||||
match server.delete_doc(&token, params).await {
|
|
||||||
Ok(_) => {},
|
|
||||||
Err(e) => {
|
|
||||||
// TODO: retry?
|
|
||||||
log::error!("Delete doc failed: {:?}", e);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn make_edit_context(&self, doc_id: &str, pool: Arc<ConnectionPool>) -> Result<Arc<ClientEditDoc>, DocError> {
|
async fn make_edit_context(&self, doc_id: &str, pool: Arc<ConnectionPool>) -> Result<Arc<ClientEditDoc>, DocError> {
|
||||||
// Opti: require upgradable_read lock and then upgrade to write lock using
|
// Opti: require upgradable_read lock and then upgrade to write lock using
|
||||||
// RwLockUpgradableReadGuard::upgrade(xx) of ws
|
// RwLockUpgradableReadGuard::upgrade(xx) of ws
|
||||||
@ -146,7 +118,7 @@ impl RevisionServer for RevisionServerImpl {
|
|||||||
|
|
||||||
ResultFuture::new(async move {
|
ResultFuture::new(async move {
|
||||||
match server.read_doc(&token, params).await? {
|
match server.read_doc(&token, params).await? {
|
||||||
None => Err(DocError::not_found()),
|
None => Err(DocError::record_not_found().context("Remote doesn't have this document")),
|
||||||
Some(doc) => Ok(doc),
|
Some(doc) => Ok(doc),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -180,7 +180,7 @@ async fn fetch_from_local(doc_id: &str, persistence: Arc<Persistence>) -> DocRes
|
|||||||
let conn = &*persistence.pool.get().map_err(internal_error)?;
|
let conn = &*persistence.pool.get().map_err(internal_error)?;
|
||||||
let revisions = persistence.rev_sql.read_rev_tables(&doc_id, None, conn)?;
|
let revisions = persistence.rev_sql.read_rev_tables(&doc_id, None, conn)?;
|
||||||
if revisions.is_empty() {
|
if revisions.is_empty() {
|
||||||
return Err(DocError::not_found());
|
return Err(DocError::record_not_found().context("Local doesn't have this document"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let base_rev_id: RevId = revisions.last().unwrap().base_rev_id.into();
|
let base_rev_id: RevId = revisions.last().unwrap().base_rev_id.into();
|
||||||
|
@ -20,8 +20,6 @@ pub trait DocumentServerAPI {
|
|||||||
fn read_doc(&self, token: &str, params: DocIdentifier) -> ResultFuture<Option<Doc>, DocError>;
|
fn read_doc(&self, token: &str, params: DocIdentifier) -> ResultFuture<Option<Doc>, DocError>;
|
||||||
|
|
||||||
fn update_doc(&self, token: &str, params: UpdateDocParams) -> ResultFuture<(), DocError>;
|
fn update_doc(&self, token: &str, params: UpdateDocParams) -> ResultFuture<(), DocError>;
|
||||||
|
|
||||||
fn delete_doc(&self, token: &str, params: DocIdentifier) -> ResultFuture<(), DocError>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn construct_doc_server(server_config: &ServerConfig) -> Arc<dyn DocumentServerAPI + Send + Sync> {
|
pub(crate) fn construct_doc_server(server_config: &ServerConfig) -> Arc<dyn DocumentServerAPI + Send + Sync> {
|
||||||
|
@ -32,12 +32,6 @@ impl DocumentServerAPI for DocServer {
|
|||||||
let url = self.config.doc_url();
|
let url = self.config.doc_url();
|
||||||
ResultFuture::new(async move { update_doc_request(&token, params, &url).await })
|
ResultFuture::new(async move { update_doc_request(&token, params, &url).await })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_doc(&self, token: &str, params: DocIdentifier) -> ResultFuture<(), DocError> {
|
|
||||||
let token = token.to_owned();
|
|
||||||
let url = self.config.doc_url();
|
|
||||||
ResultFuture::new(async move { delete_doc_request(&token, params, &url).await })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn request_builder() -> HttpRequestBuilder {
|
pub(crate) fn request_builder() -> HttpRequestBuilder {
|
||||||
@ -74,13 +68,3 @@ pub async fn update_doc_request(token: &str, params: UpdateDocParams, url: &str)
|
|||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_doc_request(token: &str, params: DocIdentifier, url: &str) -> Result<(), DocError> {
|
|
||||||
let _ = request_builder()
|
|
||||||
.delete(url)
|
|
||||||
.header(HEADER_TOKEN, token)
|
|
||||||
.protobuf(params)?
|
|
||||||
.send()
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
@ -18,8 +18,4 @@ impl DocumentServerAPI for DocServerMock {
|
|||||||
fn update_doc(&self, _token: &str, _params: UpdateDocParams) -> ResultFuture<(), DocError> {
|
fn update_doc(&self, _token: &str, _params: UpdateDocParams) -> ResultFuture<(), DocError> {
|
||||||
ResultFuture::new(async { Ok(()) })
|
ResultFuture::new(async { Ok(()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_doc(&self, _token: &str, _params: DocIdentifier) -> ResultFuture<(), DocError> {
|
|
||||||
ResultFuture::new(async { Ok(()) })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ pub fn read_workspace(sdk: &FlowyTestSDK, request: QueryWorkspaceRequest) -> Opt
|
|||||||
let mut workspaces;
|
let mut workspaces;
|
||||||
if let Some(workspace_id) = &request.workspace_id {
|
if let Some(workspace_id) = &request.workspace_id {
|
||||||
workspaces = repeated_workspace
|
workspaces = repeated_workspace
|
||||||
.take_items()
|
.into_inner()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|workspace| &workspace.id == workspace_id)
|
.filter(|workspace| &workspace.id == workspace_id)
|
||||||
.collect::<Vec<Workspace>>();
|
.collect::<Vec<Workspace>>();
|
||||||
|
@ -3,9 +3,8 @@ use flowy_test::{builder::UserTest, FlowyTest};
|
|||||||
use flowy_user::{errors::ErrorCode, event::UserEvent::*, prelude::*};
|
use flowy_user::{errors::ErrorCode, event::UserEvent::*, prelude::*};
|
||||||
use serial_test::*;
|
use serial_test::*;
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
#[serial]
|
async fn sign_up_with_invalid_email() {
|
||||||
fn sign_up_with_invalid_email() {
|
|
||||||
for email in invalid_email_test_case() {
|
for email in invalid_email_test_case() {
|
||||||
let test = FlowyTest::setup();
|
let test = FlowyTest::setup();
|
||||||
let request = SignUpRequest {
|
let request = SignUpRequest {
|
||||||
@ -18,16 +17,16 @@ fn sign_up_with_invalid_email() {
|
|||||||
UserTest::new(test.sdk)
|
UserTest::new(test.sdk)
|
||||||
.event(SignUp)
|
.event(SignUp)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.async_send()
|
||||||
|
.await
|
||||||
.error()
|
.error()
|
||||||
.code,
|
.code,
|
||||||
ErrorCode::EmailFormatInvalid
|
ErrorCode::EmailFormatInvalid
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[test]
|
#[tokio::test]
|
||||||
#[serial]
|
async fn sign_up_with_invalid_password() {
|
||||||
fn sign_up_with_invalid_password() {
|
|
||||||
for password in invalid_password_test_case() {
|
for password in invalid_password_test_case() {
|
||||||
let test = FlowyTest::setup();
|
let test = FlowyTest::setup();
|
||||||
let request = SignUpRequest {
|
let request = SignUpRequest {
|
||||||
@ -39,7 +38,8 @@ fn sign_up_with_invalid_password() {
|
|||||||
UserTest::new(test.sdk)
|
UserTest::new(test.sdk)
|
||||||
.event(SignUp)
|
.event(SignUp)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.async_send()
|
||||||
|
.await
|
||||||
.assert_error();
|
.assert_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,14 +58,14 @@ async fn sign_in_success() {
|
|||||||
let response = UserTest::new(test.sdk())
|
let response = UserTest::new(test.sdk())
|
||||||
.event(SignIn)
|
.event(SignIn)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.async_send()
|
||||||
|
.await
|
||||||
.parse::<UserProfile>();
|
.parse::<UserProfile>();
|
||||||
dbg!(&response);
|
dbg!(&response);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
#[serial]
|
async fn sign_in_with_invalid_email() {
|
||||||
fn sign_in_with_invalid_email() {
|
|
||||||
for email in invalid_email_test_case() {
|
for email in invalid_email_test_case() {
|
||||||
let test = FlowyTest::setup();
|
let test = FlowyTest::setup();
|
||||||
let request = SignInRequest {
|
let request = SignInRequest {
|
||||||
@ -77,7 +77,8 @@ fn sign_in_with_invalid_email() {
|
|||||||
UserTest::new(test.sdk)
|
UserTest::new(test.sdk)
|
||||||
.event(SignIn)
|
.event(SignIn)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.async_send()
|
||||||
|
.await
|
||||||
.error()
|
.error()
|
||||||
.code,
|
.code,
|
||||||
ErrorCode::EmailFormatInvalid
|
ErrorCode::EmailFormatInvalid
|
||||||
@ -85,9 +86,8 @@ fn sign_in_with_invalid_email() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
#[serial]
|
async fn sign_in_with_invalid_password() {
|
||||||
fn sign_in_with_invalid_password() {
|
|
||||||
for password in invalid_password_test_case() {
|
for password in invalid_password_test_case() {
|
||||||
let test = FlowyTest::setup();
|
let test = FlowyTest::setup();
|
||||||
|
|
||||||
@ -99,7 +99,8 @@ fn sign_in_with_invalid_password() {
|
|||||||
UserTest::new(test.sdk)
|
UserTest::new(test.sdk)
|
||||||
.event(SignIn)
|
.event(SignIn)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.async_send()
|
||||||
|
.await
|
||||||
.assert_error();
|
.assert_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,14 @@ use flowy_test::{builder::UserTest, FlowyTest};
|
|||||||
use flowy_user::{errors::ErrorCode, event::UserEvent::*, prelude::*};
|
use flowy_user::{errors::ErrorCode, event::UserEvent::*, prelude::*};
|
||||||
use serial_test::*;
|
use serial_test::*;
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
#[serial]
|
async fn user_profile_get_failed() {
|
||||||
fn user_profile_get_failed() {
|
|
||||||
let test = FlowyTest::setup();
|
let test = FlowyTest::setup();
|
||||||
let result = UserTest::new(test.sdk).event(GetUserProfile).assert_error().sync_send();
|
let result = UserTest::new(test.sdk)
|
||||||
|
.event(GetUserProfile)
|
||||||
|
.assert_error()
|
||||||
|
.async_send()
|
||||||
|
.await;
|
||||||
assert!(result.user_profile().is_none())
|
assert!(result.user_profile().is_none())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +27,27 @@ impl std::default::Default for TrashType {
|
|||||||
pub struct TrashIdentifiers {
|
pub struct TrashIdentifiers {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
pub items: Vec<TrashIdentifier>,
|
pub items: Vec<TrashIdentifier>,
|
||||||
|
|
||||||
|
#[pb(index = 2)]
|
||||||
|
pub delete_all: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrashIdentifiers {
|
||||||
|
pub fn all() -> TrashIdentifiers {
|
||||||
|
TrashIdentifiers {
|
||||||
|
items: vec![],
|
||||||
|
delete_all: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<Vec<TrashIdentifier>> for TrashIdentifiers {
|
impl std::convert::From<Vec<TrashIdentifier>> for TrashIdentifiers {
|
||||||
fn from(items: Vec<TrashIdentifier>) -> Self { TrashIdentifiers { items } }
|
fn from(items: Vec<TrashIdentifier>) -> Self {
|
||||||
|
TrashIdentifiers {
|
||||||
|
items,
|
||||||
|
delete_all: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<Vec<Trash>> for TrashIdentifiers {
|
impl std::convert::From<Vec<Trash>> for TrashIdentifiers {
|
||||||
@ -40,7 +57,10 @@ impl std::convert::From<Vec<Trash>> for TrashIdentifiers {
|
|||||||
.map(|t| TrashIdentifier { id: t.id, ty: t.ty })
|
.map(|t| TrashIdentifier { id: t.id, ty: t.ty })
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
TrashIdentifiers { items }
|
TrashIdentifiers {
|
||||||
|
items,
|
||||||
|
delete_all: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,12 +33,12 @@ pub(crate) async fn delete_trash_handler(
|
|||||||
|
|
||||||
#[tracing::instrument(skip(controller), err)]
|
#[tracing::instrument(skip(controller), err)]
|
||||||
pub(crate) async fn restore_all_handler(controller: Unit<Arc<TrashCan>>) -> Result<(), WorkspaceError> {
|
pub(crate) async fn restore_all_handler(controller: Unit<Arc<TrashCan>>) -> Result<(), WorkspaceError> {
|
||||||
let _ = controller.restore_all()?;
|
let _ = controller.restore_all().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(controller), err)]
|
#[tracing::instrument(skip(controller), err)]
|
||||||
pub(crate) async fn delete_all_handler(controller: Unit<Arc<TrashCan>>) -> Result<(), WorkspaceError> {
|
pub(crate) async fn delete_all_handler(controller: Unit<Arc<TrashCan>>) -> Result<(), WorkspaceError> {
|
||||||
let _ = controller.delete_all()?;
|
let _ = controller.delete_all().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
pub struct TrashIdentifiers {
|
pub struct TrashIdentifiers {
|
||||||
// message fields
|
// message fields
|
||||||
pub items: ::protobuf::RepeatedField<TrashIdentifier>,
|
pub items: ::protobuf::RepeatedField<TrashIdentifier>,
|
||||||
|
pub delete_all: bool,
|
||||||
// special fields
|
// special fields
|
||||||
pub unknown_fields: ::protobuf::UnknownFields,
|
pub unknown_fields: ::protobuf::UnknownFields,
|
||||||
pub cached_size: ::protobuf::CachedSize,
|
pub cached_size: ::protobuf::CachedSize,
|
||||||
@ -67,6 +68,21 @@ impl TrashIdentifiers {
|
|||||||
pub fn take_items(&mut self) -> ::protobuf::RepeatedField<TrashIdentifier> {
|
pub fn take_items(&mut self) -> ::protobuf::RepeatedField<TrashIdentifier> {
|
||||||
::std::mem::replace(&mut self.items, ::protobuf::RepeatedField::new())
|
::std::mem::replace(&mut self.items, ::protobuf::RepeatedField::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bool delete_all = 2;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn get_delete_all(&self) -> bool {
|
||||||
|
self.delete_all
|
||||||
|
}
|
||||||
|
pub fn clear_delete_all(&mut self) {
|
||||||
|
self.delete_all = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param is passed by value, moved
|
||||||
|
pub fn set_delete_all(&mut self, v: bool) {
|
||||||
|
self.delete_all = v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::Message for TrashIdentifiers {
|
impl ::protobuf::Message for TrashIdentifiers {
|
||||||
@ -86,6 +102,13 @@ impl ::protobuf::Message for TrashIdentifiers {
|
|||||||
1 => {
|
1 => {
|
||||||
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.items)?;
|
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.items)?;
|
||||||
},
|
},
|
||||||
|
2 => {
|
||||||
|
if wire_type != ::protobuf::wire_format::WireTypeVarint {
|
||||||
|
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
|
||||||
|
}
|
||||||
|
let tmp = is.read_bool()?;
|
||||||
|
self.delete_all = tmp;
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
|
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
|
||||||
},
|
},
|
||||||
@ -102,6 +125,9 @@ impl ::protobuf::Message for TrashIdentifiers {
|
|||||||
let len = value.compute_size();
|
let len = value.compute_size();
|
||||||
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
|
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
|
||||||
};
|
};
|
||||||
|
if self.delete_all != false {
|
||||||
|
my_size += 2;
|
||||||
|
}
|
||||||
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
|
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
|
||||||
self.cached_size.set(my_size);
|
self.cached_size.set(my_size);
|
||||||
my_size
|
my_size
|
||||||
@ -113,6 +139,9 @@ impl ::protobuf::Message for TrashIdentifiers {
|
|||||||
os.write_raw_varint32(v.get_cached_size())?;
|
os.write_raw_varint32(v.get_cached_size())?;
|
||||||
v.write_to_with_cached_sizes(os)?;
|
v.write_to_with_cached_sizes(os)?;
|
||||||
};
|
};
|
||||||
|
if self.delete_all != false {
|
||||||
|
os.write_bool(2, self.delete_all)?;
|
||||||
|
}
|
||||||
os.write_unknown_fields(self.get_unknown_fields())?;
|
os.write_unknown_fields(self.get_unknown_fields())?;
|
||||||
::std::result::Result::Ok(())
|
::std::result::Result::Ok(())
|
||||||
}
|
}
|
||||||
@ -156,6 +185,11 @@ impl ::protobuf::Message for TrashIdentifiers {
|
|||||||
|m: &TrashIdentifiers| { &m.items },
|
|m: &TrashIdentifiers| { &m.items },
|
||||||
|m: &mut TrashIdentifiers| { &mut m.items },
|
|m: &mut TrashIdentifiers| { &mut m.items },
|
||||||
));
|
));
|
||||||
|
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>(
|
||||||
|
"delete_all",
|
||||||
|
|m: &TrashIdentifiers| { &m.delete_all },
|
||||||
|
|m: &mut TrashIdentifiers| { &mut m.delete_all },
|
||||||
|
));
|
||||||
::protobuf::reflect::MessageDescriptor::new_pb_name::<TrashIdentifiers>(
|
::protobuf::reflect::MessageDescriptor::new_pb_name::<TrashIdentifiers>(
|
||||||
"TrashIdentifiers",
|
"TrashIdentifiers",
|
||||||
fields,
|
fields,
|
||||||
@ -173,6 +207,7 @@ impl ::protobuf::Message for TrashIdentifiers {
|
|||||||
impl ::protobuf::Clear for TrashIdentifiers {
|
impl ::protobuf::Clear for TrashIdentifiers {
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.items.clear();
|
self.items.clear();
|
||||||
|
self.delete_all = false;
|
||||||
self.unknown_fields.clear();
|
self.unknown_fields.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -898,52 +933,56 @@ impl ::protobuf::reflect::ProtobufValue for TrashType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||||
\n\x12trash_create.proto\":\n\x10TrashIdentifiers\x12&\n\x05items\x18\
|
\n\x12trash_create.proto\"Y\n\x10TrashIdentifiers\x12&\n\x05items\x18\
|
||||||
\x01\x20\x03(\x0b2\x10.TrashIdentifierR\x05items\"=\n\x0fTrashIdentifier\
|
\x01\x20\x03(\x0b2\x10.TrashIdentifierR\x05items\x12\x1d\n\ndelete_all\
|
||||||
\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x1a\n\x02ty\x18\x02\x20\
|
\x18\x02\x20\x01(\x08R\tdeleteAll\"=\n\x0fTrashIdentifier\x12\x0e\n\x02i\
|
||||||
\x01(\x0e2\n.TrashTypeR\x02ty\"\x8d\x01\n\x05Trash\x12\x0e\n\x02id\x18\
|
d\x18\x01\x20\x01(\tR\x02id\x12\x1a\n\x02ty\x18\x02\x20\x01(\x0e2\n.Tras\
|
||||||
\x01\x20\x01(\tR\x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\
|
hTypeR\x02ty\"\x8d\x01\n\x05Trash\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\
|
||||||
#\n\rmodified_time\x18\x03\x20\x01(\x03R\x0cmodifiedTime\x12\x1f\n\x0bcr\
|
\x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12#\n\rmodified_ti\
|
||||||
eate_time\x18\x04\x20\x01(\x03R\ncreateTime\x12\x1a\n\x02ty\x18\x05\x20\
|
me\x18\x03\x20\x01(\x03R\x0cmodifiedTime\x12\x1f\n\x0bcreate_time\x18\
|
||||||
\x01(\x0e2\n.TrashTypeR\x02ty\"-\n\rRepeatedTrash\x12\x1c\n\x05items\x18\
|
\x04\x20\x01(\x03R\ncreateTime\x12\x1a\n\x02ty\x18\x05\x20\x01(\x0e2\n.T\
|
||||||
\x01\x20\x03(\x0b2\x06.TrashR\x05items*\"\n\tTrashType\x12\x0b\n\x07Unkn\
|
rashTypeR\x02ty\"-\n\rRepeatedTrash\x12\x1c\n\x05items\x18\x01\x20\x03(\
|
||||||
own\x10\0\x12\x08\n\x04View\x10\x01J\xe7\x05\n\x06\x12\x04\0\0\x16\x01\n\
|
\x0b2\x06.TrashR\x05items*\"\n\tTrashType\x12\x0b\n\x07Unknown\x10\0\x12\
|
||||||
\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x04\x01\n\n\
|
\x08\n\x04View\x10\x01J\x9e\x06\n\x06\x12\x04\0\0\x17\x01\n\x08\n\x01\
|
||||||
\n\x03\x04\0\x01\x12\x03\x02\x08\x18\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\
|
\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\
|
||||||
\x04'\n\x0c\n\x05\x04\0\x02\0\x04\x12\x03\x03\x04\x0c\n\x0c\n\x05\x04\0\
|
\0\x01\x12\x03\x02\x08\x18\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04'\n\
|
||||||
\x02\0\x06\x12\x03\x03\r\x1c\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x1d\
|
\x0c\n\x05\x04\0\x02\0\x04\x12\x03\x03\x04\x0c\n\x0c\n\x05\x04\0\x02\0\
|
||||||
\"\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03%&\n\n\n\x02\x04\x01\x12\x04\
|
\x06\x12\x03\x03\r\x1c\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x1d\"\n\
|
||||||
\x05\0\x08\x01\n\n\n\x03\x04\x01\x01\x12\x03\x05\x08\x17\n\x0b\n\x04\x04\
|
\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03%&\n\x0b\n\x04\x04\0\x02\x01\x12\
|
||||||
\x01\x02\0\x12\x03\x06\x04\x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x06\
|
\x03\x04\x04\x18\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\x08\n\x0c\
|
||||||
\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x06\x0b\r\n\x0c\n\x05\x04\
|
\n\x05\x04\0\x02\x01\x01\x12\x03\x04\t\x13\n\x0c\n\x05\x04\0\x02\x01\x03\
|
||||||
\x01\x02\0\x03\x12\x03\x06\x10\x11\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\
|
\x12\x03\x04\x16\x17\n\n\n\x02\x04\x01\x12\x04\x06\0\t\x01\n\n\n\x03\x04\
|
||||||
\x07\x04\x15\n\x0c\n\x05\x04\x01\x02\x01\x06\x12\x03\x07\x04\r\n\x0c\n\
|
\x01\x01\x12\x03\x06\x08\x17\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x07\x04\
|
||||||
\x05\x04\x01\x02\x01\x01\x12\x03\x07\x0e\x10\n\x0c\n\x05\x04\x01\x02\x01\
|
\x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x07\x04\n\n\x0c\n\x05\x04\x01\
|
||||||
\x03\x12\x03\x07\x13\x14\n\n\n\x02\x04\x02\x12\x04\t\0\x0f\x01\n\n\n\x03\
|
\x02\0\x01\x12\x03\x07\x0b\r\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x07\
|
||||||
\x04\x02\x01\x12\x03\t\x08\r\n\x0b\n\x04\x04\x02\x02\0\x12\x03\n\x04\x12\
|
\x10\x11\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x08\x04\x15\n\x0c\n\x05\x04\
|
||||||
\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\n\x04\n\n\x0c\n\x05\x04\x02\x02\0\
|
\x01\x02\x01\x06\x12\x03\x08\x04\r\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\
|
||||||
\x01\x12\x03\n\x0b\r\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\n\x10\x11\n\
|
\x03\x08\x0e\x10\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x08\x13\x14\n\n\
|
||||||
\x0b\n\x04\x04\x02\x02\x01\x12\x03\x0b\x04\x14\n\x0c\n\x05\x04\x02\x02\
|
\n\x02\x04\x02\x12\x04\n\0\x10\x01\n\n\n\x03\x04\x02\x01\x12\x03\n\x08\r\
|
||||||
\x01\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\x0b\
|
\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0b\x04\x12\n\x0c\n\x05\x04\x02\x02\0\
|
||||||
\x0b\x0f\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x0b\x12\x13\n\x0b\n\x04\
|
\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0b\x0b\r\n\
|
||||||
\x04\x02\x02\x02\x12\x03\x0c\x04\x1c\n\x0c\n\x05\x04\x02\x02\x02\x05\x12\
|
\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0b\x10\x11\n\x0b\n\x04\x04\x02\x02\
|
||||||
\x03\x0c\x04\t\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\x0c\n\x17\n\x0c\n\
|
\x01\x12\x03\x0c\x04\x14\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\x0c\x04\
|
||||||
\x05\x04\x02\x02\x02\x03\x12\x03\x0c\x1a\x1b\n\x0b\n\x04\x04\x02\x02\x03\
|
\n\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\x0c\x0b\x0f\n\x0c\n\x05\x04\
|
||||||
\x12\x03\r\x04\x1a\n\x0c\n\x05\x04\x02\x02\x03\x05\x12\x03\r\x04\t\n\x0c\
|
\x02\x02\x01\x03\x12\x03\x0c\x12\x13\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\
|
||||||
\n\x05\x04\x02\x02\x03\x01\x12\x03\r\n\x15\n\x0c\n\x05\x04\x02\x02\x03\
|
\r\x04\x1c\n\x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\r\x04\t\n\x0c\n\x05\
|
||||||
\x03\x12\x03\r\x18\x19\n\x0b\n\x04\x04\x02\x02\x04\x12\x03\x0e\x04\x15\n\
|
\x04\x02\x02\x02\x01\x12\x03\r\n\x17\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\
|
||||||
\x0c\n\x05\x04\x02\x02\x04\x06\x12\x03\x0e\x04\r\n\x0c\n\x05\x04\x02\x02\
|
\x03\r\x1a\x1b\n\x0b\n\x04\x04\x02\x02\x03\x12\x03\x0e\x04\x1a\n\x0c\n\
|
||||||
\x04\x01\x12\x03\x0e\x0e\x10\n\x0c\n\x05\x04\x02\x02\x04\x03\x12\x03\x0e\
|
\x05\x04\x02\x02\x03\x05\x12\x03\x0e\x04\t\n\x0c\n\x05\x04\x02\x02\x03\
|
||||||
\x13\x14\n\n\n\x02\x04\x03\x12\x04\x10\0\x12\x01\n\n\n\x03\x04\x03\x01\
|
\x01\x12\x03\x0e\n\x15\n\x0c\n\x05\x04\x02\x02\x03\x03\x12\x03\x0e\x18\
|
||||||
\x12\x03\x10\x08\x15\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x11\x04\x1d\n\x0c\
|
\x19\n\x0b\n\x04\x04\x02\x02\x04\x12\x03\x0f\x04\x15\n\x0c\n\x05\x04\x02\
|
||||||
\n\x05\x04\x03\x02\0\x04\x12\x03\x11\x04\x0c\n\x0c\n\x05\x04\x03\x02\0\
|
\x02\x04\x06\x12\x03\x0f\x04\r\n\x0c\n\x05\x04\x02\x02\x04\x01\x12\x03\
|
||||||
\x06\x12\x03\x11\r\x12\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x11\x13\x18\
|
\x0f\x0e\x10\n\x0c\n\x05\x04\x02\x02\x04\x03\x12\x03\x0f\x13\x14\n\n\n\
|
||||||
\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x11\x1b\x1c\n\n\n\x02\x05\0\x12\
|
\x02\x04\x03\x12\x04\x11\0\x13\x01\n\n\n\x03\x04\x03\x01\x12\x03\x11\x08\
|
||||||
\x04\x13\0\x16\x01\n\n\n\x03\x05\0\x01\x12\x03\x13\x05\x0e\n\x0b\n\x04\
|
\x15\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x12\x04\x1d\n\x0c\n\x05\x04\x03\
|
||||||
\x05\0\x02\0\x12\x03\x14\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x14\
|
\x02\0\x04\x12\x03\x12\x04\x0c\n\x0c\n\x05\x04\x03\x02\0\x06\x12\x03\x12\
|
||||||
\x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x14\x0e\x0f\n\x0b\n\x04\x05\
|
\r\x12\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x12\x13\x18\n\x0c\n\x05\x04\
|
||||||
\0\x02\x01\x12\x03\x15\x04\r\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x15\
|
\x03\x02\0\x03\x12\x03\x12\x1b\x1c\n\n\n\x02\x05\0\x12\x04\x14\0\x17\x01\
|
||||||
\x04\x08\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x15\x0b\x0cb\x06proto3\
|
\n\n\n\x03\x05\0\x01\x12\x03\x14\x05\x0e\n\x0b\n\x04\x05\0\x02\0\x12\x03\
|
||||||
|
\x15\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x15\x04\x0b\n\x0c\n\x05\
|
||||||
|
\x05\0\x02\0\x02\x12\x03\x15\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\
|
||||||
|
\x16\x04\r\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x16\x04\x08\n\x0c\n\x05\
|
||||||
|
\x05\0\x02\x01\x02\x12\x03\x16\x0b\x0cb\x06proto3\
|
||||||
";
|
";
|
||||||
|
|
||||||
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
||||||
|
@ -2,6 +2,7 @@ syntax = "proto3";
|
|||||||
|
|
||||||
message TrashIdentifiers {
|
message TrashIdentifiers {
|
||||||
repeated TrashIdentifier items = 1;
|
repeated TrashIdentifier items = 1;
|
||||||
|
bool delete_all = 2;
|
||||||
}
|
}
|
||||||
message TrashIdentifier {
|
message TrashIdentifier {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
|
@ -55,11 +55,12 @@ impl TrashCan {
|
|||||||
let trash_table = TrashTableSql::read(trash_id, &*self.database.db_connection()?)?;
|
let trash_table = TrashTableSql::read(trash_id, &*self.database.db_connection()?)?;
|
||||||
let _ = thread::scope(|_s| {
|
let _ = thread::scope(|_s| {
|
||||||
let conn = self.database.db_connection()?;
|
let conn = self.database.db_connection()?;
|
||||||
let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
||||||
let _ = TrashTableSql::delete_trash(trash_id, &*conn)?;
|
let _ = TrashTableSql::delete_trash(trash_id, &*conn)?;
|
||||||
notify_trash_num_changed(TrashTableSql::read_all(&conn)?);
|
notify_trash_num_changed(TrashTableSql::read_all(&conn)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok::<(), WorkspaceError>(())
|
Ok::<(), WorkspaceError>(())
|
||||||
})
|
})
|
||||||
.unwrap()?;
|
.unwrap()?;
|
||||||
@ -71,6 +72,7 @@ impl TrashCan {
|
|||||||
|
|
||||||
let _ = self.delete_trash_on_server(TrashIdentifiers {
|
let _ = self.delete_trash_on_server(TrashIdentifiers {
|
||||||
items: vec![identifier.clone()],
|
items: vec![identifier.clone()],
|
||||||
|
delete_all: false,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
tracing::Span::current().record("putback", &format!("{:?}", &identifier).as_str());
|
tracing::Span::current().record("putback", &format!("{:?}", &identifier).as_str());
|
||||||
@ -80,16 +82,45 @@ impl TrashCan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self) err)]
|
#[tracing::instrument(level = "debug", skip(self) err)]
|
||||||
pub fn restore_all(&self) -> WorkspaceResult<()> { Ok(()) }
|
pub async fn restore_all(&self) -> WorkspaceResult<()> {
|
||||||
|
let repeated_trash = self.delete_all_trash_on_local()?;
|
||||||
|
let identifiers: TrashIdentifiers = repeated_trash.items.clone().into();
|
||||||
|
let (tx, mut rx) = mpsc::channel::<WorkspaceResult<()>>(1);
|
||||||
|
let _ = self.notify.send(TrashEvent::Putback(identifiers, tx));
|
||||||
|
let _ = rx.recv().await;
|
||||||
|
|
||||||
|
notify_trash_num_changed(RepeatedTrash { items: vec![] });
|
||||||
|
let _ = self.delete_all_trash_on_server().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self) err)]
|
#[tracing::instrument(level = "debug", skip(self) err)]
|
||||||
pub fn delete_all(&self) -> WorkspaceResult<()> { Ok(()) }
|
pub async fn delete_all(&self) -> WorkspaceResult<()> {
|
||||||
|
let repeated_trash = self.delete_all_trash_on_local()?;
|
||||||
|
let identifiers: TrashIdentifiers = repeated_trash.items.clone().into();
|
||||||
|
let (tx, mut rx) = mpsc::channel::<WorkspaceResult<()>>(1);
|
||||||
|
let _ = self.notify.send(TrashEvent::Delete(identifiers, tx));
|
||||||
|
let _ = rx.recv().await;
|
||||||
|
|
||||||
|
notify_trash_num_changed(RepeatedTrash { items: vec![] });
|
||||||
|
let _ = self.delete_all_trash_on_server().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_all_trash_on_local(&self) -> WorkspaceResult<RepeatedTrash> {
|
||||||
|
let conn = self.database.db_connection()?;
|
||||||
|
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
||||||
|
let repeated_trash = TrashTableSql::read_all(&*conn)?;
|
||||||
|
let _ = TrashTableSql::delete_all(&*conn)?;
|
||||||
|
Ok(repeated_trash)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self) err)]
|
#[tracing::instrument(level = "debug", skip(self) err)]
|
||||||
pub async fn delete(&self, trash_identifiers: TrashIdentifiers) -> WorkspaceResult<()> {
|
pub async fn delete(&self, trash_identifiers: TrashIdentifiers) -> WorkspaceResult<()> {
|
||||||
let (tx, mut rx) = mpsc::channel::<WorkspaceResult<()>>(1);
|
let (tx, mut rx) = mpsc::channel::<WorkspaceResult<()>>(1);
|
||||||
let _ = self.notify.send(TrashEvent::Delete(trash_identifiers.clone(), tx));
|
let _ = self.notify.send(TrashEvent::Delete(trash_identifiers.clone(), tx));
|
||||||
let _ = rx.recv().await.unwrap()?;
|
let _ = rx.recv().await;
|
||||||
|
|
||||||
let conn = self.database.db_connection()?;
|
let conn = self.database.db_connection()?;
|
||||||
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
||||||
@ -99,6 +130,7 @@ impl TrashCan {
|
|||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
notify_trash_num_changed(TrashTableSql::read_all(&conn)?);
|
||||||
let _ = self.delete_trash_on_server(trash_identifiers)?;
|
let _ = self.delete_trash_on_server(trash_identifiers)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -122,7 +154,8 @@ impl TrashCan {
|
|||||||
let conn = self.database.db_connection()?;
|
let conn = self.database.db_connection()?;
|
||||||
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
||||||
let _ = TrashTableSql::create_trash(repeated_trash.clone(), &*conn)?;
|
let _ = TrashTableSql::create_trash(repeated_trash.clone(), &*conn)?;
|
||||||
self.create_trash_on_server(repeated_trash);
|
let _ = self.create_trash_on_server(repeated_trash);
|
||||||
|
|
||||||
notify_trash_num_changed(TrashTableSql::read_all(&conn)?);
|
notify_trash_num_changed(TrashTableSql::read_all(&conn)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
@ -202,6 +235,13 @@ impl TrashCan {
|
|||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip(self), err)]
|
||||||
|
async fn delete_all_trash_on_server(&self) -> WorkspaceResult<()> {
|
||||||
|
let token = self.user.token()?;
|
||||||
|
let server = self.server.clone();
|
||||||
|
server.delete_trash(&token, TrashIdentifiers::all()).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(repeated_trash), fields(trash_count))]
|
#[tracing::instrument(skip(repeated_trash), fields(trash_count))]
|
||||||
|
@ -23,7 +23,7 @@ use flowy_document::{
|
|||||||
use crate::{entities::trash::TrashType, errors::WorkspaceResult};
|
use crate::{entities::trash::TrashType, errors::WorkspaceResult};
|
||||||
|
|
||||||
use futures::{FutureExt, StreamExt};
|
use futures::{FutureExt, StreamExt};
|
||||||
use std::sync::Arc;
|
use std::{collections::HashSet, sync::Arc};
|
||||||
|
|
||||||
pub(crate) struct ViewController {
|
pub(crate) struct ViewController {
|
||||||
user: Arc<dyn WorkspaceUser>,
|
user: Arc<dyn WorkspaceUser>,
|
||||||
@ -61,10 +61,9 @@ impl ViewController {
|
|||||||
let view = self.create_view_on_server(params.clone()).await?;
|
let view = self.create_view_on_server(params.clone()).await?;
|
||||||
let conn = &*self.database.db_connection()?;
|
let conn = &*self.database.db_connection()?;
|
||||||
let trash_can = self.trash_can.clone();
|
let trash_can = self.trash_can.clone();
|
||||||
// TODO: rollback anything created before if failed?
|
|
||||||
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
||||||
let _ = self.save_view(view.clone(), conn)?;
|
let _ = self.save_view(view.clone(), conn)?;
|
||||||
self.document.create(CreateDocParams::new(&view.id, params.data))?;
|
|
||||||
let repeated_view = read_belonging_view(&view.belong_to_id, trash_can, &conn)?;
|
let repeated_view = read_belonging_view(&view.belong_to_id, trash_can, &conn)?;
|
||||||
send_dart_notification(&view.belong_to_id, WorkspaceNotification::AppViewsChanged)
|
send_dart_notification(&view.belong_to_id, WorkspaceNotification::AppViewsChanged)
|
||||||
.payload(repeated_view)
|
.payload(repeated_view)
|
||||||
@ -241,7 +240,9 @@ async fn handle_trash_event(
|
|||||||
let conn = &*db_result?;
|
let conn = &*db_result?;
|
||||||
let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
||||||
for identifier in identifiers.items {
|
for identifier in identifiers.items {
|
||||||
let _ = notify_view_num_changed(&identifier.id, conn, trash_can.clone())?;
|
let view_table = ViewTableSql::read_view(&identifier.id, conn)?;
|
||||||
|
let repeated_view = read_belonging_view(&view_table.belong_to_id, trash_can.clone(), conn)?;
|
||||||
|
let _ = notify_view_num_changed(&view_table.belong_to_id, repeated_view)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
@ -253,11 +254,19 @@ async fn handle_trash_event(
|
|||||||
let result = || {
|
let result = || {
|
||||||
let conn = &*db_result?;
|
let conn = &*db_result?;
|
||||||
let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
||||||
|
let mut notify_ids = HashSet::new();
|
||||||
for identifier in identifiers.items {
|
for identifier in identifiers.items {
|
||||||
|
let view_table = ViewTableSql::read_view(&identifier.id, conn)?;
|
||||||
let _ = ViewTableSql::delete_view(&identifier.id, conn)?;
|
let _ = ViewTableSql::delete_view(&identifier.id, conn)?;
|
||||||
let _ = document.delete(identifier.id.clone().into())?;
|
let _ = document.delete(identifier.id.clone().into())?;
|
||||||
let _ = notify_view_num_changed(&identifier.id, conn, trash_can.clone())?;
|
notify_ids.insert(view_table.belong_to_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for notify_id in notify_ids {
|
||||||
|
let repeated_view = read_belonging_view(¬ify_id, trash_can.clone(), conn)?;
|
||||||
|
let _ = notify_view_num_changed(¬ify_id, repeated_view)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok::<(), WorkspaceError>(())
|
Ok::<(), WorkspaceError>(())
|
||||||
@ -267,12 +276,9 @@ async fn handle_trash_event(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(conn, trash_can), err)]
|
#[tracing::instrument(skip(repeated_view), err)]
|
||||||
fn notify_view_num_changed(view_id: &str, conn: &SqliteConnection, trash_can: Arc<TrashCan>) -> WorkspaceResult<()> {
|
fn notify_view_num_changed(belong_to_id: &str, repeated_view: RepeatedView) -> WorkspaceResult<()> {
|
||||||
let view_table = ViewTableSql::read_view(view_id, conn)?;
|
send_dart_notification(&belong_to_id, WorkspaceNotification::AppViewsChanged)
|
||||||
let repeated_view = read_belonging_view(&view_table.belong_to_id, trash_can, conn)?;
|
|
||||||
|
|
||||||
send_dart_notification(&view_table.belong_to_id, WorkspaceNotification::AppViewsChanged)
|
|
||||||
.payload(repeated_view)
|
.payload(repeated_view)
|
||||||
.send();
|
.send();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -35,6 +35,11 @@ impl TrashTableSql {
|
|||||||
Ok(RepeatedTrash { items })
|
Ok(RepeatedTrash { items })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn delete_all(conn: &SqliteConnection) -> Result<(), WorkspaceError> {
|
||||||
|
let _ = diesel::delete(dsl::trash_table).execute(conn)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn read(trash_id: &str, conn: &SqliteConnection) -> Result<TrashTable, WorkspaceError> {
|
pub(crate) fn read(trash_id: &str, conn: &SqliteConnection) -> Result<TrashTable, WorkspaceError> {
|
||||||
let trash_table = dsl::trash_table
|
let trash_table = dsl::trash_table
|
||||||
.filter(trash_table::id.eq(trash_id))
|
.filter(trash_table::id.eq(trash_id))
|
||||||
|
@ -29,8 +29,8 @@ async fn workspace_create_with_apps() {
|
|||||||
assert_eq!(&app, workspace_from_db.apps.first_or_crash());
|
assert_eq!(&app, workspace_from_db.apps.first_or_crash());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn workspace_create_with_invalid_name() {
|
async fn workspace_create_with_invalid_name() {
|
||||||
for name in invalid_workspace_name_test_case() {
|
for name in invalid_workspace_name_test_case() {
|
||||||
let sdk = FlowyTest::setup().sdk;
|
let sdk = FlowyTest::setup().sdk;
|
||||||
let request = CreateWorkspaceRequest {
|
let request = CreateWorkspaceRequest {
|
||||||
@ -41,7 +41,8 @@ fn workspace_create_with_invalid_name() {
|
|||||||
FlowyWorkspaceTest::new(sdk)
|
FlowyWorkspaceTest::new(sdk)
|
||||||
.event(CreateWorkspace)
|
.event(CreateWorkspace)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.async_send()
|
||||||
|
.await
|
||||||
.error()
|
.error()
|
||||||
.code,
|
.code,
|
||||||
ErrorCode::WorkspaceNameInvalid
|
ErrorCode::WorkspaceNameInvalid
|
||||||
@ -49,8 +50,8 @@ fn workspace_create_with_invalid_name() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn workspace_update_with_invalid_name() {
|
async fn workspace_update_with_invalid_name() {
|
||||||
let sdk = FlowyTest::setup().sdk;
|
let sdk = FlowyTest::setup().sdk;
|
||||||
for name in invalid_workspace_name_test_case() {
|
for name in invalid_workspace_name_test_case() {
|
||||||
let request = CreateWorkspaceRequest {
|
let request = CreateWorkspaceRequest {
|
||||||
@ -61,7 +62,8 @@ fn workspace_update_with_invalid_name() {
|
|||||||
FlowyWorkspaceTest::new(sdk.clone())
|
FlowyWorkspaceTest::new(sdk.clone())
|
||||||
.event(CreateWorkspace)
|
.event(CreateWorkspace)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.async_send()
|
||||||
|
.await
|
||||||
.error()
|
.error()
|
||||||
.code,
|
.code,
|
||||||
ErrorCode::WorkspaceNameInvalid
|
ErrorCode::WorkspaceNameInvalid
|
||||||
|
Loading…
Reference in New Issue
Block a user