瀏覽代碼

test passed

appflowy 3 年之前
父節點
當前提交
99a4beb781
共有 51 個文件被更改,包括 624 次插入853 次删除
  1. 68 122
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/app_update.pb.dart
  2. 10 14
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/app_update.pbjson.dart
  3. 2 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/errors.pbenum.dart
  4. 2 1
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/errors.pbjson.dart
  5. 14 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/workspace_create.pb.dart
  6. 2 1
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/workspace_create.pbjson.dart
  7. 0 1
      backend/src/application.rs
  8. 1 1
      backend/src/sqlx_ext/query.rs
  9. 1 1
      backend/src/user_service/auth.rs
  10. 2 13
      backend/src/workspace_service/app/app.rs
  11. 1 1
      backend/src/workspace_service/app/builder.rs
  12. 2 3
      backend/src/workspace_service/user_default/user_default.rs
  13. 3 4
      backend/src/workspace_service/view/view.rs
  14. 1 1
      backend/src/workspace_service/workspace/router.rs
  15. 4 13
      backend/src/workspace_service/workspace/workspace.rs
  16. 1 3
      backend/tests/api/workspace.rs
  17. 0 2
      rust-lib/flowy-dispatch/src/byte_trait.rs
  18. 1 1
      rust-lib/flowy-net/src/request/request.rs
  19. 1 1
      rust-lib/flowy-sdk/src/deps_resolve/editor_deps_impl.rs
  20. 6 5
      rust-lib/flowy-sdk/src/deps_resolve/user_deps_impl.rs
  21. 2 41
      rust-lib/flowy-sdk/src/deps_resolve/workspace_deps_impl.rs
  22. 0 63
      rust-lib/flowy-sdk/src/flowy_server.rs
  23. 2 2
      rust-lib/flowy-sdk/src/module.rs
  24. 2 1
      rust-lib/flowy-test/Cargo.toml
  25. 15 13
      rust-lib/flowy-test/src/builder.rs
  26. 58 1
      rust-lib/flowy-test/src/helper.rs
  27. 4 3
      rust-lib/flowy-test/src/tester.rs
  28. 4 4
      rust-lib/flowy-user/src/services/user/builder.rs
  29. 20 0
      rust-lib/flowy-user/src/services/user/user_server/mod.rs
  30. 4 48
      rust-lib/flowy-user/src/services/user/user_server/server_api.rs
  31. 49 0
      rust-lib/flowy-user/src/services/user/user_server/server_api_mock.rs
  32. 17 51
      rust-lib/flowy-user/src/services/user/user_session.rs
  33. 1 1
      rust-lib/flowy-user/src/services/workspace/action.rs
  34. 0 6
      rust-lib/flowy-user/tests/event/user_update_test.rs
  35. 9 32
      rust-lib/flowy-workspace/src/entities/app/app_update.rs
  36. 11 2
      rust-lib/flowy-workspace/src/entities/workspace/workspace_create.rs
  37. 3 0
      rust-lib/flowy-workspace/src/errors.rs
  38. 1 3
      rust-lib/flowy-workspace/src/handlers/workspace_handler.rs
  39. 1 1
      rust-lib/flowy-workspace/src/module.rs
  40. 79 252
      rust-lib/flowy-workspace/src/protobuf/model/app_update.rs
  41. 54 48
      rust-lib/flowy-workspace/src/protobuf/model/errors.rs
  42. 88 43
      rust-lib/flowy-workspace/src/protobuf/model/workspace_create.rs
  43. 8 10
      rust-lib/flowy-workspace/src/protobuf/proto/app_update.proto
  44. 1 0
      rust-lib/flowy-workspace/src/protobuf/proto/errors.proto
  45. 1 0
      rust-lib/flowy-workspace/src/protobuf/proto/workspace_create.proto
  46. 2 4
      rust-lib/flowy-workspace/src/services/workspace_controller.rs
  47. 0 2
      rust-lib/flowy-workspace/src/sql_tables/app/app_table.rs
  48. 9 5
      rust-lib/flowy-workspace/src/sql_tables/workspace/workspace_sql.rs
  49. 10 6
      rust-lib/flowy-workspace/tests/event/app_test.rs
  50. 19 12
      rust-lib/flowy-workspace/tests/event/helper.rs
  51. 28 11
      rust-lib/flowy-workspace/tests/event/workspace_test.rs

+ 68 - 122
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/app_update.pb.dart

@@ -11,11 +11,6 @@ import 'package:protobuf/protobuf.dart' as $pb;
 
 import 'app_create.pb.dart' as $0;
 
