From 6c139259303a0d3f748a541604995f0f919bb91f Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 13 Jul 2023 11:47:27 +0200 Subject: [PATCH 1/2] :bug: Fix bad interaction of file migrations components-v2 and pointer-map feature --- backend/src/app/rpc/commands/files.clj | 55 +++++++++++---------- common/src/app/common/pages/migrations.cljc | 5 +- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index 7eeaaa756..83cbfed23 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -253,22 +253,16 @@ ;; FIXME: file locking (defn- process-components-v2-feature "A special case handling of the components/v2 feature." - [conn {:keys [id features data] :as file}] - (binding [pmap/*tracked* (atom {})] - (let [data (ctf/migrate-to-components-v2 data) - features (conj features "components/v2") - features' (db/create-array conn "text" features)] - (db/update! conn :file - {:data (blob/encode data) - :features features'} - {:id id}) - (persist-pointers! conn id) - (-> file - (assoc :features features) - (assoc :data data))))) + [{:keys [features data] :as file}] + (let [data (ctf/migrate-to-components-v2 data) + features (conj features "components/v2")] + (-> file + (assoc ::pmg/migrated true) + (assoc :features features) + (assoc :data data)))) (defn handle-file-features! - [conn {:keys [features] :as file} client-features] + [{:keys [features] :as file} client-features] ;; Check features compatibility between the currently supported features on ;; the current backend instance and the file retrieved from the database @@ -290,7 +284,7 @@ ;; components and breaking the whole file." (and (contains? client-features "components/v2") (not (contains? features "components/v2"))) - (as-> file (process-components-v2-feature conn file)) + (as-> file (process-components-v2-feature file)) ;; This operation is needed for backward comapatibility with frontends that ;; does not support pointer-map resolution mechanism; this just resolves the @@ -347,22 +341,31 @@ ([conn id client-features project-id] ;; here we check if client requested features are supported (check-features-compatibility! client-features) - (binding [pmap/*load-fn* (partial load-pointer conn id)] + (binding [pmap/*load-fn* (partial load-pointer conn id) + pmap/*tracked* (atom {})] + (let [params (merge {:id id} - (when (some? project-id) - {:project-id project-id})) + (when (some? project-id) + {:project-id project-id})) + file (-> (db/get conn :file params) (decode-row) (pmg/migrate-file)) - file (handle-file-features! conn file client-features)] + file (handle-file-features! file client-features)] - ;; NOTE: if migrations are applied, probably new pointers generated so - ;; instead of persiting them on each get-file, we just resolve them until - ;; user updates the file and permanently persists the new pointers - (cond-> file - (pmg/migrated? file) - (process-pointers deref)))))) + ;; NOTE: when file is migrated, we break the rule of no perform + ;; mutations on get operations and update the file with all + ;; migrations applied + (when (pmg/migrated? file) + (let [features (db/create-array conn "text" (:features file))] + (db/update! conn :file + {:data (blob/encode (:data file)) + :features features} + {:id id}) + (persist-pointers! conn id))) + + file)))) (defn get-minimal-file [{:keys [::db/pool] :as cfg} id] @@ -380,7 +383,7 @@ ::sm/params ::get-file ::sm/result ::file-with-permissions} [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id id features project-id] :as params}] - (dm/with-open [conn (db/open pool)] + (db/with-atomic [conn pool] (let [perms (get-permissions conn profile-id id)] (check-read-permissions! perms) (let [file (-> (get-file conn id features project-id) diff --git a/common/src/app/common/pages/migrations.cljc b/common/src/app/common/pages/migrations.cljc index 72205dd4c..c9e1e80fb 100644 --- a/common/src/app/common/pages/migrations.cljc +++ b/common/src/app/common/pages/migrations.cljc @@ -45,8 +45,9 @@ (defn migrated? [{:keys [data] :as file}] - (> (:version data) - (::orig-version file))) + (or (::migrated file) + (> (:version data) + (::orig-version file)))) ;; Default handler, noop (defmethod migrate :default [data] data) From 9bcb3e9e7f407f4c7b630f0fff41320ca1f2d797 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 13 Jul 2023 16:28:11 +0200 Subject: [PATCH 2/2] :bug: Fix problem with Safari thumbnails --- frontend/src/app/config.cljs | 6 +++--- frontend/src/app/util/dom.cljs | 3 --- frontend/src/app/util/navigator.cljs | 14 ++++++++++++ frontend/src/app/util/webapi.cljs | 32 +++++++++++++++++++++++----- 4 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 frontend/src/app/util/navigator.cljs diff --git a/frontend/src/app/config.cljs b/frontend/src/app/config.cljs index 704ac51b8..2222b5018 100644 --- a/frontend/src/app/config.cljs +++ b/frontend/src/app/config.cljs @@ -11,8 +11,8 @@ [app.common.uri :as u] [app.common.version :as v] [app.util.avatars :as avatars] - [app.util.dom :as dom] [app.util.globals :refer [global location]] + [app.util.navigator :as nav] [app.util.object :as obj] [cuerdas.core :as str])) @@ -28,7 +28,7 @@ (defn- parse-browser [] - (let [user-agent (-> (dom/get-user-agent) str/lower) + (let [user-agent (-> (nav/get-user-agent) str/lower) check-chrome? (fn [] (str/includes? user-agent "chrom")) check-firefox? (fn [] (str/includes? user-agent "firefox")) check-edge? (fn [] (str/includes? user-agent "edg")) @@ -42,7 +42,7 @@ (defn- parse-platform [] - (let [user-agent (str/lower (dom/get-user-agent)) + (let [user-agent (str/lower (nav/get-user-agent)) check-windows? (fn [] (str/includes? user-agent "windows")) check-linux? (fn [] (str/includes? user-agent "linux")) check-macos? (fn [] (str/includes? user-agent "mac os"))] diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index 535d7a0d0..3c6fcbf6b 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -519,9 +519,6 @@ (when (and (some? node1) (some? node2)) (.contains ^js node2 ^js node1))) -(defn get-user-agent [] - (.-userAgent globals/navigator)) - (defn get-active [] (.-activeElement globals/document)) diff --git a/frontend/src/app/util/navigator.cljs b/frontend/src/app/util/navigator.cljs new file mode 100644 index 000000000..97bb86653 --- /dev/null +++ b/frontend/src/app/util/navigator.cljs @@ -0,0 +1,14 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns app.util.navigator + (:require [app.util.globals :as globals])) + +(defn get-user-agent [] + (.-userAgent globals/navigator)) + + + diff --git a/frontend/src/app/util/webapi.cljs b/frontend/src/app/util/webapi.cljs index db5fd1146..21675a01b 100644 --- a/frontend/src/app/util/webapi.cljs +++ b/frontend/src/app/util/webapi.cljs @@ -10,6 +10,7 @@ [app.common.data :as d] [app.common.exceptions :as ex] [app.common.logging :as log] + [app.config :as cf] [app.util.object :as obj] [app.util.thumbnails :as th] [beicon.core :as rx] @@ -150,20 +151,41 @@ ([image options] (js/createImageBitmap image options))) +(defn create-image + [src width height] + (p/create + (fn [resolve reject] + (let [img (.createElement js/document "img")] + (obj/set! img "width" width) + (obj/set! img "height" height) + (obj/set! img "src" src) + (obj/set! img "onload" #(resolve img)) + (obj/set! img "onerror" reject))))) + ;; Why this? Because as described in https://bugs.chromium.org/p/chromium/issues/detail?id=1463435 ;; the createImageBitmap seems to apply premultiplied alpha multiples times on the same image ;; which results in harsh borders around text being rendered. This is a workaround to avoid this issue. (defn create-image-bitmap-with-workaround ([image] (create-image-bitmap-with-workaround image nil)) - ([image options] + ([^js image options] (let [width (.-value (.-baseVal (.-width image))) height (.-value (.-baseVal (.-height image))) [width height] (th/get-proportional-size width height) - offscreen-canvas (create-offscreen-canvas width height) - offscreen-context (.getContext offscreen-canvas "2d")] - (.drawImage offscreen-context image 0 0) - (create-image-bitmap offscreen-canvas options)))) + + image-source + (if (cf/check-browser? :safari) + (let [src (.-baseVal (.-href image))] + (create-image src width height)) + (p/resolved image))] + + (-> image-source + (p/then + (fn [html-img] + (let [offscreen-canvas (create-offscreen-canvas width height) + offscreen-context (.getContext offscreen-canvas "2d")] + (.drawImage offscreen-context html-img 0 0) + (create-image-bitmap offscreen-canvas options)))))))) (defn request-fullscreen [el]