Skip to content

Commit

Permalink
#45,#46: done
Browse files Browse the repository at this point in the history
  • Loading branch information
simon-brooke committed Feb 16, 2020
1 parent ee46b0d commit 151987e
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 63 deletions.
30 changes: 17 additions & 13 deletions resources/config.edn
Original file line number Diff line number Diff line change
Expand Up @@ -30,37 +30,35 @@
:content-dir "resources/public/content"
;; where content is served from.
:default-locale "en-GB" ;; default language used for messages
:extensions-from :local ;; where to load JavaScript libraries
;; from: options are :local, :remote.
:formatters ;; formatters for processing markdown
;; extensions.
{:backticks {:formatter "smeagol.formatting/process-backticks"
:scripts {}
:styles {}}
:mermaid {:formatter "smeagol.extensions.mermaid/process-mermaid"
:scripts {:core {:local "vendor/mermaid/dist/mermaid.js"}}
:scripts {:core {:local "vendor/mermaid/dist/mermaid.js"
:remote "https://cdnjs.cloudflare.com/ajax/libs/mermaid/8.4.6/mermaid.min.js"}}
:styles {}}
:pswp {:formatter "smeagol.extensions.photoswipe/process-photoswipe"
:scripts {:core {:local "/vendor/node_modules/photoswipe/dist/photoswipe.min.js"
:scripts {:core {:local "vendor/node_modules/photoswipe/dist/photoswipe.min.js"
:remote "https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe.min.js"}
:ui {:local "/vendor/node_modules/photoswipe/dist/photoswipe-ui-default.min.js"
:ui {:local "vendor/node_modules/photoswipe/dist/photoswipe-ui-default.min.js"
:remote "https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe-ui-default.min.js"}}
:styles {:core {:local "/vendor/node_modules/photoswipe/dist/photoswipe.css"
:remote "/vendor/node_modules/photoswipe/dist/default-skin/default-skin.css"}}}
:styles {:core {:local "vendor/node_modules/photoswipe/dist/photoswipe.css"}
:skin {:local "vendor/node_modules/photoswipe/dist/default-skin/default-skin.css"}}}
:test {:formatter "smeagol.extensions.test/process-test" }
:vega {:formatter "smeagol.extensions.vega/process-vega"
:scripts {:core {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega/5.9.1/vega.min.js"}
:lite {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega-lite/4.1.1/vega-lite.min.js"}
:embed {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.2.2/vega-embed.min.js"}
:styles {}}}
:embed {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.2.2/vega-embed.min.js"}}}
:vis {:formatter "smeagol.extensions.vega/process-vega"
:scripts {:core {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega/5.9.1/vega.min.js"}
:lite {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega-lite/4.1.1/vega-lite.min.js"}
:embed {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.2.2/vega-embed.min.js"}
:styles {}}}
}
:embed {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.2.2/vega-embed.min.js"}}}}
:log-level :info ;; the minimum logging level; one of
;; :trace :debug :info :warn :error :fatal
:js-from :cdnjs ;; where to load JavaScript libraries
;; from: options are :local, :cdnjs
:passwd "resources/passwd"
;; where the password file is stored
:site-title "Smeagol" ;; overall title of the site, used in
Expand All @@ -71,4 +69,10 @@
;; stored in the /small directory
:med 400 ;; maximum dimension of thumbnails
;; stored in the /med directory
}}
;; you can add as many extra keys and values as
;; you like here for additional sizes of images.
;; Images will only be scaled if their maximum
;; dimension (in pixels) is greater than the value;
;; only JPEG and PNG images will be scaled.
}
}
6 changes: 2 additions & 4 deletions resources/templates/wiki.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

{% block extra-headers %}
{% for script in scripts %}
<script src="{{script}}"></script>
{% endfor %}
<script src="{{script}}"></script>{% endfor %}
{% for style in styles %}
<link href="{{style}}" rel="stylesheet" type="text/css" />
{% endfor %}
<link href="{{style}}" rel="stylesheet" type="text/css" />{% endfor %}
{% endblock %}

{% block content %}
Expand Down
42 changes: 23 additions & 19 deletions src/smeagol/formatting.clj
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
fragments
(cons fragment processed)))


(defn deep-merge [v & vs]
"Cripped in its entirety from https://clojuredocs.org/clojure.core/merge."
(letfn [(rec-merge [v1 v2]
Expand Down Expand Up @@ -124,18 +125,18 @@
fragments
(cons ident processed))))

(apply-formatter
3
{:inclusions {}}
'()
'()
"pswp
![Frost on a gate, Laurieston](content/uploads/g1.jpg)
![Feathered crystals on snow surface, Taliesin](content/uploads/g2.jpg)
![Feathered snow on log, Taliesin](content/uploads/g3.jpg)
![Crystaline growth on seed head, Taliesin](content/uploads/g4.jpg)"
"pswp"
smeagol.extensions.photoswipe/process-photoswipe)
;; (apply-formatter
;; 3
;; {:inclusions {}}
;; '()
;; '()
;; "pswp
;; ![Frost on a gate, Laurieston](content/uploads/g1.jpg)
;; ![Feathered crystals on snow surface, Taliesin](content/uploads/g2.jpg)
;; ![Feathered snow on log, Taliesin](content/uploads/g3.jpg)
;; ![Crystaline growth on seed head, Taliesin](content/uploads/g4.jpg)"
;; "pswp"
;; smeagol.extensions.photoswipe/process-photoswipe)

(defn process-text
"Process this `text`, assumed to be markdown potentially containing both local links
Expand All @@ -145,6 +146,8 @@
The map has two top-level keys: `:inclusions`, a map of constructed keywords to
inclusion specifications, and `:text`, an HTML text string with the keywords
present where the corresponding inclusion should be inserted."

;; TODO: the inclusion->index bug is in here somewhere.
([^String text]
(process-text 0 {} (cs/split (or text "") #"```") '()))
([index result fragments processed]
Expand Down Expand Up @@ -185,19 +188,19 @@
(rest fragments)
(cons ident processed))
{:inclusions {ident (apply formatter (list (subs fragment (count first-token)) index))}
:extensions (cons kw (:extensions result))}))
:extensions (assoc (or (:extensions result) {}) kw (-> config :formatters kw))}))
:else
;; Otherwise process the current fragment as markdown and recurse on
;; down the list
(process-markdown-fragment
index result remarked (rest fragments) processed)))))

