From 7e44ae62a272c8ed45d8bb9e8ad04bf2172d793c Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 27 Jun 2024 11:18:58 +0200 Subject: [PATCH] :bug: Fix profile deletion issue with 1 participant --- backend/src/app/rpc/commands/profile.clj | 22 +-- backend/src/app/tasks/orphan_teams_gc.clj | 1 - .../test/backend_tests/rpc_profile_test.clj | 157 +++++++++++++++++- 3 files changed, 167 insertions(+), 13 deletions(-) diff --git a/backend/src/app/rpc/commands/profile.clj b/backend/src/app/rpc/commands/profile.clj index fe33da10d..5bdf6943c 100644 --- a/backend/src/app/rpc/commands/profile.clj +++ b/backend/src/app/rpc/commands/profile.clj @@ -400,18 +400,18 @@ ;; --- HELPERS (def sql:owned-teams - "with owner_teams as ( - select tpr.team_id as id - from team_profile_rel as tpr - where tpr.is_owner is true - and tpr.profile_id = ? + "WITH owner_teams AS ( + SELECT tpr.team_id AS id + FROM team_profile_rel AS tpr + WHERE tpr.is_owner IS TRUE + AND tpr.profile_id = ? ) - select tpr.team_id as id, - count(tpr.profile_id) - 1 as participants - from team_profile_rel as tpr - where tpr.team_id in (select id from owner_teams) - and tpr.profile_id != ? - group by 1") + SELECT tpr.team_id AS id, + count(tpr.profile_id) AS participants + FROM team_profile_rel AS tpr + WHERE tpr.team_id IN (SELECT id from owner_teams) + AND tpr.profile_id != ? + GROUP BY 1") (defn- get-owned-teams-with-participants [conn profile-id] diff --git a/backend/src/app/tasks/orphan_teams_gc.clj b/backend/src/app/tasks/orphan_teams_gc.clj index c04123a83..bbc267e57 100644 --- a/backend/src/app/tasks/orphan_teams_gc.clj +++ b/backend/src/app/tasks/orphan_teams_gc.clj @@ -22,7 +22,6 @@ [_ cfg] (fn [params] (db/tx-run! cfg (fn [{:keys [::db/conn] :as cfg}] - (l/inf :hint "gc started" :rollback? (boolean (:rollback? params))) (let [total (delete-orphan-teams! cfg)] (l/inf :hint "task finished" :teams total diff --git a/backend/test/backend_tests/rpc_profile_test.clj b/backend/test/backend_tests/rpc_profile_test.clj index 00d2f2ac0..d52a0bac9 100644 --- a/backend/test/backend_tests/rpc_profile_test.clj +++ b/backend/test/backend_tests/rpc_profile_test.clj @@ -126,7 +126,7 @@ ;; (th/print-result! out) (t/is (nil? (:error out))))))) -(t/deftest profile-deletion-simple +(t/deftest profile-deletion-1 (let [prof (th/create-profile* 1) file (th/create-file* 1 {:profile-id (:id prof) :project-id (:default-project-id prof) @@ -177,6 +177,161 @@ (let [result (:result out)] (t/is (= uuid/zero (:id result))))))) + +(t/deftest profile-deletion-2 + (let [prof1 (th/create-profile* 1) + prof2 (th/create-profile* 2) + file1 (th/create-file* 1 {:profile-id (:id prof1) + :project-id (:default-project-id prof1) + :is-shared false}) + team1 (th/create-team* 1 {:profile-id (:id prof1)}) + + role1 (th/create-team-role* {:team-id (:id team1) + :profile-id (:id prof2) + + :role :editor})] + ;; Assert all roles for team + (let [roles (th/db-query :team-profile-rel {:team-id (:id team1)})] + (t/is (= 2 (count roles)))) + + ;; Request profile to be deleted + (let [params {::th/type :delete-profile + ::rpc/profile-id (:id prof1)} + out (th/command! params)] + ;; (th/print-result! out) + + (let [error (:error out) + edata (ex-data error)] + (t/is (th/ex-info? error)) + (t/is (= (:type edata) :validation)) + (t/is (= (:code edata) :owner-teams-with-people)))))) + +(t/deftest profile-deletion-3 + (let [prof1 (th/create-profile* 1) + prof2 (th/create-profile* 2) + prof3 (th/create-profile* 3) + file1 (th/create-file* 1 {:profile-id (:id prof1) + :project-id (:default-project-id prof1) + :is-shared false}) + team1 (th/create-team* 1 {:profile-id (:id prof1)}) + + role1 (th/create-team-role* {:team-id (:id team1) + :profile-id (:id prof2) + :role :editor}) + role2 (th/create-team-role* {:team-id (:id team1) + :profile-id (:id prof3) + :role :editor})] + + ;; Assert all roles for team + (let [roles (th/db-query :team-profile-rel {:team-id (:id team1)})] + (t/is (= 3 (count roles)))) + + ;; Request profile to be deleted (it should fail) + (let [params {::th/type :delete-profile + ::rpc/profile-id (:id prof1)} + out (th/command! params)] + ;; (th/print-result! out) + + (let [error (:error out) + edata (ex-data error)] + (t/is (th/ex-info? error)) + (t/is (= (:type edata) :validation)) + (t/is (= (:code edata) :owner-teams-with-people)))) + + ;; Leave team by role 1 + (let [params {::th/type :leave-team + ::rpc/profile-id (:id prof2) + :id (:id team1)} + out (th/command! params)] + + ;; (th/print-result! out) + (t/is (nil? (:result out))) + (t/is (nil? (:error out)))) + + ;; Request profile to be deleted (it should fail) + (let [params {::th/type :delete-profile + ::rpc/profile-id (:id prof1)} + out (th/command! params)] + ;; (th/print-result! out) + (let [error (:error out) + edata (ex-data error)] + (t/is (th/ex-info? error)) + (t/is (= (:type edata) :validation)) + (t/is (= (:code edata) :owner-teams-with-people)))) + + + ;; Leave team by role 0 (the default) and reassing owner to role 3 + ;; without reassinging it (should fail) + (let [params {::th/type :leave-team + ::rpc/profile-id (:id prof1) + ;; :reassign-to (:id prof3) + :id (:id team1)} + out (th/command! params)] + + ;; (th/print-result! out) + + (let [error (:error out) + edata (ex-data error)] + (t/is (th/ex-info? error)) + (t/is (= (:type edata) :validation)) + (t/is (= (:code edata) :owner-cant-leave-team)))) + + ;; Leave team by role 0 (the default) and reassing owner to role 3 + (let [params {::th/type :leave-team + ::rpc/profile-id (:id prof1) + :reassign-to (:id prof3) + :id (:id team1)} + out (th/command! params)] + + ;; (th/print-result! out) + (t/is (nil? (:result out))) + (t/is (nil? (:error out)))) + + ;; Request profile to be deleted (it should fail) + (let [params {::th/type :delete-profile + ::rpc/profile-id (:id prof1)} + out (th/command! params)] + ;; (th/print-result! out) + + (t/is (= {} (:result out))) + (t/is (nil? (:error out)))) + + ;; query files after profile soft deletion + (let [params {::th/type :get-project-files + ::rpc/profile-id (:id prof1) + :project-id (:default-project-id prof1)} + out (th/command! params)] + ;; (th/print-result! out) + (t/is (nil? (:error out))) + (t/is (= 1 (count (:result out))))) + + ;; execute permanent deletion task + (let [result (th/run-task! :objects-gc {:min-age 0})] + (t/is (= 1 (:processed result)))) + + (let [row (th/db-get :team + {:id (:default-team-id prof1)} + {::db/remove-deleted false})] + (t/is (nil? (:deleted-at row)))) + + (let [result (th/run-task! :orphan-teams-gc {:min-age 0})] + (t/is (= 1 (:processed result)))) + + (let [row (th/db-get :team + {:id (:default-team-id prof1)} + {::db/remove-deleted false})] + (t/is (dt/instant? (:deleted-at row)))) + + ;; query profile after delete + (let [params {::th/type :get-profile + ::rpc/profile-id (:id prof1)} + out (th/command! params)] + ;; (th/print-result! out) + (let [result (:result out)] + (t/is (= uuid/zero (:id result))))))) + + + (t/deftest registration-domain-whitelist (let [whitelist #{"gmail.com" "hey.com" "ya.ru"}] (t/testing "allowed email domain"