0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-23 05:01:23 -05:00

Merge remote-tracking branch 'origin/staging'

This commit is contained in:
Alejandro Alonso 2024-04-22 09:07:06 +02:00
commit 3ea3923751
18 changed files with 155 additions and 36 deletions

View file

@ -28,6 +28,8 @@
### :boom: Breaking changes & Deprecations
- New strokes default to inside border [Taiga #6847](https://tree.taiga.io/project/penpot/issue/6847)
- Change default z ordering on layers in flex layout. The previous behavior was inconsistent with how HTML works and we changed it to be more consistent. Previous layers that overlapped could be hidden, the fastest way to fix this is changing the z-index property but a better way is to change the order of your layers.
### :heart: Community contributions (Thank you!)
- New Hausa, Yoruba and Igbo translations and update translation files (by All For Tech Empowerment Foundation) [Taiga #6950](https://tree.taiga.io/project/penpot/us/6950), [Taiga #6534](https://tree.taiga.io/project/penpot/us/6534)

View file

@ -349,6 +349,8 @@
:audit-log-archive (ig/ref :app.loggers.audit.archive-task/handler)
:audit-log-gc (ig/ref :app.loggers.audit.gc-task/handler)
:object-update
(ig/ref :app.tasks.object-update/handler)
:process-webhook-event
(ig/ref ::webhooks/process-event-handler)
:run-webhook
@ -376,7 +378,10 @@
::sto/storage (ig/ref ::sto/storage)}
:app.tasks.orphan-teams-gc/handler
{::db/pool (ig/ref ::db/pool)}
{::db/pool (ig/ref ::db/pool)}
:app.tasks.object-update/handler
{::db/pool (ig/ref ::db/pool)}
:app.tasks.file-gc/handler
{::db/pool (ig/ref ::db/pool)

View file

@ -271,7 +271,7 @@
(when (and (some? th1)
(not= (:media-id th1)
(:media-id th2)))
(sto/touch-object! storage (:media-id th1)))
(sto/touch-object! storage (:media-id th1) :async true))
th2))

View file

@ -46,6 +46,10 @@
(let [email (str/lower email)
email (if (str/starts-with? email "mailto:")
(subs email 7)
email)
email (if (or (str/starts-with? email "<")
(str/ends-with? email ">"))
(str/trim email "<>")
email)]
email))

View file

@ -38,6 +38,11 @@
team (-> (db/get conn :team {:id (:team-id project)})
(teams/decode-row))
members (into #{} (->> (teams/get-team-members conn (:team-id project))
(map :id)))
perms (assoc perms :in-team (contains? members profile-id))
_ (-> (cfeat/get-team-enabled-features cf/flags team)
(cfeat/check-client-features! (:features params))
(cfeat/check-file-features! (:features file)))

View file

@ -16,6 +16,7 @@
[app.storage.impl :as impl]
[app.storage.s3 :as ss3]
[app.util.time :as dt]
[app.worker :as wrk]
[clojure.spec.alpha :as s]
[datoteka.fs :as fs]
[integrant.core :as ig]
@ -170,15 +171,28 @@
(impl/put-object object content))
object)))
(def ^:private default-touch-delay
"A default delay for the asynchronous touch operation"
(dt/duration "5m"))
(defn touch-object!
"Mark object as touched."
[{:keys [::db/pool-or-conn] :as storage} object-or-id]
[{:keys [::db/pool-or-conn] :as storage} object-or-id & {:keys [async]}]
(us/assert! ::storage storage)
(let [id (if (impl/object? object-or-id) (:id object-or-id) object-or-id)
rs (db/update! pool-or-conn :storage-object
{:touched-at (dt/now)}
{:id id})]
(pos? (db/get-update-count rs))))
(let [id (if (impl/object? object-or-id) (:id object-or-id) object-or-id)]
(if async
(wrk/submit! ::wrk/conn pool-or-conn
::wrk/task :object-update
::wrk/delay default-touch-delay
:object :storage-object
:id id
:key :touched-at
:val (dt/now))
(-> (db/update! pool-or-conn :storage-object
{:touched-at (dt/now)}
{:id id})
(db/get-update-count)
(pos?)))))
(defn get-object-data
"Return an input stream instance of the object content."

View file

@ -0,0 +1,32 @@
;; 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.tasks.object-update
"A task used for perform simple object properties update
in an asynchronous flow."
(:require
[app.common.data :as d]
[app.common.logging :as l]
[app.db :as db]
[clojure.spec.alpha :as s]
[integrant.core :as ig]))
(defn- update-object
[{:keys [::db/conn] :as cfg} {:keys [id object key val] :as props}]
(l/trc :hint "update object prop"
:id (str id)
:object (d/name object)
:key (d/name key)
:val val)
(db/update! conn object {key val} {:id id} {::db/return-keys false}))
(defmethod ig/pre-init-spec ::handler [_]
(s/keys :req [::db/pool]))
(defmethod ig/init-key ::handler
[_ cfg]
(fn [{:keys [props] :as params}]
(db/tx-run! cfg update-object props)))

