mirror of
https://github.com/penpot/penpot.git
synced 2025-02-02 12:28:54 -05:00
✨ Add test for orphaned teams deletion
This commit is contained in:
parent
730c26f1e2
commit
0dc7f4e07e
3 changed files with 141 additions and 88 deletions
|
@ -62,7 +62,9 @@
|
||||||
(when (:rollback? params)
|
(when (:rollback? params)
|
||||||
(db/rollback! conn))
|
(db/rollback! conn))
|
||||||
|
|
||||||
{:processed (+ stotal htotal)}))))
|
{:processed (+ stotal htotal)
|
||||||
|
:orphans stotal}))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(def ^:private sql:get-profiles-chunk
|
(def ^:private sql:get-profiles-chunk
|
||||||
|
@ -78,24 +80,22 @@
|
||||||
[{:keys [::conn ::min-age ::storage] :as cfg}]
|
[{:keys [::conn ::min-age ::storage] :as cfg}]
|
||||||
(letfn [(get-chunk [cursor]
|
(letfn [(get-chunk [cursor]
|
||||||
(let [rows (db/exec! conn [sql:get-profiles-chunk min-age cursor])]
|
(let [rows (db/exec! conn [sql:get-profiles-chunk min-age cursor])]
|
||||||
[(some->> rows peek :created-at) rows]))]
|
[(some->> rows peek :created-at) rows]))
|
||||||
(reduce
|
|
||||||
(fn [total {:keys [id photo-id]}]
|
|
||||||
(l/debug :hint "permanently delete profile" :id (str id))
|
|
||||||
|
|
||||||
;; Mark as deleted the storage object related with the
|
(process-profile [total {:keys [id photo-id]}]
|
||||||
;; photo-id field.
|
(l/debug :hint "permanently delete profile" :id (str id))
|
||||||
(some->> photo-id (sto/touch-object! storage))
|
|
||||||
|
|
||||||
;; And finally, permanently delete the profile.
|
;; Mark as deleted the storage object related with the
|
||||||
(db/delete! conn :profile {:id id})
|
;; photo-id field.
|
||||||
|
(some->> photo-id (sto/touch-object! storage))
|
||||||
|
|
||||||
(inc total))
|
;; And finally, permanently delete the profile.
|
||||||
0
|
(db/delete! conn :profile {:id id})
|
||||||
(d/iteration get-chunk
|
|
||||||
:vf second
|
(inc total))]
|
||||||
:kf first
|
|
||||||
:initk (dt/now)))))
|
(->> (d/iteration get-chunk :vf second :kf first :initk (dt/now))
|
||||||
|
(reduce process-profile 0))))
|
||||||
|
|
||||||
(def ^:private sql:get-teams-chunk
|
(def ^:private sql:get-teams-chunk
|
||||||
"select id, photo_id, created_at from team
|
"select id, photo_id, created_at from team
|
||||||
|
@ -110,24 +110,22 @@
|
||||||
[{:keys [::conn ::min-age ::storage] :as cfg}]
|
[{:keys [::conn ::min-age ::storage] :as cfg}]
|
||||||
(letfn [(get-chunk [cursor]
|
(letfn [(get-chunk [cursor]
|
||||||
(let [rows (db/exec! conn [sql:get-teams-chunk min-age cursor])]
|
(let [rows (db/exec! conn [sql:get-teams-chunk min-age cursor])]
|
||||||
[(some->> rows peek :created-at) rows]))]
|
[(some->> rows peek :created-at) rows]))
|
||||||
(reduce
|
|
||||||
(fn [total {:keys [id photo-id]}]
|
|
||||||
(l/debug :hint "permanently delete team" :id (str id))
|
|
||||||
|
|
||||||
;; Mark as deleted the storage object related with the
|
(process-team [total {:keys [id photo-id]}]
|
||||||
;; photo-id field.
|
(l/debug :hint "permanently delete team" :id (str id))
|
||||||
(some->> photo-id (sto/touch-object! storage))
|
|
||||||
|
|
||||||
;; And finally, permanently delete the team.
|
;; Mark as deleted the storage object related with the
|
||||||
(db/delete! conn :team {:id id})
|
;; photo-id field.
|
||||||
|
(some->> photo-id (sto/touch-object! storage))
|
||||||
|
|
||||||
(inc total))
|
;; And finally, permanently delete the team.
|
||||||
0
|
(db/delete! conn :team {:id id})
|
||||||
(d/iteration get-chunk
|
|
||||||
:vf second
|
(inc total))]
|
||||||
:kf first
|
|
||||||
:initk (dt/now)))))
|
(->> (d/iteration get-chunk :vf second :kf first :initk (dt/now))
|
||||||
|
(reduce process-team 0))))
|
||||||
|
|
||||||
(def ^:private sql:get-orphan-teams-chunk
|
(def ^:private sql:get-orphan-teams-chunk
|
||||||
"select t.id, t.created_at
|
"select t.id, t.created_at
|
||||||
|
@ -146,23 +144,21 @@
|
||||||
[{:keys [::conn] :as cfg}]
|
[{:keys [::conn] :as cfg}]
|
||||||
(letfn [(get-chunk [cursor]
|
(letfn [(get-chunk [cursor]
|
||||||
(let [rows (db/exec! conn [sql:get-orphan-teams-chunk cursor])]
|
(let [rows (db/exec! conn [sql:get-orphan-teams-chunk cursor])]
|
||||||
[(some->> rows peek :created-at) rows]))]
|
[(some->> rows peek :created-at) rows]))
|
||||||
(reduce
|
|
||||||
(fn [total {:keys [id]}]
|
|
||||||
(let [result (db/update! conn :team
|
|
||||||
{:deleted-at (dt/now)}
|
|
||||||
{:id id :deleted-at nil}
|
|
||||||
{::db/return-keys? false})
|
|
||||||
count (db/get-update-count result)]
|
|
||||||
(when (pos? count)
|
|
||||||
(l/debug :hint "mark team for deletion" :id (str id) ))
|
|
||||||
|
|
||||||
(+ total count)))
|
(process-team [total {:keys [id]}]
|
||||||
0
|
(let [result (db/update! conn :team
|
||||||
(d/iteration get-chunk
|
{:deleted-at (dt/now)}
|
||||||
:vf second
|
{:id id :deleted-at nil}
|
||||||
:kf first
|
{::db/return-keys? false})
|
||||||
:initk (dt/now)))))
|
count (db/get-update-count result)]
|
||||||
|
(when (pos? count)
|
||||||
|
(l/debug :hint "mark team for deletion" :id (str id) ))
|
||||||
|
|
||||||
|
(+ total count)))]
|
||||||
|
|
||||||
|
(->> (d/iteration get-chunk :vf second :kf first :initk (dt/now))
|
||||||
|
(reduce process-team 0))))
|
||||||
|
|
||||||
(def ^:private sql:get-fonts-chunk
|
(def ^:private sql:get-fonts-chunk
|
||||||
"select id, created_at, woff1_file_id, woff2_file_id, otf_file_id, ttf_file_id
|
"select id, created_at, woff1_file_id, woff2_file_id, otf_file_id, ttf_file_id
|
||||||
|
@ -178,26 +174,24 @@
|
||||||
[{:keys [::conn ::min-age ::storage] :as cfg}]
|
[{:keys [::conn ::min-age ::storage] :as cfg}]
|
||||||
(letfn [(get-chunk [cursor]
|
(letfn [(get-chunk [cursor]
|
||||||
(let [rows (db/exec! conn [sql:get-fonts-chunk min-age cursor])]
|
(let [rows (db/exec! conn [sql:get-fonts-chunk min-age cursor])]
|
||||||
[(some->> rows peek :created-at) rows]))]
|
[(some->> rows peek :created-at) rows]))
|
||||||
(reduce
|
|
||||||
(fn [total {:keys [id] :as font}]
|
|
||||||
(l/debug :hint "permanently delete font variant" :id (str id))
|
|
||||||
|
|
||||||
;; Mark as deleted the all related storage objects
|
(process-font [total {:keys [id] :as font}]
|
||||||
(some->> (:woff1-file-id font) (sto/touch-object! storage))
|
(l/debug :hint "permanently delete font variant" :id (str id))
|
||||||
(some->> (:woff2-file-id font) (sto/touch-object! storage))
|
|
||||||
(some->> (:otf-file-id font) (sto/touch-object! storage))
|
|
||||||
(some->> (:ttf-file-id font) (sto/touch-object! storage))
|
|
||||||
|
|
||||||
;; And finally, permanently delete the team font variant
|
;; Mark as deleted the all related storage objects
|
||||||
(db/delete! conn :team-font-variant {:id id})
|
(some->> (:woff1-file-id font) (sto/touch-object! storage))
|
||||||
|
(some->> (:woff2-file-id font) (sto/touch-object! storage))
|
||||||
|
(some->> (:otf-file-id font) (sto/touch-object! storage))
|
||||||
|
(some->> (:ttf-file-id font) (sto/touch-object! storage))
|
||||||
|
|
||||||
(inc total))
|
;; And finally, permanently delete the team font variant
|
||||||
0
|
(db/delete! conn :team-font-variant {:id id})
|
||||||
(d/iteration get-chunk
|
|
||||||
:vf second
|
(inc total))]
|
||||||
:kf first
|
|
||||||
:initk (dt/now)))))
|
(->> (d/iteration get-chunk :vf second :kf first :initk (dt/now))
|
||||||
|
(reduce process-font 0))))
|
||||||
|
|
||||||
(def ^:private sql:get-projects-chunk
|
(def ^:private sql:get-projects-chunk
|
||||||
"select id, created_at
|
"select id, created_at
|
||||||
|
@ -213,20 +207,17 @@
|
||||||
[{:keys [::conn ::min-age] :as cfg}]
|
[{:keys [::conn ::min-age] :as cfg}]
|
||||||
(letfn [(get-chunk [cursor]
|
(letfn [(get-chunk [cursor]
|
||||||
(let [rows (db/exec! conn [sql:get-projects-chunk min-age cursor])]
|
(let [rows (db/exec! conn [sql:get-projects-chunk min-age cursor])]
|
||||||
[(some->> rows peek :created-at) rows]))]
|
[(some->> rows peek :created-at) rows]))
|
||||||
(reduce
|
|
||||||
(fn [total {:keys [id]}]
|
|
||||||
(l/debug :hint "permanently delete project" :id (str id))
|
|
||||||
|
|
||||||
;; And finally, permanently delete the project.
|
(process-project [total {:keys [id]}]
|
||||||
(db/delete! conn :project {:id id})
|
(l/debug :hint "permanently delete project" :id (str id))
|
||||||
|
;; And finally, permanently delete the project.
|
||||||
|
(db/delete! conn :project {:id id})
|
||||||
|
|
||||||
(inc total))
|
(inc total))]
|
||||||
0
|
|
||||||
(d/iteration get-chunk
|
(->> (d/iteration get-chunk :vf second :kf first :initk (dt/now))
|
||||||
:vf second
|
(reduce process-project 0))))
|
||||||
:kf first
|
|
||||||
:initk (dt/now)))))
|
|
||||||
|
|
||||||
(def ^:private sql:get-files-chunk
|
(def ^:private sql:get-files-chunk
|
||||||
"select id, created_at
|
"select id, created_at
|
||||||
|
@ -242,17 +233,13 @@
|
||||||
[{:keys [::conn ::min-age] :as cfg}]
|
[{:keys [::conn ::min-age] :as cfg}]
|
||||||
(letfn [(get-chunk [cursor]
|
(letfn [(get-chunk [cursor]
|
||||||
(let [rows (db/exec! conn [sql:get-files-chunk min-age cursor])]
|
(let [rows (db/exec! conn [sql:get-files-chunk min-age cursor])]
|
||||||
[(some->> rows peek :created-at) rows]))]
|
[(some->> rows peek :created-at) rows]))
|
||||||
(reduce
|
|
||||||
(fn [total {:keys [id]}]
|
|
||||||
(l/debug :hint "permanently delete file" :id (str id))
|
|
||||||
|
|
||||||
;; And finally, permanently delete the file.
|
(process-file [total {:keys [id]}]
|
||||||
(db/delete! conn :file {:id id})
|
(l/debug :hint "permanently delete file" :id (str id))
|
||||||
|
;; And finally, permanently delete the file.
|
||||||
|
(db/delete! conn :file {:id id})
|
||||||
|
(inc total))]
|
||||||
|
|
||||||
(inc total))
|
(->> (d/iteration get-chunk :vf second :kf first :initk (dt/now))
|
||||||
0
|
(reduce process-file 0))))
|
||||||
(d/iteration get-chunk
|
|
||||||
:vf second
|
|
||||||
:kf first
|
|
||||||
:initk (dt/now)))))
|
|
||||||
|
|
|
@ -498,6 +498,10 @@
|
||||||
[& params]
|
[& params]
|
||||||
(apply db/insert! *pool* params))
|
(apply db/insert! *pool* params))
|
||||||
|
|
||||||
|
(defn db-delete!
|
||||||
|
[& params]
|
||||||
|
(apply db/delete! *pool* params))
|
||||||
|
|
||||||
(defn db-query
|
(defn db-query
|
||||||
[& params]
|
[& params]
|
||||||
(apply db/query *pool* params))
|
(apply db/query *pool* params))
|
||||||
|
|
|
@ -161,6 +161,68 @@
|
||||||
(let [result (:result out)]
|
(let [result (:result out)]
|
||||||
(t/is (= uuid/zero (:id result)))))))
|
(t/is (= uuid/zero (:id result)))))))
|
||||||
|
|
||||||
|
(t/deftest profile-immediate-deletion
|
||||||
|
(let [prof1 (th/create-profile* 1)
|
||||||
|
prof2 (th/create-profile* 2)
|
||||||
|
file (th/create-file* 1 {:profile-id (:id prof1)
|
||||||
|
:project-id (:default-project-id prof1)
|
||||||
|
:is-shared false})
|
||||||
|
|
||||||
|
team (th/create-team* 1 {:profile-id (:id prof1)})
|
||||||
|
_ (th/create-team-role* {:team-id (:id team)
|
||||||
|
:profile-id (:id prof2)
|
||||||
|
:role :admin})]
|
||||||
|
|
||||||
|
;; profile is not deleted because it does not meet all
|
||||||
|
;; conditions to be deleted.
|
||||||
|
(let [result (th/run-task! :objects-gc {:min-age (dt/duration 0)})]
|
||||||
|
(t/is (= 0 (:orphans result)))
|
||||||
|
(t/is (= 0 (:processed result))))
|
||||||
|
|
||||||
|
;; just delete the profile
|
||||||
|
(th/db-delete! :profile {:id (:id prof1)})
|
||||||
|
|
||||||
|
;; query files after profile deletion, expecting not found
|
||||||
|
(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 (not (th/success? out)))
|
||||||
|
(let [edata (-> out :error ex-data)]
|
||||||
|
(t/is (= :not-found (:type edata)))))
|
||||||
|
|
||||||
|
;; the files and projects still exists on the database
|
||||||
|
(let [files (th/db-query :file {:project-id (:default-project-id prof1)})
|
||||||
|
projects (th/db-query :project {:team-id (:default-team-id prof1)})]
|
||||||
|
(t/is (= 1 (count files)))
|
||||||
|
(t/is (= 1 (count projects))))
|
||||||
|
|
||||||
|
;; execute the gc task
|
||||||
|
(let [result (th/run-task! :objects-gc {:min-age (dt/duration "-1m")})]
|
||||||
|
(t/is (= 1 (:processed result)))
|
||||||
|
(t/is (= 1 (:orphans result))))
|
||||||
|
|
||||||
|
;; Check the deletion flag on the default profile team
|
||||||
|
(let [row (th/db-get :team
|
||||||
|
{:id (:default-team-id prof1)}
|
||||||
|
{::db/remove-deleted? false})]
|
||||||
|
(t/is (dt/instant? (:deleted-at row))))
|
||||||
|
|
||||||
|
;; Check the deletion flag on the shared team
|
||||||
|
(let [row (th/db-get :team
|
||||||
|
{:id (:id team)}
|
||||||
|
{::db/remove-deleted? false})]
|
||||||
|
(t/is (nil? (:deleted-at row))))
|
||||||
|
|
||||||
|
;; Check the roles on the shared team
|
||||||
|
(let [rows (th/db-query :team-profile-rel {:team-id (:id team)})]
|
||||||
|
(t/is (= 1 (count rows)))
|
||||||
|
(t/is (= (:id prof2) (get-in rows [0 :profile-id])))
|
||||||
|
(t/is (= false (get-in rows [0 :is-owner]))))
|
||||||
|
|
||||||
|
))
|
||||||
|
|
||||||
(t/deftest registration-domain-whitelist
|
(t/deftest registration-domain-whitelist
|
||||||
(let [whitelist #{"gmail.com" "hey.com" "ya.ru"}]
|
(let [whitelist #{"gmail.com" "hey.com" "ya.ru"}]
|
||||||
(t/testing "allowed email domain"
|
(t/testing "allowed email domain"
|
||||||
|
|
Loading…
Add table
Reference in a new issue