auth_test.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. use std::collections::HashMap;
  2. use assert_json_diff::assert_json_eq;
  3. use collab_database::rows::database_row_document_id_from_row_id;
  4. use collab_document::blocks::DocumentData;
  5. use collab_entity::CollabType;
  6. use collab_folder::core::FolderData;
  7. use nanoid::nanoid;
  8. use serde_json::json;
  9. use event_integration::document::document_event::DocumentEventTest;
  10. use event_integration::event_builder::EventBuilder;
  11. use event_integration::FlowyCoreTest;
  12. use flowy_core::DEFAULT_NAME;
  13. use flowy_encrypt::decrypt_text;
  14. use flowy_server::supabase::define::{USER_EMAIL, USER_UUID};
  15. use flowy_user::entities::{AuthTypePB, OauthSignInPB, UpdateUserProfilePayloadPB, UserProfilePB};
  16. use flowy_user::errors::ErrorCode;
  17. use flowy_user::event_map::UserEvent::*;
  18. use crate::util::*;
  19. #[tokio::test]
  20. async fn third_party_sign_up_test() {
  21. if get_supabase_config().is_some() {
  22. let test = FlowyCoreTest::new();
  23. let mut map = HashMap::new();
  24. map.insert(USER_UUID.to_string(), uuid::Uuid::new_v4().to_string());
  25. map.insert(
  26. USER_EMAIL.to_string(),
  27. format!("{}@appflowy.io", nanoid!(6)),
  28. );
  29. let payload = OauthSignInPB {
  30. map,
  31. auth_type: AuthTypePB::Supabase,
  32. };
  33. let response = EventBuilder::new(test.clone())
  34. .event(OauthSignIn)
  35. .payload(payload)
  36. .async_send()
  37. .await
  38. .parse::<UserProfilePB>();
  39. dbg!(&response);
  40. }
  41. }
  42. #[tokio::test]
  43. async fn third_party_sign_up_with_encrypt_test() {
  44. if get_supabase_config().is_some() {
  45. let test = FlowyCoreTest::new();
  46. test.supabase_party_sign_up().await;
  47. let user_profile = test.get_user_profile().await.unwrap();
  48. assert!(user_profile.encryption_sign.is_empty());
  49. let secret = test.enable_encryption().await;
  50. let user_profile = test.get_user_profile().await.unwrap();
  51. assert!(!user_profile.encryption_sign.is_empty());
  52. let decryption_sign = decrypt_text(user_profile.encryption_sign, &secret).unwrap();
  53. assert_eq!(decryption_sign, user_profile.id.to_string());
  54. }
  55. }
  56. #[tokio::test]
  57. async fn third_party_sign_up_with_duplicated_uuid() {
  58. if get_supabase_config().is_some() {
  59. let test = FlowyCoreTest::new();
  60. let email = format!("{}@appflowy.io", nanoid!(6));
  61. let mut map = HashMap::new();
  62. map.insert(USER_UUID.to_string(), uuid::Uuid::new_v4().to_string());
  63. map.insert(USER_EMAIL.to_string(), email.clone());
  64. let response_1 = EventBuilder::new(test.clone())
  65. .event(OauthSignIn)
  66. .payload(OauthSignInPB {
  67. map: map.clone(),
  68. auth_type: AuthTypePB::Supabase,
  69. })
  70. .async_send()
  71. .await
  72. .parse::<UserProfilePB>();
  73. dbg!(&response_1);
  74. let response_2 = EventBuilder::new(test.clone())
  75. .event(OauthSignIn)
  76. .payload(OauthSignInPB {
  77. map: map.clone(),
  78. auth_type: AuthTypePB::Supabase,
  79. })
  80. .async_send()
  81. .await
  82. .parse::<UserProfilePB>();
  83. assert_eq!(response_1, response_2);
  84. };
  85. }
  86. #[tokio::test]
  87. async fn third_party_sign_up_with_duplicated_email() {
  88. if get_supabase_config().is_some() {
  89. let test = FlowyCoreTest::new();
  90. let email = format!("{}@appflowy.io", nanoid!(6));
  91. test
  92. .supabase_sign_up_with_uuid(&uuid::Uuid::new_v4().to_string(), Some(email.clone()))
  93. .await
  94. .unwrap();
  95. let error = test
  96. .supabase_sign_up_with_uuid(&uuid::Uuid::new_v4().to_string(), Some(email.clone()))
  97. .await
  98. .err()
  99. .unwrap();
  100. assert_eq!(error.code, ErrorCode::Conflict);
  101. };
  102. }
  103. #[tokio::test]
  104. async fn sign_up_as_guest_and_then_update_to_new_cloud_user_test() {
  105. if get_supabase_config().is_some() {
  106. let test = FlowyCoreTest::new_with_guest_user().await;
  107. let old_views = test
  108. .folder_manager
  109. .get_current_workspace_views()
  110. .await
  111. .unwrap();
  112. let old_workspace = test.folder_manager.get_current_workspace().await.unwrap();
  113. let uuid = uuid::Uuid::new_v4().to_string();
  114. test.supabase_sign_up_with_uuid(&uuid, None).await.unwrap();
  115. let new_views = test
  116. .folder_manager
  117. .get_current_workspace_views()
  118. .await
  119. .unwrap();
  120. let new_workspace = test.folder_manager.get_current_workspace().await.unwrap();
  121. assert_eq!(old_views.len(), new_views.len());
  122. assert_eq!(old_workspace.name, new_workspace.name);
  123. assert_eq!(old_workspace.views.len(), new_workspace.views.len());
  124. for (index, view) in old_views.iter().enumerate() {
  125. assert_eq!(view.name, new_views[index].name);
  126. assert_eq!(view.id, new_views[index].id);
  127. assert_eq!(view.layout, new_views[index].layout);
  128. assert_eq!(view.create_time, new_views[index].create_time);
  129. }
  130. }
  131. }
  132. #[tokio::test]
  133. async fn sign_up_as_guest_and_then_update_to_existing_cloud_user_test() {
  134. if get_supabase_config().is_some() {
  135. let test = FlowyCoreTest::new_with_guest_user().await;
  136. let uuid = uuid::Uuid::new_v4().to_string();
  137. let email = format!("{}@appflowy.io", nanoid!(6));
  138. // The workspace of the guest will be migrated to the new user with given uuid
  139. let _user_profile = test
  140. .supabase_sign_up_with_uuid(&uuid, Some(email.clone()))
  141. .await
  142. .unwrap();
  143. let old_cloud_workspace = test.folder_manager.get_current_workspace().await.unwrap();
  144. let old_cloud_views = test
  145. .folder_manager
  146. .get_current_workspace_views()
  147. .await
  148. .unwrap();
  149. assert_eq!(old_cloud_views.len(), 1);
  150. assert_eq!(old_cloud_views.first().unwrap().child_views.len(), 1);
  151. // sign out and then sign in as a guest
  152. test.sign_out().await;
  153. let _sign_up_context = test.sign_up_as_guest().await;
  154. let new_workspace = test.folder_manager.get_current_workspace().await.unwrap();
  155. test
  156. .create_view(&new_workspace.id, "new workspace child view".to_string())
  157. .await;
  158. let new_workspace = test.folder_manager.get_current_workspace().await.unwrap();
  159. assert_eq!(new_workspace.views.len(), 2);
  160. // upload to cloud user with given uuid. This time the workspace of the guest will not be merged
  161. // because the cloud user already has a workspace
  162. test
  163. .supabase_sign_up_with_uuid(&uuid, Some(email))
  164. .await
  165. .unwrap();
  166. let new_cloud_workspace = test.folder_manager.get_current_workspace().await.unwrap();
  167. let new_cloud_views = test
  168. .folder_manager
  169. .get_current_workspace_views()
  170. .await
  171. .unwrap();
  172. assert_eq!(new_cloud_workspace, old_cloud_workspace);
  173. assert_eq!(new_cloud_views, old_cloud_views);
  174. }
  175. }
  176. #[tokio::test]
  177. async fn check_not_exist_user_test() {
  178. if let Some(test) = FlowySupabaseTest::new() {
  179. let err = test
  180. .check_user_with_uuid(&uuid::Uuid::new_v4().to_string())
  181. .await
  182. .unwrap_err();
  183. assert_eq!(err.code, ErrorCode::RecordNotFound);
  184. }
  185. }
  186. #[tokio::test]
  187. async fn get_user_profile_test() {
  188. if let Some(test) = FlowySupabaseTest::new() {
  189. let uuid = uuid::Uuid::new_v4().to_string();
  190. test.supabase_sign_up_with_uuid(&uuid, None).await.unwrap();
  191. let result = test.get_user_profile().await;
  192. assert!(result.is_ok());
  193. }
  194. }
  195. #[tokio::test]
  196. async fn update_user_profile_test() {
  197. if let Some(test) = FlowySupabaseTest::new() {
  198. let uuid = uuid::Uuid::new_v4().to_string();
  199. let profile = test.supabase_sign_up_with_uuid(&uuid, None).await.unwrap();
  200. test
  201. .update_user_profile(UpdateUserProfilePayloadPB::new(profile.id).name("lucas"))
  202. .await;
  203. let new_profile = test.get_user_profile().await.unwrap();
  204. assert_eq!(new_profile.name, "lucas")
  205. }
  206. }
  207. #[tokio::test]
  208. async fn update_user_profile_with_existing_email_test() {
  209. if let Some(test) = FlowySupabaseTest::new() {
  210. let email = format!("{}@appflowy.io", nanoid!(6));
  211. let _ = test
  212. .supabase_sign_up_with_uuid(&uuid::Uuid::new_v4().to_string(), Some(email.clone()))
  213. .await;
  214. let profile = test
  215. .supabase_sign_up_with_uuid(
  216. &uuid::Uuid::new_v4().to_string(),
  217. Some(format!("{}@appflowy.io", nanoid!(6))),
  218. )
  219. .await
  220. .unwrap();
  221. let error = test
  222. .update_user_profile(
  223. UpdateUserProfilePayloadPB::new(profile.id)
  224. .name("lucas")
  225. .email(&email),
  226. )
  227. .await
  228. .unwrap();
  229. assert_eq!(error.code, ErrorCode::Conflict);
  230. }
  231. }
  232. #[tokio::test]
  233. async fn migrate_anon_document_on_cloud_signup() {
  234. if get_supabase_config().is_some() {
  235. let test = FlowyCoreTest::new();
  236. let user_profile = test.sign_up_as_guest().await.user_profile;
  237. let view = test
  238. .create_view(&user_profile.workspace_id, "My first view".to_string())
  239. .await;
  240. let document_event = DocumentEventTest::new_with_core(test.clone());
  241. let block_id = document_event
  242. .insert_index(&view.id, "hello world", 1, None)
  243. .await;
  244. let _ = test.supabase_party_sign_up().await;
  245. let workspace_id = test.user_manager.workspace_id().unwrap();
  246. // After sign up, the documents should be migrated to the cloud
  247. // So, we can get the document data from the cloud
  248. let data: DocumentData = test
  249. .document_manager
  250. .get_cloud_service()
  251. .get_document_data(&view.id, &workspace_id)
  252. .await
  253. .unwrap()
  254. .unwrap();
  255. let block = data.blocks.get(&block_id).unwrap();
  256. assert_json_eq!(
  257. block.data,
  258. json!({
  259. "delta": [
  260. {
  261. "insert": "hello world"
  262. }
  263. ]
  264. })
  265. );
  266. }
  267. }
  268. #[tokio::test]
  269. async fn migrate_anon_data_on_cloud_signup() {
  270. if get_supabase_config().is_some() {
  271. let (cleaner, user_db_path) = unzip_history_user_db(
  272. "./tests/user/supabase_test/history_user_db",
  273. "workspace_sync",
  274. )
  275. .unwrap();
  276. let test = FlowyCoreTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string());
  277. let user_profile = test.supabase_party_sign_up().await;
  278. // Get the folder data from remote
  279. let folder_data: FolderData = test
  280. .folder_manager
  281. .get_cloud_service()
  282. .get_folder_data(&user_profile.workspace_id)
  283. .await
  284. .unwrap()
  285. .unwrap();
  286. let expected_folder_data = expected_workspace_sync_folder_data();
  287. if folder_data.workspaces.len() != expected_folder_data.workspaces.len() {
  288. dbg!(&folder_data.workspaces);
  289. }
  290. assert_eq!(
  291. folder_data.workspaces.len(),
  292. expected_folder_data.workspaces.len()
  293. );
  294. assert_eq!(folder_data.views.len(), expected_folder_data.views.len());
  295. // After migration, the ids of the folder_data should be different from the expected_folder_data
  296. for i in 0..folder_data.views.len() {
  297. let left_view = &folder_data.views[i];
  298. let right_view = &expected_folder_data.views[i];
  299. assert_ne!(left_view.id, right_view.id);
  300. assert_ne!(left_view.parent_view_id, right_view.parent_view_id);
  301. assert_eq!(left_view.name, right_view.name);
  302. }
  303. assert_ne!(
  304. folder_data.current_workspace_id,
  305. expected_folder_data.current_workspace_id
  306. );
  307. assert_ne!(folder_data.current_view, expected_folder_data.current_view);
  308. let database_views = folder_data
  309. .views
  310. .iter()
  311. .filter(|view| view.layout.is_database())
  312. .collect::<Vec<_>>();
  313. // Try to load the database from the cloud.
  314. for (i, database_view) in database_views.iter().enumerate() {
  315. let cloud_service = test.database_manager.get_cloud_service();
  316. let database_id = test
  317. .database_manager
  318. .get_database_id_with_view_id(&database_view.id)
  319. .await
  320. .unwrap();
  321. let editor = test
  322. .database_manager
  323. .get_database(&database_id)
  324. .await
  325. .unwrap();
  326. // The database view setting should be loaded by the view id
  327. let _ = editor
  328. .get_database_view_setting(&database_view.id)
  329. .await
  330. .unwrap();
  331. let rows = editor.get_rows(&database_view.id).await.unwrap();
  332. assert_eq!(rows.len(), 3);
  333. let workspace_id = test.user_manager.workspace_id().unwrap();
  334. if i == 0 {
  335. let first_row = rows.first().unwrap().as_ref();
  336. let icon_url = first_row.meta.icon_url.clone().unwrap();
  337. assert_eq!(icon_url, "😄");
  338. let document_id = database_row_document_id_from_row_id(&first_row.row.id);
  339. let document_data: DocumentData = test
  340. .document_manager
  341. .get_cloud_service()
  342. .get_document_data(&document_id, &workspace_id)
  343. .await
  344. .unwrap()
  345. .unwrap();
  346. let editor = test
  347. .document_manager
  348. .get_document(&document_id)
  349. .await
  350. .unwrap();
  351. let expected_document_data = editor.lock().get_document_data().unwrap();
  352. // let expected_document_data = test
  353. // .document_manager
  354. // .get_document_data(&document_id)
  355. // .await
  356. // .unwrap();
  357. assert_eq!(document_data, expected_document_data);
  358. let json = json!(document_data);
  359. assert_eq!(
  360. json["blocks"]["LPMpo0Qaab"]["data"]["delta"][0]["insert"],
  361. json!("Row document")
  362. );
  363. }
  364. assert!(cloud_service
  365. .get_collab_update(&database_id, CollabType::Database, &workspace_id)
  366. .await
  367. .is_ok());
  368. }
  369. drop(cleaner);
  370. }
  371. }
  372. fn expected_workspace_sync_folder_data() -> FolderData {
  373. serde_json::from_value::<FolderData>(json!({
  374. "current_view": "e0811131-9928-4541-a174-20b7553d9e4c",
  375. "current_workspace_id": "8df7f755-fa5d-480e-9f8e-48ea0fed12b3",
  376. "views": [
  377. {
  378. "children": {
  379. "items": [
  380. {
  381. "id": "e0811131-9928-4541-a174-20b7553d9e4c"
  382. },
  383. {
  384. "id": "53333949-c262-447b-8597-107589697059"
  385. }
  386. ]
  387. },
  388. "created_at": 1693147093,
  389. "desc": "",
  390. "icon": null,
  391. "id": "e203afb3-de5d-458a-8380-33cd788a756e",
  392. "is_favorite": false,
  393. "layout": 0,
  394. "name": "⭐️ Getting started",
  395. "parent_view_id": "8df7f755-fa5d-480e-9f8e-48ea0fed12b3"
  396. },
  397. {
  398. "children": {
  399. "items": [
  400. {
  401. "id": "11c697ba-5ed1-41c0-adfc-576db28ad27b"
  402. },
  403. {
  404. "id": "4a5c25e2-a734-440c-973b-4c0e7ab0039c"
  405. }
  406. ]
  407. },
  408. "created_at": 1693147096,
  409. "desc": "",
  410. "icon": null,
  411. "id": "e0811131-9928-4541-a174-20b7553d9e4c",
  412. "is_favorite": false,
  413. "layout": 1,
  414. "name": "database",
  415. "parent_view_id": "e203afb3-de5d-458a-8380-33cd788a756e"
  416. },
  417. {
  418. "children": {
  419. "items": []
  420. },
  421. "created_at": 1693147124,
  422. "desc": "",
  423. "icon": null,
  424. "id": "11c697ba-5ed1-41c0-adfc-576db28ad27b",
  425. "is_favorite": false,
  426. "layout": 3,
  427. "name": "calendar",
  428. "parent_view_id": "e0811131-9928-4541-a174-20b7553d9e4c"
  429. },
  430. {
  431. "children": {
  432. "items": []
  433. },
  434. "created_at": 1693147125,
  435. "desc": "",
  436. "icon": null,
  437. "id": "4a5c25e2-a734-440c-973b-4c0e7ab0039c",
  438. "is_favorite": false,
  439. "layout": 2,
  440. "name": "board",
  441. "parent_view_id": "e0811131-9928-4541-a174-20b7553d9e4c"
  442. },
  443. {
  444. "children": {
  445. "items": []
  446. },
  447. "created_at": 1693147133,
  448. "desc": "",
  449. "icon": null,
  450. "id": "53333949-c262-447b-8597-107589697059",
  451. "is_favorite": false,
  452. "layout": 0,
  453. "name": "document",
  454. "parent_view_id": "e203afb3-de5d-458a-8380-33cd788a756e"
  455. }
  456. ],
  457. "workspaces": [
  458. {
  459. "child_views": {
  460. "items": [
  461. {
  462. "id": "e203afb3-de5d-458a-8380-33cd788a756e"
  463. }
  464. ]
  465. },
  466. "created_at": 1693147093,
  467. "id": "8df7f755-fa5d-480e-9f8e-48ea0fed12b3",
  468. "name": "Workspace"
  469. }
  470. ]
  471. }))
  472. .unwrap()
  473. }