(process-text
"pswp
![Frost on a gate, Laurieston](content/uploads/g1.jpg)
![Feathered crystals on snow surface, Taliesin](content/uploads/g2.jpg)
![Feathered snow on log, Taliesin](content/uploads/g3.jpg)
![Crystaline growth on seed head, Taliesin](content/uploads/g4.jpg)" )
;; (process-text
;; "pswp
;; ![Frost on a gate, Laurieston](content/uploads/g1.jpg)
;; ![Feathered crystals on snow surface, Taliesin](content/uploads/g2.jpg)
;; ![Feathered snow on log, Taliesin](content/uploads/g3.jpg)
;; ![Crystaline growth on seed head, Taliesin](content/uploads/g4.jpg)" )

(defn reintegrate-inclusions
"Given a map of the form produced by `process-text`, return a string of HTML text
Expand Down Expand Up @@ -236,3 +239,4 @@




68 changes: 49 additions & 19 deletions src/smeagol/routes/wiki.clj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
[com.stuartsierra.component :as component]
[smeagol.configuration :refer [config]]
[smeagol.include.resolve-local-file :as resolve]
[smeagol.include :as include]))
[smeagol.include :as include]
[smeagol.util :refer [content-dir local-url]]))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
Expand Down Expand Up @@ -118,40 +119,69 @@


(def md-include-system
"Allowing Markdown includes. Unfortunately the contributor who contributed
this didn't document it, and I haven't yet worked out how it works. TODO:
investigate and document."
(component/start
(component/system-map
:resolver (resolve/new-resolver util/content-dir)
:includer (component/using
(include/new-includer)
[:resolver]))))


