diff --git a/resources/config.edn b/resources/config.edn index c6a66ae..a929a9d 100644 --- a/resources/config.edn +++ b/resources/config.edn @@ -45,7 +45,7 @@ :remote "https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.1.0/papaparse.min.js"}} :styles {:leaflet {:local "vendor/node_modules/leaflet/dist/leaflet.css" :remote "https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"}} - :icon-url-base "uploads/map-pin/"} + :icon-url-base "map-pin/"} :mermaid {:formatter "smeagol.extensions.mermaid/process-mermaid" :scripts {:core {:local "vendor/node_modules/mermaid/dist/mermaid.min.js" :remote "https://cdnjs.cloudflare.com/ajax/libs/mermaid/8.4.6/mermaid.min.js"}}} diff --git a/resources/public/img/Unknown-pin.png b/resources/public/img/Unknown-pin.png new file mode 100644 index 0000000..f0b8fbb Binary files /dev/null and b/resources/public/img/Unknown-pin.png differ diff --git a/resources/public/img/shadow_pin.png b/resources/public/img/shadow_pin.png new file mode 100644 index 0000000..07c4daa Binary files /dev/null and b/resources/public/img/shadow_pin.png differ diff --git a/src/smeagol/finder.clj b/src/smeagol/finder.clj new file mode 100644 index 0000000..9b4daa6 --- /dev/null +++ b/src/smeagol/finder.clj @@ -0,0 +1,139 @@ +(ns ^{:doc "Find (by doing a 302 redirect to) appropriate files; if no + appropriate file is found return a 302 redirect to a default file." + :author "Simon Brooke"} + smeagol.finder + (:require [clojure.string :as cs] + [me.raynes.fs :as fs] + [noir.io :as io] + [noir.response :as response] + [smeagol.configuration :refer [config]] + [smeagol.util :refer [local-url-base content-dir]] + [taoensso.timbre :as log])) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; +;;;; Smeagol: a very simple Wiki engine. +;;;; +;;;; This program is free software; you can redistribute it and/or +;;;; modify it under the terms of the GNU General Public License +;;;; as published by the Free Software Foundation; either version 2 +;;;; of the License, or (at your option) any later version. +;;;; +;;;; This program is distributed in the hope that it will be useful, +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;;; GNU General Public License for more details. +;;;; +;;;; You should have received a copy of the GNU General Public License +;;;; along with this program; if not, write to the Free Software +;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +;;;; USA. +;;;; +;;;; Copyright (C) 2017 Simon Brooke +;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; See: +;; https://github.com/weavejester/compojure/wiki/Routes-In-Detail +;; https://github.com/weavejester/compojure/wiki/Destructuring-Syntax + +(defn to-url + "Given the absolute file path `fqn`, return the relative URL to that path + within Smeagol, if any, else `nil`." + [fqn] + (let [f (when fqn (str fqn)) + l (str local-url-base) + c (str content-dir)] + (cond + (nil? f) nil + (cs/starts-with? f l) (subs f (count l)) + ;; content-dir may not be within local-url-base + ;; TODO: potential bad bug: check that when uploads isn't within local-url-base + ;; the right copies of files are actually getting served! + (cs/starts-with? f c) (str "content/" (subs f (count c)))))) + + +(defn find-file-on-path + "Find a file with a name like this `n` on this `path` with + one of these `extensions`. Question: should we recurse down + the hierarchy?" + [n path extensions] + (let [ext (fs/extension n) + basename (subs n 0 (- (count n) (count ext))) + fqn (fs/absolute (fs/file path n))] + (if (and (fs/exists? fqn) (fs/readable? fqn)) + fqn + (first + (remove + nil? + (map + #(let [fqn' (fs/absolute (fs/file path (str basename %)))] + (when (and (fs/exists? fqn') (fs/readable? fqn')) + fqn')) + extensions)))))) + + +(defn find-file-on-paths + "Find a file with a name like this `n` on one of these `paths` with + one of these `extensions`" + [n paths extensions] + (first + (remove + nil? + (map + #(find-file-on-path n % extensions) + paths)))) + + +(defn find-image-url + "Return a 302 redirect to + 1. The requested file, if available; + 2. This default URL otherwise." + [request requested-name default-url paths] + (let [url (to-url + (find-file-on-paths requested-name paths + [".gif" ".png" ".jpg" ".jpeg" ".svg"]))] + (if url + (log/info "Found image" requested-name "at" url) + (log/warn "Failed to find image matching" requested-name)) + (response/redirect + ;; (str "/" (:servlet-context request) url) ;; TODO: >>> Nasty + (if url + (str (name (:scheme request)) "://" (:host request) ":" (:server-port request) "/" url) + default-url) + :found ))) + + +;; (def r {:ssl-client-cert nil, +;; :access-rules [{:redirect "/auth", +;; :rule #object[smeagol.handler$user_access 0x7ee9346 "smeagol.handler$user_access@7ee9346"]}], +;; :protocol "HTTP/1.1", +;; :cookies {"ring-session" {:value "4e7c059e-2796-44a0-b03a-c712dae43588"}}, +;; :remote-addr "127.0.0.1", +;; :params {:n "froboz"}, +;; :flash nil, +;; :route-params {:n "froboz"}, +;; :headers {"cookie" "ring-session=4e7c059e-2796-44a0-b03a-c712dae43588", +;; "accept" "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", +;; "upgrade-insecure-requests" "1", "user-agent" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0", +;; "connection" "keep-alive", +;; "host" "localhost:3000", +;; "accept-language" "en-GB,en;q=0.7,en-US;q=0.3", +;; "accept-encoding" "gzip, deflate", +;; "dnt" "1"}, +;; :server-port 3000, +;; :content-length nil, +;; :form-params {}, +;; :session/key "4e7c059e-2796-44a0-b03a-c712dae43588", +;; :query-params {}, +;; :content-type nil, +;; :character-encoding nil, +;; :uri "/map-pin/froboz", +;; :server-name "localhost", +;; :query-string nil, +;; :body #object[org.eclipse.jetty.server.HttpInputOverHTTP 0x5abc1216 "HttpInputOverHTTP@5abc1216"], +;; :multipart-params {}, +;; :scheme :http, +;; :request-method :get, +;; :session {:ring.middleware.anti-forgery/anti-forgery-token "2HVXUnBfpuw6kpLTWXTbiSk4zQN5/qPfvJtI/rw5Ju+m/f5I4r5nsOeEr1tuS5YWrXlNRWO6ruX/MHl4", +;; :ring.middleware.session-timeout/idle-timeout 1582725564}} diff --git a/src/smeagol/image_finder.clj b/src/smeagol/image_finder.clj deleted file mode 100644 index 81ef52e..0000000 --- a/src/smeagol/image_finder.clj +++ /dev/null @@ -1,44 +0,0 @@ -(ns ^{:doc "Find (by doing a 302 redirect to) appropriate images; if no - appropriate image is found return a 302 redirect to a default image." - :author "Simon Brooke"} - smeagol.uploads - (:require [clojure.string :as cs] - [me.raynes.fs :as fs] - [noir.io :as nio] - [noir.response :as response] - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;; -;;;; Smeagol: a very simple Wiki engine. -;;;; -;;;; This program is free software; you can redistribute it and/or -;;;; modify it under the terms of the GNU General Public License -;;;; as published by the Free Software Foundation; either version 2 -;;;; of the License, or (at your option) any later version. -;;;; -;;;; This program is distributed in the hope that it will be useful, -;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;;;; GNU General Public License for more details. -;;;; -;;;; You should have received a copy of the GNU General Public License -;;;; along with this program; if not, write to the Free Software -;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -;;;; USA. -;;;; -;;;; Copyright (C) 2017 Simon Brooke -;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; See: -;; https://github.com/weavejester/compojure/wiki/Routes-In-Detail -;; https://github.com/weavejester/compojure/wiki/Destructuring-Syntax - -(defn find-image - "Return a 302 redirect to - 1. The requested file, if available; - 2. This default URL otherwise." - [request requested-name default-url paths-to-explore] - (let [url (do-something-to-find-appropriate-file request)] - (response/redirect url :found ))) diff --git a/src/smeagol/routes/wiki.clj b/src/smeagol/routes/wiki.clj index 6695c36..2933fcb 100644 --- a/src/smeagol/routes/wiki.clj +++ b/src/smeagol/routes/wiki.clj @@ -18,6 +18,7 @@ [smeagol.authenticate :as auth] [smeagol.configuration :refer [config]] [smeagol.diff2html :as d2h] + [smeagol.finder :refer [find-image-url]] [smeagol.formatting :refer [md->html]] [smeagol.history :as hist] [smeagol.layout :as layout] @@ -31,7 +32,7 @@ [smeagol.configuration :refer [config]] [smeagol.include.resolve-local-file :as resolve] [smeagol.include :as include] - [smeagol.util :refer [content-dir local-url]])) + [smeagol.util :refer [content-dir local-url local-url-base upload-dir]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; @@ -466,12 +467,39 @@ (GET "/edit-user" request (route/restricted (admin/edit-user request))) (POST "/edit-user" request (route/restricted (admin/edit-user request))) (GET "/history" request (history-page request)) + (GET "/image/:n" request (find-image-url + request + (-> request :route-params :n) + "http://localhost:3000/img/smeagol.png" + [(fs/file local-url-base "img") + upload-dir + ;; TODO: should map over the configured + ;; thumbnail paths in descending order + ;; by size - generally, bigger images are + ;; better. + (fs/file upload-dir "med") + (fs/file upload-dir "small") + (fs/file upload-dir "map-pin")])) (GET "/list-uploads" request (route/restricted (list-uploads-page request))) (POST "/list-uploads" request (route/restricted (list-uploads-page request))) - (GET "/version" request (version-page request)) + (GET "/map-pin/:n" request (find-image-url + request + (-> request :route-params :n) + "http://localhost:3000/img/Unknown-pin.png" + [(fs/file local-url-base "img") + ;; TODO: should map over the configured + ;; thumbnail paths in ascending order + ;; by size - for map pins, smaller images are + ;; better. + (fs/file upload-dir "map-pin") + (fs/file upload-dir "small") + (fs/file upload-dir "med") + upload-dir + local-url-base])) (GET "/passwd" request (passwd-page request)) (POST "/passwd" request (passwd-page request)) (GET "/upload" request (route/restricted (upload-page request))) (POST "/upload" request (route/restricted (upload-page request))) + (GET "/version" request (version-page request)) (GET "/wiki" request (wiki-page request)) ) diff --git a/src/smeagol/util.clj b/src/smeagol/util.clj index 6989681..caf1396 100644 --- a/src/smeagol/util.clj +++ b/src/smeagol/util.clj @@ -61,6 +61,12 @@ (let [a (str (fs/absolute content-dir))] (subs a 0 (- (count a) (count "content"))))) +;; (def local-url-base +;; "Essentially, the slash-terminated absolute path of the `public` resource +;; directory. **NOTE** that this MAY NOT contain `content-dir`." +;; (cjio/file (io/resource-path))) + + (defn not-servable-reason "As a string, the reason this `file-path` cannot safely be served, or `nil` if it is safe to serve. This reason may be logged, but should *not* be