View file

@ -119,11 +119,13 @@
:next.jdbc/update-count))]
(l/trc :hint "submit task"
:name task
:task-id (str id)
:queue queue
:label label
:dedupe (boolean dedupe)
:deleted (or deleted 0)
:in (dt/format-duration duration))
:delay (dt/format-duration duration)
:replace (or deleted 0))
(db/exec-one! conn [sql:insert-new-task id task props queue
label priority max-retries interval])

View file

@ -92,7 +92,7 @@
(let [ts (ms-until-valid cron)
ft (px/schedule! ts (partial execute-cron-task cfg task))]
(l/dbg :hint "schedule task" :id id
(l/dbg :hint "schedule" :id id
:ts (dt/format-duration ts)
:at (dt/format-instant (dt/in-future ts)))

View file

@ -139,7 +139,7 @@
:else
(try
(l/trc :hint "start task"
(l/dbg :hint "start"
:name (:name task)
:task-id (str task-id)
:queue queue
@ -149,7 +149,7 @@
result (handle-task task)
elapsed (dt/format-duration (tpoint))]
(l/trc :hint "end task"
(l/dbg :hint "end"
:name (:name task)
:task-id (str task-id)
:queue queue
@ -228,9 +228,9 @@
(recur))))
(catch InterruptedException _
(l/debug :hint "interrupted"
:id id
:queue queue))
(l/dbg :hint "interrupted"
:id id
:queue queue))
(catch Throwable cause
(l/err :hint "unexpected exception"
:id id

View file

@ -277,8 +277,6 @@
(t/is (thrown? org.postgresql.util.PSQLException
(th/db-delete! :storage-object {:id (:media-id row1)}))))))
(t/deftest get-file-object-thumbnail
(let [storage (::sto/storage th/*system*)
profile (th/create-profile* 1)
@ -317,3 +315,44 @@
(let [result (:result out)]
(t/is (contains? result "test-key-2"))))))
(t/deftest create-file-object-thumbnail
(th/db-delete! :task {:name "object-update"})
(let [storage (::sto/storage th/*system*)
profile (th/create-profile* 1)
file (th/create-file* 1 {:profile-id (:id profile)
:project-id (:default-project-id profile)
:is-shared false})
data {::th/type :create-file-object-thumbnail
::rpc/profile-id (:id profile)
:file-id (:id file)
:object-id "test-key-2"
:media {:filename "sample.jpg"
:mtype "image/jpeg"}}]
(let [data (update data :media
(fn [media]
(-> media
(assoc :path (th/tempfile "backend_tests/test_files/sample2.jpg"))
(assoc :size 7923))))
out (th/command! data)]
(t/is (nil? (:error out)))
(t/is (map? (:result out))))
(let [data (update data :media
(fn [media]
(-> media
(assoc :path (th/tempfile "backend_tests/test_files/sample.jpg"))
(assoc :size 312043))))
out (th/command! data)]
(t/is (nil? (:error out)))
(t/is (map? (:result out))))
(let [[row1 :as rows]
(->> (th/db-query :task {:name "object-update"})
(map #(update % :props db/decode-transit-pgobject)))]
;; (app.common.pprint/pprint rows)
(t/is (= 1 (count rows)))
(t/is (> (inst-ms (dt/diff (:created-at row1) (:scheduled-at row1)))
(inst-ms (dt/duration "4m")))))))

View file

@ -27,6 +27,14 @@
(t/use-fixtures :once th/state-init)
(t/use-fixtures :each th/database-reset)
(t/deftest clean-email
(t/is "foo@example.com" (profile/clean-email "mailto:foo@example.com"))
(t/is "foo@example.com" (profile/clean-email "mailto:<foo@example.com>"))
(t/is "foo@example.com" (profile/clean-email "<foo@example.com>"))
(t/is "foo@example.com" (profile/clean-email "foo@example.com>"))
(t/is "foo@example.com" (profile/clean-email "<foo@example.com")))
;; Test with wrong credentials
(t/deftest profile-login-failed-1
(let [profile (th/create-profile* 1)

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View file

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />

View file

@ -48,7 +48,8 @@
(dom/set-html-title (tr "title.default")))
[:main {:class (stl/css :auth-section)}
[:a {:href "#/" :class (stl/css :logo-btn)} i/logo]
[:h1 {:class (stl/css :logo-container)}
[:a {:href "#/" :title "Penpot" :class (stl/css :logo-btn)} i/logo]]
[:div {:class (stl/css :login-illustration)}
i/login-illustration]

View file

@ -24,6 +24,16 @@
}
}
.logo-container {
position: absolute;
top: $s-20;
left: $s-20;
display: flex;
justify-content: flex-start;
width: $s-120;
margin-block-end: $s-52;
}
.login-illustration {
display: flex;
justify-content: center;
@ -55,14 +65,6 @@
}
.logo-btn {
position: absolute;
top: $s-20;
left: $s-20;
display: flex;
justify-content: flex-start;
width: $s-120;
margin-block-end: $s-52;
svg {
width: $s-120;
height: $s-40;

View file

@ -54,9 +54,10 @@
(let [props (.-props tab)
id (.-id props)
title (.-title props)
sid (d/name id)]
sid (d/name id)
tooltip (if (string? title) title nil)]
[:div {:key (str/concat "tab-" sid)
:title title
:title tooltip
:data-id sid
:on-click on-click
:class (stl/css-case

View file

@ -180,7 +180,7 @@
:on-zoom-fit handle-zoom-fit
:on-fullscreen toggle-fullscreen}]
(when (:can-edit permissions)
(when (:in-team permissions)
[:span {:on-click go-to-workspace
:class (stl/css :edit-btn)}
i/curve])
@ -191,7 +191,9 @@
:on-click toggle-fullscreen}
i/expand]
(when (:is-admin permissions)
(when (and
(:in-team permissions)
(:is-admin permissions))
[:button {:on-click open-share-dialog
:class (stl/css :share-btn)}
(tr "labels.share")])
@ -301,8 +303,8 @@
;; If the user doesn't have permission we disable the link
[:a {:class (stl/css :home-link)
:on-click go-to-dashboard
:style {:cursor (when-not (:can-edit permissions) "auto")
:pointer-events (when-not (:can-edit permissions) "none")}}
:style {:cursor (when-not (:in-team permissions) "auto")
:pointer-events (when-not (:in-team permissions) "none")}}
[:span {:class (stl/css :logo-icon)}
i/logo-icon]]
@ -321,7 +323,7 @@
:title (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))}
i/play]
(when (or (:can-edit permissions)
(when (or (:in-team permissions)
(= (:who-comment permissions) "all"))
[:button {:on-click navigate
:data-value "comments"