(defn preferred-source
"Here, `component` is expected to be a map with two keys, `:local` and
`:remote`. If the value of `:extensions-from` in `config.edn` is remote
AND the value of `:remote` is not nil, then the value of `:remote` will
be returned. Otherwise, if the value of `:local` is nil and the value of
`:remote` is non-nil, the value of `:remote` will be returned. By default,
the value of `:local` will be returned."
[component]
(let [l (:local component) ;; TODO: look at the trick in Selmer to get relative URL
r (:remote component)]
(cond
(= (:extensions-from config) :remote) (if (empty? r) l r)
(empty? l) r
:else l)))
[component ks]
(try
(let [l (:local component)
l' (if-not (empty? l) (local-url l) l)
r (:remote component)]
(cond
(= (:extensions-from config) :remote)
(if (empty? r) l' r)
(empty? l') r
:else l'))
(catch Exception any
(log/error "Failed to find appropriate source for component" ks "because:" any)
nil)))

;; (preferred-source {:local "vendor/node_modules/photoswipe/dist/photoswipe.min.js",
;; :remote "https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe.min.js"} :core)

(defn collect-preferred
"From extensions referenced in this `processed-text`, extract the preferred
URLs for this keyword `k`, expected to be either `:scripts` or `:styles`."
[processed-text k]
(set
(remove
nil?
(map
preferred-source
(apply
concat
(map vals (map k (vals (:extensions processed-text)))))))))
([processed-text]
(concat
(collect-preferred processed-text :scripts)
(collect-preferred processed-text :styles)))
([processed-text resource-type]
(reduce concat
(map
(fn [extension-key]
(map
(fn [requirement]
(let [r (preferred-source
(-> processed-text :extensions extension-key resource-type requirement)
requirement)]
(if (empty? r)
(log/warn "Found no valid URL for requirement"
requirement "of extension" extension-key))
r))
(keys (-> processed-text :extensions extension-key resource-type))))
(keys (:extensions processed-text))))))

(cjio/file content-dir "vendor/node_modules/photoswipe/dist/photoswipe.min.js")

(def processed-text (md->html (slurp "resources/public/content/Simplified example gallery.md" )))

(preferred-source (-> processed-text :extensions :pswp :scripts :core) :pswp)

(collect-preferred processed-text :scripts)

(defn wiki-page
"Render the markdown page specified in this `request`, if any. If none found, redirect to edit-page"
Expand Down
48 changes: 40 additions & 8 deletions src/smeagol/util.clj
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
(str (cjio/file content-dir "uploads")))

(def local-url-base
"Essentially, the slash-terminated absolute path of the `public` resource
directory."
(let [a (str (fs/absolute content-dir))]
(subs a 0 (- (count a) (count "content")))))

Expand All @@ -59,7 +61,11 @@
if it is safe to serve. This reason may be logged, but should *not* be
shown to remote users, as it would allow file system probing."
[file-path]
(let [path (fs/absolute file-path)]
(try
(let [path (if
(cs/starts-with? (str file-path) "/")
file-path
(cjio/file local-url-base file-path))]
(cond
(cs/includes? file-path "..")
(cs/join " " file-path
Expand All @@ -69,31 +75,57 @@
(not (fs/exists? path))
(cs/join " " [path "does not exist"])
(not (fs/readable? path))
(cs/join " " [path "is not readable"]))))
(cs/join " " [path "is not readable"])))
(catch Exception any (cs/join " " file-path "is not servable because" (.getMessage any)))))


;; (not-servable-reason "/home/simon/workspace/smeagol/resources/public/content/vendor/node_modules/photoswipe/dist/photoswipe.min.js")
;; (not-servable-reason "/root/froboz")

(defn local-url?
"True if this `file-path` can be served as a local URL, else false."
[file-path]
(empty? (not-servable-reason file-path)))
(try
(if
(empty? (not-servable-reason file-path))
true
(do
(log/error
"In `smeagol.util/local-url? `" file-path "` is not a servable resource.")
false))
(catch Exception any
(log/error
"In `smeagol.util/local-url `" file-path "` is not a servable resource:" any)
false)))

(defn local-url
"Return a local URL for this `file-path`, or a deliberate 404 if none
can be safely served."
;; TODO: this actually returns a relative URL relative to local-url-base.
;; That's not quite what we want because in Tomcat contexts the absolute
;; URL may be different. We *ought* to be able to extract the offset from the
;; servlet context, but it may be simpler to jam it in the config.
[file-path]
(try
(let [path (fs/absolute file-path)
(let [path (if
(cs/starts-with? file-path local-url-base)
(subs file-path (count local-url-base))
file-path)
problem (not-servable-reason path)]
(if
(empty? problem)
(subs (str path) (count local-url-base))
path
(do
(log/error
"In `smeagol.util/local-url `" file-path "` is not a servable resource.")
(str "404-not-found?path=" file-path))))
(catch Exception any
(log/error
"In `smeagol.util/local-url `" file-path "` is not a servable resource:" any)
(str "404-not-found?path=" file-path))))
(log/error
"In `smeagol.util/local-url `" file-path "` is not a servable resource:" any)
(str "404-not-found?path=" file-path))))

(local-url? "vendor/node_modules/photoswipe/dist/photoswipe.min.js")
(local-url? "/home/simon/workspace/smeagol/resources/public/vendor/node_modules/photoswipe/dist/photoswipe.min.js")

(defn standard-params
"Return a map of standard parameters to pass to the template renderer."
Expand Down

0 comments on commit 151987e

Please sign in to comment.