-enum UpdateAppRequest_OneOfWorkspaceId {
-  workspaceId, 
-  notSet
-}
-
 enum UpdateAppRequest_OneOfName {
   name, 
   notSet
@@ -37,24 +32,20 @@ enum UpdateAppRequest_OneOfIsTrash {
 }
 
 class UpdateAppRequest extends $pb.GeneratedMessage {
-  static const $core.Map<$core.int, UpdateAppRequest_OneOfWorkspaceId> _UpdateAppRequest_OneOfWorkspaceIdByTag = {
-    2 : UpdateAppRequest_OneOfWorkspaceId.workspaceId,
-    0 : UpdateAppRequest_OneOfWorkspaceId.notSet
-  };
   static const $core.Map<$core.int, UpdateAppRequest_OneOfName> _UpdateAppRequest_OneOfNameByTag = {
-    3 : UpdateAppRequest_OneOfName.name,
+    2 : UpdateAppRequest_OneOfName.name,
     0 : UpdateAppRequest_OneOfName.notSet
   };
   static const $core.Map<$core.int, UpdateAppRequest_OneOfDesc> _UpdateAppRequest_OneOfDescByTag = {
-    4 : UpdateAppRequest_OneOfDesc.desc,
+    3 : UpdateAppRequest_OneOfDesc.desc,
     0 : UpdateAppRequest_OneOfDesc.notSet
   };
   static const $core.Map<$core.int, UpdateAppRequest_OneOfColorStyle> _UpdateAppRequest_OneOfColorStyleByTag = {
-    5 : UpdateAppRequest_OneOfColorStyle.colorStyle,
+    4 : UpdateAppRequest_OneOfColorStyle.colorStyle,
     0 : UpdateAppRequest_OneOfColorStyle.notSet
   };
   static const $core.Map<$core.int, UpdateAppRequest_OneOfIsTrash> _UpdateAppRequest_OneOfIsTrashByTag = {
-    6 : UpdateAppRequest_OneOfIsTrash.isTrash,
+    5 : UpdateAppRequest_OneOfIsTrash.isTrash,
     0 : UpdateAppRequest_OneOfIsTrash.notSet
   };
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'UpdateAppRequest', createEmptyInstance: create)
@@ -62,20 +53,17 @@ class UpdateAppRequest extends $pb.GeneratedMessage {
     ..oo(1, [3])
     ..oo(2, [4])
     ..oo(3, [5])
-    ..oo(4, [6])
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'appId')
-    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'workspaceId')
-    ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
-    ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
-    ..aOM<$0.ColorStyle>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'colorStyle', subBuilder: $0.ColorStyle.create)
-    ..aOB(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isTrash')
+    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
+    ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
+    ..aOM<$0.ColorStyle>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'colorStyle', subBuilder: $0.ColorStyle.create)
+    ..aOB(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isTrash')
     ..hasRequiredFields = false
   ;
 
   UpdateAppRequest._() : super();
   factory UpdateAppRequest({
     $core.String? appId,
-    $core.String? workspaceId,
     $core.String? name,
     $core.String? desc,
     $0.ColorStyle? colorStyle,
@@ -85,9 +73,6 @@ class UpdateAppRequest extends $pb.GeneratedMessage {
     if (appId != null) {
       _result.appId = appId;
     }
-    if (workspaceId != null) {
-      _result.workspaceId = workspaceId;
-    }
     if (name != null) {
       _result.name = name;
     }
@@ -123,20 +108,17 @@ class UpdateAppRequest extends $pb.GeneratedMessage {
   static UpdateAppRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdateAppRequest>(create);
   static UpdateAppRequest? _defaultInstance;
 
-  UpdateAppRequest_OneOfWorkspaceId whichOneOfWorkspaceId() => _UpdateAppRequest_OneOfWorkspaceIdByTag[$_whichOneof(0)]!;
-  void clearOneOfWorkspaceId() => clearField($_whichOneof(0));
-
-  UpdateAppRequest_OneOfName whichOneOfName() => _UpdateAppRequest_OneOfNameByTag[$_whichOneof(1)]!;
-  void clearOneOfName() => clearField($_whichOneof(1));
+  UpdateAppRequest_OneOfName whichOneOfName() => _UpdateAppRequest_OneOfNameByTag[$_whichOneof(0)]!;
+  void clearOneOfName() => clearField($_whichOneof(0));
 
-  UpdateAppRequest_OneOfDesc whichOneOfDesc() => _UpdateAppRequest_OneOfDescByTag[$_whichOneof(2)]!;
-  void clearOneOfDesc() => clearField($_whichOneof(2));
+  UpdateAppRequest_OneOfDesc whichOneOfDesc() => _UpdateAppRequest_OneOfDescByTag[$_whichOneof(1)]!;
+  void clearOneOfDesc() => clearField($_whichOneof(1));
 
-  UpdateAppRequest_OneOfColorStyle whichOneOfColorStyle() => _UpdateAppRequest_OneOfColorStyleByTag[$_whichOneof(3)]!;
-  void clearOneOfColorStyle() => clearField($_whichOneof(3));
+  UpdateAppRequest_OneOfColorStyle whichOneOfColorStyle() => _UpdateAppRequest_OneOfColorStyleByTag[$_whichOneof(2)]!;
+  void clearOneOfColorStyle() => clearField($_whichOneof(2));
 
-  UpdateAppRequest_OneOfIsTrash whichOneOfIsTrash() => _UpdateAppRequest_OneOfIsTrashByTag[$_whichOneof(4)]!;
-  void clearOneOfIsTrash() => clearField($_whichOneof(4));
+  UpdateAppRequest_OneOfIsTrash whichOneOfIsTrash() => _UpdateAppRequest_OneOfIsTrashByTag[$_whichOneof(3)]!;
+  void clearOneOfIsTrash() => clearField($_whichOneof(3));
 
   @$pb.TagNumber(1)
   $core.String get appId => $_getSZ(0);
@@ -148,56 +130,42 @@ class UpdateAppRequest extends $pb.GeneratedMessage {
   void clearAppId() => clearField(1);
 
   @$pb.TagNumber(2)
-  $core.String get workspaceId => $_getSZ(1);
+  $core.String get name => $_getSZ(1);
   @$pb.TagNumber(2)
-  set workspaceId($core.String v) { $_setString(1, v); }
+  set name($core.String v) { $_setString(1, v); }
   @$pb.TagNumber(2)
-  $core.bool hasWorkspaceId() => $_has(1);
+  $core.bool hasName() => $_has(1);
   @$pb.TagNumber(2)
-  void clearWorkspaceId() => clearField(2);
+  void clearName() => clearField(2);
 
   @$pb.TagNumber(3)
-  $core.String get name => $_getSZ(2);
+  $core.String get desc => $_getSZ(2);
   @$pb.TagNumber(3)
-  set name($core.String v) { $_setString(2, v); }
+  set desc($core.String v) { $_setString(2, v); }
   @$pb.TagNumber(3)
-  $core.bool hasName() => $_has(2);
+  $core.bool hasDesc() => $_has(2);
   @$pb.TagNumber(3)
-  void clearName() => clearField(3);
+  void clearDesc() => clearField(3);
 
   @$pb.TagNumber(4)
-  $core.String get desc => $_getSZ(3);
+  $0.ColorStyle get colorStyle => $_getN(3);
   @$pb.TagNumber(4)
-  set desc($core.String v) { $_setString(3, v); }
+  set colorStyle($0.ColorStyle v) { setField(4, v); }
   @$pb.TagNumber(4)
-  $core.bool hasDesc() => $_has(3);
+  $core.bool hasColorStyle() => $_has(3);
   @$pb.TagNumber(4)
-  void clearDesc() => clearField(4);
+  void clearColorStyle() => clearField(4);
+  @$pb.TagNumber(4)
+  $0.ColorStyle ensureColorStyle() => $_ensure(3);
 
   @$pb.TagNumber(5)
-  $0.ColorStyle get colorStyle => $_getN(4);
-  @$pb.TagNumber(5)
-  set colorStyle($0.ColorStyle v) { setField(5, v); }
+  $core.bool get isTrash => $_getBF(4);
   @$pb.TagNumber(5)
-  $core.bool hasColorStyle() => $_has(4);
+  set isTrash($core.bool v) { $_setBool(4, v); }
   @$pb.TagNumber(5)
-  void clearColorStyle() => clearField(5);
+  $core.bool hasIsTrash() => $_has(4);
   @$pb.TagNumber(5)
-  $0.ColorStyle ensureColorStyle() => $_ensure(4);
-
-  @$pb.TagNumber(6)
-  $core.bool get isTrash => $_getBF(5);
-  @$pb.TagNumber(6)
-  set isTrash($core.bool v) { $_setBool(5, v); }
-  @$pb.TagNumber(6)
-  $core.bool hasIsTrash() => $_has(5);
-  @$pb.TagNumber(6)
-  void clearIsTrash() => clearField(6);
-}
-
-enum UpdateAppParams_OneOfWorkspaceId {
-  workspaceId, 
-  notSet
+  void clearIsTrash() => clearField(5);
 }
 
 enum UpdateAppParams_OneOfName {
@@ -221,24 +189,20 @@ enum UpdateAppParams_OneOfIsTrash {
 }
 
 class UpdateAppParams extends $pb.GeneratedMessage {
-  static const $core.Map<$core.int, UpdateAppParams_OneOfWorkspaceId> _UpdateAppParams_OneOfWorkspaceIdByTag = {
-    2 : UpdateAppParams_OneOfWorkspaceId.workspaceId,
-    0 : UpdateAppParams_OneOfWorkspaceId.notSet
-  };
   static const $core.Map<$core.int, UpdateAppParams_OneOfName> _UpdateAppParams_OneOfNameByTag = {
-    3 : UpdateAppParams_OneOfName.name,
+    2 : UpdateAppParams_OneOfName.name,
     0 : UpdateAppParams_OneOfName.notSet
   };
   static const $core.Map<$core.int, UpdateAppParams_OneOfDesc> _UpdateAppParams_OneOfDescByTag = {
-    4 : UpdateAppParams_OneOfDesc.desc,
+    3 : UpdateAppParams_OneOfDesc.desc,
     0 : UpdateAppParams_OneOfDesc.notSet
   };
   static const $core.Map<$core.int, UpdateAppParams_OneOfColorStyle> _UpdateAppParams_OneOfColorStyleByTag = {
-    5 : UpdateAppParams_OneOfColorStyle.colorStyle,
+    4 : UpdateAppParams_OneOfColorStyle.colorStyle,
     0 : UpdateAppParams_OneOfColorStyle.notSet
   };
   static const $core.Map<$core.int, UpdateAppParams_OneOfIsTrash> _UpdateAppParams_OneOfIsTrashByTag = {
-    6 : UpdateAppParams_OneOfIsTrash.isTrash,
+    5 : UpdateAppParams_OneOfIsTrash.isTrash,
     0 : UpdateAppParams_OneOfIsTrash.notSet
   };
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'UpdateAppParams', createEmptyInstance: create)
@@ -246,20 +210,17 @@ class UpdateAppParams extends $pb.GeneratedMessage {
     ..oo(1, [3])
     ..oo(2, [4])
     ..oo(3, [5])
-    ..oo(4, [6])
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'appId')
-    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'workspaceId')
-    ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
-    ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
-    ..aOM<$0.ColorStyle>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'colorStyle', subBuilder: $0.ColorStyle.create)
-    ..aOB(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isTrash')
+    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
+    ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
+    ..aOM<$0.ColorStyle>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'colorStyle', subBuilder: $0.ColorStyle.create)
+    ..aOB(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isTrash')
     ..hasRequiredFields = false
   ;
 
   UpdateAppParams._() : super();
   factory UpdateAppParams({
     $core.String? appId,
-    $core.String? workspaceId,
     $core.String? name,
     $core.String? desc,
     $0.ColorStyle? colorStyle,
@@ -269,9 +230,6 @@ class UpdateAppParams extends $pb.GeneratedMessage {
     if (appId != null) {
       _result.appId = appId;
     }
-    if (workspaceId != null) {
-      _result.workspaceId = workspaceId;
-    }
     if (name != null) {
       _result.name = name;
     }
@@ -307,20 +265,17 @@ class UpdateAppParams extends $pb.GeneratedMessage {
   static UpdateAppParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdateAppParams>(create);
   static UpdateAppParams? _defaultInstance;
 
-  UpdateAppParams_OneOfWorkspaceId whichOneOfWorkspaceId() => _UpdateAppParams_OneOfWorkspaceIdByTag[$_whichOneof(0)]!;
-  void clearOneOfWorkspaceId() => clearField($_whichOneof(0));
-
-  UpdateAppParams_OneOfName whichOneOfName() => _UpdateAppParams_OneOfNameByTag[$_whichOneof(1)]!;
-  void clearOneOfName() => clearField($_whichOneof(1));
+  UpdateAppParams_OneOfName whichOneOfName() => _UpdateAppParams_OneOfNameByTag[$_whichOneof(0)]!;
+  void clearOneOfName() => clearField($_whichOneof(0));
 
-  UpdateAppParams_OneOfDesc whichOneOfDesc() => _UpdateAppParams_OneOfDescByTag[$_whichOneof(2)]!;
-  void clearOneOfDesc() => clearField($_whichOneof(2));
+  UpdateAppParams_OneOfDesc whichOneOfDesc() => _UpdateAppParams_OneOfDescByTag[$_whichOneof(1)]!;
+  void clearOneOfDesc() => clearField($_whichOneof(1));
 
-  UpdateAppParams_OneOfColorStyle whichOneOfColorStyle() => _UpdateAppParams_OneOfColorStyleByTag[$_whichOneof(3)]!;
-  void clearOneOfColorStyle() => clearField($_whichOneof(3));
+  UpdateAppParams_OneOfColorStyle whichOneOfColorStyle() => _UpdateAppParams_OneOfColorStyleByTag[$_whichOneof(2)]!;
+  void clearOneOfColorStyle() => clearField($_whichOneof(2));
 
-  UpdateAppParams_OneOfIsTrash whichOneOfIsTrash() => _UpdateAppParams_OneOfIsTrashByTag[$_whichOneof(4)]!;
-  void clearOneOfIsTrash() => clearField($_whichOneof(4));
+  UpdateAppParams_OneOfIsTrash whichOneOfIsTrash() => _UpdateAppParams_OneOfIsTrashByTag[$_whichOneof(3)]!;
+  void clearOneOfIsTrash() => clearField($_whichOneof(3));
 
   @$pb.TagNumber(1)
   $core.String get appId => $_getSZ(0);
@@ -332,50 +287,41 @@ class UpdateAppParams extends $pb.GeneratedMessage {
   void clearAppId() => clearField(1);
 
   @$pb.TagNumber(2)
-  $core.String get workspaceId => $_getSZ(1);
+  $core.String get name => $_getSZ(1);
   @$pb.TagNumber(2)
-  set workspaceId($core.String v) { $_setString(1, v); }
+  set name($core.String v) { $_setString(1, v); }
   @$pb.TagNumber(2)
-  $core.bool hasWorkspaceId() => $_has(1);
+  $core.bool hasName() => $_has(1);
   @$pb.TagNumber(2)
-  void clearWorkspaceId() => clearField(2);
+  void clearName() => clearField(2);
 
   @$pb.TagNumber(3)
-  $core.String get name => $_getSZ(2);
+  $core.String get desc => $_getSZ(2);
   @$pb.TagNumber(3)
-  set name($core.String v) { $_setString(2, v); }
+  set desc($core.String v) { $_setString(2, v); }
   @$pb.TagNumber(3)
-  $core.bool hasName() => $_has(2);
+  $core.bool hasDesc() => $_has(2);
   @$pb.TagNumber(3)
-  void clearName() => clearField(3);
+  void clearDesc() => clearField(3);
 
   @$pb.TagNumber(4)
-  $core.String get desc => $_getSZ(3);
+  $0.ColorStyle get colorStyle => $_getN(3);
   @$pb.TagNumber(4)
-  set desc($core.String v) { $_setString(3, v); }
+  set colorStyle($0.ColorStyle v) { setField(4, v); }
   @$pb.TagNumber(4)
-  $core.bool hasDesc() => $_has(3);
+  $core.bool hasColorStyle() => $_has(3);
   @$pb.TagNumber(4)
-  void clearDesc() => clearField(4);
+  void clearColorStyle() => clearField(4);
+  @$pb.TagNumber(4)
+  $0.ColorStyle ensureColorStyle() => $_ensure(3);
 
   @$pb.TagNumber(5)
-  $0.ColorStyle get colorStyle => $_getN(4);
-  @$pb.TagNumber(5)
-  set colorStyle($0.ColorStyle v) { setField(5, v); }
+  $core.bool get isTrash => $_getBF(4);
   @$pb.TagNumber(5)
-  $core.bool hasColorStyle() => $_has(4);
+  set isTrash($core.bool v) { $_setBool(4, v); }
   @$pb.TagNumber(5)
-  void clearColorStyle() => clearField(5);
+  $core.bool hasIsTrash() => $_has(4);
   @$pb.TagNumber(5)
-  $0.ColorStyle ensureColorStyle() => $_ensure(4);
-
-  @$pb.TagNumber(6)
-  $core.bool get isTrash => $_getBF(5);
-  @$pb.TagNumber(6)
-  set isTrash($core.bool v) { $_setBool(5, v); }
-  @$pb.TagNumber(6)
-  $core.bool hasIsTrash() => $_has(5);
-  @$pb.TagNumber(6)
-  void clearIsTrash() => clearField(6);
+  void clearIsTrash() => clearField(5);
 }
 

+ 10 - 14
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/app_update.pbjson.dart

@@ -13,14 +13,12 @@ const UpdateAppRequest$json = const {
   '1': 'UpdateAppRequest',
   '2': const [
     const {'1': 'app_id', '3': 1, '4': 1, '5': 9, '10': 'appId'},
-    const {'1': 'workspace_id', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'workspaceId'},
-    const {'1': 'name', '3': 3, '4': 1, '5': 9, '9': 1, '10': 'name'},
-    const {'1': 'desc', '3': 4, '4': 1, '5': 9, '9': 2, '10': 'desc'},
-    const {'1': 'color_style', '3': 5, '4': 1, '5': 11, '6': '.ColorStyle', '9': 3, '10': 'colorStyle'},
-    const {'1': 'is_trash', '3': 6, '4': 1, '5': 8, '9': 4, '10': 'isTrash'},
+    const {'1': 'name', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'name'},
+    const {'1': 'desc', '3': 3, '4': 1, '5': 9, '9': 1, '10': 'desc'},
+    const {'1': 'color_style', '3': 4, '4': 1, '5': 11, '6': '.ColorStyle', '9': 2, '10': 'colorStyle'},
+    const {'1': 'is_trash', '3': 5, '4': 1, '5': 8, '9': 3, '10': 'isTrash'},
   ],
   '8': const [
-    const {'1': 'one_of_workspace_id'},
     const {'1': 'one_of_name'},
     const {'1': 'one_of_desc'},
     const {'1': 'one_of_color_style'},
@@ -29,20 +27,18 @@ const UpdateAppRequest$json = const {
 };
 
 /// Descriptor for `UpdateAppRequest`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List updateAppRequestDescriptor = $convert.base64Decode('ChBVcGRhdGVBcHBSZXF1ZXN0EhUKBmFwcF9pZBgBIAEoCVIFYXBwSWQSIwoMd29ya3NwYWNlX2lkGAIgASgJSABSC3dvcmtzcGFjZUlkEhQKBG5hbWUYAyABKAlIAVIEbmFtZRIUCgRkZXNjGAQgASgJSAJSBGRlc2MSLgoLY29sb3Jfc3R5bGUYBSABKAsyCy5Db2xvclN0eWxlSANSCmNvbG9yU3R5bGUSGwoIaXNfdHJhc2gYBiABKAhIBFIHaXNUcmFzaEIVChNvbmVfb2Zfd29ya3NwYWNlX2lkQg0KC29uZV9vZl9uYW1lQg0KC29uZV9vZl9kZXNjQhQKEm9uZV9vZl9jb2xvcl9zdHlsZUIRCg9vbmVfb2ZfaXNfdHJhc2g=');
+final $typed_data.Uint8List updateAppRequestDescriptor = $convert.base64Decode('ChBVcGRhdGVBcHBSZXF1ZXN0EhUKBmFwcF9pZBgBIAEoCVIFYXBwSWQSFAoEbmFtZRgCIAEoCUgAUgRuYW1lEhQKBGRlc2MYAyABKAlIAVIEZGVzYxIuCgtjb2xvcl9zdHlsZRgEIAEoCzILLkNvbG9yU3R5bGVIAlIKY29sb3JTdHlsZRIbCghpc190cmFzaBgFIAEoCEgDUgdpc1RyYXNoQg0KC29uZV9vZl9uYW1lQg0KC29uZV9vZl9kZXNjQhQKEm9uZV9vZl9jb2xvcl9zdHlsZUIRCg9vbmVfb2ZfaXNfdHJhc2g=');
 @$core.Deprecated('Use updateAppParamsDescriptor instead')
 const UpdateAppParams$json = const {
   '1': 'UpdateAppParams',
   '2': const [
     const {'1': 'app_id', '3': 1, '4': 1, '5': 9, '10': 'appId'},
-    const {'1': 'workspace_id', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'workspaceId'},
-    const {'1': 'name', '3': 3, '4': 1, '5': 9, '9': 1, '10': 'name'},
-    const {'1': 'desc', '3': 4, '4': 1, '5': 9, '9': 2, '10': 'desc'},
-    const {'1': 'color_style', '3': 5, '4': 1, '5': 11, '6': '.ColorStyle', '9': 3, '10': 'colorStyle'},
-    const {'1': 'is_trash', '3': 6, '4': 1, '5': 8, '9': 4, '10': 'isTrash'},
+    const {'1': 'name', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'name'},
+    const {'1': 'desc', '3': 3, '4': 1, '5': 9, '9': 1, '10': 'desc'},
+    const {'1': 'color_style', '3': 4, '4': 1, '5': 11, '6': '.ColorStyle', '9': 2, '10': 'colorStyle'},
+    const {'1': 'is_trash', '3': 5, '4': 1, '5': 8, '9': 3, '10': 'isTrash'},
   ],
   '8': const [
-    const {'1': 'one_of_workspace_id'},
     const {'1': 'one_of_name'},
     const {'1': 'one_of_desc'},
     const {'1': 'one_of_color_style'},
@@ -51,4 +47,4 @@ const UpdateAppParams$json = const {
 };
 
 /// Descriptor for `UpdateAppParams`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List updateAppParamsDescriptor = $convert.base64Decode('Cg9VcGRhdGVBcHBQYXJhbXMSFQoGYXBwX2lkGAEgASgJUgVhcHBJZBIjCgx3b3Jrc3BhY2VfaWQYAiABKAlIAFILd29ya3NwYWNlSWQSFAoEbmFtZRgDIAEoCUgBUgRuYW1lEhQKBGRlc2MYBCABKAlIAlIEZGVzYxIuCgtjb2xvcl9zdHlsZRgFIAEoCzILLkNvbG9yU3R5bGVIA1IKY29sb3JTdHlsZRIbCghpc190cmFzaBgGIAEoCEgEUgdpc1RyYXNoQhUKE29uZV9vZl93b3Jrc3BhY2VfaWRCDQoLb25lX29mX25hbWVCDQoLb25lX29mX2Rlc2NCFAoSb25lX29mX2NvbG9yX3N0eWxlQhEKD29uZV9vZl9pc190cmFzaA==');
+final $typed_data.Uint8List updateAppParamsDescriptor = $convert.base64Decode('Cg9VcGRhdGVBcHBQYXJhbXMSFQoGYXBwX2lkGAEgASgJUgVhcHBJZBIUCgRuYW1lGAIgASgJSABSBG5hbWUSFAoEZGVzYxgDIAEoCUgBUgRkZXNjEi4KC2NvbG9yX3N0eWxlGAQgASgLMgsuQ29sb3JTdHlsZUgCUgpjb2xvclN0eWxlEhsKCGlzX3RyYXNoGAUgASgISANSB2lzVHJhc2hCDQoLb25lX29mX25hbWVCDQoLb25lX29mX2Rlc2NCFAoSb25lX29mX2NvbG9yX3N0eWxlQhEKD29uZV9vZl9pc190cmFzaA==');

+ 2 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/errors.pbenum.dart

@@ -26,6 +26,7 @@ class WsErrCode extends $pb.ProtobufEnum {
   static const WsErrCode WorkspaceDatabaseError = WsErrCode._(101, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceDatabaseError');
   static const WsErrCode UserInternalError = WsErrCode._(102, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserInternalError');
   static const WsErrCode UserNotLoginYet = WsErrCode._(103, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNotLoginYet');
+  static const WsErrCode UserIdIsEmpty = WsErrCode._(104, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserIdIsEmpty');
   static const WsErrCode ServerError = WsErrCode._(1000, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ServerError');
   static const WsErrCode RecordNotFound = WsErrCode._(1001, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RecordNotFound');
 
@@ -46,6 +47,7 @@ class WsErrCode extends $pb.ProtobufEnum {
     WorkspaceDatabaseError,
     UserInternalError,
     UserNotLoginYet,
+    UserIdIsEmpty,
     ServerError,
     RecordNotFound,
   ];

+ 2 - 1
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/errors.pbjson.dart

@@ -28,13 +28,14 @@ const WsErrCode$json = const {
     const {'1': 'WorkspaceDatabaseError', '2': 101},
     const {'1': 'UserInternalError', '2': 102},
     const {'1': 'UserNotLoginYet', '2': 103},
+    const {'1': 'UserIdIsEmpty', '2': 104},
     const {'1': 'ServerError', '2': 1000},
     const {'1': 'RecordNotFound', '2': 1001},
   ],
 };
 
 /// Descriptor for `WsErrCode`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List wsErrCodeDescriptor = $convert.base64Decode('CglXc0VyckNvZGUSCwoHVW5rbm93bhAAEhgKFFdvcmtzcGFjZU5hbWVJbnZhbGlkEAESFgoSV29ya3NwYWNlSWRJbnZhbGlkEAISGAoUQXBwQ29sb3JTdHlsZUludmFsaWQQAxIYChRXb3Jrc3BhY2VEZXNjSW52YWxpZBAEEhwKGEN1cnJlbnRXb3Jrc3BhY2VOb3RGb3VuZBAFEhAKDEFwcElkSW52YWxpZBAKEhIKDkFwcE5hbWVJbnZhbGlkEAsSEwoPVmlld05hbWVJbnZhbGlkEBQSGAoUVmlld1RodW1ibmFpbEludmFsaWQQFRIRCg1WaWV3SWRJbnZhbGlkEBYSEwoPVmlld0Rlc2NJbnZhbGlkEBcSGgoWRGF0YWJhc2VDb25uZWN0aW9uRmFpbBBkEhoKFldvcmtzcGFjZURhdGFiYXNlRXJyb3IQZRIVChFVc2VySW50ZXJuYWxFcnJvchBmEhMKD1VzZXJOb3RMb2dpbllldBBnEhAKC1NlcnZlckVycm9yEOgHEhMKDlJlY29yZE5vdEZvdW5kEOkH');
+final $typed_data.Uint8List wsErrCodeDescriptor = $convert.base64Decode('CglXc0VyckNvZGUSCwoHVW5rbm93bhAAEhgKFFdvcmtzcGFjZU5hbWVJbnZhbGlkEAESFgoSV29ya3NwYWNlSWRJbnZhbGlkEAISGAoUQXBwQ29sb3JTdHlsZUludmFsaWQQAxIYChRXb3Jrc3BhY2VEZXNjSW52YWxpZBAEEhwKGEN1cnJlbnRXb3Jrc3BhY2VOb3RGb3VuZBAFEhAKDEFwcElkSW52YWxpZBAKEhIKDkFwcE5hbWVJbnZhbGlkEAsSEwoPVmlld05hbWVJbnZhbGlkEBQSGAoUVmlld1RodW1ibmFpbEludmFsaWQQFRIRCg1WaWV3SWRJbnZhbGlkEBYSEwoPVmlld0Rlc2NJbnZhbGlkEBcSGgoWRGF0YWJhc2VDb25uZWN0aW9uRmFpbBBkEhoKFldvcmtzcGFjZURhdGFiYXNlRXJyb3IQZRIVChFVc2VySW50ZXJuYWxFcnJvchBmEhMKD1VzZXJOb3RMb2dpbllldBBnEhEKDVVzZXJJZElzRW1wdHkQaBIQCgtTZXJ2ZXJFcnJvchDoBxITCg5SZWNvcmROb3RGb3VuZBDpBw==');
 @$core.Deprecated('Use workspaceErrorDescriptor instead')
 const WorkspaceError$json = const {
   '1': 'WorkspaceError',

+ 14 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/workspace_create.pb.dart

@@ -15,6 +15,7 @@ class CreateWorkspaceRequest extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateWorkspaceRequest', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
+    ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'userId')
     ..hasRequiredFields = false
   ;
 
@@ -22,6 +23,7 @@ class CreateWorkspaceRequest extends $pb.GeneratedMessage {
   factory CreateWorkspaceRequest({
     $core.String? name,
     $core.String? desc,
+    $core.String? userId,
   }) {
     final _result = create();
     if (name != null) {
@@ -30,6 +32,9 @@ class CreateWorkspaceRequest extends $pb.GeneratedMessage {
     if (desc != null) {
       _result.desc = desc;
     }
+    if (userId != null) {
+      _result.userId = userId;
+    }
     return _result;
   }
   factory CreateWorkspaceRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@@ -70,6 +75,15 @@ class CreateWorkspaceRequest extends $pb.GeneratedMessage {
   $core.bool hasDesc() => $_has(1);
   @$pb.TagNumber(2)
   void clearDesc() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get userId => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set userId($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasUserId() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearUserId() => clearField(3);
 }
 
 class CreateWorkspaceParams extends $pb.GeneratedMessage {

+ 2 - 1
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/workspace_create.pbjson.dart

@@ -14,11 +14,12 @@ const CreateWorkspaceRequest$json = const {
   '2': const [
     const {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'},
     const {'1': 'desc', '3': 2, '4': 1, '5': 9, '10': 'desc'},
+    const {'1': 'user_id', '3': 3, '4': 1, '5': 9, '10': 'userId'},
   ],
 };
 
 /// Descriptor for `CreateWorkspaceRequest`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List createWorkspaceRequestDescriptor = $convert.base64Decode('ChZDcmVhdGVXb3Jrc3BhY2VSZXF1ZXN0EhIKBG5hbWUYASABKAlSBG5hbWUSEgoEZGVzYxgCIAEoCVIEZGVzYw==');
+final $typed_data.Uint8List createWorkspaceRequestDescriptor = $convert.base64Decode('ChZDcmVhdGVXb3Jrc3BhY2VSZXF1ZXN0EhIKBG5hbWUYASABKAlSBG5hbWUSEgoEZGVzYxgCIAEoCVIEZGVzYxIXCgd1c2VyX2lkGAMgASgJUgZ1c2VySWQ=');
 @$core.Deprecated('Use createWorkspaceParamsDescriptor instead')
 const CreateWorkspaceParams$json = const {
   '1': 'CreateWorkspaceParams',

+ 0 - 1
backend/src/application.rs

@@ -5,7 +5,6 @@ use crate::{
         Settings,
     },
     context::AppContext,
-    routers::*,
     user_service::router as user,
     workspace_service::{app::router as app, view::router as view, workspace::router as workspace},
     ws_service,

+ 1 - 1
backend/src/sqlx_ext/query.rs

@@ -1,6 +1,6 @@
 use flowy_net::errors::ServerError;
 use sql_builder::SqlBuilder as InnerBuilder;
-use sqlx::{postgres::PgArguments, Arguments, Encode, PgPool, Postgres, Type};
+use sqlx::{postgres::PgArguments, Arguments, Encode, Postgres, Type};
 
 enum BuilderType {
     Create,

+ 1 - 1
backend/src/user_service/auth.rs

@@ -15,7 +15,7 @@ use flowy_user::{
     entities::parser::{UserEmail, UserName, UserPassword},
     protobuf::{SignInParams, SignInResponse, SignUpParams, SignUpResponse},
 };
-use sqlx::{PgPool, Postgres, Transaction};
+use sqlx::{PgPool, Postgres};
 
 pub async fn sign_in(
     pool: &PgPool,

+ 2 - 13
backend/src/workspace_service/app/app.rs

@@ -14,14 +14,13 @@ use flowy_net::errors::invalid_params;
 use flowy_user::entities::parser::UserId;
 use flowy_workspace::{
     entities::{
-        app::parser::{AppDesc, AppId, AppName},
+        app::parser::{AppDesc, AppName},
         workspace::parser::WorkspaceId,
     },
     protobuf::{App, CreateAppParams, QueryAppParams, RepeatedApp, RepeatedView, UpdateAppParams},
 };
 use protobuf::Message;
-use sqlx::{postgres::PgArguments, PgPool, Postgres, Transaction};
-use uuid::Uuid;
+use sqlx::{postgres::PgArguments, PgPool, Postgres};
 
 pub(crate) async fn create_app(
     pool: &PgPool,
@@ -108,15 +107,6 @@ pub(crate) async fn update_app(
         ),
     };
 
-    let workspace_id = match params.has_workspace_id() {
-        false => None,
-        true => Some(
-            WorkspaceId::parse(params.get_workspace_id().to_owned())
-                .map_err(invalid_params)?
-                .0,
-        ),
-    };
-
     let color_style = match params.has_color_style() {
         false => None,
         true => {
@@ -141,7 +131,6 @@ pub(crate) async fn update_app(
 
     let (sql, args) = SqlBuilder::update("app_table")
         .add_some_arg("name", name)
-        .add_some_arg("workspace_id", workspace_id)
         .add_some_arg("color_style", color_style)
         .add_some_arg("description", desc)
         .add_some_arg("modified_time", Some(Utc::now()))

+ 1 - 1
backend/src/workspace_service/app/builder.rs

@@ -75,7 +75,7 @@ impl Builder {
 }
 
 fn default_color_style() -> Vec<u8> {
-    let mut style = ColorStyle::default();
+    let style = ColorStyle::default();
     match style.write_to_bytes() {
         Ok(bytes) => bytes,
         Err(e) => {

+ 2 - 3
backend/src/workspace_service/user_default/user_default.rs

@@ -1,15 +1,14 @@
 use crate::{
-    sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
+    sqlx_ext::{map_sqlx_error, DBTransaction},
     workspace_service::{
         app::Builder as AppBuilder,
         view::Builder as ViewBuilder,
         workspace::Builder as WorkspaceBuilder,
     },
 };
-use chrono::Utc;
+
 use flowy_net::errors::ServerError;
 use flowy_workspace::protobuf::{App, View, ViewType, Workspace};
-use sqlx::{Postgres, Transaction};
 
 pub async fn create_default_workspace(
     transaction: &mut DBTransaction<'_>,

+ 3 - 4
backend/src/workspace_service/view/view.rs

@@ -12,13 +12,12 @@ use flowy_net::{
 use flowy_workspace::{
     entities::{
         app::parser::AppId,
-        view::parser::{ViewDesc, ViewId, ViewName, ViewThumbnail},
+        view::parser::{ViewDesc, ViewName, ViewThumbnail},
     },
     protobuf::{CreateViewParams, QueryViewParams, RepeatedView, UpdateViewParams, View},
 };
-use protobuf::ProtobufEnum;
-use sqlx::{postgres::PgArguments, PgPool, Postgres, Transaction};
-use uuid::Uuid;
+
+use sqlx::{postgres::PgArguments, PgPool, Postgres};
 
 pub(crate) async fn create_view(
     pool: &PgPool,

+ 1 - 1
backend/src/workspace_service/workspace/router.rs

@@ -7,7 +7,7 @@ use crate::{
         update_workspace,
     },
 };
-use actix_identity::Identity;
+
 use actix_web::{
     web::{Data, Path, Payload},
     HttpResponse,

+ 4 - 13
backend/src/workspace_service/workspace/workspace.rs

@@ -5,7 +5,7 @@ use crate::{
     workspace_service::app::app::read_apps_belong_to_workspace,
 };
 use anyhow::Context;
-use chrono::Utc;
+
 use flowy_net::{
     errors::{invalid_params, ServerError},
     response::FlowyResponse,
@@ -14,19 +14,10 @@ use flowy_user::entities::parser::UserId;
 
 use crate::workspace_service::workspace::{check_workspace_id, make_workspace_from_table};
 use flowy_workspace::{
-    entities::workspace::parser::{WorkspaceDesc, WorkspaceId, WorkspaceName},
-    protobuf::{
-        CreateWorkspaceParams,
-        DeleteWorkspaceParams,
-        QueryWorkspaceParams,
-        RepeatedApp,
-        RepeatedWorkspace,
-        UpdateWorkspaceParams,
-        Workspace,
-    },
+    entities::workspace::parser::{WorkspaceDesc, WorkspaceName},
+    protobuf::{CreateWorkspaceParams, RepeatedApp, RepeatedWorkspace, UpdateWorkspaceParams},
 };
-use sqlx::{postgres::PgArguments, PgPool, Postgres, Transaction};
-use uuid::Uuid;
+use sqlx::{postgres::PgArguments, PgPool, Postgres};
 
 pub(crate) async fn create_workspace(
     pool: &PgPool,

+ 1 - 3
backend/tests/api/workspace.rs

@@ -34,9 +34,7 @@ async fn workspace_read_with_belongs() {
     let _ = create_test_app(&application, &workspace.id, &user_id).await;
     let _ = create_test_app(&application, &workspace.id, &user_id).await;
 
-    let read_params = QueryWorkspaceParams::new(&user_id)
-        .workspace_id(&workspace.id)
-        .read_apps();
+    let read_params = QueryWorkspaceParams::new(&user_id).workspace_id(&workspace.id);
     let workspaces = application.read_workspace(read_params).await;
     let workspace = workspaces.items.first().unwrap();
     assert_eq!(workspace.apps.len(), 3);

+ 0 - 2
rust-lib/flowy-dispatch/src/byte_trait.rs

@@ -1,8 +1,6 @@
 use crate::errors::{DispatchError, InternalError};
 use bytes::Bytes;
 
-use std::convert::TryFrom;
-
 // To bytes
 pub trait ToBytes {
     fn into_bytes(self) -> Result<Bytes, DispatchError>;

+ 1 - 1
rust-lib/flowy-net/src/request/request.rs

@@ -50,7 +50,7 @@ impl HttpRequestBuilder {
         builder
     }
 
-    pub fn protobuf<T1>(mut self, body: T1) -> Result<Self, ServerError>
+    pub fn protobuf<T1>(self, body: T1) -> Result<Self, ServerError>
     where
         T1: TryInto<Bytes, Error = ProtobufError>,
     {

+ 1 - 1
rust-lib/flowy-sdk/src/deps_resolve/editor_deps_impl.rs

@@ -26,7 +26,7 @@ pub struct EditorUserImpl {
 
 impl DocumentUser for EditorUserImpl {
     fn user_doc_dir(&self) -> Result<String, DocError> {
-        let dir = self.user_session.get_user_dir().map_err(|e| {
+        let dir = self.user_session.user_dir().map_err(|e| {
             ErrorBuilder::new(DocErrorCode::EditorUserNotLoginYet)
                 .error(e)
                 .build()

+ 6 - 5
rust-lib/flowy-sdk/src/deps_resolve/user_deps_impl.rs

@@ -8,25 +8,26 @@ use flowy_dispatch::prelude::{
 };
 use flowy_user::{
     errors::{ErrorBuilder, UserErrCode, UserError},
-    prelude::WorkspaceAction,
+    prelude::UserWorkspaceController,
 };
 use flowy_workspace::{
     entities::workspace::{CreateWorkspaceRequest, Workspace},
     event::WorkspaceEvent::CreateWorkspace,
 };
 
-pub struct UserWorkspaceActionImpl {}
-impl WorkspaceAction for UserWorkspaceActionImpl {
+pub struct UserWorkspaceControllerImpl {}
+impl UserWorkspaceController for UserWorkspaceControllerImpl {
     fn create_workspace(
         &self,
         name: &str,
         desc: &str,
-        _user_id: &str,
+        user_id: &str,
     ) -> DispatchFuture<Result<String, UserError>> {
-        log::info!("Create user workspace: {:?}", name);
+        log::info!("Create new workspace: {:?}", name);
         let payload: Bytes = CreateWorkspaceRequest {
             name: name.to_string(),
             desc: desc.to_string(),
+            user_id: user_id.to_string(),
         }
         .into_bytes()
         .unwrap();

+ 2 - 41
rust-lib/flowy-sdk/src/deps_resolve/workspace_deps_impl.rs

@@ -1,8 +1,7 @@
 use flowy_database::DBConnection;
-use flowy_dispatch::prelude::DispatchFuture;
+
 use flowy_user::prelude::UserSession;
 use flowy_workspace::{
-    entities::workspace::CurrentWorkspace,
     errors::{ErrorBuilder, WorkspaceError, WsErrCode},
     module::{WorkspaceDatabase, WorkspaceUser},
 };
@@ -14,50 +13,12 @@ pub struct WorkspaceUserImpl {
 
 impl WorkspaceUser for WorkspaceUserImpl {
     fn user_id(&self) -> Result<String, WorkspaceError> {
-        self.user_session.get_user_id().map_err(|e| {
+        self.user_session.user_id().map_err(|e| {
             ErrorBuilder::new(WsErrCode::UserInternalError)
                 .error(e)
                 .build()
         })
     }
-
-    // fn set_cur_workspace_id(
-    //     &self,
-    //     workspace_id: &str,
-    // ) -> DispatchFuture<Result<(), WorkspaceError>> {
-    //     let user_session = self.user_session.clone();
-    //     let workspace_id = workspace_id.to_owned();
-    //     DispatchFuture {
-    //         fut: Box::pin(async move {
-    //             let _ = user_session
-    //                 .set_current_workspace(&workspace_id)
-    //                 .await
-    //                 .map_err(|e| {
-    //                     ErrorBuilder::new(WsErrCode::UserInternalError)
-    //                         .error(e)
-    //                         .build()
-    //                 })?;
-    //             Ok(())
-    //         }),
-    //     }
-    // }
-    //
-    // fn get_cur_workspace(&self) -> DispatchFuture<Result<CurrentWorkspace,
-    // WorkspaceError>> {     let user_session = self.user_session.clone();
-    //     DispatchFuture {
-    //         fut: Box::pin(async move {
-    //             let user_detail = user_session.user_detail().map_err(|e| {
-    //                 ErrorBuilder::new(WsErrCode::UserNotLoginYet)
-    //                     .error(e)
-    //                     .build()
-    //             })?;
-    //
-    //             Ok(CurrentWorkspace {
-    //                 workspace_id: "".to_owned(),
-    //             })
-    //         }),
-    //     }
-    // }
 }
 
 pub struct WorkspaceDatabaseImpl {

+ 0 - 63
rust-lib/flowy-sdk/src/flowy_server.rs

@@ -1,63 +0,0 @@
-use flowy_dispatch::prelude::{
-    DispatchError,
-    DispatchFuture,
-    EventDispatch,
-    ModuleRequest,
-    ToBytes,
-};
-use flowy_user::{
-    entities::{SignInParams, SignUpParams, UserDetail},
-    errors::{ErrorBuilder, UserErrCode, UserError},
-    prelude::UserWorkspaceAction,
-    sql_tables::UserTable,
-};
-use flowy_workspace::{
-    entities::workspace::{CreateWorkspaceRequest, Workspace},
-    event::WorkspaceEvent::CreateWorkspace,
-};
-
-pub type ArcFlowyServer = std::sync::Arc<dyn FlowyServer>;
-
-pub trait FlowyServer: UserWorkspaceAction {}
-
-pub struct FlowyServerMocker {}
-
-impl FlowyServer for FlowyServerMocker {}
-
-impl UserWorkspaceAction for FlowyServerMocker {
-    fn create_workspace(
-        &self,
-        name: &str,
-        desc: &str,
-        _user_id: &str,
-    ) -> DispatchFuture<Result<String, UserError>> {
-        log::info!("Create user workspace: {:?}", name);
-        let payload: Vec<u8> = CreateWorkspaceRequest {
-            name: name.to_string(),
-            desc: desc.to_string(),
-        }
-        .into_bytes()
-        .unwrap();
-
-        let request = ModuleRequest::new(CreateWorkspace).payload(payload);
-        DispatchFuture {
-            fut: Box::pin(async move {
-                let result = EventDispatch::async_send(request)
-                    .await
-                    .parse::<Workspace, DispatchError>()
-                    .map_err(|e| {
-                        ErrorBuilder::new(UserErrCode::CreateDefaultWorkspaceFailed)
-                            .error(e)
-                            .build()
-                    })?;
-
-                let workspace = result.map_err(|e| {
-                    ErrorBuilder::new(UserErrCode::CreateDefaultWorkspaceFailed)
-                        .error(e)
-                        .build()
-                })?;
-                Ok(workspace.id)
-            }),
-        }
-    }
-}

+ 2 - 2
rust-lib/flowy-sdk/src/module.rs

@@ -4,7 +4,7 @@ use flowy_user::prelude::*;
 use crate::deps_resolve::{
     EditorDatabaseImpl,
     EditorUserImpl,
-    UserWorkspaceActionImpl,
+    UserWorkspaceControllerImpl,
     WorkspaceDatabaseImpl,
     WorkspaceUserImpl,
 };
@@ -18,7 +18,7 @@ pub fn build_modules(config: ModuleConfig) -> Vec<Module> {
     let user_session = Arc::new(
         UserSessionBuilder::new()
             .root_dir(&config.root)
-            .build(Arc::new(UserWorkspaceActionImpl {})),
+            .build(Arc::new(UserWorkspaceControllerImpl {})),
     );
 
     let workspace_user_impl = Arc::new(WorkspaceUserImpl {

+ 2 - 1
rust-lib/flowy-test/Cargo.toml

@@ -19,4 +19,5 @@ claim = "0.5.0"
 tokio = { version = "1", features = ["full"]}
 futures-util = "0.3.15"
 thread-id = "3.3.0"
-log = "0.4"
+log = "0.4"
+bytes = "1.0"

+ 15 - 13
rust-lib/flowy-test/src/builder.rs

@@ -6,34 +6,29 @@ use std::{
 };
 
 use crate::{
-    helper::valid_email,
+    helper::{create_default_workspace_if_need, valid_email},
     tester::{TesterContext, TesterTrait},
 };
 use flowy_user::errors::UserError;
 use flowy_workspace::errors::WorkspaceError;
-use std::{marker::PhantomData, sync::Once};
-static INIT: Once = Once::new();
+use std::marker::PhantomData;
 
 pub type SingleUserTestBuilder = TestBuilder<FixedUserTester<WorkspaceError>>;
 impl SingleUserTestBuilder {
     pub fn new() -> Self {
-        let mut builder = Self {
-            tester: Box::new(FixedUserTester::<WorkspaceError>::new()),
-            user_detail: None,
-        };
+        let mut builder = TestBuilder::test(Box::new(FixedUserTester::<WorkspaceError>::new()));
+        builder.login_if_need();
+
+        let user_id = builder.user_detail.as_ref().unwrap().id.clone();
+        let _ = create_default_workspace_if_need(&user_id);
 
-        INIT.call_once(|| builder.login_if_need());
         builder
     }
 }
-
 pub type UserTestBuilder = TestBuilder<RandomUserTester<UserError>>;
 impl UserTestBuilder {
     pub fn new() -> Self {
-        let builder = Self {
-            tester: Box::new(RandomUserTester::<UserError>::new()),
-            user_detail: None,
-        };
+        let builder = TestBuilder::test(Box::new(RandomUserTester::<UserError>::new()));
 
         builder
     }
@@ -50,6 +45,13 @@ impl<T> TestBuilder<T>
 where
     T: TesterTrait,
 {
+    pub fn test(tester: Box<T>) -> Self {
+        Self {
+            tester,
+            user_detail: None,
+        }
+    }
+
     pub fn login(mut self) -> Self {
         let user_detail = self.tester.login();
         self.user_detail = Some(user_detail);

+ 58 - 1
rust-lib/flowy-test/src/helper.rs

@@ -1,4 +1,11 @@
-use flowy_infra::uuid;
+use bytes::Bytes;
+use flowy_dispatch::prelude::{DispatchError, EventDispatch, ModuleRequest, ToBytes};
+use flowy_infra::{kv::KVStore, uuid};
+use flowy_user::errors::{ErrorBuilder, UserErrCode, UserError};
+use flowy_workspace::{
+    entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest, Workspace},
+    event::WorkspaceEvent::{CreateWorkspace, OpenWorkspace},
+};
 use std::{fs, path::PathBuf};
 
 pub fn root_dir() -> String {
@@ -22,3 +29,53 @@ pub fn random_valid_email() -> String { format!("{}@appflowy.io", uuid()) }
 pub fn valid_email() -> String { "[email protected]".to_string() }
 
 pub fn valid_password() -> String { "HelloWorld!123".to_string() }
+
+const DEFAULT_WORKSPACE_NAME: &'static str = "My workspace";
+const DEFAULT_WORKSPACE_DESC: &'static str = "This is your first workspace";
+const DEFAULT_WORKSPACE: &'static str = "Default_Workspace";
+
+pub(crate) fn create_default_workspace_if_need(user_id: &str) -> Result<(), UserError> {
+    let key = format!("{}{}", user_id, DEFAULT_WORKSPACE);
+    if KVStore::get_bool(&key).unwrap_or(false) {
+        return Err(ErrorBuilder::new(UserErrCode::DefaultWorkspaceAlreadyExist).build());
+    }
+    KVStore::set_bool(&key, true);
+
+    let payload: Bytes = CreateWorkspaceRequest {
+        name: DEFAULT_WORKSPACE_NAME.to_string(),
+        desc: DEFAULT_WORKSPACE_DESC.to_string(),
+        user_id: user_id.to_string(),
+    }
+    .into_bytes()
+    .unwrap();
+
+    let request = ModuleRequest::new(CreateWorkspace).payload(payload);
+    let result = EventDispatch::sync_send(request)
+        .parse::<Workspace, DispatchError>()
+        .map_err(|e| {
+            ErrorBuilder::new(UserErrCode::CreateDefaultWorkspaceFailed)
+                .error(e)
+                .build()
+        })?;
+
+    let workspace = result.map_err(|e| {
+        ErrorBuilder::new(UserErrCode::CreateDefaultWorkspaceFailed)
+            .error(e)
+            .build()
+    })?;
+
+    let query: Bytes = QueryWorkspaceRequest {
+        workspace_id: Some(workspace.id.clone()),
+        user_id: user_id.to_string(),
+    }
+    .into_bytes()
+    .unwrap();
+
+    let request = ModuleRequest::new(OpenWorkspace).payload(query);
+    let _result = EventDispatch::sync_send(request)
+        .parse::<Workspace, DispatchError>()
+        .unwrap()
+        .unwrap();
+
+    Ok(())
+}

+ 4 - 3
rust-lib/flowy-test/src/tester.rs

@@ -6,7 +6,7 @@ use flowy_dispatch::prelude::*;
 pub use flowy_sdk::*;
 use flowy_user::{
     errors::UserError,
-    event::UserEvent::{GetStatus, SignIn, SignOut},
+    event::UserEvent::{GetStatus, SignOut, SignUp},
     prelude::*,
 };
 use std::{
@@ -103,14 +103,15 @@ pub trait TesterTrait {
 
     fn login(&self) -> UserDetail {
         init_test_sdk();
-        let payload = SignInRequest {
+        let payload = SignUpRequest {
             email: self.context().user_email.clone(),
+            name: "app flowy".to_string(),
             password: valid_password(),
         }
         .into_bytes()
         .unwrap();
 
-        let request = ModuleRequest::new(SignIn).payload(payload);
+        let request = ModuleRequest::new(SignUp).payload(payload);
         let user_detail = EventDispatch::sync_send(request)
             .parse::<UserDetail, UserError>()
             .unwrap()

+ 4 - 4
rust-lib/flowy-user/src/services/user/builder.rs

@@ -1,6 +1,6 @@
 use crate::services::{
     user::{UserSession, UserSessionConfig},
-    workspace::WorkspaceAction,
+    workspace::UserWorkspaceController,
 };
 use std::sync::Arc;
 
@@ -16,12 +16,12 @@ impl UserSessionBuilder {
         self
     }
 
-    pub fn build<S>(mut self, workspace: Arc<S>) -> UserSession
+    pub fn build<S>(mut self, workspace_controller: Arc<S>) -> UserSession
     where
-        S: 'static + WorkspaceAction + Send + Sync,
+        S: 'static + UserWorkspaceController + Send + Sync,
     {
         let config = self.config.take().unwrap();
 
-        UserSession::new(config, workspace)
+        UserSession::new(config, workspace_controller)
     }
 }

+ 20 - 0
rust-lib/flowy-user/src/services/user/user_server/mod.rs

@@ -0,0 +1,20 @@
+mod server_api;
+mod server_api_mock;
+
+pub use server_api::*;
+pub use server_api_mock::*;
+
+use crate::services::workspace::UserWorkspaceController;
+use std::sync::Arc;
+
+pub(crate) fn construct_user_server(
+    workspace_controller: Arc<dyn UserWorkspaceController + Send + Sync>,
+) -> Arc<dyn UserServerAPI + Send + Sync> {
+    if cfg!(feature = "http_server") {
+        Arc::new(UserServer {})
+    } else {
+        Arc::new(UserServerMock {
+            workspace_controller,
+        })
+    }
+}

+ 4 - 48
rust-lib/flowy-user/src/services/user/user_server.rs → rust-lib/flowy-user/src/services/user/user_server/server_api.rs

@@ -4,29 +4,20 @@ use crate::{
 };
 
 use flowy_net::{config::*, future::ResultFuture, request::HttpRequestBuilder};
-use std::sync::Arc;
 
-pub trait UserServer {
+pub trait UserServerAPI {
     fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError>;
     fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError>;
     fn sign_out(&self, user_id: &str) -> ResultFuture<(), UserError>;
     fn get_user_info(&self, user_id: &str) -> ResultFuture<UserDetail, UserError>;
 }
 
-pub(crate) fn construct_server() -> Arc<dyn UserServer + Send + Sync> {
-    if cfg!(feature = "http_server") {
-        Arc::new(UserServerImpl {})
-    } else {
-        Arc::new(UserServerMock {})
-    }
-}
-
-pub struct UserServerImpl {}
-impl UserServerImpl {
+pub struct UserServer {}
+impl UserServer {
     pub fn new() -> Self { Self {} }
 }
 
-impl UserServer for UserServerImpl {
+impl UserServerAPI for UserServer {
     fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError> {
         ResultFuture::new(async move { user_sign_up(params, SIGN_UP_URL.as_ref()).await })
     }
@@ -63,38 +54,3 @@ pub async fn user_sign_in(params: SignInParams, url: &str) -> Result<SignInRespo
         .await?;
     Ok(response)
 }
-
-pub struct UserServerMock {}
-
-impl UserServer for UserServerMock {
-    fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError> {
-        let uid = params.email.clone();
-        ResultFuture::new(async {
-            Ok(SignUpResponse {
-                uid,
-                name: params.name,
-                email: params.email,
-            })
-        })
-    }
-
-    fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
-        let uid = params.email.clone();
-        ResultFuture::new(async {
-            Ok(SignInResponse {
-                uid,
-                name: params.email.clone(),
-                email: params.email,
-                token: "".to_string(),
-            })
-        })
-    }
-
-    fn sign_out(&self, _user_id: &str) -> ResultFuture<(), UserError> {
-        ResultFuture::new(async { Ok(()) })
-    }
-
-    fn get_user_info(&self, _user_id: &str) -> ResultFuture<UserDetail, UserError> {
-        ResultFuture::new(async { Err(ErrorBuilder::new(UserErrCode::Unknown).build()) })
-    }
-}

+ 49 - 0
rust-lib/flowy-user/src/services/user/user_server/server_api_mock.rs

@@ -0,0 +1,49 @@
+use crate::{
+    entities::{SignInParams, SignInResponse, SignUpParams, SignUpResponse, UserDetail},
+    errors::{ErrorBuilder, UserErrCode, UserError},
+    services::user::UserServerAPI,
+};
+
+use crate::services::workspace::UserWorkspaceController;
+
+use flowy_net::future::ResultFuture;
+use std::sync::Arc;
+
+pub struct UserServerMock {
+    pub workspace_controller: Arc<dyn UserWorkspaceController + Send + Sync>,
+}
+
+impl UserServerMock {}
+
+impl UserServerAPI for UserServerMock {
+    fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError> {
+        let uid = params.email.clone();
+        ResultFuture::new(async move {
+            Ok(SignUpResponse {
+                uid,
+                name: params.name,
+                email: params.email,
+            })
+        })
+    }
+
+    fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
+        let uid = params.email.clone();
+        ResultFuture::new(async {
+            Ok(SignInResponse {
+                uid,
+                name: params.email.clone(),
+                email: params.email,
+                token: "".to_string(),
+            })
+        })
+    }
+
+    fn sign_out(&self, _user_id: &str) -> ResultFuture<(), UserError> {
+        ResultFuture::new(async { Ok(()) })
+    }
+
+    fn get_user_info(&self, _user_id: &str) -> ResultFuture<UserDetail, UserError> {
+        ResultFuture::new(async { Err(ErrorBuilder::new(UserErrCode::Unknown).build()) })
+    }
+}

+ 17 - 51
rust-lib/flowy-user/src/services/user/user_session.rs

@@ -1,14 +1,13 @@
 use crate::{
-    entities::{SignInParams, SignUpParams, UpdateUserParams, UpdateUserRequest, UserDetail},
+    entities::{SignInParams, SignUpParams, UpdateUserParams, UserDetail},
     errors::{ErrorBuilder, UserErrCode, UserError},
-    event::UserEvent::*,
     services::{
-        user::{construct_server, database::UserDB, UserServer},
-        workspace::WorkspaceAction,
+        user::{construct_user_server, database::UserDB, UserServerAPI},
+        workspace::UserWorkspaceController,
     },
     sql_tables::{UserTable, UserTableChangeset},
 };
-use bytes::Bytes;
+
 use flowy_database::{
     query_dsl::*,
     schema::{user_table, user_table::dsl},
@@ -16,14 +15,10 @@ use flowy_database::{
     ExpressionMethods,
     UserDatabaseConnection,
 };
-use flowy_dispatch::prelude::{EventDispatch, ModuleRequest, ToBytes};
+
 use flowy_infra::kv::KVStore;
 use std::sync::{Arc, RwLock};
 
-const DEFAULT_WORKSPACE_NAME: &'static str = "My workspace";
-const DEFAULT_WORKSPACE_DESC: &'static str = "This is your first workspace";
-const DEFAULT_WORKSPACE: &'static str = "Default_Workspace";
-
 pub struct UserSessionConfig {
     root_dir: String,
 }
@@ -39,29 +34,29 @@ impl UserSessionConfig {
 pub struct UserSession {
     database: UserDB,
     config: UserSessionConfig,
-    workspace: Arc<dyn WorkspaceAction + Send + Sync>,
-    server: Arc<dyn UserServer + Send + Sync>,
+    workspace_controller: Arc<dyn UserWorkspaceController + Send + Sync>,
+    server: Arc<dyn UserServerAPI + Send + Sync>,
     user_id: RwLock<Option<String>>,
 }
 
 impl UserSession {
-    pub fn new<R>(config: UserSessionConfig, workspace: Arc<R>) -> Self
+    pub fn new<R>(config: UserSessionConfig, workspace_controller: Arc<R>) -> Self
     where
-        R: 'static + WorkspaceAction + Send + Sync,
+        R: 'static + UserWorkspaceController + Send + Sync,
     {
         let db = UserDB::new(&config.root_dir);
-        let server = construct_server();
+        let server = construct_user_server(workspace_controller.clone());
         Self {
             database: db,
             config,
-            workspace,
+            workspace_controller,
             server,
             user_id: RwLock::new(None),
         }
     }
 
     pub fn get_db_connection(&self) -> Result<DBConnection, UserError> {
-        let user_id = self.get_user_id()?;
+        let user_id = self.user_id()?;
         self.database.get_connection(&user_id)
     }
 
@@ -82,7 +77,7 @@ impl UserSession {
     }
 
     pub fn sign_out(&self) -> Result<(), UserError> {
-        let user_id = self.get_user_id()?;
+        let user_id = self.user_id()?;
         let conn = self.get_db_connection()?;
         let _ = diesel::delete(dsl::user_table.filter(dsl::id.eq(&user_id))).execute(&*conn)?;
         let _ = self.server.sign_out(&user_id);
@@ -110,7 +105,7 @@ impl UserSession {
     }
 
     pub fn user_detail(&self) -> Result<UserDetail, UserError> {
-        let user_id = self.get_user_id()?;
+        let user_id = self.user_id()?;
         let user = dsl::user_table
             .filter(user_table::id.eq(&user_id))
             .first::<UserTable>(&*(self.get_db_connection()?))?;
@@ -134,12 +129,12 @@ impl UserSession {
         }
     }
 
-    pub fn get_user_dir(&self) -> Result<String, UserError> {
-        let user_id = self.get_user_id()?;
+    pub fn user_dir(&self) -> Result<String, UserError> {
+        let user_id = self.user_id()?;
         Ok(format!("{}/{}", self.config.root_dir, user_id))
     }
 
-    pub fn get_user_id(&self) -> Result<String, UserError> {
+    pub fn user_id(&self) -> Result<String, UserError> {
         let mut user_id = {
             let read_guard = self.user_id.read().map_err(|e| {
                 ErrorBuilder::new(UserErrCode::ReadCurrentIdFailed)
@@ -160,35 +155,6 @@ impl UserSession {
             Some(user_id) => Ok(user_id),
         }
     }
-
-    // pub async fn set_current_workspace(&self, workspace_id: &str) -> Result<(),
-    // UserError> {     let user_id = self.get_user_id()?;
-    //     let payload: Bytes = UpdateUserRequest::new(&user_id)
-    //         .workspace(workspace_id)
-    //         .into_bytes()
-    //         .unwrap();
-    //
-    //     let request = ModuleRequest::new(UpdateUser).payload(payload);
-    //     let _ = EventDispatch::async_send(request)
-    //         .await
-    //         .parse::<UserDetail, UserError>()
-    //         .unwrap()?;
-    //     Ok(())
-    // }
-
-    async fn create_default_workspace_if_need(&self, user_id: &str) -> Result<String, UserError> {
-        let key = format!("{}{}", user_id, DEFAULT_WORKSPACE);
-        if KVStore::get_bool(&key).unwrap_or(false) {
-            return Err(ErrorBuilder::new(UserErrCode::DefaultWorkspaceAlreadyExist).build());
-        }
-        KVStore::set_bool(&key, true);
-        log::debug!("Create user:{} default workspace", user_id);
-        let workspace_id = self
-            .workspace
-            .create_workspace(DEFAULT_WORKSPACE_NAME, DEFAULT_WORKSPACE_DESC, user_id)
-            .await?;
-        Ok(workspace_id)
-    }
 }
 
 pub fn current_user_id() -> Result<String, UserError> {

+ 1 - 1
rust-lib/flowy-user/src/services/workspace/action.rs

@@ -1,7 +1,7 @@
 use crate::errors::UserError;
 use flowy_dispatch::prelude::DispatchFuture;
 
-pub trait WorkspaceAction {
+pub trait UserWorkspaceController {
     fn create_workspace(
         &self,
         name: &str,

+ 0 - 6
rust-lib/flowy-user/tests/event/user_update_test.rs

@@ -11,7 +11,6 @@ fn user_update_with_name() {
         id: user_detail.id.clone(),
         name: Some(new_name.clone()),
         email: None,
-        workspace: None,
         password: None,
     };
 
@@ -33,7 +32,6 @@ fn user_update_with_email() {
         id: user_detail.id.clone(),
         name: None,
         email: Some(new_email.clone()),
-        workspace: None,
         password: None,
     };
 
@@ -55,7 +53,6 @@ fn user_update_with_password() {
         id: user_detail.id.clone(),
         name: None,
         email: None,
-        workspace: None,
         password: Some(new_password.clone()),
     };
 
@@ -75,7 +72,6 @@ fn user_update_with_invalid_email() {
             id: user_detail.id.clone(),
             name: None,
             email: Some(email),
-            workspace: None,
             password: None,
         };
 
@@ -100,7 +96,6 @@ fn user_update_with_invalid_password() {
             id: user_detail.id.clone(),
             name: None,
             email: None,
-            workspace: None,
             password: Some(password),
         };
 
@@ -120,7 +115,6 @@ fn user_update_with_invalid_name() {
         id: user_detail.id.clone(),
         name: Some("".to_string()),
         email: None,
-        workspace: None,
         password: None,
     };
 

+ 9 - 32
rust-lib/flowy-workspace/src/entities/app/app_update.rs

@@ -1,10 +1,7 @@
 use crate::{
-    entities::{
-        app::{
-            parser::{AppColorStyle, AppId, AppName},
-            ColorStyle,
-        },
-        workspace::parser::WorkspaceId,
+    entities::app::{
+        parser::{AppColorStyle, AppId, AppName},
+        ColorStyle,
     },
     errors::{ErrorBuilder, WorkspaceError, WsErrCode},
 };
@@ -17,18 +14,15 @@ pub struct UpdateAppRequest {
     pub app_id: String,
 
     #[pb(index = 2, one_of)]
-    pub workspace_id: Option<String>,
-
-    #[pb(index = 3, one_of)]
     pub name: Option<String>,
 
-    #[pb(index = 4, one_of)]
+    #[pb(index = 3, one_of)]
     pub desc: Option<String>,
 
-    #[pb(index = 5, one_of)]
+    #[pb(index = 4, one_of)]
     pub color_style: Option<ColorStyle>,
 
-    #[pb(index = 6, one_of)]
+    #[pb(index = 5, one_of)]
     pub is_trash: Option<bool>,
 }
 
@@ -38,18 +32,15 @@ pub struct UpdateAppParams {
     pub app_id: String,
 
     #[pb(index = 2, one_of)]
-    pub workspace_id: Option<String>,
-
-    #[pb(index = 3, one_of)]
     pub name: Option<String>,
 
-    #[pb(index = 4, one_of)]
+    #[pb(index = 3, one_of)]
     pub desc: Option<String>,
 
-    #[pb(index = 5, one_of)]
+    #[pb(index = 4, one_of)]
     pub color_style: Option<ColorStyle>,
 
-    #[pb(index = 6, one_of)]
+    #[pb(index = 5, one_of)]
     pub is_trash: Option<bool>,
 }
 
@@ -98,19 +89,6 @@ impl TryInto<UpdateAppParams> for UpdateAppRequest {
             ),
         };
 
-        let workspace_id = match self.workspace_id {
-            None => None,
-            Some(wid) => Some(
-                WorkspaceId::parse(wid)
-                    .map_err(|e| {
-                        ErrorBuilder::new(WsErrCode::WorkspaceIdInvalid)
-                            .msg(e)
-                            .build()
-                    })?
-                    .0,
-            ),
-        };
-
         let color_style = match self.color_style {
             None => None,
             Some(color_style) => Some(
@@ -126,7 +104,6 @@ impl TryInto<UpdateAppParams> for UpdateAppRequest {
 
         Ok(UpdateAppParams {
             app_id,
-            workspace_id,
             name,
             desc: self.desc,
             color_style,

+ 11 - 2
rust-lib/flowy-workspace/src/entities/workspace/workspace_create.rs

@@ -13,6 +13,9 @@ pub struct CreateWorkspaceRequest {
 
     #[pb(index = 2)]
     pub desc: String,
+
+    #[pb(index = 3)]
+    pub user_id: String,
 }
 
 #[derive(ProtoBuf, Default)]
@@ -32,7 +35,7 @@ impl TryInto<CreateWorkspaceParams> for CreateWorkspaceRequest {
 
     fn try_into(self) -> Result<CreateWorkspaceParams, Self::Error> {
         let name = WorkspaceName::parse(self.name).map_err(|e| {
-            ErrorBuilder::new(WsErrCode::WorkspaceDescInvalid)
+            ErrorBuilder::new(WsErrCode::WorkspaceNameInvalid)
                 .msg(e)
                 .build()
         })?;
@@ -43,10 +46,16 @@ impl TryInto<CreateWorkspaceParams> for CreateWorkspaceRequest {
                 .build()
         })?;
 
+        if self.user_id.is_empty() {
+            return Err(ErrorBuilder::new(WsErrCode::UserIdIsEmpty)
+                .msg("Create workspace failed. UserId is empty")
+                .build());
+        }
+
         Ok(CreateWorkspaceParams {
             name: name.0,
             desc: desc.0,
-            user_id: "".to_string(),
+            user_id: self.user_id,
         })
     }
 }

+ 3 - 0
rust-lib/flowy-workspace/src/errors.rs

@@ -73,6 +73,9 @@ pub enum WsErrCode {
     #[display(fmt = "User not login yet")]
     UserNotLoginYet      = 103,
 
+    #[display(fmt = "UserIn is empty")]
+    UserIdIsEmpty        = 104,
+
     #[display(fmt = "Server error")]
     ServerError          = 1000,
     #[display(fmt = "Record not found")]

+ 1 - 3
rust-lib/flowy-workspace/src/handlers/workspace_handler.rs

@@ -1,5 +1,5 @@
 use crate::{
-    entities::{app::RepeatedApp, workspace::*},
+    entities::workspace::*,
     errors::{ErrorBuilder, WorkspaceError, WsErrCode},
     services::WorkspaceController,
 };
@@ -31,9 +31,7 @@ pub async fn read_workspace(
     controller: Unit<Arc<WorkspaceController>>,
 ) -> DataResult<RepeatedWorkspace, WorkspaceError> {
     let params: QueryWorkspaceParams = data.into_inner().try_into()?;
-
     let workspaces = controller.read_workspaces(params.workspace_id).await?;
-
     data_result(workspaces)
 }
 

+ 1 - 1
rust-lib/flowy-workspace/src/module.rs

@@ -7,7 +7,7 @@ use crate::{
 };
 use flowy_database::DBConnection;
 
-use crate::{entities::workspace::CurrentWorkspace, handlers::*, services::ViewController};
+use crate::{handlers::*, services::ViewController};
 use std::sync::Arc;
 
 pub trait WorkspaceDeps: WorkspaceUser + WorkspaceDatabase {}

+ 79 - 252
rust-lib/flowy-workspace/src/protobuf/model/app_update.rs

@@ -28,7 +28,6 @@ pub struct UpdateAppRequest {
     // message fields
     pub app_id: ::std::string::String,
     // message oneof groups
-    pub one_of_workspace_id: ::std::option::Option<UpdateAppRequest_oneof_one_of_workspace_id>,
     pub one_of_name: ::std::option::Option<UpdateAppRequest_oneof_one_of_name>,
     pub one_of_desc: ::std::option::Option<UpdateAppRequest_oneof_one_of_desc>,
     pub one_of_color_style: ::std::option::Option<UpdateAppRequest_oneof_one_of_color_style>,
@@ -44,11 +43,6 @@ impl<'a> ::std::default::Default for &'a UpdateAppRequest {
     }
 }
 
-#[derive(Clone,PartialEq,Debug)]
-pub enum UpdateAppRequest_oneof_one_of_workspace_id {
-    workspace_id(::std::string::String),
-}
-
 #[derive(Clone,PartialEq,Debug)]
 pub enum UpdateAppRequest_oneof_one_of_name {
     name(::std::string::String),
@@ -100,56 +94,7 @@ impl UpdateAppRequest {
         ::std::mem::replace(&mut self.app_id, ::std::string::String::new())
     }
 
-    // string workspace_id = 2;
-
-
-    pub fn get_workspace_id(&self) -> &str {
-        match self.one_of_workspace_id {
-            ::std::option::Option::Some(UpdateAppRequest_oneof_one_of_workspace_id::workspace_id(ref v)) => v,
-            _ => "",
-        }
-    }
-    pub fn clear_workspace_id(&mut self) {
-        self.one_of_workspace_id = ::std::option::Option::None;
-    }
-
-    pub fn has_workspace_id(&self) -> bool {
-        match self.one_of_workspace_id {
-            ::std::option::Option::Some(UpdateAppRequest_oneof_one_of_workspace_id::workspace_id(..)) => true,
-            _ => false,
-        }
-    }
-
-    // Param is passed by value, moved
-    pub fn set_workspace_id(&mut self, v: ::std::string::String) {
-        self.one_of_workspace_id = ::std::option::Option::Some(UpdateAppRequest_oneof_one_of_workspace_id::workspace_id(v))
-    }
-
-    // Mutable pointer to the field.
-    pub fn mut_workspace_id(&mut self) -> &mut ::std::string::String {
-        if let ::std::option::Option::Some(UpdateAppRequest_oneof_one_of_workspace_id::workspace_id(_)) = self.one_of_workspace_id {
-        } else {
-            self.one_of_workspace_id = ::std::option::Option::Some(UpdateAppRequest_oneof_one_of_workspace_id::workspace_id(::std::string::String::new()));
-        }
-        match self.one_of_workspace_id {
-            ::std::option::Option::Some(UpdateAppRequest_oneof_one_of_workspace_id::workspace_id(ref mut v)) => v,
-            _ => panic!(),
-        }
-    }
-
-    // Take field
-    pub fn take_workspace_id(&mut self) -> ::std::string::String {
-        if self.has_workspace_id() {
-            match self.one_of_workspace_id.take() {
-                ::std::option::Option::Some(UpdateAppRequest_oneof_one_of_workspace_id::workspace_id(v)) => v,
-                _ => panic!(),
-            }
-        } else {
-            ::std::string::String::new()
-        }
-    }
-
-    // string name = 3;
+    // string name = 2;
 
 
     pub fn get_name(&self) -> &str {
@@ -198,7 +143,7 @@ impl UpdateAppRequest {
         }
     }
 
-    // string desc = 4;
+    // string desc = 3;
 
 
     pub fn get_desc(&self) -> &str {
@@ -247,7 +192,7 @@ impl UpdateAppRequest {
         }
     }
 
-    // .ColorStyle color_style = 5;
+    // .ColorStyle color_style = 4;
 
 
     pub fn get_color_style(&self) -> &super::app_create::ColorStyle {
@@ -296,7 +241,7 @@ impl UpdateAppRequest {
         }
     }
 
-    // bool is_trash = 6;
+    // bool is_trash = 5;
 
 
     pub fn get_is_trash(&self) -> bool {
@@ -340,30 +285,24 @@ impl ::protobuf::Message for UpdateAppRequest {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.app_id)?;
                 },
                 2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    self.one_of_workspace_id = ::std::option::Option::Some(UpdateAppRequest_oneof_one_of_workspace_id::workspace_id(is.read_string()?));
-                },
-                3 => {
                     if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
                         return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
                     }
                     self.one_of_name = ::std::option::Option::Some(UpdateAppRequest_oneof_one_of_name::name(is.read_string()?));
                 },
-                4 => {
+                3 => {
                     if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
                         return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
                     }
                     self.one_of_desc = ::std::option::Option::Some(UpdateAppRequest_oneof_one_of_desc::desc(is.read_string()?));
                 },
-                5 => {
+                4 => {
                     if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
                         return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
                     }
                     self.one_of_color_style = ::std::option::Option::Some(UpdateAppRequest_oneof_one_of_color_style::color_style(is.read_message()?));
                 },
-                6 => {
+                5 => {
                     if wire_type != ::protobuf::wire_format::WireTypeVarint {
                         return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
                     }
@@ -384,24 +323,17 @@ impl ::protobuf::Message for UpdateAppRequest {
         if !self.app_id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.app_id);
         }
-        if let ::std::option::Option::Some(ref v) = self.one_of_workspace_id {
-            match v {
-                &UpdateAppRequest_oneof_one_of_workspace_id::workspace_id(ref v) => {
-                    my_size += ::protobuf::rt::string_size(2, &v);
-                },
-            };
-        }
         if let ::std::option::Option::Some(ref v) = self.one_of_name {
             match v {
                 &UpdateAppRequest_oneof_one_of_name::name(ref v) => {
-                    my_size += ::protobuf::rt::string_size(3, &v);
+                    my_size += ::protobuf::rt::string_size(2, &v);
                 },
             };
         }
         if let ::std::option::Option::Some(ref v) = self.one_of_desc {
             match v {
                 &UpdateAppRequest_oneof_one_of_desc::desc(ref v) => {
-                    my_size += ::protobuf::rt::string_size(4, &v);
+                    my_size += ::protobuf::rt::string_size(3, &v);
                 },
             };
         }
@@ -429,31 +361,24 @@ impl ::protobuf::Message for UpdateAppRequest {
         if !self.app_id.is_empty() {
             os.write_string(1, &self.app_id)?;
         }
-        if let ::std::option::Option::Some(ref v) = self.one_of_workspace_id {
-            match v {
-                &UpdateAppRequest_oneof_one_of_workspace_id::workspace_id(ref v) => {
-                    os.write_string(2, v)?;
-                },
-            };
-        }
         if let ::std::option::Option::Some(ref v) = self.one_of_name {
             match v {
                 &UpdateAppRequest_oneof_one_of_name::name(ref v) => {
-                    os.write_string(3, v)?;
+                    os.write_string(2, v)?;
                 },
             };
         }
         if let ::std::option::Option::Some(ref v) = self.one_of_desc {
             match v {
                 &UpdateAppRequest_oneof_one_of_desc::desc(ref v) => {
-                    os.write_string(4, v)?;
+                    os.write_string(3, v)?;
                 },
             };
         }
         if let ::std::option::Option::Some(ref v) = self.one_of_color_style {
             match v {
                 &UpdateAppRequest_oneof_one_of_color_style::color_style(ref v) => {
-                    os.write_tag(5, ::protobuf::wire_format::WireTypeLengthDelimited)?;
+                    os.write_tag(4, ::protobuf::wire_format::WireTypeLengthDelimited)?;
                     os.write_raw_varint32(v.get_cached_size())?;
                     v.write_to_with_cached_sizes(os)?;
                 },
@@ -462,7 +387,7 @@ impl ::protobuf::Message for UpdateAppRequest {
         if let ::std::option::Option::Some(ref v) = self.one_of_is_trash {
             match v {
                 &UpdateAppRequest_oneof_one_of_is_trash::is_trash(v) => {
-                    os.write_bool(6, v)?;
+                    os.write_bool(5, v)?;
                 },
             };
         }
@@ -509,11 +434,6 @@ impl ::protobuf::Message for UpdateAppRequest {
                 |m: &UpdateAppRequest| { &m.app_id },
                 |m: &mut UpdateAppRequest| { &mut m.app_id },
             ));
-            fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
-                "workspace_id",
-                UpdateAppRequest::has_workspace_id,
-                UpdateAppRequest::get_workspace_id,
-            ));
             fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
                 "name",
                 UpdateAppRequest::has_name,
@@ -551,7 +471,6 @@ impl ::protobuf::Message for UpdateAppRequest {
 impl ::protobuf::Clear for UpdateAppRequest {
     fn clear(&mut self) {
         self.app_id.clear();
-        self.one_of_workspace_id = ::std::option::Option::None;
         self.one_of_name = ::std::option::Option::None;
         self.one_of_desc = ::std::option::Option::None;
         self.one_of_color_style = ::std::option::Option::None;
@@ -577,7 +496,6 @@ pub struct UpdateAppParams {
     // message fields
     pub app_id: ::std::string::String,
     // message oneof groups
-    pub one_of_workspace_id: ::std::option::Option<UpdateAppParams_oneof_one_of_workspace_id>,
     pub one_of_name: ::std::option::Option<UpdateAppParams_oneof_one_of_name>,
     pub one_of_desc: ::std::option::Option<UpdateAppParams_oneof_one_of_desc>,
     pub one_of_color_style: ::std::option::Option<UpdateAppParams_oneof_one_of_color_style>,
@@ -593,11 +511,6 @@ impl<'a> ::std::default::Default for &'a UpdateAppParams {
     }
 }
 
-#[derive(Clone,PartialEq,Debug)]
-pub enum UpdateAppParams_oneof_one_of_workspace_id {
-    workspace_id(::std::string::String),
-}
-
 #[derive(Clone,PartialEq,Debug)]
 pub enum UpdateAppParams_oneof_one_of_name {
     name(::std::string::String),
@@ -649,56 +562,7 @@ impl UpdateAppParams {
         ::std::mem::replace(&mut self.app_id, ::std::string::String::new())
     }
 
-    // string workspace_id = 2;
-
-
-    pub fn get_workspace_id(&self) -> &str {
-        match self.one_of_workspace_id {
-            ::std::option::Option::Some(UpdateAppParams_oneof_one_of_workspace_id::workspace_id(ref v)) => v,
-            _ => "",
-        }
-    }
-    pub fn clear_workspace_id(&mut self) {
-        self.one_of_workspace_id = ::std::option::Option::None;
-    }
-
-    pub fn has_workspace_id(&self) -> bool {
-        match self.one_of_workspace_id {
-            ::std::option::Option::Some(UpdateAppParams_oneof_one_of_workspace_id::workspace_id(..)) => true,
-            _ => false,
-        }
-    }
-
-    // Param is passed by value, moved
-    pub fn set_workspace_id(&mut self, v: ::std::string::String) {
-        self.one_of_workspace_id = ::std::option::Option::Some(UpdateAppParams_oneof_one_of_workspace_id::workspace_id(v))
-    }
-
-    // Mutable pointer to the field.
-    pub fn mut_workspace_id(&mut self) -> &mut ::std::string::String {
-        if let ::std::option::Option::Some(UpdateAppParams_oneof_one_of_workspace_id::workspace_id(_)) = self.one_of_workspace_id {
-        } else {
-            self.one_of_workspace_id = ::std::option::Option::Some(UpdateAppParams_oneof_one_of_workspace_id::workspace_id(::std::string::String::new()));
-        }
-        match self.one_of_workspace_id {
-            ::std::option::Option::Some(UpdateAppParams_oneof_one_of_workspace_id::workspace_id(ref mut v)) => v,
-            _ => panic!(),
-        }
-    }
-
-    // Take field
-    pub fn take_workspace_id(&mut self) -> ::std::string::String {
-        if self.has_workspace_id() {
-            match self.one_of_workspace_id.take() {
-                ::std::option::Option::Some(UpdateAppParams_oneof_one_of_workspace_id::workspace_id(v)) => v,
-                _ => panic!(),
-            }
-        } else {
-            ::std::string::String::new()
-        }
-    }
-
-    // string name = 3;
+    // string name = 2;
 
 
     pub fn get_name(&self) -> &str {
@@ -747,7 +611,7 @@ impl UpdateAppParams {
         }
     }
 
-    // string desc = 4;
+    // string desc = 3;
 
 
     pub fn get_desc(&self) -> &str {
@@ -796,7 +660,7 @@ impl UpdateAppParams {
         }
     }
 
-    // .ColorStyle color_style = 5;
+    // .ColorStyle color_style = 4;
 
 
     pub fn get_color_style(&self) -> &super::app_create::ColorStyle {
@@ -845,7 +709,7 @@ impl UpdateAppParams {
         }
     }
 
-    // bool is_trash = 6;
+    // bool is_trash = 5;
 
 
     pub fn get_is_trash(&self) -> bool {
@@ -889,30 +753,24 @@ impl ::protobuf::Message for UpdateAppParams {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.app_id)?;
                 },
                 2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    self.one_of_workspace_id = ::std::option::Option::Some(UpdateAppParams_oneof_one_of_workspace_id::workspace_id(is.read_string()?));
-                },
-                3 => {
                     if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
                         return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
                     }
                     self.one_of_name = ::std::option::Option::Some(UpdateAppParams_oneof_one_of_name::name(is.read_string()?));
                 },
-                4 => {
+                3 => {
                     if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
                         return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
                     }
                     self.one_of_desc = ::std::option::Option::Some(UpdateAppParams_oneof_one_of_desc::desc(is.read_string()?));
                 },
-                5 => {
+                4 => {
                     if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
                         return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
                     }
                     self.one_of_color_style = ::std::option::Option::Some(UpdateAppParams_oneof_one_of_color_style::color_style(is.read_message()?));
                 },
-                6 => {
+                5 => {
                     if wire_type != ::protobuf::wire_format::WireTypeVarint {
                         return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
                     }
@@ -933,24 +791,17 @@ impl ::protobuf::Message for UpdateAppParams {
         if !self.app_id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.app_id);
         }
-        if let ::std::option::Option::Some(ref v) = self.one_of_workspace_id {
-            match v {
-                &UpdateAppParams_oneof_one_of_workspace_id::workspace_id(ref v) => {
-                    my_size += ::protobuf::rt::string_size(2, &v);
-                },
-            };
-        }
         if let ::std::option::Option::Some(ref v) = self.one_of_name {
             match v {
                 &UpdateAppParams_oneof_one_of_name::name(ref v) => {
-                    my_size += ::protobuf::rt::string_size(3, &v);
+                    my_size += ::protobuf::rt::string_size(2, &v);
                 },
             };
         }
         if let ::std::option::Option::Some(ref v) = self.one_of_desc {
             match v {
                 &UpdateAppParams_oneof_one_of_desc::desc(ref v) => {
-                    my_size += ::protobuf::rt::string_size(4, &v);
+                    my_size += ::protobuf::rt::string_size(3, &v);
                 },
             };
         }
@@ -978,31 +829,24 @@ impl ::protobuf::Message for UpdateAppParams {
         if !self.app_id.is_empty() {
             os.write_string(1, &self.app_id)?;
         }
-        if let ::std::option::Option::Some(ref v) = self.one_of_workspace_id {
-            match v {
-                &UpdateAppParams_oneof_one_of_workspace_id::workspace_id(ref v) => {
-                    os.write_string(2, v)?;
-                },
-            };
-        }
         if let ::std::option::Option::Some(ref v) = self.one_of_name {
             match v {
                 &UpdateAppParams_oneof_one_of_name::name(ref v) => {
-                    os.write_string(3, v)?;
+                    os.write_string(2, v)?;
                 },
             };
         }
         if let ::std::option::Option::Some(ref v) = self.one_of_desc {
             match v {
                 &UpdateAppParams_oneof_one_of_desc::desc(ref v) => {
-                    os.write_string(4, v)?;
+                    os.write_string(3, v)?;
                 },
             };
         }
         if let ::std::option::Option::Some(ref v) = self.one_of_color_style {
             match v {
                 &UpdateAppParams_oneof_one_of_color_style::color_style(ref v) => {
-                    os.write_tag(5, ::protobuf::wire_format::WireTypeLengthDelimited)?;
+                    os.write_tag(4, ::protobuf::wire_format::WireTypeLengthDelimited)?;
                     os.write_raw_varint32(v.get_cached_size())?;
                     v.write_to_with_cached_sizes(os)?;
                 },
@@ -1011,7 +855,7 @@ impl ::protobuf::Message for UpdateAppParams {
         if let ::std::option::Option::Some(ref v) = self.one_of_is_trash {
             match v {
                 &UpdateAppParams_oneof_one_of_is_trash::is_trash(v) => {
-                    os.write_bool(6, v)?;
+                    os.write_bool(5, v)?;
                 },
             };
         }
@@ -1058,11 +902,6 @@ impl ::protobuf::Message for UpdateAppParams {
                 |m: &UpdateAppParams| { &m.app_id },
                 |m: &mut UpdateAppParams| { &mut m.app_id },
             ));
-            fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
-                "workspace_id",
-                UpdateAppParams::has_workspace_id,
-                UpdateAppParams::get_workspace_id,
-            ));
             fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
                 "name",
                 UpdateAppParams::has_name,
@@ -1100,7 +939,6 @@ impl ::protobuf::Message for UpdateAppParams {
 impl ::protobuf::Clear for UpdateAppParams {
     fn clear(&mut self) {
         self.app_id.clear();
-        self.one_of_workspace_id = ::std::option::Option::None;
         self.one_of_name = ::std::option::Option::None;
         self.one_of_desc = ::std::option::Option::None;
         self.one_of_color_style = ::std::option::Option::None;
@@ -1122,70 +960,59 @@ impl ::protobuf::reflect::ProtobufValue for UpdateAppParams {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x10app_update.proto\x1a\x10app_create.proto\"\xa5\x02\n\x10UpdateAppR\
-    equest\x12\x15\n\x06app_id\x18\x01\x20\x01(\tR\x05appId\x12#\n\x0cworksp\
-    ace_id\x18\x02\x20\x01(\tH\0R\x0bworkspaceId\x12\x14\n\x04name\x18\x03\
-    \x20\x01(\tH\x01R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\x02R\x04\
-    desc\x12.\n\x0bcolor_style\x18\x05\x20\x01(\x0b2\x0b.ColorStyleH\x03R\nc\
-    olorStyle\x12\x1b\n\x08is_trash\x18\x06\x20\x01(\x08H\x04R\x07isTrashB\
-    \x15\n\x13one_of_workspace_idB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\
-    \x14\n\x12one_of_color_styleB\x11\n\x0fone_of_is_trash\"\xa4\x02\n\x0fUp\
-    dateAppParams\x12\x15\n\x06app_id\x18\x01\x20\x01(\tR\x05appId\x12#\n\
-    \x0cworkspace_id\x18\x02\x20\x01(\tH\0R\x0bworkspaceId\x12\x14\n\x04name\
-    \x18\x03\x20\x01(\tH\x01R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\
-    \x02R\x04desc\x12.\n\x0bcolor_style\x18\x05\x20\x01(\x0b2\x0b.ColorStyle\
-    H\x03R\ncolorStyle\x12\x1b\n\x08is_trash\x18\x06\x20\x01(\x08H\x04R\x07i\
-    sTrashB\x15\n\x13one_of_workspace_idB\r\n\x0bone_of_nameB\r\n\x0bone_of_\
-    descB\x14\n\x12one_of_color_styleB\x11\n\x0fone_of_is_trashJ\xef\x07\n\
-    \x06\x12\x04\0\0\x12\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\t\n\x02\x03\0\
-    \x12\x03\x01\0\x1a\n\n\n\x02\x04\0\x12\x04\x03\0\n\x01\n\n\n\x03\x04\0\
-    \x01\x12\x03\x03\x08\x18\n\x0b\n\x04\x04\0\x02\0\x12\x03\x04\x04\x16\n\
-    \x0c\n\x05\x04\0\x02\0\x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\
-    \x12\x03\x04\x0b\x11\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x04\x14\x15\n\
-    \x0b\n\x04\x04\0\x08\0\x12\x03\x05\x04:\n\x0c\n\x05\x04\0\x08\0\x01\x12\
-    \x03\x05\n\x1d\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x05\x208\n\x0c\n\x05\
-    \x04\0\x02\x01\x05\x12\x03\x05\x20&\n\x0c\n\x05\x04\0\x02\x01\x01\x12\
-    \x03\x05'3\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x0567\n\x0b\n\x04\x04\0\
-    \x08\x01\x12\x03\x06\x04*\n\x0c\n\x05\x04\0\x08\x01\x01\x12\x03\x06\n\
-    \x15\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x06\x18(\n\x0c\n\x05\x04\0\x02\
-    \x02\x05\x12\x03\x06\x18\x1e\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x06\
-    \x1f#\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x06&'\n\x0b\n\x04\x04\0\x08\
-    \x02\x12\x03\x07\x04*\n\x0c\n\x05\x04\0\x08\x02\x01\x12\x03\x07\n\x15\n\
-    \x0b\n\x04\x04\0\x02\x03\x12\x03\x07\x18(\n\x0c\n\x05\x04\0\x02\x03\x05\
-    \x12\x03\x07\x18\x1e\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x07\x1f#\n\
-    \x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x07&'\n\x0b\n\x04\x04\0\x08\x03\x12\
-    \x03\x08\x04<\n\x0c\n\x05\x04\0\x08\x03\x01\x12\x03\x08\n\x1c\n\x0b\n\
-    \x04\x04\0\x02\x04\x12\x03\x08\x1f:\n\x0c\n\x05\x04\0\x02\x04\x06\x12\
-    \x03\x08\x1f)\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x08*5\n\x0c\n\x05\
-    \x04\0\x02\x04\x03\x12\x03\x0889\n\x0b\n\x04\x04\0\x08\x04\x12\x03\t\x04\
-    0\n\x0c\n\x05\x04\0\x08\x04\x01\x12\x03\t\n\x19\n\x0b\n\x04\x04\0\x02\
-    \x05\x12\x03\t\x1c.\n\x0c\n\x05\x04\0\x02\x05\x05\x12\x03\t\x1c\x20\n\
-    \x0c\n\x05\x04\0\x02\x05\x01\x12\x03\t!)\n\x0c\n\x05\x04\0\x02\x05\x03\
-    \x12\x03\t,-\n\n\n\x02\x04\x01\x12\x04\x0b\0\x12\x01\n\n\n\x03\x04\x01\
-    \x01\x12\x03\x0b\x08\x17\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x0c\x04\x16\n\
-    \x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x0c\x04\n\n\x0c\n\x05\x04\x01\x02\0\
-    \x01\x12\x03\x0c\x0b\x11\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x0c\x14\
-    \x15\n\x0b\n\x04\x04\x01\x08\0\x12\x03\r\x04:\n\x0c\n\x05\x04\x01\x08\0\
-    \x01\x12\x03\r\n\x1d\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\r\x208\n\x0c\n\
-    \x05\x04\x01\x02\x01\x05\x12\x03\r\x20&\n\x0c\n\x05\x04\x01\x02\x01\x01\
-    \x12\x03\r'3\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\r67\n\x0b\n\x04\x04\
-    \x01\x08\x01\x12\x03\x0e\x04*\n\x0c\n\x05\x04\x01\x08\x01\x01\x12\x03\
-    \x0e\n\x15\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\x0e\x18(\n\x0c\n\x05\x04\
-    \x01\x02\x02\x05\x12\x03\x0e\x18\x1e\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\
-    \x03\x0e\x1f#\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\x0e&'\n\x0b\n\x04\
-    \x04\x01\x08\x02\x12\x03\x0f\x04*\n\x0c\n\x05\x04\x01\x08\x02\x01\x12\
-    \x03\x0f\n\x15\n\x0b\n\x04\x04\x01\x02\x03\x12\x03\x0f\x18(\n\x0c\n\x05\
-    \x04\x01\x02\x03\x05\x12\x03\x0f\x18\x1e\n\x0c\n\x05\x04\x01\x02\x03\x01\
-    \x12\x03\x0f\x1f#\n\x0c\n\x05\x04\x01\x02\x03\x03\x12\x03\x0f&'\n\x0b\n\
-    \x04\x04\x01\x08\x03\x12\x03\x10\x04<\n\x0c\n\x05\x04\x01\x08\x03\x01\
-    \x12\x03\x10\n\x1c\n\x0b\n\x04\x04\x01\x02\x04\x12\x03\x10\x1f:\n\x0c\n\
-    \x05\x04\x01\x02\x04\x06\x12\x03\x10\x1f)\n\x0c\n\x05\x04\x01\x02\x04\
-    \x01\x12\x03\x10*5\n\x0c\n\x05\x04\x01\x02\x04\x03\x12\x03\x1089\n\x0b\n\
-    \x04\x04\x01\x08\x04\x12\x03\x11\x040\n\x0c\n\x05\x04\x01\x08\x04\x01\
-    \x12\x03\x11\n\x19\n\x0b\n\x04\x04\x01\x02\x05\x12\x03\x11\x1c.\n\x0c\n\
-    \x05\x04\x01\x02\x05\x05\x12\x03\x11\x1c\x20\n\x0c\n\x05\x04\x01\x02\x05\
-    \x01\x12\x03\x11!)\n\x0c\n\x05\x04\x01\x02\x05\x03\x12\x03\x11,-b\x06pro\
-    to3\
+    \n\x10app_update.proto\x1a\x10app_create.proto\"\xe9\x01\n\x10UpdateAppR\
+    equest\x12\x15\n\x06app_id\x18\x01\x20\x01(\tR\x05appId\x12\x14\n\x04nam\
+    e\x18\x02\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x03\x20\x01(\tH\
+    \x01R\x04desc\x12.\n\x0bcolor_style\x18\x04\x20\x01(\x0b2\x0b.ColorStyle\
+    H\x02R\ncolorStyle\x12\x1b\n\x08is_trash\x18\x05\x20\x01(\x08H\x03R\x07i\
+    sTrashB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x14\n\x12one_of_color_st\
+    yleB\x11\n\x0fone_of_is_trash\"\xe8\x01\n\x0fUpdateAppParams\x12\x15\n\
+    \x06app_id\x18\x01\x20\x01(\tR\x05appId\x12\x14\n\x04name\x18\x02\x20\
+    \x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x03\x20\x01(\tH\x01R\x04desc\
+    \x12.\n\x0bcolor_style\x18\x04\x20\x01(\x0b2\x0b.ColorStyleH\x02R\ncolor\
+    Style\x12\x1b\n\x08is_trash\x18\x05\x20\x01(\x08H\x03R\x07isTrashB\r\n\
+    \x0bone_of_nameB\r\n\x0bone_of_descB\x14\n\x12one_of_color_styleB\x11\n\
+    \x0fone_of_is_trashJ\xcb\x06\n\x06\x12\x04\0\0\x10\x01\n\x08\n\x01\x0c\
+    \x12\x03\0\0\x12\n\t\n\x02\x03\0\x12\x03\x01\0\x1a\n\n\n\x02\x04\0\x12\
+    \x04\x03\0\t\x01\n\n\n\x03\x04\0\x01\x12\x03\x03\x08\x18\n\x0b\n\x04\x04\
+    \0\x02\0\x12\x03\x04\x04\x16\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x04\x04\
+    \n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x04\x0b\x11\n\x0c\n\x05\x04\0\x02\
+    \0\x03\x12\x03\x04\x14\x15\n\x0b\n\x04\x04\0\x08\0\x12\x03\x05\x04*\n\
+    \x0c\n\x05\x04\0\x08\0\x01\x12\x03\x05\n\x15\n\x0b\n\x04\x04\0\x02\x01\
+    \x12\x03\x05\x18(\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x05\x18\x1e\n\
+    \x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x05\x1f#\n\x0c\n\x05\x04\0\x02\x01\
+    \x03\x12\x03\x05&'\n\x0b\n\x04\x04\0\x08\x01\x12\x03\x06\x04*\n\x0c\n\
+    \x05\x04\0\x08\x01\x01\x12\x03\x06\n\x15\n\x0b\n\x04\x04\0\x02\x02\x12\
+    \x03\x06\x18(\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x06\x18\x1e\n\x0c\n\
+    \x05\x04\0\x02\x02\x01\x12\x03\x06\x1f#\n\x0c\n\x05\x04\0\x02\x02\x03\
+    \x12\x03\x06&'\n\x0b\n\x04\x04\0\x08\x02\x12\x03\x07\x04<\n\x0c\n\x05\
+    \x04\0\x08\x02\x01\x12\x03\x07\n\x1c\n\x0b\n\x04\x04\0\x02\x03\x12\x03\
+    \x07\x1f:\n\x0c\n\x05\x04\0\x02\x03\x06\x12\x03\x07\x1f)\n\x0c\n\x05\x04\
+    \0\x02\x03\x01\x12\x03\x07*5\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x0789\
+    \n\x0b\n\x04\x04\0\x08\x03\x12\x03\x08\x040\n\x0c\n\x05\x04\0\x08\x03\
+    \x01\x12\x03\x08\n\x19\n\x0b\n\x04\x04\0\x02\x04\x12\x03\x08\x1c.\n\x0c\
+    \n\x05\x04\0\x02\x04\x05\x12\x03\x08\x1c\x20\n\x0c\n\x05\x04\0\x02\x04\
+    \x01\x12\x03\x08!)\n\x0c\n\x05\x04\0\x02\x04\x03\x12\x03\x08,-\n\n\n\x02\
+    \x04\x01\x12\x04\n\0\x10\x01\n\n\n\x03\x04\x01\x01\x12\x03\n\x08\x17\n\
+    \x0b\n\x04\x04\x01\x02\0\x12\x03\x0b\x04\x16\n\x0c\n\x05\x04\x01\x02\0\
+    \x05\x12\x03\x0b\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x0b\x0b\x11\
+    \n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x0b\x14\x15\n\x0b\n\x04\x04\x01\
+    \x08\0\x12\x03\x0c\x04*\n\x0c\n\x05\x04\x01\x08\0\x01\x12\x03\x0c\n\x15\
+    \n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x0c\x18(\n\x0c\n\x05\x04\x01\x02\
+    \x01\x05\x12\x03\x0c\x18\x1e\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x0c\
+    \x1f#\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x0c&'\n\x0b\n\x04\x04\x01\
+    \x08\x01\x12\x03\r\x04*\n\x0c\n\x05\x04\x01\x08\x01\x01\x12\x03\r\n\x15\
+    \n\x0b\n\x04\x04\x01\x02\x02\x12\x03\r\x18(\n\x0c\n\x05\x04\x01\x02\x02\
+    \x05\x12\x03\r\x18\x1e\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\r\x1f#\n\
+    \x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\r&'\n\x0b\n\x04\x04\x01\x08\x02\
+    \x12\x03\x0e\x04<\n\x0c\n\x05\x04\x01\x08\x02\x01\x12\x03\x0e\n\x1c\n\
+    \x0b\n\x04\x04\x01\x02\x03\x12\x03\x0e\x1f:\n\x0c\n\x05\x04\x01\x02\x03\
+    \x06\x12\x03\x0e\x1f)\n\x0c\n\x05\x04\x01\x02\x03\x01\x12\x03\x0e*5\n\
+    \x0c\n\x05\x04\x01\x02\x03\x03\x12\x03\x0e89\n\x0b\n\x04\x04\x01\x08\x03\
+    \x12\x03\x0f\x040\n\x0c\n\x05\x04\x01\x08\x03\x01\x12\x03\x0f\n\x19\n\
+    \x0b\n\x04\x04\x01\x02\x04\x12\x03\x0f\x1c.\n\x0c\n\x05\x04\x01\x02\x04\
+    \x05\x12\x03\x0f\x1c\x20\n\x0c\n\x05\x04\x01\x02\x04\x01\x12\x03\x0f!)\n\
+    \x0c\n\x05\x04\x01\x02\x04\x03\x12\x03\x0f,-b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 54 - 48
rust-lib/flowy-workspace/src/protobuf/model/errors.rs

@@ -231,6 +231,7 @@ pub enum WsErrCode {
     WorkspaceDatabaseError = 101,
     UserInternalError = 102,
     UserNotLoginYet = 103,
+    UserIdIsEmpty = 104,
     ServerError = 1000,
     RecordNotFound = 1001,
 }
@@ -258,6 +259,7 @@ impl ::protobuf::ProtobufEnum for WsErrCode {
             101 => ::std::option::Option::Some(WsErrCode::WorkspaceDatabaseError),
             102 => ::std::option::Option::Some(WsErrCode::UserInternalError),
             103 => ::std::option::Option::Some(WsErrCode::UserNotLoginYet),
+            104 => ::std::option::Option::Some(WsErrCode::UserIdIsEmpty),
             1000 => ::std::option::Option::Some(WsErrCode::ServerError),
             1001 => ::std::option::Option::Some(WsErrCode::RecordNotFound),
             _ => ::std::option::Option::None
@@ -282,6 +284,7 @@ impl ::protobuf::ProtobufEnum for WsErrCode {
             WsErrCode::WorkspaceDatabaseError,
             WsErrCode::UserInternalError,
             WsErrCode::UserNotLoginYet,
+            WsErrCode::UserIdIsEmpty,
             WsErrCode::ServerError,
             WsErrCode::RecordNotFound,
         ];
@@ -314,7 +317,7 @@ impl ::protobuf::reflect::ProtobufValue for WsErrCode {
 static file_descriptor_proto_data: &'static [u8] = b"\
     \n\x0cerrors.proto\"B\n\x0eWorkspaceError\x12\x1e\n\x04code\x18\x01\x20\
     \x01(\x0e2\n.WsErrCodeR\x04code\x12\x10\n\x03msg\x18\x02\x20\x01(\tR\x03\
-    msg*\xa4\x03\n\tWsErrCode\x12\x0b\n\x07Unknown\x10\0\x12\x18\n\x14Worksp\
+    msg*\xb7\x03\n\tWsErrCode\x12\x0b\n\x07Unknown\x10\0\x12\x18\n\x14Worksp\
     aceNameInvalid\x10\x01\x12\x16\n\x12WorkspaceIdInvalid\x10\x02\x12\x18\n\
     \x14AppColorStyleInvalid\x10\x03\x12\x18\n\x14WorkspaceDescInvalid\x10\
     \x04\x12\x1c\n\x18CurrentWorkspaceNotFound\x10\x05\x12\x10\n\x0cAppIdInv\
@@ -322,53 +325,56 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     lid\x10\x14\x12\x18\n\x14ViewThumbnailInvalid\x10\x15\x12\x11\n\rViewIdI\
     nvalid\x10\x16\x12\x13\n\x0fViewDescInvalid\x10\x17\x12\x1a\n\x16Databas\
     eConnectionFail\x10d\x12\x1a\n\x16WorkspaceDatabaseError\x10e\x12\x15\n\
-    \x11UserInternalError\x10f\x12\x13\n\x0fUserNotLoginYet\x10g\x12\x10\n\
-    \x0bServerError\x10\xe8\x07\x12\x13\n\x0eRecordNotFound\x10\xe9\x07J\x92\
-    \x07\n\x06\x12\x04\0\0\x19\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
-    \x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x16\n\
-    \x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x17\n\x0c\n\x05\x04\0\x02\0\x06\
-    \x12\x03\x03\x04\r\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0e\x12\n\x0c\
-    \n\x05\x04\0\x02\0\x03\x12\x03\x03\x15\x16\n\x0b\n\x04\x04\0\x02\x01\x12\
-    \x03\x04\x04\x13\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\n\n\x0c\n\
-    \x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\x0e\n\x0c\n\x05\x04\0\x02\x01\x03\
-    \x12\x03\x04\x11\x12\n\n\n\x02\x05\0\x12\x04\x06\0\x19\x01\n\n\n\x03\x05\
-    \0\x01\x12\x03\x06\x05\x0e\n\x0b\n\x04\x05\0\x02\0\x12\x03\x07\x04\x10\n\
-    \x0c\n\x05\x05\0\x02\0\x01\x12\x03\x07\x04\x0b\n\x0c\n\x05\x05\0\x02\0\
-    \x02\x12\x03\x07\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x08\x04\x1d\n\
-    \x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x08\x04\x18\n\x0c\n\x05\x05\0\x02\
-    \x01\x02\x12\x03\x08\x1b\x1c\n\x0b\n\x04\x05\0\x02\x02\x12\x03\t\x04\x1b\
-    \n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\t\x04\x16\n\x0c\n\x05\x05\0\x02\
-    \x02\x02\x12\x03\t\x19\x1a\n\x0b\n\x04\x05\0\x02\x03\x12\x03\n\x04\x1d\n\
-    \x0c\n\x05\x05\0\x02\x03\x01\x12\x03\n\x04\x18\n\x0c\n\x05\x05\0\x02\x03\
-    \x02\x12\x03\n\x1b\x1c\n\x0b\n\x04\x05\0\x02\x04\x12\x03\x0b\x04\x1d\n\
-    \x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x0b\x04\x18\n\x0c\n\x05\x05\0\x02\
-    \x04\x02\x12\x03\x0b\x1b\x1c\n\x0b\n\x04\x05\0\x02\x05\x12\x03\x0c\x04!\
-    \n\x0c\n\x05\x05\0\x02\x05\x01\x12\x03\x0c\x04\x1c\n\x0c\n\x05\x05\0\x02\
-    \x05\x02\x12\x03\x0c\x1f\x20\n\x0b\n\x04\x05\0\x02\x06\x12\x03\r\x04\x16\
-    \n\x0c\n\x05\x05\0\x02\x06\x01\x12\x03\r\x04\x10\n\x0c\n\x05\x05\0\x02\
-    \x06\x02\x12\x03\r\x13\x15\n\x0b\n\x04\x05\0\x02\x07\x12\x03\x0e\x04\x18\
-    \n\x0c\n\x05\x05\0\x02\x07\x01\x12\x03\x0e\x04\x12\n\x0c\n\x05\x05\0\x02\
-    \x07\x02\x12\x03\x0e\x15\x17\n\x0b\n\x04\x05\0\x02\x08\x12\x03\x0f\x04\
-    \x19\n\x0c\n\x05\x05\0\x02\x08\x01\x12\x03\x0f\x04\x13\n\x0c\n\x05\x05\0\
-    \x02\x08\x02\x12\x03\x0f\x16\x18\n\x0b\n\x04\x05\0\x02\t\x12\x03\x10\x04\
-    \x1e\n\x0c\n\x05\x05\0\x02\t\x01\x12\x03\x10\x04\x18\n\x0c\n\x05\x05\0\
-    \x02\t\x02\x12\x03\x10\x1b\x1d\n\x0b\n\x04\x05\0\x02\n\x12\x03\x11\x04\
-    \x17\n\x0c\n\x05\x05\0\x02\n\x01\x12\x03\x11\x04\x11\n\x0c\n\x05\x05\0\
-    \x02\n\x02\x12\x03\x11\x14\x16\n\x0b\n\x04\x05\0\x02\x0b\x12\x03\x12\x04\
-    \x19\n\x0c\n\x05\x05\0\x02\x0b\x01\x12\x03\x12\x04\x13\n\x0c\n\x05\x05\0\
-    \x02\x0b\x02\x12\x03\x12\x16\x18\n\x0b\n\x04\x05\0\x02\x0c\x12\x03\x13\
-    \x04!\n\x0c\n\x05\x05\0\x02\x0c\x01\x12\x03\x13\x04\x1a\n\x0c\n\x05\x05\
-    \0\x02\x0c\x02\x12\x03\x13\x1d\x20\n\x0b\n\x04\x05\0\x02\r\x12\x03\x14\
-    \x04!\n\x0c\n\x05\x05\0\x02\r\x01\x12\x03\x14\x04\x1a\n\x0c\n\x05\x05\0\
-    \x02\r\x02\x12\x03\x14\x1d\x20\n\x0b\n\x04\x05\0\x02\x0e\x12\x03\x15\x04\
-    \x1c\n\x0c\n\x05\x05\0\x02\x0e\x01\x12\x03\x15\x04\x15\n\x0c\n\x05\x05\0\
-    \x02\x0e\x02\x12\x03\x15\x18\x1b\n\x0b\n\x04\x05\0\x02\x0f\x12\x03\x16\
-    \x04\x1a\n\x0c\n\x05\x05\0\x02\x0f\x01\x12\x03\x16\x04\x13\n\x0c\n\x05\
-    \x05\0\x02\x0f\x02\x12\x03\x16\x16\x19\n\x0b\n\x04\x05\0\x02\x10\x12\x03\
-    \x17\x04\x17\n\x0c\n\x05\x05\0\x02\x10\x01\x12\x03\x17\x04\x0f\n\x0c\n\
-    \x05\x05\0\x02\x10\x02\x12\x03\x17\x12\x16\n\x0b\n\x04\x05\0\x02\x11\x12\
-    \x03\x18\x04\x1a\n\x0c\n\x05\x05\0\x02\x11\x01\x12\x03\x18\x04\x12\n\x0c\
-    \n\x05\x05\0\x02\x11\x02\x12\x03\x18\x15\x19b\x06proto3\
+    \x11UserInternalError\x10f\x12\x13\n\x0fUserNotLoginYet\x10g\x12\x11\n\r\
+    UserIdIsEmpty\x10h\x12\x10\n\x0bServerError\x10\xe8\x07\x12\x13\n\x0eRec\
+    ordNotFound\x10\xe9\x07J\xbb\x07\n\x06\x12\x04\0\0\x1a\x01\n\x08\n\x01\
+    \x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\
+    \0\x01\x12\x03\x02\x08\x16\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x17\n\
+    \x0c\n\x05\x04\0\x02\0\x06\x12\x03\x03\x04\r\n\x0c\n\x05\x04\0\x02\0\x01\
+    \x12\x03\x03\x0e\x12\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x15\x16\n\
+    \x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x13\n\x0c\n\x05\x04\0\x02\x01\
+    \x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\x0e\
+    \n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x11\x12\n\n\n\x02\x05\0\x12\
+    \x04\x06\0\x1a\x01\n\n\n\x03\x05\0\x01\x12\x03\x06\x05\x0e\n\x0b\n\x04\
+    \x05\0\x02\0\x12\x03\x07\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x07\
+    \x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x07\x0e\x0f\n\x0b\n\x04\x05\
+    \0\x02\x01\x12\x03\x08\x04\x1d\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x08\
+    \x04\x18\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x08\x1b\x1c\n\x0b\n\x04\
+    \x05\0\x02\x02\x12\x03\t\x04\x1b\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\t\
+    \x04\x16\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\t\x19\x1a\n\x0b\n\x04\x05\
+    \0\x02\x03\x12\x03\n\x04\x1d\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\n\x04\
+    \x18\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\n\x1b\x1c\n\x0b\n\x04\x05\0\
+    \x02\x04\x12\x03\x0b\x04\x1d\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x0b\
+    \x04\x18\n\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x0b\x1b\x1c\n\x0b\n\x04\
+    \x05\0\x02\x05\x12\x03\x0c\x04!\n\x0c\n\x05\x05\0\x02\x05\x01\x12\x03\
+    \x0c\x04\x1c\n\x0c\n\x05\x05\0\x02\x05\x02\x12\x03\x0c\x1f\x20\n\x0b\n\
+    \x04\x05\0\x02\x06\x12\x03\r\x04\x16\n\x0c\n\x05\x05\0\x02\x06\x01\x12\
+    \x03\r\x04\x10\n\x0c\n\x05\x05\0\x02\x06\x02\x12\x03\r\x13\x15\n\x0b\n\
+    \x04\x05\0\x02\x07\x12\x03\x0e\x04\x18\n\x0c\n\x05\x05\0\x02\x07\x01\x12\
+    \x03\x0e\x04\x12\n\x0c\n\x05\x05\0\x02\x07\x02\x12\x03\x0e\x15\x17\n\x0b\
+    \n\x04\x05\0\x02\x08\x12\x03\x0f\x04\x19\n\x0c\n\x05\x05\0\x02\x08\x01\
+    \x12\x03\x0f\x04\x13\n\x0c\n\x05\x05\0\x02\x08\x02\x12\x03\x0f\x16\x18\n\
+    \x0b\n\x04\x05\0\x02\t\x12\x03\x10\x04\x1e\n\x0c\n\x05\x05\0\x02\t\x01\
+    \x12\x03\x10\x04\x18\n\x0c\n\x05\x05\0\x02\t\x02\x12\x03\x10\x1b\x1d\n\
+    \x0b\n\x04\x05\0\x02\n\x12\x03\x11\x04\x17\n\x0c\n\x05\x05\0\x02\n\x01\
+    \x12\x03\x11\x04\x11\n\x0c\n\x05\x05\0\x02\n\x02\x12\x03\x11\x14\x16\n\
+    \x0b\n\x04\x05\0\x02\x0b\x12\x03\x12\x04\x19\n\x0c\n\x05\x05\0\x02\x0b\
+    \x01\x12\x03\x12\x04\x13\n\x0c\n\x05\x05\0\x02\x0b\x02\x12\x03\x12\x16\
+    \x18\n\x0b\n\x04\x05\0\x02\x0c\x12\x03\x13\x04!\n\x0c\n\x05\x05\0\x02\
+    \x0c\x01\x12\x03\x13\x04\x1a\n\x0c\n\x05\x05\0\x02\x0c\x02\x12\x03\x13\
+    \x1d\x20\n\x0b\n\x04\x05\0\x02\r\x12\x03\x14\x04!\n\x0c\n\x05\x05\0\x02\
+    \r\x01\x12\x03\x14\x04\x1a\n\x0c\n\x05\x05\0\x02\r\x02\x12\x03\x14\x1d\
+    \x20\n\x0b\n\x04\x05\0\x02\x0e\x12\x03\x15\x04\x1c\n\x0c\n\x05\x05\0\x02\
+    \x0e\x01\x12\x03\x15\x04\x15\n\x0c\n\x05\x05\0\x02\x0e\x02\x12\x03\x15\
+    \x18\x1b\n\x0b\n\x04\x05\0\x02\x0f\x12\x03\x16\x04\x1a\n\x0c\n\x05\x05\0\
+    \x02\x0f\x01\x12\x03\x16\x04\x13\n\x0c\n\x05\x05\0\x02\x0f\x02\x12\x03\
+    \x16\x16\x19\n\x0b\n\x04\x05\0\x02\x10\x12\x03\x17\x04\x18\n\x0c\n\x05\
+    \x05\0\x02\x10\x01\x12\x03\x17\x04\x11\n\x0c\n\x05\x05\0\x02\x10\x02\x12\
+    \x03\x17\x14\x17\n\x0b\n\x04\x05\0\x02\x11\x12\x03\x18\x04\x17\n\x0c\n\
+    \x05\x05\0\x02\x11\x01\x12\x03\x18\x04\x0f\n\x0c\n\x05\x05\0\x02\x11\x02\
+    \x12\x03\x18\x12\x16\n\x0b\n\x04\x05\0\x02\x12\x12\x03\x19\x04\x1a\n\x0c\
+    \n\x05\x05\0\x02\x12\x01\x12\x03\x19\x04\x12\n\x0c\n\x05\x05\0\x02\x12\
+    \x02\x12\x03\x19\x15\x19b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 88 - 43
rust-lib/flowy-workspace/src/protobuf/model/workspace_create.rs

@@ -28,6 +28,7 @@ pub struct CreateWorkspaceRequest {
     // message fields
     pub name: ::std::string::String,
     pub desc: ::std::string::String,
+    pub user_id: ::std::string::String,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
@@ -95,6 +96,32 @@ impl CreateWorkspaceRequest {
     pub fn take_desc(&mut self) -> ::std::string::String {
         ::std::mem::replace(&mut self.desc, ::std::string::String::new())
     }
+
+    // string user_id = 3;
+
+
+    pub fn get_user_id(&self) -> &str {
+        &self.user_id
+    }
+    pub fn clear_user_id(&mut self) {
+        self.user_id.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_user_id(&mut self, v: ::std::string::String) {
+        self.user_id = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_user_id(&mut self) -> &mut ::std::string::String {
+        &mut self.user_id
+    }
+
+    // Take field
+    pub fn take_user_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.user_id, ::std::string::String::new())
+    }
 }
 
 impl ::protobuf::Message for CreateWorkspaceRequest {
@@ -112,6 +139,9 @@ impl ::protobuf::Message for CreateWorkspaceRequest {
                 2 => {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.desc)?;
                 },
+                3 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.user_id)?;
+                },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
                 },
@@ -130,6 +160,9 @@ impl ::protobuf::Message for CreateWorkspaceRequest {
         if !self.desc.is_empty() {
             my_size += ::protobuf::rt::string_size(2, &self.desc);
         }
+        if !self.user_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(3, &self.user_id);
+        }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
         my_size
@@ -142,6 +175,9 @@ impl ::protobuf::Message for CreateWorkspaceRequest {
         if !self.desc.is_empty() {
             os.write_string(2, &self.desc)?;
         }
+        if !self.user_id.is_empty() {
+            os.write_string(3, &self.user_id)?;
+        }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
     }
@@ -190,6 +226,11 @@ impl ::protobuf::Message for CreateWorkspaceRequest {
                 |m: &CreateWorkspaceRequest| { &m.desc },
                 |m: &mut CreateWorkspaceRequest| { &mut m.desc },
             ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "user_id",
+                |m: &CreateWorkspaceRequest| { &m.user_id },
+                |m: &mut CreateWorkspaceRequest| { &mut m.user_id },
+            ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<CreateWorkspaceRequest>(
                 "CreateWorkspaceRequest",
                 fields,
@@ -208,6 +249,7 @@ impl ::protobuf::Clear for CreateWorkspaceRequest {
     fn clear(&mut self) {
         self.name.clear();
         self.desc.clear();
+        self.user_id.clear();
         self.unknown_fields.clear();
     }
 }
@@ -934,50 +976,53 @@ impl ::protobuf::reflect::ProtobufValue for RepeatedWorkspace {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x16workspace_create.proto\x1a\x10app_create.proto\"@\n\x16CreateWorks\
+    \n\x16workspace_create.proto\x1a\x10app_create.proto\"Y\n\x16CreateWorks\
     paceRequest\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\x12\x12\n\x04d\
-    esc\x18\x02\x20\x01(\tR\x04desc\"X\n\x15CreateWorkspaceParams\x12\x12\n\
-    \x04name\x18\x01\x20\x01(\tR\x04name\x12\x12\n\x04desc\x18\x02\x20\x01(\
-    \tR\x04desc\x12\x17\n\x07user_id\x18\x03\x20\x01(\tR\x06userId\"e\n\tWor\
-    kspace\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x12\n\x04name\x18\
-    \x02\x20\x01(\tR\x04name\x12\x12\n\x04desc\x18\x03\x20\x01(\tR\x04desc\
-    \x12\x20\n\x04apps\x18\x04\x20\x01(\x0b2\x0c.RepeatedAppR\x04apps\"5\n\
-    \x11RepeatedWorkspace\x12\x20\n\x05items\x18\x01\x20\x03(\x0b2\n.Workspa\
-    ceR\x05itemsJ\xb1\x05\n\x06\x12\x04\0\0\x14\x01\n\x08\n\x01\x0c\x12\x03\
-    \0\0\x12\n\t\n\x02\x03\0\x12\x03\x01\0\x1a\n\n\n\x02\x04\0\x12\x04\x03\0\
-    \x06\x01\n\n\n\x03\x04\0\x01\x12\x03\x03\x08\x1e\n\x0b\n\x04\x04\0\x02\0\
-    \x12\x03\x04\x04\x14\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x04\x04\n\n\x0c\
-    \n\x05\x04\0\x02\0\x01\x12\x03\x04\x0b\x0f\n\x0c\n\x05\x04\0\x02\0\x03\
-    \x12\x03\x04\x12\x13\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x05\x04\x14\n\x0c\
-    \n\x05\x04\0\x02\x01\x05\x12\x03\x05\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\
-    \x12\x03\x05\x0b\x0f\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x05\x12\x13\n\
-    \n\n\x02\x04\x01\x12\x04\x07\0\x0b\x01\n\n\n\x03\x04\x01\x01\x12\x03\x07\
-    \x08\x1d\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x08\x04\x14\n\x0c\n\x05\x04\
-    \x01\x02\0\x05\x12\x03\x08\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\
-    \x08\x0b\x0f\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x08\x12\x13\n\x0b\n\
-    \x04\x04\x01\x02\x01\x12\x03\t\x04\x14\n\x0c\n\x05\x04\x01\x02\x01\x05\
-    \x12\x03\t\x04\n\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\t\x0b\x0f\n\x0c\
-    \n\x05\x04\x01\x02\x01\x03\x12\x03\t\x12\x13\n\x0b\n\x04\x04\x01\x02\x02\
-    \x12\x03\n\x04\x17\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\n\x04\n\n\x0c\
-    \n\x05\x04\x01\x02\x02\x01\x12\x03\n\x0b\x12\n\x0c\n\x05\x04\x01\x02\x02\
-    \x03\x12\x03\n\x15\x16\n\n\n\x02\x04\x02\x12\x04\x0c\0\x11\x01\n\n\n\x03\
-    \x04\x02\x01\x12\x03\x0c\x08\x11\n\x0b\n\x04\x04\x02\x02\0\x12\x03\r\x04\
-    \x12\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\r\x04\n\n\x0c\n\x05\x04\x02\
-    \x02\0\x01\x12\x03\r\x0b\r\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\r\x10\
-    \x11\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x0e\x04\x14\n\x0c\n\x05\x04\x02\
-    \x02\x01\x05\x12\x03\x0e\x04\n\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\
-    \x0e\x0b\x0f\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x0e\x12\x13\n\x0b\n\
-    \x04\x04\x02\x02\x02\x12\x03\x0f\x04\x14\n\x0c\n\x05\x04\x02\x02\x02\x05\
-    \x12\x03\x0f\x04\n\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\x0f\x0b\x0f\n\
-    \x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\x0f\x12\x13\n\x0b\n\x04\x04\x02\
-    \x02\x03\x12\x03\x10\x04\x19\n\x0c\n\x05\x04\x02\x02\x03\x06\x12\x03\x10\
-    \x04\x0f\n\x0c\n\x05\x04\x02\x02\x03\x01\x12\x03\x10\x10\x14\n\x0c\n\x05\
-    \x04\x02\x02\x03\x03\x12\x03\x10\x17\x18\n\n\n\x02\x04\x03\x12\x04\x12\0\
-    \x14\x01\n\n\n\x03\x04\x03\x01\x12\x03\x12\x08\x19\n\x0b\n\x04\x04\x03\
-    \x02\0\x12\x03\x13\x04!\n\x0c\n\x05\x04\x03\x02\0\x04\x12\x03\x13\x04\
-    \x0c\n\x0c\n\x05\x04\x03\x02\0\x06\x12\x03\x13\r\x16\n\x0c\n\x05\x04\x03\
-    \x02\0\x01\x12\x03\x13\x17\x1c\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x13\
-    \x1f\x20b\x06proto3\
+    esc\x18\x02\x20\x01(\tR\x04desc\x12\x17\n\x07user_id\x18\x03\x20\x01(\tR\
+    \x06userId\"X\n\x15CreateWorkspaceParams\x12\x12\n\x04name\x18\x01\x20\
+    \x01(\tR\x04name\x12\x12\n\x04desc\x18\x02\x20\x01(\tR\x04desc\x12\x17\n\
+    \x07user_id\x18\x03\x20\x01(\tR\x06userId\"e\n\tWorkspace\x12\x0e\n\x02i\
+    d\x18\x01\x20\x01(\tR\x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04nam\
+    e\x12\x12\n\x04desc\x18\x03\x20\x01(\tR\x04desc\x12\x20\n\x04apps\x18\
+    \x04\x20\x01(\x0b2\x0c.RepeatedAppR\x04apps\"5\n\x11RepeatedWorkspace\
+    \x12\x20\n\x05items\x18\x01\x20\x03(\x0b2\n.WorkspaceR\x05itemsJ\xe8\x05\
+    \n\x06\x12\x04\0\0\x15\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\t\n\x02\x03\
+    \0\x12\x03\x01\0\x1a\n\n\n\x02\x04\0\x12\x04\x03\0\x07\x01\n\n\n\x03\x04\
+    \0\x01\x12\x03\x03\x08\x1e\n\x0b\n\x04\x04\0\x02\0\x12\x03\x04\x04\x14\n\
+    \x0c\n\x05\x04\0\x02\0\x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\
+    \x12\x03\x04\x0b\x0f\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x04\x12\x13\n\
+    \x0b\n\x04\x04\0\x02\x01\x12\x03\x05\x04\x14\n\x0c\n\x05\x04\0\x02\x01\
+    \x05\x12\x03\x05\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x05\x0b\x0f\
+    \n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x05\x12\x13\n\x0b\n\x04\x04\0\x02\
+    \x02\x12\x03\x06\x04\x17\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x06\x04\n\
+    \n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x06\x0b\x12\n\x0c\n\x05\x04\0\x02\
+    \x02\x03\x12\x03\x06\x15\x16\n\n\n\x02\x04\x01\x12\x04\x08\0\x0c\x01\n\n\
+    \n\x03\x04\x01\x01\x12\x03\x08\x08\x1d\n\x0b\n\x04\x04\x01\x02\0\x12\x03\
+    \t\x04\x14\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\
+    \x01\x02\0\x01\x12\x03\t\x0b\x0f\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\t\
+    \x12\x13\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\n\x04\x14\n\x0c\n\x05\x04\
+    \x01\x02\x01\x05\x12\x03\n\x04\n\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\
+    \n\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\n\x12\x13\n\x0b\n\x04\
+    \x04\x01\x02\x02\x12\x03\x0b\x04\x17\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\
+    \x03\x0b\x04\n\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\x0b\x0b\x12\n\x0c\
+    \n\x05\x04\x01\x02\x02\x03\x12\x03\x0b\x15\x16\n\n\n\x02\x04\x02\x12\x04\
+    \r\0\x12\x01\n\n\n\x03\x04\x02\x01\x12\x03\r\x08\x11\n\x0b\n\x04\x04\x02\
+    \x02\0\x12\x03\x0e\x04\x12\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0e\x04\
+    \n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0e\x0b\r\n\x0c\n\x05\x04\x02\
+    \x02\0\x03\x12\x03\x0e\x10\x11\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x0f\
+    \x04\x14\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\x0f\x04\n\n\x0c\n\x05\
+    \x04\x02\x02\x01\x01\x12\x03\x0f\x0b\x0f\n\x0c\n\x05\x04\x02\x02\x01\x03\
+    \x12\x03\x0f\x12\x13\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\x10\x04\x14\n\
+    \x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\x10\x04\n\n\x0c\n\x05\x04\x02\x02\
+    \x02\x01\x12\x03\x10\x0b\x0f\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\x10\
+    \x12\x13\n\x0b\n\x04\x04\x02\x02\x03\x12\x03\x11\x04\x19\n\x0c\n\x05\x04\
+    \x02\x02\x03\x06\x12\x03\x11\x04\x0f\n\x0c\n\x05\x04\x02\x02\x03\x01\x12\
+    \x03\x11\x10\x14\n\x0c\n\x05\x04\x02\x02\x03\x03\x12\x03\x11\x17\x18\n\n\
+    \n\x02\x04\x03\x12\x04\x13\0\x15\x01\n\n\n\x03\x04\x03\x01\x12\x03\x13\
+    \x08\x19\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x14\x04!\n\x0c\n\x05\x04\x03\
+    \x02\0\x04\x12\x03\x14\x04\x0c\n\x0c\n\x05\x04\x03\x02\0\x06\x12\x03\x14\
+    \r\x16\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x14\x17\x1c\n\x0c\n\x05\x04\
+    \x03\x02\0\x03\x12\x03\x14\x1f\x20b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 8 - 10
rust-lib/flowy-workspace/src/protobuf/proto/app_update.proto

@@ -3,17 +3,15 @@ import "app_create.proto";
 
 message UpdateAppRequest {
     string app_id = 1;
-    oneof one_of_workspace_id { string workspace_id = 2; };
-    oneof one_of_name { string name = 3; };
-    oneof one_of_desc { string desc = 4; };
-    oneof one_of_color_style { ColorStyle color_style = 5; };
-    oneof one_of_is_trash { bool is_trash = 6; };
+    oneof one_of_name { string name = 2; };
+    oneof one_of_desc { string desc = 3; };
+    oneof one_of_color_style { ColorStyle color_style = 4; };
+    oneof one_of_is_trash { bool is_trash = 5; };
 }
 message UpdateAppParams {
     string app_id = 1;
-    oneof one_of_workspace_id { string workspace_id = 2; };
-    oneof one_of_name { string name = 3; };
-    oneof one_of_desc { string desc = 4; };
-    oneof one_of_color_style { ColorStyle color_style = 5; };
-    oneof one_of_is_trash { bool is_trash = 6; };
+    oneof one_of_name { string name = 2; };
+    oneof one_of_desc { string desc = 3; };
+    oneof one_of_color_style { ColorStyle color_style = 4; };
+    oneof one_of_is_trash { bool is_trash = 5; };
 }

+ 1 - 0
rust-lib/flowy-workspace/src/protobuf/proto/errors.proto

@@ -21,6 +21,7 @@ enum WsErrCode {
     WorkspaceDatabaseError = 101;
     UserInternalError = 102;
     UserNotLoginYet = 103;
+    UserIdIsEmpty = 104;
     ServerError = 1000;
     RecordNotFound = 1001;
 }

+ 1 - 0
rust-lib/flowy-workspace/src/protobuf/proto/workspace_create.proto

@@ -4,6 +4,7 @@ import "app_create.proto";
 message CreateWorkspaceRequest {
     string name = 1;
     string desc = 2;
+    string user_id = 3;
 }
 message CreateWorkspaceParams {
     string name = 1;

+ 2 - 4
rust-lib/flowy-workspace/src/services/workspace_controller.rs

@@ -33,11 +33,9 @@ impl WorkspaceController {
 
     pub async fn create_workspace(
         &self,
-        mut params: CreateWorkspaceParams,
+        params: CreateWorkspaceParams,
     ) -> Result<Workspace, WorkspaceError> {
-        let user_id = self.user.user_id()?;
-        params.user_id = user_id.clone();
-
+        let user_id = params.user_id.clone();
         // TODO: server
 
         let workspace_table = WorkspaceTable::new(params, &user_id);

+ 0 - 2
rust-lib/flowy-workspace/src/sql_tables/app/app_table.rs

@@ -83,7 +83,6 @@ impl_sql_binary_expression!(ColorStyleCol);
 #[table_name = "app_table"]
 pub struct AppTableChangeset {
     pub id: String,
-    pub workspace_id: Option<String>,
     pub name: Option<String>,
     pub desc: Option<String>,
     pub is_trash: Option<bool>,
@@ -93,7 +92,6 @@ impl AppTableChangeset {
     pub fn new(params: UpdateAppParams) -> Self {
         AppTableChangeset {
             id: params.app_id,
-            workspace_id: params.workspace_id,
             name: params.name,
             desc: params.desc,
             is_trash: params.is_trash,

+ 9 - 5
rust-lib/flowy-workspace/src/sql_tables/workspace/workspace_sql.rs

@@ -29,12 +29,16 @@ impl WorkspaceSql {
         workspace_id: Option<String>,
         user_id: &str,
     ) -> Result<Vec<WorkspaceTable>, WorkspaceError> {
-        let mut filter = dsl::workspace_table.filter(workspace_table::user_id.eq(user_id));
-        if let Some(workspace_id) = workspace_id {
-            filter.filter(workspace_table::id.eq(&workspace_id));
-        }
+        let workspaces = match workspace_id {
+            None => dsl::workspace_table
+                .filter(workspace_table::user_id.eq(user_id))
+                .load::<WorkspaceTable>(&*(self.database.db_connection()?))?,
+            Some(workspace_id) => dsl::workspace_table
+                .filter(workspace_table::user_id.eq(user_id))
+                .filter(workspace_table::id.eq(&workspace_id))
+                .load::<WorkspaceTable>(&*(self.database.db_connection()?))?,
+        };
 
-        let workspaces = filter.load::<WorkspaceTable>(&*(self.database.db_connection()?))?;
         Ok(workspaces)
     }
 

+ 10 - 6
rust-lib/flowy-workspace/tests/event/app_test.rs

@@ -7,14 +7,16 @@ use flowy_workspace::entities::{
 
 #[test]
 fn app_create_success() {
-    let app = create_app("App A", "AppFlowy Github Project");
+    let workspace = create_workspace("Workspace", "").1;
+    let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
     dbg!(&app);
 }
 
 #[test]
 #[should_panic]
 fn app_delete_success() {
-    let app = create_app("App A", "AppFlowy Github Project");
+    let workspace = create_workspace("Workspace", "").1;
+    let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
     delete_app(&app.id);
     let query = QueryAppRequest::new(&app.id);
     let _ = read_app(query);
@@ -22,7 +24,8 @@ fn app_delete_success() {
 
 #[test]
 fn app_create_and_then_get_success() {
-    let app = create_app("App A", "AppFlowy Github Project");
+    let workspace = create_workspace("Workspace", "").1;
+    let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
     let query = QueryAppRequest::new(&app.id);
     let app_from_db = read_app(query);
     assert_eq!(app_from_db, app);
@@ -30,7 +33,8 @@ fn app_create_and_then_get_success() {
 
 #[test]
 fn app_create_with_view_and_then_get_success() {
-    let app = create_app("App A", "AppFlowy Github Project");
+    let workspace = create_workspace("Workspace", "").1;
+    let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
     let request_a = CreateViewRequest {
         belong_to_id: app.id.clone(),
         name: "View A".to_string(),
@@ -73,10 +77,10 @@ fn app_update_with_trash_flag_and_read_without_trash_flag_fail() {
 }
 
 pub fn create_app_with_trash_flag() -> String {
-    let app = create_app("App A", "AppFlowy Github Project");
+    let workspace = create_workspace("Workspace", "").1;
+    let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
     let request = UpdateAppRequest {
         app_id: app.id.clone(),
-        workspace_id: None,
         name: None,
         desc: None,
         color_style: None,

+ 19 - 12
rust-lib/flowy-workspace/tests/event/helper.rs

@@ -11,36 +11,42 @@ pub(crate) fn invalid_workspace_name_test_case() -> Vec<String> {
         .collect::<Vec<_>>()
 }
 
-pub fn create_workspace(name: &str, desc: &str) -> Workspace {
+pub fn create_workspace(name: &str, desc: &str) -> (String, Workspace) {
+    let builder = SingleUserTestBuilder::new();
+    let user_id = builder.user_detail.as_ref().unwrap().id.clone();
+
     let request = CreateWorkspaceRequest {
         name: name.to_owned(),
         desc: desc.to_owned(),
+        user_id: user_id.clone(),
     };
 
-    let workspace = SingleUserTestBuilder::new()
+    let workspace = builder
         .event(CreateWorkspace)
         .request(request)
         .sync_send()
         .parse::<Workspace>();
 
-    workspace
+    (user_id, workspace)
 }
 
-pub fn read_workspace(request: QueryWorkspaceRequest) -> Workspace {
-    let workspace = SingleUserTestBuilder::new()
+pub fn read_workspaces(request: QueryWorkspaceRequest) -> Option<Workspace> {
+    let mut repeated_workspace = SingleUserTestBuilder::new()
         .event(ReadWorkspace)
         .request(request)
         .sync_send()
-        .parse::<Workspace>();
+        .parse::<RepeatedWorkspace>();
 
-    workspace
+    debug_assert_eq!(repeated_workspace.len(), 1);
+    repeated_workspace
+        .drain(..1)
+        .collect::<Vec<Workspace>>()
+        .pop()
 }
 
-pub fn create_app(name: &str, desc: &str) -> App {
-    let workspace = create_workspace("Workspace", "");
-
+pub fn create_app(name: &str, desc: &str, workspace_id: &str) -> App {
     let create_app_request = CreateAppRequest {
-        workspace_id: workspace.id,
+        workspace_id: workspace_id.to_owned(),
         name: name.to_string(),
         desc: desc.to_string(),
         color_style: Default::default(),
@@ -93,7 +99,8 @@ pub fn create_view_with_request(request: CreateViewRequest) -> View {
 }
 
 pub fn create_view() -> View {
-    let app = create_app("App A", "AppFlowy Github Project");
+    let workspace = create_workspace("Workspace", "").1;
+    let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
     let request = CreateViewRequest {
         belong_to_id: app.id.clone(),
         name: "View A".to_string(),

+ 28 - 11
rust-lib/flowy-workspace/tests/event/workspace_test.rs

@@ -15,7 +15,14 @@ fn workspace_create_success() { let _ = create_workspace("First workspace", "");
 
 #[test]
 fn workspace_get_success() {
-    let workspace = SingleUserTestBuilder::new()
+    let builder = SingleUserTestBuilder::new();
+
+    let _workspaces = SingleUserTestBuilder::new()
+        .event(ReadAllWorkspace)
+        .sync_send()
+        .parse::<RepeatedWorkspace>();
+
+    let workspace = builder
         .event(ReadCurWorkspace)
         .sync_send()
         .parse::<Workspace>();
@@ -35,41 +42,47 @@ fn workspace_read_all_success() {
 
 #[test]
 fn workspace_create_and_then_get_workspace_success() {
-    let workspace = create_workspace(
+    let (user_id, workspace) = create_workspace(
         "Workspace A",
         "workspace_create_and_then_get_workspace_success",
     );
     let request = QueryWorkspaceRequest {
-        workspace_id: workspace.id.clone(),
-        read_apps: false,
+        workspace_id: Some(workspace.id.clone()),
+        user_id,
     };
 
-    let workspace_from_db = read_workspace(request);
+    let workspace_from_db = read_workspaces(request).unwrap();
     assert_eq!(workspace.name, workspace_from_db.name);
 }
 
 #[test]
 fn workspace_create_with_apps_success() {
-    let app = create_app("App A", "");
+    let (user_id, workspace) = create_workspace("Workspace", "");
+    let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
+
     let query_workspace_request = QueryWorkspaceRequest {
-        workspace_id: app.workspace_id.clone(),
-        read_apps: true,
+        workspace_id: Some(workspace.id),
+        user_id,
     };
 
-    let workspace_from_db = read_workspace(query_workspace_request);
+    let workspace_from_db = read_workspaces(query_workspace_request).unwrap();
     assert_eq!(&app, workspace_from_db.apps.first_or_crash());
 }
 
 #[test]
 fn workspace_create_with_invalid_name_test() {
     for name in invalid_workspace_name_test_case() {
+        let builder = SingleUserTestBuilder::new();
+        let user_id = builder.user_detail.as_ref().unwrap().id.clone();
+
         let request = CreateWorkspaceRequest {
             name,
             desc: "".to_owned(),
+            user_id: user_id.clone(),
         };
 
         assert_eq!(
-            SingleUserTestBuilder::new()
+            builder
                 .event(CreateWorkspace)
                 .request(request)
                 .sync_send()
@@ -83,13 +96,17 @@ fn workspace_create_with_invalid_name_test() {
 #[test]
 fn workspace_update_with_invalid_name_test() {
     for name in invalid_workspace_name_test_case() {
+        let builder = SingleUserTestBuilder::new();
+        let user_id = builder.user_detail.as_ref().unwrap().id.clone();
+
         let request = CreateWorkspaceRequest {
             name,
             desc: "".to_owned(),
+            user_id: user_id.clone(),
         };
 
         assert_eq!(
-            SingleUserTestBuilder::new()
+            builder
                 .event(CreateWorkspace)
                 .request(request)
                 .sync_send()