mirror of
https://github.com/penpot/penpot.git
synced 2026-09-16 17:06:17 +00:00
Port join-uri and get-public-uri from the unified jobs substrate WIP and use them for the link-preview image URLs, replacing the naive string concatenation that dropped configured subpaths. Includes the ported config tests. AI-assisted-by: muse-spark-1.3-contributor Signed-off-by: Andrey Antukh <niwi@niwi.nz>
83 lines
3.2 KiB
Clojure
83 lines
3.2 KiB
Clojure
;; 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 Sucursal en España SL
|
|
|
|
(ns app.http.link-preview
|
|
"Link preview (Open Graph metadata) related handlers.
|
|
|
|
Serves a minimal HTML page with Open Graph metadata used by link
|
|
preview crawlers (Slack, Discord, Twitter, ...). The reverse proxy
|
|
routes crawler requests for the application root to this endpoint,
|
|
preserving the query string params that the frontend mirrors on
|
|
navigation (`file-id`, `project-id` and `team-id`)."
|
|
(:require
|
|
[app.common.data :as d]
|
|
[app.config :as cf]
|
|
[app.db :as db]
|
|
[app.util.template :as tmpl]
|
|
[clojure.java.io :as io]
|
|
[integrant.core :as ig]
|
|
[yetti.response :as-alias yres]))
|
|
|
|
(def ^:private default-context
|
|
{:title "Penpot | Full-stack design"
|
|
:description "Penpot is the open-source design platform for teams that build digital products at scale."})
|
|
|
|
(def ^:private sql:get-file
|
|
"SELECT f.name, ft.media_id
|
|
FROM file AS f
|
|
LEFT JOIN file_thumbnail AS ft
|
|
ON (ft.file_id = f.id AND ft.deleted_at IS NULL)
|
|
WHERE f.id = ?
|
|
AND f.deleted_at IS NULL
|
|
ORDER BY ft.revn DESC NULLS LAST
|
|
LIMIT 1")
|
|
|
|
(defn- get-file-context
|
|
"Return the link preview context for a file link: the file name as title
|
|
and, when available, the last dashboard thumbnail as image."
|
|
[pool file-id]
|
|
(when-let [{:keys [name media-id]} (db/exec-one! pool [sql:get-file file-id])]
|
|
(cond-> (assoc default-context :title (str name " | Penpot"))
|
|
(some? media-id)
|
|
(assoc :image (cf/get-public-uri (str "assets/by-id/" media-id))))))
|
|
|
|
(defn- get-context
|
|
[pool params]
|
|
(let [project-id (some-> (:project-id params) d/parse-uuid)
|
|
team-id (some-> (:team-id params) d/parse-uuid)]
|
|
;; A present file-id is decisive: file links never fall through to the
|
|
;; project/team card, even when the value is malformed or unknown (both
|
|
;; yield nil and the handler falls back to the default context).
|
|
(if (contains? params :file-id)
|
|
(when-some [file-id (d/parse-uuid (:file-id params))]
|
|
(get-file-context pool file-id))
|
|
(cond
|
|
(some? project-id) (assoc default-context :title "Project | Penpot")
|
|
(some? team-id) (assoc default-context :title "Team dashboard | Penpot")))))
|
|
|
|
(defn- handler
|
|
[{:keys [::db/pool]} request]
|
|
(let [context (when (contains? cf/flags :link-preview)
|
|
(get-context pool (:query-params request)))
|
|
context (-> (or context default-context)
|
|
(update :image #(or % (cf/get-public-uri "images/penpot-link-preview.png"))))]
|
|
{::yres/status 200
|
|
::yres/headers {"content-type" "text/html; charset=utf-8"
|
|
"cache-control" "no-store, no-cache, max-age=0"}
|
|
::yres/body (-> (io/resource "app/templates/link-preview.tmpl")
|
|
(tmpl/render context))}))
|
|
|
|
;; --- Initialization
|
|
|
|
(defmethod ig/assert-key ::routes
|
|
[_ params]
|
|
(assert (db/pool? (::db/pool params)) "expect valid database pool"))
|
|
|
|
(defmethod ig/init-key ::routes
|
|
[_ cfg]
|
|
["/link-preview" {:handler (partial handler cfg)
|
|
:allowed-methods #{:get :head}}])
|