From 9f3c16a3482b0f57665571ddc10943de61fe7da1 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Mon, 11 Sep 2017 08:05:20 +0100 Subject: [PATCH 01/48] Set version to 0.99.10-SNAPSHOT --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index eb2ad78..b3e3f82 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject smeagol "1.0.0-rc3" +(defproject smeagol "0.99.10-SNAPSHOT" :description "A simple Git-backed Wiki inspired by Gollum" :url "https://github.com/simon-brooke/smeagol" :license {:name "GNU General Public License,version 2.0 or (at your option) any later version" From 2f6f9286a329b9d9733a4733dc151aa34be19fed Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 11 Sep 2017 13:04:51 +0100 Subject: [PATCH 02/48] Tidy-up and robustness; no major functional change. --- project.clj | 2 - resources/passwd | 2 +- resources/public/content/stylesheet.css | 8 + src/smeagol/authenticate.clj | 8 +- src/smeagol/configuration.clj | 3 +- src/smeagol/handler.clj | 2 +- src/smeagol/routes/admin.clj | 2 +- src/smeagol/routes/wiki.clj | 11 +- src/smeagol/sanity.clj | 185 +++++++++++++++--------- src/smeagol/util.clj | 22 ++- 10 files changed, 147 insertions(+), 98 deletions(-) diff --git a/project.clj b/project.clj index b3e3f82..4159363 100644 --- a/project.clj +++ b/project.clj @@ -8,9 +8,7 @@ [com.cemerick/url "0.1.1"] [com.fzakaria/slf4j-timbre "0.3.7"] [com.taoensso/encore "2.92.0"] - [com.cemerick/url "0.1.1"] [com.taoensso/timbre "4.10.0"] - [com.fzakaria/slf4j-timbre "0.3.7"] [com.taoensso/tower "3.0.2" :exclusions [com.taoensso/encore]] [crypto-password "0.2.0"] [environ "1.1.0"] diff --git a/resources/passwd b/resources/passwd index 6b5e6ac..fe61aaf 100644 --- a/resources/passwd +++ b/resources/passwd @@ -1 +1 @@ -{:admin {:admin true, :email "info@weft.scot", :password "admin"}, :jenny {:email "jenny@auchencairn.org", :admin false, :password "$s0$f0801$1uniQfftB37G5e5GklJANQ==$kQ0+/YcCuaz2x5iYjwhNlDlnWX/exE/8pSC+R4C0WvQ="}} \ No newline at end of file +{:admin {:admin true, :email "info@weft.scot", :password "admin"}} diff --git a/resources/public/content/stylesheet.css b/resources/public/content/stylesheet.css index 187b346..81a661c 100644 --- a/resources/public/content/stylesheet.css +++ b/resources/public/content/stylesheet.css @@ -265,6 +265,14 @@ th { padding: 0 2em 0 0; } +.sanity-cause .sanity-stacktrace { + display: none; +} + +.sanity-cause:hover .sanity-stacktrace { + display: block; +} + .vega-bindings, .vega-actions { font-size: 66%; } diff --git a/src/smeagol/authenticate.clj b/src/smeagol/authenticate.clj index 8f83703..c65b5ad 100644 --- a/src/smeagol/authenticate.clj +++ b/src/smeagol/authenticate.clj @@ -38,7 +38,7 @@ (def password-file-path (or (env :smeagol-passwd) - (str (clojure.java.io/resource "passwd")))) + (str (io/resource-path) "../passwd"))) (defn- get-users @@ -112,7 +112,7 @@ (timbre/info (str "Successfully changed password for user " username)) true)) (catch Exception any - (timbre/error + (timbre/error any (format "Changing password failed for user %s failed: %s (%s)" username (.getName (.getClass any)) (.getMessage any))) false)))) @@ -162,7 +162,7 @@ (timbre/info "Successfully added user " username) true) (catch Exception any - (timbre/error + (timbre/error any (format "Adding user %s failed: %s (%s)" username (.getName (.getClass any)) (.getMessage any))) false))))) @@ -179,7 +179,7 @@ (timbre/info (str "Successfully deleted user " username)) true) (catch Exception any - (timbre/error + (timbre/error any (format "Deleting user %s failed: %s (%s)" username (.getName (.getClass any)) (.getMessage any))) false)))) diff --git a/src/smeagol/configuration.clj b/src/smeagol/configuration.clj index d630adc..0f9bcd4 100644 --- a/src/smeagol/configuration.clj +++ b/src/smeagol/configuration.clj @@ -37,7 +37,6 @@ ;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - (def config-file-path "The relative path to the config file." (or @@ -50,5 +49,5 @@ (try (read-string (slurp config-file-path)) (catch Exception any - (timbre/error "Could not load configuration" any) + (timbre/error any "Could not load configuration") {}))) diff --git a/src/smeagol/handler.clj b/src/smeagol/handler.clj index 2b2c0f9..d44dfc8 100644 --- a/src/smeagol/handler.clj +++ b/src/smeagol/handler.clj @@ -76,7 +76,7 @@ (timbre/info "\n-=[ smeagol started successfully" (when (env :dev) "using the development profile") "]=-") (catch Exception any - (timbre/error "Failure during startup" any) + (timbre/error any "Failure during startup") (destroy)))) ;; timeout sessions after 30 minutes diff --git a/src/smeagol/routes/admin.clj b/src/smeagol/routes/admin.clj index 9491116..106ca35 100644 --- a/src/smeagol/routes/admin.clj +++ b/src/smeagol/routes/admin.clj @@ -98,7 +98,7 @@ :details details :users (auth/list-users)}))) (catch Exception any - (timbre/error (.getMessage any)) + (timbre/error any) (layout/render "edit-user.html" (merge (util/standard-params request) {:title (str (:edit-title-prefix (util/get-messages request)) " " (:target params)) diff --git a/src/smeagol/routes/wiki.clj b/src/smeagol/routes/wiki.clj index 15b3a68..fe80349 100644 --- a/src/smeagol/routes/wiki.clj +++ b/src/smeagol/routes/wiki.clj @@ -45,13 +45,6 @@ ;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defn get-git-repo - "Get the git repository for my content, creating it if necessary" - [] - (hist/load-or-init-repo util/content-dir)) - - (defn process-source "Process `source-text` and save it to the specified `file-path`, committing it to Git and finally redirecting to wiki-page." @@ -61,7 +54,7 @@ file-name (str page suffix) file-path (cjio/file util/content-dir file-name) exists? (.exists (cjio/as-file file-path)) - git-repo (get-git-repo) + git-repo (hist/load-or-init-repo util/content-dir) user (session/get :user) email (auth/get-email user) summary (format "%s: %s" user (or (:summary params) "no summary"))] @@ -157,7 +150,7 @@ [request] (let [params (keywordize-keys (:params request)) data-path (str (io/resource-path) "/content/uploads/") - git-repo (get-git-repo) + git-repo (hist/load-or-init-repo util/content-dir) upload (:upload params) uploaded (if upload (ul/store-upload params data-path)) user (session/get :user) diff --git a/src/smeagol/sanity.clj b/src/smeagol/sanity.clj index 02f7b2d..e7c0503 100644 --- a/src/smeagol/sanity.clj +++ b/src/smeagol/sanity.clj @@ -252,13 +252,28 @@ (as-hiccup [this dictionary] "") clojure.lang.Keyword - (as-hiccup [this dictionary] (str (or (this dictionary)(string/replace (name this) "-" " ")) " ")) + (as-hiccup [this dictionary] + (str + (or + (this dictionary) + (string/replace (name this) "-" " ")) + " ")) clojure.lang.PersistentList - (as-hiccup [this dictionary] (apply vector (cons :div (map #(as-hiccup % dictionary) this)))) + (as-hiccup [this dictionary] + (apply + vector + (cons + :div + (map #(as-hiccup % dictionary) this)))) clojure.lang.PersistentVector - (as-hiccup [this dictionary] (apply vector (cons :div (map #(as-hiccup % dictionary) this)))) + (as-hiccup [this dictionary] + (apply + vector + (cons + :div + (map #(as-hiccup % dictionary) this)))) clojure.lang.PersistentArrayMap (as-hiccup [this dictionary] @@ -296,66 +311,94 @@ vector (cons :div - (cons - {:class "sanity-exception"} - (map - (fn [x] - [:div - {:class "sanity-cause"} - (.getMessage x) - [:div {:class "sanity-stacktrace"} - (apply - vector - (cons - :ol - (map - as-hiccup - (.getStackTrace x) - dictionary)))]]) - (get-causes this)))))) + (cons + {:class "sanity-exception"} + (map + (fn [x] + [:div + {:class "sanity-cause"} + [:h2 (.getMessage x)] + [:div {:class "sanity-stacktrace"} + (apply + vector + (cons + :ol + (map + as-hiccup + (.getStackTrace x) + dictionary)))]]) + (get-causes this)))))) java.lang.Object (as-hiccup [this dictionary] (str this " "))) -(defn sanity-check-report - [problems] +(defn get-locale-messages + "Get messages for the server-side locale." + [] (let [locale (Locale/getDefault) - locale-specifier (str (.getLanguage locale) "-" (.getCountry locale)) - messages (try - (i18n/get-messages locale-specifier "i18n" "en-GB") - (catch Exception any {}))] + locale-specifier (str (.getLanguage locale) "-" (.getCountry locale))] + (try + (i18n/get-messages locale-specifier "i18n" "en-GB") + (catch Exception any {})))) + + +;; Prepackaged hiccup sub-units +(defn as-hiccup-head + [messages] + [:head + [:title (as-hiccup :smeagol-not-initialised messages)] + [:link {:href "/content/stylesheet.css" :rel "stylesheet"}]]) + + +(defn as-hiccup-header + [messages] + [:header + [:div {:id "nav"} " "] + [:h1 (as-hiccup :smeagol-not-initialised messages)] + [:p " "]]) + + +(defn as-hiccup-see-doc + [messages] + [:p (as-hiccup :see-documentation messages) + [:a + {:href + "https://github.com/journeyman-cc/smeagol/wiki/Deploying-Smeagol"} + (as-hiccup :here messages)] "."]) + + +(defn as-hiccup-footer + [messages] + [:footer + [:div {:id "credits"} + [:div + [:img {:height "16" :width "16" :alt "one wiki to rule them all" :src "img/smeagol.png"}] + " One Wiki to rule them all || Smeagol wiki engine || " + [:img + {:height "16" :width "16" + :alt "The Web Engineering Factory & Toolworks" + :src "http://www.weft.scot/images/weft.logo.64.png"}] + " Developed by " + [:a {:href "http://www.weft.scot/"}"WEFT"]]]]) + + +(defn sanity-check-report + "Convert this `problem` report into a nicely formatted HTML page" + [problems] + (let [messages (get-locale-messages)] (html [:html - [:head - [:title (as-hiccup :smeagol-not-initialised messages)] - [:link {:href "/content/stylesheet.css" :rel "stylesheet"}]] + (as-hiccup-head messages) [:body - [:header - [:div {:id "nav"} " "] - [:h1 (as-hiccup :smeagol-not-initialised messages)] - [:p " "]] - [:div {:id "error" :class "error"} - [:div {:class "error"} - (as-hiccup [(count (keys problems)) :problems-found] messages)]] + (as-hiccup-header messages) + [:div {:id "error"} + [:p {:class "error"} + (rest (as-hiccup [(count (keys problems)) :problems-found] messages))]] [:div {:id "main-container" :class "sanity-check-report"} [:p (as-hiccup :smeagol-misconfiguration messages)] (as-hiccup problems messages) - [:p (as-hiccup :see-documentation messages) - [:a - {:href - "https://github.com/journeyman-cc/smeagol/blob/master/resources/public/content/Deploying%20Smeagol.md"} - (as-hiccup :here messages)]]] - [:footer - [:div {:id "credits"} - [:div - [:img {:height "16" :width "16" :alt "one wiki to rule them all" :src "img/smeagol.png"}] - " One Wiki to rule them all || Smeagol wiki engine || " - [:img - {:height "16" :width "16" - :alt "The Web Engineering Factory & Toolworks" - :src "http://www.weft.scot/images/weft.logo.64.png"}] - " Developed by " - [:a {:href "http://www.weft.scot/"}"WEFT"]]]]]]))) + (as-hiccup-see-doc messages)] + (as-hiccup-footer messages)]]))) (defn- raw-sanity-check-installation @@ -383,26 +426,26 @@ If no argument is passed, run the sanity check and if it fails return page contents; if `error` is passed, just return page content describing the error." ([error] - (html - [:html - [:head - [:title "Smeagol is not initialised correctly"] - [:link {:href "/content/stylesheet.css" :rel "stylesheet"}]] - [:body - [:header - [:h1 "Smeagol is not initialised correctly"]] - [:div {:id "error"} - [:p {:class "error"} (.getMessage error)]] - [:p "There was a problem launching Smeagol probably because of misconfiguration:"] - (apply - vector - (cons :ol - (map #(vector :li (.getMessage %)) - (get-causes error)))) - [:p :see-documentation - [:a {:href "https://github.com/journeyman-cc/smeagol/blob/develop/resources/public/content/Deploying%20Smeagol.md"} "here"]]]])) + (let [messages (get-locale-messages)] + (html + [:html + (as-hiccup-head messages) + [:body + (as-hiccup-header messages) + [:div {:id "error"} + [:p {:class "error"} (.getMessage error)]] + [:div {:id "main-container" :class "sanity-check-report"} + [:p (as-hiccup :smeagol-misconfiguration messages)] + (as-hiccup error messages) + (as-hiccup-see-doc messages)] + (as-hiccup-footer messages)]]))) ([] (try (sanity-check-installation) - (catch Exception any (show-sanity-check-error any))))) + (catch Exception any + (timbre/error any "Failure during sanity check") + (show-sanity-check-error any))))) + +(show-sanity-check-error (Exception. "That's insane!")) + diff --git a/src/smeagol/util.clj b/src/smeagol/util.clj index 69cce68..902e377 100644 --- a/src/smeagol/util.clj +++ b/src/smeagol/util.clj @@ -8,7 +8,8 @@ [scot.weft.i18n.core :as i18n] [smeagol.authenticate :as auth] [smeagol.configuration :refer [config]] - [smeagol.formatting :refer [md->html]])) + [smeagol.formatting :refer [md->html]] + [taoensso.timbre :as timbre])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; @@ -55,12 +56,19 @@ "Return the most acceptable messages collection we have given the `Accept-Language` header in this `request`." [request] - (merge - (i18n/get-messages - ((:headers request) "accept-language") - "i18n" - "en-GB") - config)) + (let [specifier ((:headers request) "accept-language") + messages (try + (i18n/get-messages specifier "i18n" "en-GB") + (catch Exception any + (timbre/error + any + (str + "Failed to parse accept-language header " + specifier)) + {}))] + (merge + messages + config))) (def get-messages (memoize raw-get-messages)) From f3883c6b07f1b62ad96e35c9edc81d2fee592080 Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 11 Sep 2017 13:25:10 +0100 Subject: [PATCH 03/48] Experimental changes to Dockerfile --- Dockerfile | 26 ++++++++++++++++++++++++-- resources/public/uploads/water.png | Bin 15083 -> 0 bytes 2 files changed, 24 insertions(+), 2 deletions(-) delete mode 100644 resources/public/uploads/water.png diff --git a/Dockerfile b/Dockerfile index 0dfae96..87bfd0e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,25 @@ -FROM tomcat:alpine -COPY target/smeagol-*-standalone.war $CATALINA_HOME/webapps/smeagol.war +FROM alpine:3.6 + +MAINTAINER Simon Brooke + +ENV JAVA_HOME=/usr/lib/jvm/default-jvm + +RUN apk add --no-cache openjdk7 && \ + ln -sf "${JAVA_HOME}/bin/"* "/usr/bin/" + +# ensure the directories I'm going to write to actually exist! +RUN mkdir -p /usr/local/bin +RUN mkdir -p /usr/local/etc + +COPY target/smeagol-*-standalone.jar /usr/local/bin/smeagol.jar +COPY resources/passwd /usr/local/etc/passwd +COPY resources/config.edn /usr/local/etc/config.edn +COPY resources/pubilc/content /usr/local/etc/content + +ENV SMEAGOL_CONFIG=/usr/local/etc/config.edn +ENV SMEAGOL_CONTENT_DIR=/usr/local/etc/content +ENV SMEAGOL_PASSWD=/usr/local/etc/passwd +ENV TIMBRE_DEFAULT_STACKTRACE_FONTS="{}" + +CMD java -jar /usr/local/bin/smeagol.jar diff --git a/resources/public/uploads/water.png b/resources/public/uploads/water.png deleted file mode 100644 index e97d1ed9eda34a1c3d5ecff8007d20537590de9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15083 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 N002ovPDHLkV1lJl!a)E4 From 2f4f7aa1c5793ead5c85bc4c63d27bcf3d8834ca Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Tue, 12 Sep 2017 00:49:16 +0100 Subject: [PATCH 04/48] #33: Fix --- Dockerfile | 8 ++- resources/public/content/Deploying Smeagol.md | 23 +------- resources/public/content/Docker Image.md | 55 +++++++++++++++++++ 3 files changed, 62 insertions(+), 24 deletions(-) create mode 100644 resources/public/content/Docker Image.md diff --git a/Dockerfile b/Dockerfile index 87bfd0e..c546620 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER Simon Brooke ENV JAVA_HOME=/usr/lib/jvm/default-jvm -RUN apk add --no-cache openjdk7 && \ +RUN apk add --no-cache openjdk8 && \ ln -sf "${JAVA_HOME}/bin/"* "/usr/bin/" # ensure the directories I'm going to write to actually exist! @@ -14,12 +14,16 @@ RUN mkdir -p /usr/local/etc COPY target/smeagol-*-standalone.jar /usr/local/bin/smeagol.jar COPY resources/passwd /usr/local/etc/passwd COPY resources/config.edn /usr/local/etc/config.edn -COPY resources/pubilc/content /usr/local/etc/content +COPY resources/public/content /usr/local/etc/content ENV SMEAGOL_CONFIG=/usr/local/etc/config.edn ENV SMEAGOL_CONTENT_DIR=/usr/local/etc/content ENV SMEAGOL_PASSWD=/usr/local/etc/passwd ENV TIMBRE_DEFAULT_STACKTRACE_FONTS="{}" +ENV TIMBRE_LEVEL=':info' +ENV PORT=80 + +EXPOSE 80 CMD java -jar /usr/local/bin/smeagol.jar diff --git a/resources/public/content/Deploying Smeagol.md b/resources/public/content/Deploying Smeagol.md index 653831a..009d610 100644 --- a/resources/public/content/Deploying Smeagol.md +++ b/resources/public/content/Deploying Smeagol.md @@ -36,25 +36,4 @@ The problem with this is that unless the environment variables (see above) were ## Experimental Docker image -You can now run Smeagol as a [Docker](http://www.docker.com) image. Read more about [[Using the Docker Image]]. - -To run my Docker image, use - - docker run simonbrooke/smeagol - -Smeagol will run, obviously, on the IP address of your Docker image, on port 8080. To find the IP address, start the image using the command above and then use - - docker inspect --format '{{ .NetworkSettings.IPAddress }}' $(docker ps -q) - -Suppose this prints '10.10.10.10', then the URL to browse to will be http://10.10.10.10:8080/smeagol/ - -This image is _experimental_, but it does seem to work fairly well. What it does **not** yet do, however, is push the git repository to a remote location, so when you tear the Docker image down your edits will be lost. My next objective for this image is for it to have a cammand line parameter being the git address of a repository from which it can initialise the Wiki content, and to which it will periodically push local changes to the Wiki content. - -To build your own Docker image, run: - - lein clean - lein bower install - lein ring uberwar - lein docker build - -This will build a new Docker image locally; you can, obviously, push it to your own Docker repository if you wish. +You can now run Smeagol as a [Docker](http://www.docker.com) image. Read more about using the [[Docker Image]]. diff --git a/resources/public/content/Docker Image.md b/resources/public/content/Docker Image.md new file mode 100644 index 0000000..4bfc58f --- /dev/null +++ b/resources/public/content/Docker Image.md @@ -0,0 +1,55 @@ +Smeagol is available as a Docker image + +To run my Docker image, use + + docker run -p 127.0.0.1:80:80 simonbrooke/smeagol + +Where 127.0.0.1 is the IP address through which you want to forward port 80 (in real life it wouldn't be 127.0.0.1, but that's safe for testing). + +You can then browse to Smeagol by pointing your browser at http://localhost/. + +As of version 0.99.10, the Docker image is now based on the Jetty, rather than the Tomcat, deployment of Smeagol (that is to say, it runs the executable jar file). This makes for a lighter weight Docker image, but there are still some problems which need to be addressed. + +The `config.edn` and `passwd` files and the `content` directory are copied into `/usr/local/etc` in the Docker image, and the appropriate environment variables are set up to point to them: +``` +COPY resources/passwd /usr/local/etc/passwd +COPY resources/config.edn /usr/local/etc/config.edn +COPY resources/public/content /usr/local/etc/content + +ENV SMEAGOL_CONFIG=/usr/local/etc/config.edn +ENV SMEAGOL_CONTENT_DIR=/usr/local/etc/content +ENV SMEAGOL_PASSWD=/usr/local/etc/passwd +``` +This works for play purposes. However, it means that any edits made to either the `passwd` file or the `content` directory will be lost when the Docker image is shut down. You really need to have these resources copied to a place in a real file system which is mounted by the image. While I intend that by the 1.1.0 release of Smeagol it will be possible to configure a remote origin repository to which changes are periodically pushed, which will backup and preserve the content, this won't save the `passwd` file, as this is deliberately not stored in the git repository for security reasons. + +## Mounting real file systems + +It's possible to mount external file systems, and to override environment variables, with arguments to Docker's extraordinarily complex [run command](https://docs.docker.com/engine/reference/commandline/run/). + +I'm currently working with a recipe: + + docker run -p 127.0.0.1:80:80 -v ~/tmp/etc:/usr/local/etc simonbrooke/smeagol + +Where: + +1. `127.0.0.1` is the IP address on the real host on which you wish to serve; +2. `:80:80` maps port 80 on the image to port 80 on the specified IP address; +3. `~/tmp/etc` is the directory on the file system of the real host where files are stored; +4. `/usr/local/etc` is the directory within the image file system to which that will be mounted; + +This works, and uses the default values of the environment variables which are set up in the Docker image. However, I'm very much prepared to believe there are better recipes. + +## Status + +This image is _experimental_, but it does seem to work fairly well. What it does **not** yet do, however, is push the git repository to a remote location, so when you tear the Docker image down your edits will be lost. My next objective for this image is for it to have a cammand line parameter being the git address of a repository from which it can initialise the Wiki content, and to which it will periodically push local changes to the Wiki content. + +## Building the Docker image + +To build your own Docker image, run: + + lein clean + lein bower install + lein ring uberjar + lein docker build + +This will build a new Docker image locally; you can, obviously, push it to your own Docker repository if you wish. From 3a4d177923196bd83dab675e4eca094801e53f28 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Tue, 12 Sep 2017 01:03:18 +0100 Subject: [PATCH 05/48] Version 0.99.10 --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index d599bae..36f3ba6 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject smeagol "0.99.10-SNAPSHOT" +(defproject smeagol "0.99.10" :description "A simple Git-backed Wiki inspired by Gollum" :url "https://github.com/simon-brooke/smeagol" :license {:name "GNU General Public License,version 2.0 or (at your option) any later version" From 9152d1fe6d5beb3428832cb155c89555174bb3b5 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Tue, 12 Sep 2017 01:14:45 +0100 Subject: [PATCH 06/48] Version 0.99.11-SNAPSHOT --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 36f3ba6..0645d57 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject smeagol "0.99.10" +(defproject smeagol "0.99.11-SNAPSHOT" :description "A simple Git-backed Wiki inspired by Gollum" :url "https://github.com/simon-brooke/smeagol" :license {:name "GNU General Public License,version 2.0 or (at your option) any later version" From ee0453e395a3b26dffd3e92bc59a7a98ece99842 Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 12 Sep 2017 11:29:42 +0100 Subject: [PATCH 07/48] Allow configuration to be overridden by environment variables This is (I think) the final piece in enabling Smeagol to be run neatly from Docker and, indeed, from a pre-packaged jar file. --- src/smeagol/configuration.clj | 52 +++++++++++++++++++++++++++++++++-- src/smeagol/handler.clj | 10 ++++++- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/smeagol/configuration.clj b/src/smeagol/configuration.clj index 0f9bcd4..7b14ed6 100644 --- a/src/smeagol/configuration.clj +++ b/src/smeagol/configuration.clj @@ -44,10 +44,58 @@ (str (io/resource-path) "../config.edn"))) +(defn- from-env-vars + "Read a map from those of these environment variables which have values" + [& vars] + (reduce + #(let [v (env %2)] + (if v (assoc %1 %2 v) %1)) + {} + vars)) + + +(defn transform-map + "transform this map `m` by applying these `transforms`. Each transforms + is expected to comprise a map with the keys :from and :to, whose values + are respectively a key to match and a key to replace that match with, + and optionally a key :transform, whose value is a function of one + argument to be used to transform the value of that key." + [m tuples] + (reduce + (fn [m tuple] + (if + (and (map? tuple) (map? m) (m (:from tuple))) + (let [old-val (m (:from tuple)) + t (:transform tuple) + new-val (if t (apply t (list old-val)) old-val)] + (assoc (dissoc m (:from tuple)) (:to tuple) new-val)) + m)) + m + tuples)) + + +(def config-env-transforms + "Transforms to use with `transform-map` to convert environment + variable names (which need to be specific) into the shorter names + used internally" + '( {:from :smeagol-site-title :to :site-title} + {:from :smeagol-default-locale :to :default-locale} + {:from :smeagol-formatters :to :formatters :transform read-string})) + + (def config - "The actual configuration, as a map." + "The actual configuration, as a map. The idea here is that the config + file is read (if it is specified and present), but that individual + values " (try - (read-string (slurp config-file-path)) + (let [file-contents (try + (read-string (slurp config-file-path)) + (catch Exception _ {}))] + (merge + file-contents + (transform-map + (from-env-vars :smeagol-site-title :smeagol-default-locale) + config-env-transforms))) (catch Exception any (timbre/error any "Could not load configuration") {}))) diff --git a/src/smeagol/handler.clj b/src/smeagol/handler.clj index d44dfc8..dfcf187 100644 --- a/src/smeagol/handler.clj +++ b/src/smeagol/handler.clj @@ -2,6 +2,7 @@ :author "Simon Brooke"} smeagol.handler (:require [clojure.java.io :as cjio] + [clojure.string :refer [lower-case]] [compojure.core :refer [defroutes]] [compojure.route :as route] [cronj.core :as cronj] @@ -43,6 +44,7 @@ (defn user-access [request] (session/get :user)) + (defroutes base-routes (route/resources "/") (route/not-found "Not Found")) @@ -69,7 +71,13 @@ {:rotor (rotor/rotor-appender {:path "smeagol.log" :max-size (* 512 1024) - :backlog 10})}}) + :backlog 10})} + :level (or + (read-string (env :timbre-level)) + (let [level (read-string (env :log-level))] + (if (string? level) (lower-case (keyword level)))) + (if (env :dev) :debug) + :info)}) (cronj/start! session-manager/cleanup-job) (if (env :dev) (parser/cache-off!)) ;;start the expired session cleanup job From a7aca5fab21f92533036486fc96fb30ee2205dfa Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 12 Sep 2017 12:26:34 +0100 Subject: [PATCH 08/48] Documentation of new configuration. --- resources/config.edn | 12 ++++-- resources/public/content/Configuration.md | 37 +++++++++++++------ resources/public/content/Deploying Smeagol.md | 14 +++++-- resources/public/content/Docker Image.md | 2 +- .../public/content/Environment Variables.md | 11 ++++++ src/smeagol/authenticate.clj | 3 +- src/smeagol/configuration.clj | 5 ++- src/smeagol/handler.clj | 5 +-- src/smeagol/util.clj | 2 +- 9 files changed, 65 insertions(+), 26 deletions(-) create mode 100644 resources/public/content/Environment Variables.md diff --git a/resources/config.edn b/resources/config.edn index 27c6a8b..0b86bc2 100644 --- a/resources/config.edn +++ b/resources/config.edn @@ -26,9 +26,15 @@ ;; ; ; ; ; ; ; ; ; ; { - :site-title "Smeagol" ;; overall title of the site, used in page headings - :default-locale "en-GB" ;; default language used for messages - :formatters {"vega" smeagol.formatting/process-vega + :site-title "Smeagol" ;; overall title of the site, used in page headings + :default-locale "en-GB" ;; default language used for messages +;; :content-dir "/home/simon/tmp/test-content" + ;; where content is served from + :passwd "/home/simon/tmp/passwd" + ;; where the password file is stored + :log-level :info ;; the minimum logging level; one of + ;; TRACE DEBUG INFO WARN ERROR FATAL + :formatters {"vega" smeagol.formatting/process-vega "vis" smeagol.formatting/process-vega "mermaid" smeagol.formatting/process-mermaid "backticks" smeagol.formatting/process-backticks} diff --git a/resources/public/content/Configuration.md b/resources/public/content/Configuration.md index fd29caf..4e5d987 100644 --- a/resources/public/content/Configuration.md +++ b/resources/public/content/Configuration.md @@ -2,19 +2,32 @@ Smeagol reads a configuration file, whose content should be formatted as a cloju The default content is as follows: - { - :site-title "Smeagol" ;; overall title of the site, used in page headings - :default-locale "en-GB" ;; default language used for messages - :formatters {"vega" smeagol.formatting/process-vega - "vis" smeagol.formatting/process-vega - "mermaid" smeagol.formatting/process-mermaid - "backticks" smeagol.formatting/process-backticks} - } +``` +{ + :site-title "Smeagol" ;; overall title of the site, used in page headings + :default-locale "en-GB" ;; default language used for messages + :content-dir "/usr/local/etc/content" + ;; where content is served from + :passwd "/usr/local/etc/passwd" + ;; where the password file is stored + :log-level :info ;; the minimum logging level; one of + ;; :trace :debug :info :warn :error :fatal + :formatters {"vega" smeagol.formatting/process-vega + "vis" smeagol.formatting/process-vega + "mermaid" smeagol.formatting/process-mermaid + "backticks" smeagol.formatting/process-backticks} +} +``` -The three keys given above should be present. The values should be: +The values should be: -* **:site-title** The title for your wiki -* **:default-locale** A string comprising a lower-case [ISO 639](https://en.wikipedia.org/wiki/ISO_639) code specifying a language, optionally followed by a hyphen and an upper-case [ISO 3166](https://en.wikipedia.org/wiki/ISO_3166) specifying a country. -* **:formatters** A map of formatters used in [[Extensible Markup]], q.v. +* `:content-dir` The directory in which your editable content is stored; +* `:default-locale` A string comprising a lower-case [ISO 639](https://en.wikipedia.org/wiki/ISO_639) code specifying a language, optionally followed by a hyphen and an upper-case [ISO 3166](https://en.wikipedia.org/wiki/ISO_3166) specifying a country. +* `:formatters` A map of formatters used in [[Extensible Markup]], q.v. +* `:log-level` The minimum level of log messages to be logged; one of `:trace :debug :info :warn :error :fatal` +* `:passwd` The path to your `passwd` file - see [[Security and authentication]]; +* `:site-title` The title for your wiki. The default file is at `resources/config.edn`; this default can be overridden by providing an environment variable, `SMEAGOL_CONFIG`, whose value is the full or relative pathname of a suitable file. + +Note that all the values in the configuration can be overridden with [[Environment Variables]]. diff --git a/resources/public/content/Deploying Smeagol.md b/resources/public/content/Deploying Smeagol.md index 009d610..65c8eae 100644 --- a/resources/public/content/Deploying Smeagol.md +++ b/resources/public/content/Deploying Smeagol.md @@ -6,12 +6,18 @@ To deploy Smeagol as a stand-alone application, either download the jar file for This will create a jar file in the `target` directory, named `smeagol-`*VERSION*`-standalone.jar`. -Smeagol cannot access either its configuration or its content from the jar file, as otherwise they would not be editable. Consequently you should set up three environment variables: +Smeagol cannot access either its configuration or its content from the jar file, as otherwise they would not be editable. There are three solutions to this: -1. `SMEAGOL_CONFIG` should be the full or relative pathname of a Smeagol [[Configuration]] file; -2. `SMEAGOL_CONTENT_DIR` should be the full or relative pathname of the directory from which Smeagol should serve content (which may initially be empty, but must be writable by the process which runs Smeagol)' -3. `SMEAGOL_PASSWD` should be the full or relative pathname of a Smeagol Passwd file - see [[Security and authentication]]. This file must contain an entry for at least your initial user, and, if you want to administer users through the user interface, must be writable by the process which runs Smeagol. +### Custom configuration file +You can copy the standard [[Configuration]] file `resources/config.edn` to somewhere outside the jar file, edit it to suit your installation, and set up a single environment variable, `SMEAGOL_CONFIG`, whose value is the path to your new configuration file. +### Environment variables +Alternatively, you can configure everything through [[Environment Variables]]. + +### Hybrid strategy +You can have both a configuration file and environment variables. If you do this, the environment variables override the values in the configuration file. + +### Necessary content **NOTE** that `SMEAGOL_CONTENT_DIR` must contain at least the following files: 1. `_edit-side-bar.md` - the side-bar that should be displayed when editing pages; diff --git a/resources/public/content/Docker Image.md b/resources/public/content/Docker Image.md index 4bfc58f..c4e4b9a 100644 --- a/resources/public/content/Docker Image.md +++ b/resources/public/content/Docker Image.md @@ -8,7 +8,7 @@ Where 127.0.0.1 is the IP address through which you want to forward port 80 (in You can then browse to Smeagol by pointing your browser at http://localhost/. -As of version 0.99.10, the Docker image is now based on the Jetty, rather than the Tomcat, deployment of Smeagol (that is to say, it runs the executable jar file). This makes for a lighter weight Docker image, but there are still some problems which need to be addressed. +As of version 0.99.10, the Docker image is now based on the Jetty, rather than the Tomcat, deployment of Smeagol (that is to say, it runs the executable jar file). This makes for a lighter weight Docker image. All configuration can be overridden with [[Environment Variables]], which can be passed into the Docker container when the image is invoked, or from a [[Configuration]] file. The `config.edn` and `passwd` files and the `content` directory are copied into `/usr/local/etc` in the Docker image, and the appropriate environment variables are set up to point to them: ``` diff --git a/resources/public/content/Environment Variables.md b/resources/public/content/Environment Variables.md new file mode 100644 index 0000000..cca8a0b --- /dev/null +++ b/resources/public/content/Environment Variables.md @@ -0,0 +1,11 @@ +Smeagol can be configured entirely with environment variables. The variables are: + +1. `SMEAGOL_CONFIG` (optional but advised) should be the full or relative pathname of a Smeagol [[Configuration]] file; +2. `SMEAGOL_CONTENT_DIR` should be the full or relative pathname of the directory from which Smeagol should serve content (which may initially be empty, but must be writable by the process which runs Smeagol); +3. `SMEAGOL_DEFAULT_LOCALE` which should be a locale specification in the form "en-GB", "fr-FR", or whatever to suit your users; +4. `SMEAGOL_FORMATTERS` should be an [edn](https://github.com/edn-format/edn)-formatted map of formatter directives (this would be pretty hard to do from an environment variable); +5. `SMEAGOL_LOG_LEVEL` which should be one of `TRACE DEBUG INFO WARN ERROR FATAL` +6. `SMEAGOL_PASSWD` should be the full or relative pathname of a Smeagol Passwd file - see [[Security and authentication]]. This file must contain an entry for at least your initial user, and, if you want to administer users through the user interface, must be writable by the process which runs Smeagol. +7. `SMEAGOL_SITE_TITLE` which should be the title you want shown on the header of all pages. + +You can have both a configuration file and environment variables; if you do, the values of the environment variables take precedence over the values in the config file. diff --git a/src/smeagol/authenticate.clj b/src/smeagol/authenticate.clj index c65b5ad..e4219e9 100644 --- a/src/smeagol/authenticate.clj +++ b/src/smeagol/authenticate.clj @@ -4,6 +4,7 @@ (:require [crypto.password.scrypt :as password] [environ.core :refer [env]] [noir.io :as io] + [smeagol.configuration :refer [config]] [taoensso.timbre :as timbre])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -37,7 +38,7 @@ ;; the relative path to the password file. (def password-file-path (or - (env :smeagol-passwd) + (:passwd config) (str (io/resource-path) "../passwd"))) diff --git a/src/smeagol/configuration.clj b/src/smeagol/configuration.clj index 7b14ed6..9c67d91 100644 --- a/src/smeagol/configuration.clj +++ b/src/smeagol/configuration.clj @@ -80,7 +80,10 @@ used internally" '( {:from :smeagol-site-title :to :site-title} {:from :smeagol-default-locale :to :default-locale} - {:from :smeagol-formatters :to :formatters :transform read-string})) + {:from :smeagol-formatters :to :formatters :transform read-string} + {:from :smeagol-content-dir :to :content-dir} + {:from :smeagol-passwd :to :passwd} + {:from :smeagol-log-level :to :log-level :transform (fn [s] (keyword (lower-case s)))})) (def config diff --git a/src/smeagol/handler.clj b/src/smeagol/handler.clj index dfcf187..d25e415 100644 --- a/src/smeagol/handler.clj +++ b/src/smeagol/handler.clj @@ -12,6 +12,7 @@ [noir.util.middleware :refer [app-handler]] [ring.middleware.defaults :refer [site-defaults]] [selmer.parser :as parser] + [smeagol.configuration :refer [config]] [smeagol.routes.wiki :refer [wiki-routes]] [smeagol.middleware :refer [load-middleware]] [smeagol.session-manager :as session-manager] @@ -73,9 +74,7 @@ :max-size (* 512 1024) :backlog 10})} :level (or - (read-string (env :timbre-level)) - (let [level (read-string (env :log-level))] - (if (string? level) (lower-case (keyword level)))) + (:log-level config) (if (env :dev) :debug) :info)}) (cronj/start! session-manager/cleanup-job) diff --git a/src/smeagol/util.clj b/src/smeagol/util.clj index 902e377..015a5db 100644 --- a/src/smeagol/util.clj +++ b/src/smeagol/util.clj @@ -37,7 +37,7 @@ (def content-dir (or - (env :smeagol-content-dir) + (:content-dir config) (cjio/file (io/resource-path) "content"))) From 009ae30a08d35f7f9f5cb3952daed3695ea3fb37 Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 12 Sep 2017 16:29:23 +0100 Subject: [PATCH 09/48] Making new config more robust --- resources/config.edn | 18 +++--- resources/passwd | 2 +- resources/public/content/Deploying Smeagol.md | 39 ++++++++++-- .../public/content/Environment Variables.md | 34 ++++++---- src/smeagol/configuration.clj | 63 ++++++++++++++----- src/smeagol/sanity.clj | 5 +- 6 files changed, 119 insertions(+), 42 deletions(-) diff --git a/resources/config.edn b/resources/config.edn index 0b86bc2..0fcb152 100644 --- a/resources/config.edn +++ b/resources/config.edn @@ -22,20 +22,22 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; config.edn: a simple configuration map for Smeagol; inspired by Cryogen. -;;; This is top-level configuration. +;;; This is top-level configuration. All values can be overridden with +;;; environment variables. ;; ; ; ; ; ; ; ; ; ; { - :site-title "Smeagol" ;; overall title of the site, used in page headings + :content-dir "resources/public/content" + ;; where content is served from. :default-locale "en-GB" ;; default language used for messages -;; :content-dir "/home/simon/tmp/test-content" - ;; where content is served from - :passwd "/home/simon/tmp/passwd" - ;; where the password file is stored - :log-level :info ;; the minimum logging level; one of - ;; TRACE DEBUG INFO WARN ERROR FATAL :formatters {"vega" smeagol.formatting/process-vega "vis" smeagol.formatting/process-vega "mermaid" smeagol.formatting/process-mermaid "backticks" smeagol.formatting/process-backticks} + :log-level :info ;; the minimum logging level; one of + ;; :trace :debug :info :warn :error :fatal + :passwd "resources/passwd" + ;; where the password file is stored + :site-title "Smeagol" ;; overall title of the site, used in + ;; page headings } diff --git a/resources/passwd b/resources/passwd index fe61aaf..07bf1d9 100644 --- a/resources/passwd +++ b/resources/passwd @@ -1 +1 @@ -{:admin {:admin true, :email "info@weft.scot", :password "admin"}} +{:admin {:admin true, :email "info@weft.scot", :password "admin"}, :simon {:email "simon@journeyman.cc", :admin true, :password "$s0$f0801$sqhbxtzK6nx9RnVUhwtQlg==$dMIUbof8esjsGyiB+zb3gMH21L/WSCR+wD3vIag4EVc="}} \ No newline at end of file diff --git a/resources/public/content/Deploying Smeagol.md b/resources/public/content/Deploying Smeagol.md index 65c8eae..4bcd304 100644 --- a/resources/public/content/Deploying Smeagol.md +++ b/resources/public/content/Deploying Smeagol.md @@ -1,3 +1,8 @@ +## Choosing a deployment mechanism +There are currently three ways you can deploy Smeagol: as an executable Jar file, as a Docker image, and as a web-app in a [Servlet container](https://en.wikipedia.org/wiki/Web_container). Each method has advantages and disadvantages. + +The Jar file is extremely easy to deploy and to configure, but cannot currently serve [HTTPS](https://en.wikipedia.org/wiki/HTTPS), which, on the modern web, is a significant disadvantage. The Docker image is just a wrapper around the Jar file; it's particularly suitable for automated deployment. The web-app solution offloads responsibility for things like HTTPS to the Servlet container, and consequently can be much more secure; but it can really only be configured at compile time. + ## Deploying as a stand-alone application To deploy Smeagol as a stand-alone application, either download the jar file for the release you want to deploy, or clone the source and compile it with: @@ -9,7 +14,7 @@ This will create a jar file in the `target` directory, named `smeagol-`*VERSION* Smeagol cannot access either its configuration or its content from the jar file, as otherwise they would not be editable. There are three solutions to this: ### Custom configuration file -You can copy the standard [[Configuration]] file `resources/config.edn` to somewhere outside the jar file, edit it to suit your installation, and set up a single environment variable, `SMEAGOL_CONFIG`, whose value is the path to your new configuration file. +You can copy the standard configuration file `resources/config.edn` to somewhere outside the jar file, edit it to suit your installation, and set up a single environment variable, `SMEAGOL_CONFIG`, whose value is the path to your new configuration file. ### Environment variables Alternatively, you can configure everything through [[Environment Variables]]. @@ -18,13 +23,14 @@ Alternatively, you can configure everything through [[Environment Variables]]. You can have both a configuration file and environment variables. If you do this, the environment variables override the values in the configuration file. ### Necessary content -**NOTE** that `SMEAGOL_CONTENT_DIR` must contain at least the following files: + +**NOTE** that the directory at `SMEAGOL_CONTENT_DIR` must contain at least the following files: 1. `_edit-side-bar.md` - the side-bar that should be displayed when editing pages; 2. `_header.md` - the header to be displayed on all pages; 3. `_side-bar.md` - the side-bar that should be displayed when not editing pages. -Standard versions of these files can be found in the [source repository](https://github.com/journeyman-cc/smeagol/tree/master/resources/public/content). All these files should be in markdown format - see [[Extensible Markup]]. +Standard versions of these files can be found in the [source repository](https://github.com/journeyman-cc/smeagol/tree/master/resources/public/content). You can run the jar file with: @@ -38,8 +44,31 @@ To deploy Smeagol within a servlet container, either download the jar file for t This will create a war file in the `target` directory, named `smeagol-`*VERSION*`-standalone.war`. Deploy this to your servlet container in the normal way; details will depend on your container. Instructions for Tomcat are [here](https://tomcat.apache.org/tomcat-8.0-doc/deployer-howto.html). -The problem with this is that unless the environment variables (see above) were already set up in the environment of the servlet container at the time when the servlet container were launched, Smeagol will run with its built-in defaults. This will run perfectly satisfactorily provided your servlet container is configured to unpack war files, which most are. +The problem with this is that unless the environment variables (see above) were already set up in the environment of the servlet container at the time when the servlet container were launched, Smeagol will run with its built-in defaults. If you want to change the defaults, you would have to edit the `resources/config.edn` file and recompile the war file. + +Smeagol will run as a web-app with the default configuration perfectly satisfactorily. ## Experimental Docker image -You can now run Smeagol as a [Docker](http://www.docker.com) image. Read more about using the [[Docker Image]]. +You can now run Smeagol as a [Docker](http://www.docker.com) image. Read more about [[Using the Docker Image]]. + +To run my Docker image, use + + docker run simonbrooke/smeagol + +Smeagol will run, obviously, on the IP address of your Docker image, on port 8080. To find the IP address, start the image using the command above and then use + + docker inspect --format '{{ .NetworkSettings.IPAddress }}' $(docker ps -q) + +Suppose this prints '10.10.10.10', then the URL to browse to will be http://10.10.10.10:8080/smeagol/ + +This image is _experimental_, but it does seem to work fairly well. What it does **not** yet do, however, is push the git repository to a remote location, so when you tear the Docker image down your edits will be lost. My next objective for this image is for it to have a cammand line parameter being the git address of a repository from which it can initialise the Wiki content, and to which it will periodically push local changes to the Wiki content. + +To build your own Docker image, run: + + lein clean + lein bower install + lein ring uberwar + lein docker build + +This will build a new Docker image locally; you can, obviously, push it to your own Docker repository if you wish. diff --git a/resources/public/content/Environment Variables.md b/resources/public/content/Environment Variables.md index cca8a0b..6f95178 100644 --- a/resources/public/content/Environment Variables.md +++ b/resources/public/content/Environment Variables.md @@ -1,11 +1,23 @@ -Smeagol can be configured entirely with environment variables. The variables are: - -1. `SMEAGOL_CONFIG` (optional but advised) should be the full or relative pathname of a Smeagol [[Configuration]] file; -2. `SMEAGOL_CONTENT_DIR` should be the full or relative pathname of the directory from which Smeagol should serve content (which may initially be empty, but must be writable by the process which runs Smeagol); -3. `SMEAGOL_DEFAULT_LOCALE` which should be a locale specification in the form "en-GB", "fr-FR", or whatever to suit your users; -4. `SMEAGOL_FORMATTERS` should be an [edn](https://github.com/edn-format/edn)-formatted map of formatter directives (this would be pretty hard to do from an environment variable); -5. `SMEAGOL_LOG_LEVEL` which should be one of `TRACE DEBUG INFO WARN ERROR FATAL` -6. `SMEAGOL_PASSWD` should be the full or relative pathname of a Smeagol Passwd file - see [[Security and authentication]]. This file must contain an entry for at least your initial user, and, if you want to administer users through the user interface, must be writable by the process which runs Smeagol. -7. `SMEAGOL_SITE_TITLE` which should be the title you want shown on the header of all pages. - -You can have both a configuration file and environment variables; if you do, the values of the environment variables take precedence over the values in the config file. +## Smeagol-specific environment variables +Smeagol can be configured entirely with environment variables. The variables are: + +1. `SMEAGOL_CONFIG` (optional but advised) should be the full or relative pathname of a Smeagol [[Configuration]] file; +2. `SMEAGOL_CONTENT_DIR` should be the full or relative pathname of the directory from which Smeagol should serve content (which may initially be empty, but must be writable by the process which runs Smeagol); +3. `SMEAGOL_DEFAULT_LOCALE` which should be a locale specification in the form "en-GB", "fr-FR", or whatever to suit your users; +4. `SMEAGOL_FORMATTERS` should be an [edn](https://github.com/edn-format/edn)-formatted map of formatter directives (this would be pretty hard to do from an environment variable); +5. `SMEAGOL_LOG_LEVEL` which should be one of `TRACE DEBUG INFO WARN ERROR FATAL` +6. `SMEAGOL_PASSWD` should be the full or relative pathname of a Smeagol Passwd file - see [[Security and authentication]]. This file must contain an entry for at least your initial user, and, if you want to administer users through the user interface, must be writable by the process which runs Smeagol. +7. `SMEAGOL_SITE_TITLE` which should be the title you want shown on the header of all pages. + +You can have both a configuration file and environment variables; if you do, the values of the environment variables take precedence over the values in the config file. + +## Other environment variables + +If Smeagol is compiled as an executable jar file, the actual web server component is [Ring server](https://github.com/weavejester/ring-server). This recognises the `PORT` environment variable, and, if this is present and its value is a positive integer, will listen on the specified port (otherwise its default is 3000, which is... unusual). + +Smeagol uses the [Timbre](https://github.com/ptaoussanis/timbre) logging library. This recognises the following environment variables: + +1. `TIMBRE_DEFAULT_STACKTRACE_FONTS` Timbre by default colourises stacktrace dumps using ANSI terminal codes. This can be quite useful in a console, but is a real pain in a log file. To turn colourised stacktraces off, set the value of this to an empty string; +2. `TIMBRE_LEVEL` Sets the minimum logging level; but there are two problems with this. The first is that the environment variable is only read at compile time not at run time, and the second is that the syntax is a bit odd, which is why I've implemented `SMEAGOL_LOG_LEVEL` (above); +3. `TIMBRE_NS_WHITELIST` Sets a list of [Clojure namespaces](https://clojure.org/reference/namespaces) from which messages should be logged; however this is only read at compile time so isn't much use in practice; +4. `TIMBRE_NS_BLACKLIST` As above, but sets a list of namespaces from which messages should **not** be logged. \ No newline at end of file diff --git a/src/smeagol/configuration.clj b/src/smeagol/configuration.clj index 9c67d91..f4631f9 100644 --- a/src/smeagol/configuration.clj +++ b/src/smeagol/configuration.clj @@ -1,7 +1,9 @@ (ns ^{:doc "Read and make available configuration." :author "Simon Brooke"} smeagol.configuration - (:require [environ.core :refer [env]] + (:require [clojure.pprint :refer [pprint]] + [clojure.string :as s] + [environ.core :refer [env]] [noir.io :as io] [taoensso.timbre :as timbre])) @@ -54,6 +56,16 @@ vars)) +(defn to-keyword + "Convert this argument into an idiomatic clojure keyword." + [arg] + (if (and arg (not (keyword? arg))) + (keyword + (s/lower-case + (s/replace (str arg) #"[^A-Za-z0-9]+" "-"))) + arg)) + + (defn transform-map "transform this map `m` by applying these `transforms`. Each transforms is expected to comprise a map with the keys :from and :to, whose values @@ -61,14 +73,21 @@ and optionally a key :transform, whose value is a function of one argument to be used to transform the value of that key." [m tuples] + (timbre/debug + "transform-map:\n" + (with-out-str (clojure.pprint/pprint m))) (reduce (fn [m tuple] (if (and (map? tuple) (map? m) (m (:from tuple))) (let [old-val (m (:from tuple)) - t (:transform tuple) - new-val (if t (apply t (list old-val)) old-val)] - (assoc (dissoc m (:from tuple)) (:to tuple) new-val)) + t (:transform tuple)] + (assoc + (dissoc m (:from tuple)) + (:to tuple) + (if-not + (nil? t) + (eval (list t old-val)) old-val))) m)) m tuples)) @@ -78,27 +97,41 @@ "Transforms to use with `transform-map` to convert environment variable names (which need to be specific) into the shorter names used internally" - '( {:from :smeagol-site-title :to :site-title} + '( {:from :smeagol-content-dir :to :content-dir} {:from :smeagol-default-locale :to :default-locale} {:from :smeagol-formatters :to :formatters :transform read-string} - {:from :smeagol-content-dir :to :content-dir} + {:from :smeagol-log-level :to :log-level :transform to-keyword} {:from :smeagol-passwd :to :passwd} - {:from :smeagol-log-level :to :log-level :transform (fn [s] (keyword (lower-case s)))})) + {:from :smeagol-site-title :to :site-title})) -(def config +(defn build-config + [] "The actual configuration, as a map. The idea here is that the config file is read (if it is specified and present), but that individual - values " + values can be overridden by environment variables." (try (let [file-contents (try (read-string (slurp config-file-path)) - (catch Exception _ {}))] - (merge - file-contents - (transform-map - (from-env-vars :smeagol-site-title :smeagol-default-locale) - config-env-transforms))) + (catch Exception _ {})) + config (merge + file-contents + (transform-map + (from-env-vars + :smeagol-content-dir + :smeagol-default-locale + :smeagol-formatters + :smeagol-log-level + :smeagol-passwd + :smeagol-site-title) + config-env-transforms))] + (if (env :dev) + (timbre/debug + "Loaded configuration\n" + (with-out-str (clojure.pprint/pprint config)))) + config) (catch Exception any (timbre/error any "Could not load configuration") {}))) + +(def config (build-config)) diff --git a/src/smeagol/sanity.clj b/src/smeagol/sanity.clj index e7c0503..1e3430e 100644 --- a/src/smeagol/sanity.clj +++ b/src/smeagol/sanity.clj @@ -1,4 +1,5 @@ -(ns ^{:doc "Functions related to sanity checks and error reporting in conditions where the environment may not be sane." +(ns ^{:doc "Functions related to sanity checks and error reporting in conditions + where the environment may not be sane." :author "Simon Brooke"} smeagol.sanity (:import (java.util Locale)) @@ -412,7 +413,7 @@ (timbre/warn "Sanity check completed; " (count (keys result)) " problem(s) found") (sanity-check-report result)) (do - (timbre/info "Sanity check completed; no problem(s) found") + (timbre/info "Sanity check completed; no problems found") nil)))) From 0194ff477f71abf765e884fdc8980f1a770b341c Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Tue, 12 Sep 2017 16:44:54 +0100 Subject: [PATCH 10/48] Version 0.99.11 --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 0645d57..2bb78a0 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject smeagol "0.99.11-SNAPSHOT" +(defproject smeagol "0.99.11" :description "A simple Git-backed Wiki inspired by Gollum" :url "https://github.com/simon-brooke/smeagol" :license {:name "GNU General Public License,version 2.0 or (at your option) any later version" From a509cadd82a4c5bab419a29d4acc560d87886dfa Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Tue, 12 Sep 2017 16:58:04 +0100 Subject: [PATCH 11/48] Version 0.99.12-SNAPSHOT --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 2bb78a0..73b870e 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject smeagol "0.99.11" +(defproject smeagol "0.99.12-SNAPSHOT" :description "A simple Git-backed Wiki inspired by Gollum" :url "https://github.com/simon-brooke/smeagol" :license {:name "GNU General Public License,version 2.0 or (at your option) any later version" From 948d718b3d97cf71556b8ff155543b8a68f15211 Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 12 Sep 2017 17:02:27 +0100 Subject: [PATCH 12/48] Upversion to 1.0.0 --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 73b870e..38c96f5 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject smeagol "0.99.12-SNAPSHOT" +(defproject smeagol "1.0.0" :description "A simple Git-backed Wiki inspired by Gollum" :url "https://github.com/simon-brooke/smeagol" :license {:name "GNU General Public License,version 2.0 or (at your option) any later version" From c4a0d45adec5bd572d99f671f7171192152a9343 Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 12 Sep 2017 17:07:31 +0100 Subject: [PATCH 13/48] upversion to 1.0.1-SNAPSHOT --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 38c96f5..efd7bc2 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject smeagol "1.0.0" +(defproject smeagol "1.0.1-SNAPSHOT" :description "A simple Git-backed Wiki inspired by Gollum" :url "https://github.com/simon-brooke/smeagol" :license {:name "GNU General Public License,version 2.0 or (at your option) any later version" From 80bb64465b27a02c81b75aa23c5193ffb9e96b1f Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 12 Sep 2017 17:31:55 +0100 Subject: [PATCH 14/48] Bringing the default content and the GitHub wiki into line --- resources/public/content/Deploying Smeagol.md | 21 +------------------ resources/public/content/Docker Image.md | 6 +++--- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/resources/public/content/Deploying Smeagol.md b/resources/public/content/Deploying Smeagol.md index 4bcd304..222d5fe 100644 --- a/resources/public/content/Deploying Smeagol.md +++ b/resources/public/content/Deploying Smeagol.md @@ -50,25 +50,6 @@ Smeagol will run as a web-app with the default configuration perfectly satisfact ## Experimental Docker image -You can now run Smeagol as a [Docker](http://www.docker.com) image. Read more about [[Using the Docker Image]]. +You can now run Smeagol as a [Docker](http://www.docker.com) image. Read more about using the [[Docker Image]]. -To run my Docker image, use - docker run simonbrooke/smeagol - -Smeagol will run, obviously, on the IP address of your Docker image, on port 8080. To find the IP address, start the image using the command above and then use - - docker inspect --format '{{ .NetworkSettings.IPAddress }}' $(docker ps -q) - -Suppose this prints '10.10.10.10', then the URL to browse to will be http://10.10.10.10:8080/smeagol/ - -This image is _experimental_, but it does seem to work fairly well. What it does **not** yet do, however, is push the git repository to a remote location, so when you tear the Docker image down your edits will be lost. My next objective for this image is for it to have a cammand line parameter being the git address of a repository from which it can initialise the Wiki content, and to which it will periodically push local changes to the Wiki content. - -To build your own Docker image, run: - - lein clean - lein bower install - lein ring uberwar - lein docker build - -This will build a new Docker image locally; you can, obviously, push it to your own Docker repository if you wish. diff --git a/resources/public/content/Docker Image.md b/resources/public/content/Docker Image.md index c4e4b9a..9341628 100644 --- a/resources/public/content/Docker Image.md +++ b/resources/public/content/Docker Image.md @@ -3,7 +3,7 @@ Smeagol is available as a Docker image To run my Docker image, use docker run -p 127.0.0.1:80:80 simonbrooke/smeagol - + Where 127.0.0.1 is the IP address through which you want to forward port 80 (in real life it wouldn't be 127.0.0.1, but that's safe for testing). You can then browse to Smeagol by pointing your browser at http://localhost/. @@ -24,7 +24,7 @@ This works for play purposes. However, it means that any edits made to either th ## Mounting real file systems -It's possible to mount external file systems, and to override environment variables, with arguments to Docker's extraordinarily complex [run command](https://docs.docker.com/engine/reference/commandline/run/). +It's possible to mount external file systems, and to override environment variables, with arguments to Docker's extraordinarily complex [run command](https://docs.docker.com/engine/reference/commandline/run/). I'm currently working with a recipe: @@ -41,7 +41,7 @@ This works, and uses the default values of the environment variables which are s ## Status -This image is _experimental_, but it does seem to work fairly well. What it does **not** yet do, however, is push the git repository to a remote location, so when you tear the Docker image down your edits will be lost. My next objective for this image is for it to have a cammand line parameter being the git address of a repository from which it can initialise the Wiki content, and to which it will periodically push local changes to the Wiki content. +This image is _experimental_, but it does seem to work fairly well. What it does **not** yet do, however, is push the git repository to a remote location, so unless you have mounted an external file store, when you tear the Docker image down your edits will be lost. My next objective for this image is for it to have a cammand line parameter being the git address of a repository from which it can initialise the Wiki content, and to which it will periodically push local changes to the Wiki content. ## Building the Docker image From 1cfc3876e03876f1eae1bd67cc2ddf325bb3e587 Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 15 Sep 2017 19:23:31 +0100 Subject: [PATCH 15/48] Translations provided by Soukyan --- resources/i18n/de-DE.edn | 144 +++++++++++++++++++++++++++++++++++++++ resources/i18n/en-GB.edn | 2 +- resources/i18n/lt_LT.edn | 143 ++++++++++++++++++++++++++++++++++++++ resources/i18n/ru_RU.edn | 144 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 432 insertions(+), 1 deletion(-) create mode 100644 resources/i18n/de-DE.edn create mode 100644 resources/i18n/lt_LT.edn create mode 100644 resources/i18n/ru_RU.edn diff --git a/resources/i18n/de-DE.edn b/resources/i18n/de-DE.edn new file mode 100644 index 0000000..e65114d --- /dev/null +++ b/resources/i18n/de-DE.edn @@ -0,0 +1,144 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; +;;;; 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. +;;;; +;;;; German language translation contributed by and +;;;; Copyright (C) 2017 Soukyan Blackwood +;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; en-GB.edn: English-language messages. +;;; This is essentially all the text in the chrome - that which isn't editable +;;; through the wiki itself; and the test in the sanity check report. + +;; ; ; ; ; ; ; ; ; ; +{:add-user-label "Neuen Benutzer zufügen" ;; label for the add user link on edit users page + :change-pass-label "Kennwort ändern!" + ;; text of the change password widget itself on the + ;; change password page + :change-pass-link "Kennwort ändern" + ;; text of the change password link on the menu + :change-pass-prompt "Um Ihr Kennwort zu ändern" + ;; text of the change password widget prompt on the + ;; change password page + :change-col-hdr "Änderungen" ;; header for the changes column in history + :chpass-bad-match "Die von Ihnen vorgeschlagenen Kennwörter stimmen nicht überein" + ;; error text if proposed passwords don't match + :chpass-fail "Ihr Kennwort wurde nicht geändert" + ;; error text on fail other htan too short or bad match + :chpass-success "Ihr Kennwort wurde geändert" + ;; confirmation text on password change + :chpass-too-short "Das von Ihnen vorgeschlagene Kennwort war zu kurz: 8 Zeichen erforderlich" + ;; error text if proposed password is too short + :chpass-title-prefix "Kennwort ändern für" + ;; prefix for title of change password page + :content-dir "Das Inhaltsverzeichnis" + ;; used in sanity check report + :content-dir-exists "Das Inhaltsverzeichnis existiert" + ;; used in sanity check report + :content-dir-is-dir "Das Inhaltsverzeichnis ist ein Verzeichnis" + ;; used in sanity check report + :cookies-about "Über Cookies" ;; about cookies text + :cookies-more "Es wird von Ihrem Browser gelöscht, sobald Sie diese Seite verlassen. Diese Webseite benutzt keine Cookies von dritten Parteien, daher kann Ihr Besuch hier nicht von anderen Seiten verfolgt werden." + ;; more about cookies text + :default-page-title "Einleitung" ;; title of the default page in this wiki + :del-col-hdr "Löschen" ;; header for delete column on edit users page + :del-user-fail "Könnte Benutzer nicht löschen" + ;; error message on failure to delete user + :del-user-success "Benutzer wurde erfolgreich gelöscht" + ;; confirmation message on deletion of user + :diff-title-prefix "Änderungen seit der Version" + ;; prefix for the header of the changes page + :does-not-exist "existiert nicht" + ;; (of a file or directory); used in sanity check report + :edit-col-hdr "Bearbeiten" ;; header for edit column on edit users page + :edit-page-link "Diese Seite bearbeiten" + ;; text of the edit page link on the content frame + :edit-title-prefix "Bearbeiten" ;; prefix for title of edit content page + :edit-users-link "Benutzer bearbeiten" ;; text of the edit users link on the menu + :edit-users-title "Benutzer zum Bearbeiten auswählen" + ;; title of edit users page + :email-prompt "E-Mail Adresse" ;; text of the email widget prompt on edit user page + :file-or-directory "Datei oder Verzeichnis" + ;; used in sanity check report + :file-summary-prompt "Beschreibung/was wurde gändert" + ;; prompt for the file upload summary input + :file-upload-link-text "Sie können auf diese Datei verweisen, mit Hilfe von einer Verknüpfung von der Form" + ;; Text introducing the link to an uploaded file + :file-upload-prompt "Datei zum Hochladen" ;; prompt string for the file upload widget + :file-upload-title "Upload a file" ;; title for the file upload page + :is-admin-prompt "Ist Administrator?" + :here "hier" ;; used in sanity check report + :home-link "Startseite" ;; text of the home link on the menu + :is-not-directory "ist kein Verzeichnis" + ;; (of a file or directory) used in sanity check report + :is-not-readable "ist nicht lesbar" + ;; (of a file or directory) used in sanity check report + :is-not-writable "ist nicht schreibbar" + ;; (of a file or directory) used in sanity check report + :login-label "Log in!" ;; text of the login widget on the login page + :login-link "Log in" ;; text of the login link on the menu + :login-prompt "Um dieses Wiki zu bearbeiten" + ;; text of the action widget prompt on the login page + :logout-label "Abmelden!" ;; text of the logout widget on the logout page + :logout-link "Abmelden" ;; text of the logout link on the menu + :logged-in-as "Sie sind angemeldet als" + ;; text of the 'logged in as' label on the menu + :history-link "Historie" ;; text of the history link on the content frame + :history-title-prefix "Historie von" ;; prefix of the title on the history page + :new-pass-prompt "Neues Kennwort" ;; text of the new password widget prompt on the change + ;; password and edit user pages + :no-admin-users "In der Datei 'passwd' gibt es keine Benutzer mit Administratorrechten" + ;; used in sanity check report + :old-pass-prompt "Ihr Kennwort" + ;; text of the old password widget prompt on the change + ;; password page, and password widget on login page + :password-file "Die Kennwort ('passwd') Datei" + ;; used in sanity check report + :problems-found "Probleme gefunden" + ;; used in sanity check report + :rpt-pass-prompt "und noch einmal" ;; text of the new password widget prompt on the change + ;; password and edit user pages + :save-prompt "Wenn Sie mit dem Bearbeiten fertig sind" + ;; text of the save widget label on edit content + ;; and edit user page + :save-label "Speichern!" ;; text of the save widget itself + :save-user-fail "Benutzer konnte nicht gespeichert werden" + :save-user-success "Benutzer erfolgreich gespeichert" + :see-documentation "Für mehr Information sehen Sie bitte die Dokumentation " + ;; used in sanity check report + :smeagol-not-initialised + "Smeagol ist nicht richtig initialisiert" + ;; title of the sanity check report + :smeagol-misconfiguration + "Smeagol konnte einige der Ressourcen, von denen es abhängt, +nicht finden; wahrscheinlich wegen einer Fehlkonfiguration oder fehlenden Umgebungsvariablen." + ;; used in sanity check report + :user-lacks-field "Das Feld für den Benutzereintrag in die passwd Datei fehlt" + ;; used in sanity check report + :username-prompt "Benutzername" ;; text of the username widget prompt on edit user page + ;; text of the is admin widget prompt on edit user page + :user-title-prefix "Benutzer bearbeiten" ;; prefix for title of edit user page + :vers-col-hdr "Version" ;; header for the version column in history + :what-col-hdr "Wann" ;; header for the what column in history + :what-changed-prompt "Was haben Sie verändert?" + ;; text of the summary widget prompt on edit + ;; content page + :when-col-hdr "When" ;; header for the when column in history + :your-uname-prompt "Ihr Benutzername" ;; text of the username widget prompt on the login page + } diff --git a/resources/i18n/en-GB.edn b/resources/i18n/en-GB.edn index a7b8789..64c164c 100644 --- a/resources/i18n/en-GB.edn +++ b/resources/i18n/en-GB.edn @@ -42,7 +42,7 @@ ;; error text on fail other htan too short or bad match :chpass-success "Your password was changed" ;; confirmation text on password change - :chpass-too-short "You proposed password wasn't long enough: eight characters required" + :chpass-too-short "Your proposed password wasn't long enough: eight characters required" ;; error text if proposed password is too short :chpass-title-prefix "Change password for" ;; prefix for title of change password page diff --git a/resources/i18n/lt_LT.edn b/resources/i18n/lt_LT.edn new file mode 100644 index 0000000..9d585c9 --- /dev/null +++ b/resources/i18n/lt_LT.edn @@ -0,0 +1,143 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; +;;;; 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. +;;;; +;;;; Lithuanian language translation contributed by and +;;;; Copyright (C) 2017 Soukyan Blackwood +;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; en-GB.edn: English-language messages. +;;; This is essentially all the text in the chrome - that which isn't editable +;;; through the wiki itself; and the test in the sanity check report. + +;; ; ; ; ; ; ; ; ; ; +{:add-user-label "Pridėti naują naudotoją" ;; label for the add user link on edit users page + :change-pass-label "Pakeiskite slaptažodį!" + ;; text of the change password widget itself on the + ;; change password page + :change-pass-link "Pakeiskite slaptažodį" + ;; text of the change password link on the menu + :change-pass-prompt "Pakeisti slaptažodį" + ;; text of the change password widget prompt on the + ;; change password page + :change-col-hdr "Pakeitimai" ;; header for the changes column in history + :chpass-bad-match "Jūsų siūlomi slaptažodžiai - nesutampa" + ;; error text if proposed passwords don't match + :chpass-fail "Jūsų slaptažodis nebuvo pakeistas" + ;; error text on fail other htan too short or bad match + :chpass-success "Jūsų slaptažodis buvo pakeistas" + ;; confirmation text on password change + :chpass-too-short "Jūsų siūlomas slaptožodis – per trumpas: reikia bent aštuonių ženklų" + ;; error text if proposed password is too short + :chpass-title-prefix "Pakeisti slaptažodį, dėl" + ;; prefix for title of change password page + :content-dir "Turinio katalogas" + ;; used in sanity check report + :content-dir-exists "Turinio katalogas egzistuoja" + ;; used in sanity check report + :content-dir-is-dir "Turinio katalogas yra katalogas" + ;; used in sanity check report + :cookies-about "About cookies" ;; about cookies text + :cookies-more "Šis puslapis saugo jūsų sesijų informaciją jūsų naršyklėje “slapukų” forma. Tai mums leidžia jums rodyti tik tai, ką norite matyti. Slapukai neturi jokių jūsų identifikavimo duomenų ir kiti puslapiai negali jų “perskaityti”. Šie slapukai ištrinami iš karto, vos jūs išjungiate šį puslapį. Šis puslapis nenaudoja jokių trečiųjų asmenų slapukų, ir jūsų apsilankymas čia negali būti atsektas jokio kito puslapio." + ;; more about cookies text + :default-page-title "Pristatymas" ;; title of the default page in this wiki + :del-col-hdr "Ištrinti" ;; header for delete column on edit users page + :del-user-fail "Naudotojas negalėjo būti ištrintas" + ;; error message on failure to delete user + :del-user-success "Naudotojas sėkmingai ištrintas" + ;; confirmation message on deletion of user + :diff-title-prefix "Pakeitimai nuo versijos" + ;; prefix for the header of the changes page + :does-not-exist "neegzsituoja" + ;; (of a file or directory); used in sanity check report + :edit-col-hdr "Keisti" ;; header for edit column on edit users page + :edit-page-link "Keisti šį puslapį" + ;; text of the edit page link on the content frame + :edit-title-prefix "Keisti" ;; prefix for title of edit content page + :edit-users-link "Keisti naudotojus" ;; text of the edit users link on the menu + :edit-users-title "Pasirinkti naudotojus keitimui" + ;; title of edit users page + :email-prompt "el. Paštas" ;; text of the email widget prompt on edit user page + :file-or-directory "Failas ar katalogas" + ;; used in sanity check report + :file-summary-prompt "Aprašymas/kas pakeista" + ;; prompt for the file upload summary input + :file-upload-link-text "Galite nukreipti į šį failą naudodami formos nuorodą" + ;; Text introducing the link to an uploaded file + :file-upload-prompt "Failas įkėlimui" ;; prompt string for the file upload widget + :file-upload-title "Įkelti failą" ;; title for the file upload page + :is-admin-prompt "Administratorius?" + :here "čia" ;; used in sanity check report + :home-link "Pradinis" ;; text of the home link on the menu + :is-not-directory "ne katalogas" + ;; (of a file or directory) used in sanity check report + :is-not-readable "neperskaitomas" + ;; (of a file or directory) used in sanity check report + :is-not-writable "nerašomas" + ;; (of a file or directory) used in sanity check report + :login-label "Prisijunkite!" ;; text of the login widget on the login page + :login-link "Prisijunkite" ;; text of the login link on the menu + :login-prompt "Pakeisti šį viki" + ;; text of the action widget prompt on the login page + :logout-label "Atsijunkite!" ;; text of the logout widget on the logout page + :logout-link "Atsijunkite" ;; text of the logout link on the menu + :logged-in-as "Jūs prisijungęs, kaip" + ;; text of the 'logged in as' label on the menu + :history-link "Istorija" ;; text of the history link on the content frame + :history-title-prefix "Istorija apie" ;; prefix of the title on the history page + :new-pass-prompt "Naujas slaptažodis" ;; text of the new password widget prompt on the change + ;; password and edit user pages + :no-admin-users "Naudotojų ‘passwd’ faile su administatoriaus privilegijomis nėra" + ;; used in sanity check report + :old-pass-prompt "Jūsų slaptažodis" + ;; text of the old password widget prompt on the change + ;; password page, and password widget on login page + :password-file "slaptažodžio (‘passwd’) failas" + ;; used in sanity check report + :problems-found "rasta problemų" + ;; used in sanity check report + :rpt-pass-prompt "Ir dar kartą" ;; text of the new password widget prompt on the change + ;; password and edit user pages + :save-prompt "Kai baigsite redaguoti" + ;; text of the save widget label on edit content + ;; and edit user page + :save-label "Išsaugokite!" ;; text of the save widget itself + :save-user-fail "Nepavyko išsaugoti naudotojo" + :save-user-success "Naudotojas sėkmingai išsaugotas" + :see-documentation "Daugiau informacijos ieškokite dokumentacijoje " + ;; used in sanity check report + :smeagol-not-initialised + "Smygolas buvo blogai paleistas" + ;; title of the sanity check report + :smeagol-misconfiguration + "Smygolas nerado kai kurių jam reikalingų resursų, taip nutikti galėjo dėl neteisingų nustatymų, arba trūkstamų aplinkos kintamųjų" + ;; used in sanity check report + :user-lacks-field "Naudotojo passwd failo įraše trūksta laukelio" + ;; used in sanity check report + :username-prompt "Naudotojo vardas" ;; text of the username widget prompt on edit user page + ;; text of the is admin widget prompt on edit user page + :user-title-prefix "Pakeisti naudotoją" ;; prefix for title of edit user page + :vers-col-hdr "Versija" ;; header for the version column in history + :what-col-hdr "Kas" ;; header for the what column in history + :what-changed-prompt "Ką pakeitėte?" + ;; text of the summary widget prompt on edit + ;; content page + :when-col-hdr "Kada" ;; header for the when column in history + :your-uname-prompt "Jūsų naudotojo vardas" ;; text of the username widget prompt on the login page + } diff --git a/resources/i18n/ru_RU.edn b/resources/i18n/ru_RU.edn new file mode 100644 index 0000000..73400d6 --- /dev/null +++ b/resources/i18n/ru_RU.edn @@ -0,0 +1,144 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; +;;;; 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. +;;;; +;;;; Russian language translation contributed by and +;;;; Copyright (C) 2017 Soukyan Blackwood +;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; en-GB.edn: English-language messages. +;;; This is essentially all the text in the chrome - that which isn't editable +;;; through the wiki itself; and the test in the sanity check report. + +;; ; ; ; ; ; ; ; ; ; +{:add-user-label "добавить нового пользователя" ;; label for the add user link on edit users page + :change-pass-label "изменить пароль!" + ;; text of the change password widget itself on the + ;; change password page + :change-pass-link "изменить пароль" + ;; text of the change password link on the menu + :change-pass-prompt "Чтобы изменить пароль" + ;; text of the change password widget prompt on the + ;; change password page + :change-col-hdr "изменения" ;; header for the changes column in history + :chpass-bad-match "Ваши предложенные пароли не совпадают" + ;; error text if proposed passwords don't match + :chpass-fail "Ваш пароль не был изменён" + ;; error text on fail other htan too short or bad match + :chpass-success "Ваш пароль был изменён" + ;; confirmation text on password change + :chpass-too-short "Вы предложили пароль недостаточно длины: требуется восемь символов" + ;; error text if proposed password is too short + :chpass-title-prefix "Изменить пароль для" + ;; prefix for title of change password page + :content-dir "Каталог содержимого" + ;; used in sanity check report + :content-dir-exists "Каталог содержимого существуе" + ;; used in sanity check report + :content-dir-is-dir "Каталог содержимого - это каталог" + ;; used in sanity check report + :cookies-about "Об кукисах" ;; about cookies text + :cookies-more "Этот сайт хранит информацию о сеансе как «cookie» в вашем браузере. Это поможет нам показать вам контент, который вы хотите увидеть. Этот файл cookie не идентифицирует вас и не может быть прочитан другими веб-сайтами. Он удаляется браузером, как только вы покидаете этот сайт. Этот веб-сайт не использует сторонние файлы cookie, поэтому ваш визит здесь не может быть отслежен другими веб-сайтами" + ;; more about cookies text + :default-page-title "представление" ;; title of the default page in this wiki + :del-col-hdr "Удалить" ;; header for delete column on edit users page + :del-user-fail "Не удалось удалить пользователя" + ;; error message on failure to delete user + :del-user-success "успешно удалён пользователь" + ;; confirmation message on deletion of user + :diff-title-prefix "Изменения с версии" + ;; prefix for the header of the changes page + :does-not-exist "не существует" + ;; (of a file or directory); used in sanity check report + :edit-col-hdr "редактировать" ;; header for edit column on edit users page + :edit-page-link "Редактировать эту страницу" + ;; text of the edit page link on the content frame + :edit-title-prefix "редактировать" ;; prefix for title of edit content page + :edit-users-link "Редактировать пользователей" ;; text of the edit users link on the menu + :edit-users-title "Выберите пользователя для редактирования" + ;; title of edit users page + :email-prompt "Адрес электронной почты" ;; text of the email widget prompt on edit user page + :file-or-directory "Файл или каталог" + ;; used in sanity check report + :file-summary-prompt "Описание / что изменилось" + ;; prompt for the file upload summary input + :file-upload-link-text "Вы можете ссылать этот файл, используя ссылку формы" + ;; Text introducing the link to an uploaded file + :file-upload-prompt "Файл для загрузки" ;; prompt string for the file upload widget + :file-upload-title "Загрузить файл" ;; title for the file upload page + :is-admin-prompt "Администратор?" + :here "здесь" ;; used in sanity check report + :home-link "Главная" ;; text of the home link on the menu + :is-not-directory "не является каталогом" + ;; (of a file or directory) used in sanity check report + :is-not-readable "не читаемый" + ;; (of a file or directory) used in sanity check report + :is-not-writable "недоступен для записи" + ;; (of a file or directory) used in sanity check report + :login-label "Вход!" ;; text of the login widget on the login page + :login-link "Вход" ;; text of the login link on the menu + :login-prompt "Чтобы отредактировать эту вики" + ;; text of the action widget prompt on the login page + :logout-label "Выйти!" ;; text of the logout widget on the logout page + :logout-link "Выйти" ;; text of the logout link on the menu + :logged-in-as "Вы вошли как" + ;; text of the 'logged in as' label on the menu + :history-link "история" ;; text of the history link on the content frame + :history-title-prefix "История об" ;; prefix of the title on the history page + :new-pass-prompt "Новый пароль" ;; text of the new password widget prompt on the change + ;; password and edit user pages + :no-admin-users "В файле 'passwd' нет пользователей с правами администратора" + ;; used in sanity check report + :old-pass-prompt "Ваш пароль" + ;; text of the old password widget prompt on the change + ;; password page, and password widget on login page + :password-file "файл пароля ('passwd')" + ;; used in sanity check report + :problems-found "проблемы были найдены" + ;; used in sanity check report + :rpt-pass-prompt "И опять" ;; text of the new password widget prompt on the change + ;; password and edit user pages + :save-prompt "Когда вы закончили редактирование" + ;; text of the save widget label on edit content + ;; and edit user page + :save-label "Сохранить!" ;; text of the save widget itself + :save-user-fail "Не удалось сохранить пользователя" + :save-user-success "Успешно сохранённый пользователь" + :see-documentation "для получения дополнительной информации смотрите документацию " + ;; used in sanity check report + :smeagol-not-initialised + "Смеаголь неправильно инициализирован" + ;; title of the sanity check report + :smeagol-misconfiguration + "Смеаголь не смог найти некоторые ресурсы, от которых это зависит, + возможно, из-за неправильной конфигурации или отсутствующих переменных среды." + ;; used in sanity check report + :user-lacks-field "В пользовательской записи в файле passwd отсутствует поле" + ;; used in sanity check report + :username-prompt "Имя пользователя" ;; text of the username widget prompt on edit user page + ;; text of the is admin widget prompt on edit user page + :user-title-prefix "Изменить пользователя" ;; prefix for title of edit user page + :vers-col-hdr "Версия" ;; header for the version column in history + :what-col-hdr "Что" ;; header for the what column in history + :what-changed-prompt "Что вы изменили?" + ;; text of the summary widget prompt on edit + ;; content page + :when-col-hdr "когда" ;; header for the when column in history + :your-uname-prompt "Ваш логин" ;; text of the username widget prompt on the login page + } From fbb04e558acbdac9898c2b026e129a141f76830b Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 15 Sep 2017 21:32:28 +0100 Subject: [PATCH 16/48] Minor fixes to translations --- resources/config.edn | 4 ++-- resources/i18n/de-DE.edn | 4 ++-- resources/i18n/de.edn | 1 + resources/i18n/lt.edn | 1 + resources/i18n/ru.edn | 1 + resources/public/content/Introduction.md | 3 +++ src/smeagol/routes/wiki.clj | 2 +- 7 files changed, 11 insertions(+), 5 deletions(-) create mode 120000 resources/i18n/de.edn create mode 120000 resources/i18n/lt.edn create mode 120000 resources/i18n/ru.edn diff --git a/resources/config.edn b/resources/config.edn index 0fcb152..23b1f58 100644 --- a/resources/config.edn +++ b/resources/config.edn @@ -29,12 +29,12 @@ { :content-dir "resources/public/content" ;; where content is served from. - :default-locale "en-GB" ;; default language used for messages + :default-locale "lt-LT" ;; default language used for messages :formatters {"vega" smeagol.formatting/process-vega "vis" smeagol.formatting/process-vega "mermaid" smeagol.formatting/process-mermaid "backticks" smeagol.formatting/process-backticks} - :log-level :info ;; the minimum logging level; one of + :log-level :trace ;; the minimum logging level; one of ;; :trace :debug :info :warn :error :fatal :passwd "resources/passwd" ;; where the password file is stored diff --git a/resources/i18n/de-DE.edn b/resources/i18n/de-DE.edn index e65114d..5457d10 100644 --- a/resources/i18n/de-DE.edn +++ b/resources/i18n/de-DE.edn @@ -135,10 +135,10 @@ nicht finden; wahrscheinlich wegen einer Fehlkonfiguration oder fehlenden Umgebu ;; text of the is admin widget prompt on edit user page :user-title-prefix "Benutzer bearbeiten" ;; prefix for title of edit user page :vers-col-hdr "Version" ;; header for the version column in history - :what-col-hdr "Wann" ;; header for the what column in history + :what-col-hdr "Wass" ;; header for the what column in history :what-changed-prompt "Was haben Sie verändert?" ;; text of the summary widget prompt on edit ;; content page - :when-col-hdr "When" ;; header for the when column in history + :when-col-hdr "Was" ;; header for the when column in history :your-uname-prompt "Ihr Benutzername" ;; text of the username widget prompt on the login page } diff --git a/resources/i18n/de.edn b/resources/i18n/de.edn new file mode 120000 index 0000000..d74964e --- /dev/null +++ b/resources/i18n/de.edn @@ -0,0 +1 @@ +de-DE.edn \ No newline at end of file diff --git a/resources/i18n/lt.edn b/resources/i18n/lt.edn new file mode 120000 index 0000000..ef91fe5 --- /dev/null +++ b/resources/i18n/lt.edn @@ -0,0 +1 @@ +lt_LT.edn \ No newline at end of file diff --git a/resources/i18n/ru.edn b/resources/i18n/ru.edn new file mode 120000 index 0000000..4a740ce --- /dev/null +++ b/resources/i18n/ru.edn @@ -0,0 +1 @@ +ru_RU.edn \ No newline at end of file diff --git a/resources/public/content/Introduction.md b/resources/public/content/Introduction.md index 6709957..07d263f 100644 --- a/resources/public/content/Introduction.md +++ b/resources/public/content/Introduction.md @@ -17,6 +17,9 @@ Smeagol uses the Markdown format as provided by [markdown-clj](https://github.co ## Security and authentication Smeagol now has good security and authentication. While the initial password supplied with the system is not encrypted, when it is changed it will be; and passwords for new users added through the user administration pages are encrypted. Read more about [[Security and authentication]]. +## Internationalisation +Smeagol has built in internationalisation. Currently it has translation files for English, German, Lithuanian and Russian. We'd welcome volunteers to translate it into other languages. + ## Images You can (if you're logged in) upload files, including images, using the **Upload a file** link on the top menu bar. You can link to an uploaded image, or to other images already available on the web, like this: diff --git a/src/smeagol/routes/wiki.clj b/src/smeagol/routes/wiki.clj index fe80349..28e97fb 100644 --- a/src/smeagol/routes/wiki.clj +++ b/src/smeagol/routes/wiki.clj @@ -141,7 +141,7 @@ (timbre/info (format "Showing history of page '%s'" page)) (layout/render "history.html" (merge (util/standard-params request) - {:title (str "History of " page) + {:title (util/get-message :history-title-prefix request) :page page :history (hist/find-history repo-path file-name)})))) From 45dc3017dd7407425bcb3da6e34f20d47a00f629 Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 15 Sep 2017 21:37:03 +0100 Subject: [PATCH 17/48] And one translation I'd missed... --- resources/i18n/lt_LT.edn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/i18n/lt_LT.edn b/resources/i18n/lt_LT.edn index 9d585c9..13185d0 100644 --- a/resources/i18n/lt_LT.edn +++ b/resources/i18n/lt_LT.edn @@ -53,7 +53,7 @@ ;; used in sanity check report :content-dir-is-dir "Turinio katalogas yra katalogas" ;; used in sanity check report - :cookies-about "About cookies" ;; about cookies text + :cookies-about "Apie slapukus" ;; about cookies text :cookies-more "Šis puslapis saugo jūsų sesijų informaciją jūsų naršyklėje “slapukų” forma. Tai mums leidžia jums rodyti tik tai, ką norite matyti. Slapukai neturi jokių jūsų identifikavimo duomenų ir kiti puslapiai negali jų “perskaityti”. Šie slapukai ištrinami iš karto, vos jūs išjungiate šį puslapį. Šis puslapis nenaudoja jokių trečiųjų asmenų slapukų, ir jūsų apsilankymas čia negali būti atsektas jokio kito puslapio." ;; more about cookies text :default-page-title "Pristatymas" ;; title of the default page in this wiki From 1e2e9ea49b0d88ddebc80ea0d18059dfe369e408 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sat, 23 Sep 2017 15:18:06 +0100 Subject: [PATCH 18/48] Enabled committing during lein release with an unsigned tag. --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index efd7bc2..2ba7ad2 100644 --- a/project.clj +++ b/project.clj @@ -59,7 +59,7 @@ :release-tasks [["vcs" "assert-committed"] ["change" "version" "leiningen.release/bump-version" "release"] ["vcs" "commit"] - ;; ["vcs" "tag"] -- not working, problems with secret key + ["vcs" "tag" "v." "--no-sign"] ["clean"] ["bower" "install"] ["ring" "uberjar"] From cd25d8bd761adac650035a801f3d9f9a351c40f1 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sat, 23 Sep 2017 15:18:35 +0100 Subject: [PATCH 19/48] Version 1.0.1 --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 2ba7ad2..51fb2f3 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject smeagol "1.0.1-SNAPSHOT" +(defproject smeagol "1.0.1" :description "A simple Git-backed Wiki inspired by Gollum" :url "https://github.com/simon-brooke/smeagol" :license {:name "GNU General Public License,version 2.0 or (at your option) any later version" From 6be21214b0267c18d203bef0c44768804e25bb0b Mon Sep 17 00:00:00 2001 From: jem Date: Tue, 15 May 2018 18:50:54 +0200 Subject: [PATCH 20/48] start with some thinking about the problem ... --- doc/include.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 doc/include.md diff --git a/doc/include.md b/doc/include.md new file mode 100644 index 0000000..8614fc9 --- /dev/null +++ b/doc/include.md @@ -0,0 +1,14 @@ +# Include Feature +## Requirements +The user can include page title, abstract or the whole content in a given page. Headings and enumerations can be indented by a given include-level. + +## Thoughts & Questions +* Which include syntax should be used? + * page include can be definde alongsite of image includes - sth. like `#[indent-level](relative or absolute url)` +* Which kind of urls should we accept for page includes? + * relative local urls (we will need some care to prohibit directory traversal ...) + * absolute github / gitlab / gitblit urls without authentication. +* Which metadata can be used for title / abstract ? + * MultiMarcdown-Metadata is supported by clj-markdown :-) +* How can we test page includes? + * we will need a content resolver component for testing and at least one for production resolving. From 464e9af7d63a89c2625fee34bf3cc5cacc541df1 Mon Sep 17 00:00:00 2001 From: jem Date: Tue, 15 May 2018 19:31:24 +0200 Subject: [PATCH 21/48] use dependency injection in order to make include resolving testable --- project.clj | 3 ++- src/smeagol/include.clj | 11 +++++++++++ test/smeagol/test/include.clj | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/smeagol/include.clj create mode 100644 test/smeagol/test/include.clj diff --git a/project.clj b/project.clj index 38c96f5..86806dd 100644 --- a/project.clj +++ b/project.clj @@ -29,7 +29,8 @@ [prone "1.1.4"] [ring/ring-anti-forgery "1.1.0"] [ring-server "0.4.0"] - [selmer "1.11.0"]] + [selmer "1.11.0"] + [com.stuartsierra/component "0.3.2"]] :repl-options {:init-ns smeagol.repl} diff --git a/src/smeagol/include.clj b/src/smeagol/include.clj new file mode 100644 index 0000000..adc361f --- /dev/null +++ b/src/smeagol/include.clj @@ -0,0 +1,11 @@ +(ns smeagol.include + (:require + [com.stuartsierra.component :as component])) + +(defrecord Resolver [resolver-fn]) + +(defn new-resolver [resolver-fn] + (map->Resolver {:resolver-fn resolver-fn})) + +(defn resolve-include [resolver uri] + (apply (:resolver-fn resolver) [uri])) diff --git a/test/smeagol/test/include.clj b/test/smeagol/test/include.clj new file mode 100644 index 0000000..143eb61 --- /dev/null +++ b/test/smeagol/test/include.clj @@ -0,0 +1,16 @@ +(ns smeagol.test.include + (:require [clojure.test :refer :all] + [com.stuartsierra.component :as component] + [smeagol.include :as sut])) + +(defn test-include-resolver [uri] + (cond + (= uri "./simple.md") "Simple content.")) + +(def system-under-test + (component/system-map + :resolver (sut/new-resolver test-include-resolver))) + +(deftest test-local-links + (testing "Rewriting of local links" + (is (= "Simple content." (sut/resolve-include (:resolver system-under-test) "./simple.md"))))) From 9607657cc12558f3ba1d49a26ad15fb0bc5d4699 Mon Sep 17 00:00:00 2001 From: jem Date: Wed, 16 May 2018 18:41:54 +0200 Subject: [PATCH 22/48] added schema & use separated resolver & includer component. --- project.clj | 3 +- src/smeagol/include.clj | 27 ++++++++++++++---- src/smeagol/include/resolver.clj | 38 ++++++++++++++++++++++++++ test/smeagol/test/include.clj | 24 +++++++++++++--- test/smeagol/test/include/resolver.clj | 8 ++++++ 5 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 src/smeagol/include/resolver.clj create mode 100644 test/smeagol/test/include/resolver.clj diff --git a/project.clj b/project.clj index 86806dd..9f20be0 100644 --- a/project.clj +++ b/project.clj @@ -30,7 +30,8 @@ [ring/ring-anti-forgery "1.1.0"] [ring-server "0.4.0"] [selmer "1.11.0"] - [com.stuartsierra/component "0.3.2"]] + [com.stuartsierra/component "0.3.2"] + [prismatic/schema "1.1.9"]] :repl-options {:init-ns smeagol.repl} diff --git a/src/smeagol/include.clj b/src/smeagol/include.clj index adc361f..80d9640 100644 --- a/src/smeagol/include.clj +++ b/src/smeagol/include.clj @@ -1,11 +1,26 @@ (ns smeagol.include (:require - [com.stuartsierra.component :as component])) + [schema.core :as s] + [com.stuartsierra.component :as component] + [smeagol.include.resolver :as resolver])) -(defrecord Resolver [resolver-fn]) +(s/defrecord Includer + [resolver]) -(defn new-resolver [resolver-fn] - (map->Resolver {:resolver-fn resolver-fn})) +(defprotocol IncludeMd + (expand-include-md + [includer md-src] + "return a markfown file content for given uri.")) -(defn resolve-include [resolver uri] - (apply (:resolver-fn resolver) [uri])) +(extend-type Includer + IncludeMd + (expand-include-md [includer md-src] + ;parse md-src + ;resolve found includes + ;indent & integrate + md-src)) + +(s/defn + new-includer + [] + (map->Includer {})) diff --git a/src/smeagol/include/resolver.clj b/src/smeagol/include/resolver.clj new file mode 100644 index 0000000..cca0934 --- /dev/null +++ b/src/smeagol/include/resolver.clj @@ -0,0 +1,38 @@ +(ns smeagol.include.resolver + (:require + [schema.core :as s] + [com.stuartsierra.component :as component])) + +(s/defrecord Resolver + [type :- s/Keyword]) + +;As schema does'nt support s/defprotocol we use the dispatcher for annotation & validation. +(s/defn dispatch-by-resolver-type :- s/Keyword + "Dispatcher for different resolver implementations." + [resolver :- Resolver + uri :- s/Str] + (:type resolver)) + +(defmulti do-resolve-md + "Multimethod return a markfown file content for given uri." + dispatch-by-resolver-type) +(s/defmethod do-resolve-md :default + [resolver :- Resolver + uri :- s/Str] + (throw (Exception. (str "No implementation for " resolver)))) + +(defprotocol ResolveMd + (resolve-md + [resolver uri] + "return a markfown file content for given uru.")) + +(extend-type Resolver + ResolveMd + (resolve-md [resolver uri] + (s/validate s/Str uri) + (s/validate s/Str (do-resolve-md resolver uri)))) + +(s/defn + new-resolver + [type :- s/Keyword] + (map->Resolver {:type type})) diff --git a/test/smeagol/test/include.clj b/test/smeagol/test/include.clj index 143eb61..749482b 100644 --- a/test/smeagol/test/include.clj +++ b/test/smeagol/test/include.clj @@ -1,16 +1,32 @@ (ns smeagol.test.include (:require [clojure.test :refer :all] + [schema.core :as s] [com.stuartsierra.component :as component] + [smeagol.include.resolver :as resolver] [smeagol.include :as sut])) -(defn test-include-resolver [uri] +(s/defmethod resolver/do-resolve-md :test-mock + [resolver + uri :- s/Str] (cond (= uri "./simple.md") "Simple content.")) (def system-under-test (component/system-map - :resolver (sut/new-resolver test-include-resolver))) + :resolver (resolver/new-resolver :test-mock) + :includer (component/using + (sut/new-includer) + {:resolver :resolver}))) -(deftest test-local-links +(deftest test-expand-include-md (testing "Rewriting of local links" - (is (= "Simple content." (sut/resolve-include (:resolver system-under-test) "./simple.md"))))) + (is + (= "# Heading" + (sut/expand-include-md (:includer system-under-test) "# Heading"))) + (is + (= "# Heading 1 + Simple content." + (sut/expand-include-md + (:includer system-under-test) + "# Heading1 +#[](.simple.md)"))))) diff --git a/test/smeagol/test/include/resolver.clj b/test/smeagol/test/include/resolver.clj new file mode 100644 index 0000000..fd080d9 --- /dev/null +++ b/test/smeagol/test/include/resolver.clj @@ -0,0 +1,8 @@ +(ns smeagol.test.include.resolver + (:require [clojure.test :refer :all] + [smeagol.include.resolver :as sut])) + +(deftest test-local-links + (testing "Rewriting of local links" + (is (thrown? Exception + (sut/resolve-md (sut/new-resolver (:default)) "./some-uri.md"))))) From 6918ba27e8198cb069b5212b0d252469f436285b Mon Sep 17 00:00:00 2001 From: jem Date: Thu, 17 May 2018 09:08:09 +0200 Subject: [PATCH 23/48] implemented simple parsing --- doc/include.md | 3 ++- src/smeagol/include.clj | 16 +++++++++++ test/smeagol/test/include.clj | 50 ++++++++++++++++++++++++++++++++--- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/doc/include.md b/doc/include.md index 8614fc9..f8b115c 100644 --- a/doc/include.md +++ b/doc/include.md @@ -4,7 +4,8 @@ The user can include page title, abstract or the whole content in a given page. ## Thoughts & Questions * Which include syntax should be used? - * page include can be definde alongsite of image includes - sth. like `#[indent-level](relative or absolute url)` + * page include can be definde alongsite of image includes - sth. like + `&[:indent-heading s/Num :indent-list s/Num](relative or absolute url s/Str)` * Which kind of urls should we accept for page includes? * relative local urls (we will need some care to prohibit directory traversal ...) * absolute github / gitlab / gitblit urls without authentication. diff --git a/src/smeagol/include.clj b/src/smeagol/include.clj index 80d9640..6052ff6 100644 --- a/src/smeagol/include.clj +++ b/src/smeagol/include.clj @@ -24,3 +24,19 @@ new-includer [] (map->Includer {})) + +(def IncludeLink + {:uri s/Str + :indent-heading s/Num + :indent-list s/Num}) + +(s/defn + parse-include-md :- [IncludeLink] + [md-src :- s/Str] + (vec + (map + (fn [parse-element] + {:uri (nth parse-element 5) + :indent-heading 0 + :indent-list 0}) + (re-seq #"&\[(:indent-heading (d*))?w*(:indent-list (d*))?\]\((.*)\)" md-src)))) diff --git a/test/smeagol/test/include.clj b/test/smeagol/test/include.clj index 749482b..99ee31d 100644 --- a/test/smeagol/test/include.clj +++ b/test/smeagol/test/include.clj @@ -5,6 +5,49 @@ [smeagol.include.resolver :as resolver] [smeagol.include :as sut])) +(def include-simple + "# Heading1 +&[](./simple.md)") + +(def include-surounding-simple + "# Heading1 +Some surounding &[](./simple.md) text") + +(def include-heading-0 + "# Heading1 +&[:indent-heading 0](./with-heading.md)") + +(def include-heading-list-1 + "# Heading1 +&[:indent-heading 1 :indent-list 1](./with-heading-and-list.md)") + +(def include-heading-list-0 + "# Heading1 +&[:indent-heading 0 :indent-list 0](./with-heading-and-list.md)") + +(def include-invalid-indent + "# Heading1 +&[ invalid input should default to indent 0 ](./simple.md)") + +(def include-spaced-indent + "# Heading1 +&[ :indent-heading 0 :indent-list 0 ](./with-heading-and-list.md)") + + +(deftest test-parse-include-md + (testing "parse include links" + (is + (= [] + (sut/parse-include-md "# Heading"))) + (is + (= [{:uri "./simple.md", :indent-heading 0, :indent-list 0}] + (sut/parse-include-md + include-simple))) + (is + (= [{:uri "./simple.md", :indent-heading 1, :indent-list 1}] + (sut/parse-include-md + include-heading-list-1))))) + (s/defmethod resolver/do-resolve-md :test-mock [resolver uri :- s/Str] @@ -19,14 +62,13 @@ {:resolver :resolver}))) (deftest test-expand-include-md - (testing "Rewriting of local links" + (testing "The whole integration of include" (is (= "# Heading" (sut/expand-include-md (:includer system-under-test) "# Heading"))) (is (= "# Heading 1 - Simple content." +Simple content." (sut/expand-include-md (:includer system-under-test) - "# Heading1 -#[](.simple.md)"))))) + include-simple))))) From 4025b1e29caf8bb7d1146503ee8b59941d981cb0 Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 18 May 2018 12:05:13 +0200 Subject: [PATCH 24/48] include link parsing now works --- src/smeagol/include.clj | 32 ++++++++++++++++++++++++++++---- test/smeagol/test/include.clj | 28 ++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/smeagol/include.clj b/src/smeagol/include.clj index 6052ff6..74e8cdb 100644 --- a/src/smeagol/include.clj +++ b/src/smeagol/include.clj @@ -30,13 +30,37 @@ :indent-heading s/Num :indent-list s/Num}) +(s/defn + convert-indent-to-int :- s/Num + [indents :- [s/Str]] + (if (some? indents) + (Integer/valueOf (nth indents 2)) + 0)) + +(s/defn + parse-indent-list + [md-src :- s/Str] + (re-matches #".*(:indent-list (\d)).*" md-src)) + +(s/defn + parse-indent-heading + [md-src :- s/Str] + (re-matches #".*(:indent-heading (\d)).*" md-src)) + +(s/defn + parse-include-link + [md-src :- s/Str] + (re-seq #".*&\[\w*(.*)\w*\]\((.*)\).*" md-src)) + (s/defn parse-include-md :- [IncludeLink] [md-src :- s/Str] (vec (map (fn [parse-element] - {:uri (nth parse-element 5) - :indent-heading 0 - :indent-list 0}) - (re-seq #"&\[(:indent-heading (d*))?w*(:indent-list (d*))?\]\((.*)\)" md-src)))) + (let [uri (nth parse-element 2) + indents-text (nth parse-element 1)] + {:uri uri + :indent-heading (convert-indent-to-int (parse-indent-heading indents-text)) + :indent-list (convert-indent-to-int (parse-indent-list indents-text))})) + (parse-include-link md-src)))) diff --git a/test/smeagol/test/include.clj b/test/smeagol/test/include.clj index 99ee31d..ae602b2 100644 --- a/test/smeagol/test/include.clj +++ b/test/smeagol/test/include.clj @@ -23,7 +23,7 @@ Some surounding &[](./simple.md) text") (def include-heading-list-0 "# Heading1 -&[:indent-heading 0 :indent-list 0](./with-heading-and-list.md)") +&[:indent-list 0 :indent-heading 0](./with-heading-and-list.md)") (def include-invalid-indent "# Heading1 @@ -31,7 +31,7 @@ Some surounding &[](./simple.md) text") (def include-spaced-indent "# Heading1 -&[ :indent-heading 0 :indent-list 0 ](./with-heading-and-list.md)") +&[ :indent-heading 2 :indent-list 33 ](./with-heading-and-list.md)") (deftest test-parse-include-md @@ -44,9 +44,29 @@ Some surounding &[](./simple.md) text") (sut/parse-include-md include-simple))) (is - (= [{:uri "./simple.md", :indent-heading 1, :indent-list 1}] + (= [{:uri "./simple.md", :indent-heading 0, :indent-list 0}] (sut/parse-include-md - include-heading-list-1))))) + include-surounding-simple))) + (is + (= [{:uri "./with-heading.md", :indent-heading 0, :indent-list 0}] + (sut/parse-include-md + include-heading-0))) + (is + (= [{:uri "./with-heading-and-list.md", :indent-heading 1, :indent-list 1}] + (sut/parse-include-md + include-heading-list-1))) + (is + (= [{:uri "./with-heading-and-list.md", :indent-heading 0, :indent-list 0}] + (sut/parse-include-md + include-heading-list-0))) + (is + (= [{:uri "./simple.md", :indent-heading 0, :indent-list 0}] + (sut/parse-include-md + include-invalid-indent))) + (is + (= [{:uri "./with-heading-and-list.md", :indent-heading 2, :indent-list 0}] + (sut/parse-include-md + include-spaced-indent))))) (s/defmethod resolver/do-resolve-md :test-mock [resolver From 7d479e95b16a9fcca6b1af49f62799c0847be690 Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 18 May 2018 12:09:16 +0200 Subject: [PATCH 25/48] add one more parsing testcase --- test/smeagol/test/include.clj | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/smeagol/test/include.clj b/test/smeagol/test/include.clj index ae602b2..860fcf6 100644 --- a/test/smeagol/test/include.clj +++ b/test/smeagol/test/include.clj @@ -33,6 +33,13 @@ Some surounding &[](./simple.md) text") "# Heading1 &[ :indent-heading 2 :indent-list 33 ](./with-heading-and-list.md)") +(def multi + "# Heading1 +&[ :indent-heading 2 :indent-list 33 ](./with-heading-and-list.md) +some text +&[](./simple.md) +more text.") + (deftest test-parse-include-md (testing "parse include links" @@ -64,9 +71,16 @@ Some surounding &[](./simple.md) text") (sut/parse-include-md include-invalid-indent))) (is - (= [{:uri "./with-heading-and-list.md", :indent-heading 2, :indent-list 0}] + (= [{:uri "./with-heading-and-list.md", :indent-heading 2, :indent-list 3}] (sut/parse-include-md - include-spaced-indent))))) + include-spaced-indent))) + (is + (= [{:uri "./with-heading-and-list.md", + :indent-heading 2, + :indent-list 3} + {:uri "./simple.md", :indent-heading 0, :indent-list 0}] + (sut/parse-include-md + multi))))) (s/defmethod resolver/do-resolve-md :test-mock [resolver From 4a4269d2022945ea64ad612c72a5685d63fe162e Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 18 May 2018 12:32:49 +0200 Subject: [PATCH 26/48] renamed resolver -> resolve --- src/smeagol/include/{resolver.clj => resolve.clj} | 2 +- test/smeagol/test/include/{resolver.clj => resolve.clj} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/smeagol/include/{resolver.clj => resolve.clj} (97%) rename test/smeagol/test/include/{resolver.clj => resolve.clj} (71%) diff --git a/src/smeagol/include/resolver.clj b/src/smeagol/include/resolve.clj similarity index 97% rename from src/smeagol/include/resolver.clj rename to src/smeagol/include/resolve.clj index cca0934..13a67ce 100644 --- a/src/smeagol/include/resolver.clj +++ b/src/smeagol/include/resolve.clj @@ -1,4 +1,4 @@ -(ns smeagol.include.resolver +(ns smeagol.include.resolve (:require [schema.core :as s] [com.stuartsierra.component :as component])) diff --git a/test/smeagol/test/include/resolver.clj b/test/smeagol/test/include/resolve.clj similarity index 71% rename from test/smeagol/test/include/resolver.clj rename to test/smeagol/test/include/resolve.clj index fd080d9..4da32ed 100644 --- a/test/smeagol/test/include/resolver.clj +++ b/test/smeagol/test/include/resolve.clj @@ -1,6 +1,6 @@ -(ns smeagol.test.include.resolver +(ns smeagol.test.include.resolve (:require [clojure.test :refer :all] - [smeagol.include.resolver :as sut])) + [smeagol.include.resolve :as sut])) (deftest test-local-links (testing "Rewriting of local links" From 6714dc04bfcb0f1041b8677949abe6abc2e1324e Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 18 May 2018 12:33:07 +0200 Subject: [PATCH 27/48] refactor parse out of include ns --- src/smeagol/include.clj | 51 +++--------------- src/smeagol/include/parse.clj | 43 +++++++++++++++ test/smeagol/test/include.clj | 48 ++--------------- test/smeagol/test/include/parse.clj | 81 +++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 90 deletions(-) create mode 100644 src/smeagol/include/parse.clj create mode 100644 test/smeagol/test/include/parse.clj diff --git a/src/smeagol/include.clj b/src/smeagol/include.clj index 74e8cdb..14a97da 100644 --- a/src/smeagol/include.clj +++ b/src/smeagol/include.clj @@ -2,7 +2,8 @@ (:require [schema.core :as s] [com.stuartsierra.component :as component] - [smeagol.include.resolver :as resolver])) + [smeagol.include.parse :as parse] + [smeagol.include.resolve :as resolve])) (s/defrecord Includer [resolver]) @@ -15,52 +16,12 @@ (extend-type Includer IncludeMd (expand-include-md [includer md-src] - ;parse md-src - ;resolve found includes - ;indent & integrate - md-src)) + (let [includes (parse/parse-include-md md-src)] + ;resolve found includes + ;indent & integrate + md-src))) (s/defn new-includer [] (map->Includer {})) - -(def IncludeLink - {:uri s/Str - :indent-heading s/Num - :indent-list s/Num}) - -(s/defn - convert-indent-to-int :- s/Num - [indents :- [s/Str]] - (if (some? indents) - (Integer/valueOf (nth indents 2)) - 0)) - -(s/defn - parse-indent-list - [md-src :- s/Str] - (re-matches #".*(:indent-list (\d)).*" md-src)) - -(s/defn - parse-indent-heading - [md-src :- s/Str] - (re-matches #".*(:indent-heading (\d)).*" md-src)) - -(s/defn - parse-include-link - [md-src :- s/Str] - (re-seq #".*&\[\w*(.*)\w*\]\((.*)\).*" md-src)) - -(s/defn - parse-include-md :- [IncludeLink] - [md-src :- s/Str] - (vec - (map - (fn [parse-element] - (let [uri (nth parse-element 2) - indents-text (nth parse-element 1)] - {:uri uri - :indent-heading (convert-indent-to-int (parse-indent-heading indents-text)) - :indent-list (convert-indent-to-int (parse-indent-list indents-text))})) - (parse-include-link md-src)))) diff --git a/src/smeagol/include/parse.clj b/src/smeagol/include/parse.clj new file mode 100644 index 0000000..0c4dbae --- /dev/null +++ b/src/smeagol/include/parse.clj @@ -0,0 +1,43 @@ +(ns smeagol.include.parse + (:require + [schema.core :as s])) + +(def IncludeLink + {:uri s/Str + :indent-heading s/Num + :indent-list s/Num}) + +(s/defn + convert-indent-to-int :- s/Num + [indents :- [s/Str]] + (if (some? indents) + (Integer/valueOf (nth indents 2)) + 0)) + +(s/defn + parse-indent-list + [md-src :- s/Str] + (re-matches #".*(:indent-list (\d)).*" md-src)) + +(s/defn + parse-indent-heading + [md-src :- s/Str] + (re-matches #".*(:indent-heading (\d)).*" md-src)) + +(s/defn + parse-include-link + [md-src :- s/Str] + (re-seq #".*&\[\w*(.*)\w*\]\((.*)\).*" md-src)) + +(s/defn + parse-include-md :- [IncludeLink] + [md-src :- s/Str] + (vec + (map + (fn [parse-element] + (let [uri (nth parse-element 2) + indents-text (nth parse-element 1)] + {:uri uri + :indent-heading (convert-indent-to-int (parse-indent-heading indents-text)) + :indent-list (convert-indent-to-int (parse-indent-list indents-text))})) + (parse-include-link md-src)))) diff --git a/test/smeagol/test/include.clj b/test/smeagol/test/include.clj index 860fcf6..45219e1 100644 --- a/test/smeagol/test/include.clj +++ b/test/smeagol/test/include.clj @@ -2,7 +2,7 @@ (:require [clojure.test :refer :all] [schema.core :as s] [com.stuartsierra.component :as component] - [smeagol.include.resolver :as resolver] + [smeagol.include.resolve :as resolve] [smeagol.include :as sut])) (def include-simple @@ -40,49 +40,7 @@ some text &[](./simple.md) more text.") - -(deftest test-parse-include-md - (testing "parse include links" - (is - (= [] - (sut/parse-include-md "# Heading"))) - (is - (= [{:uri "./simple.md", :indent-heading 0, :indent-list 0}] - (sut/parse-include-md - include-simple))) - (is - (= [{:uri "./simple.md", :indent-heading 0, :indent-list 0}] - (sut/parse-include-md - include-surounding-simple))) - (is - (= [{:uri "./with-heading.md", :indent-heading 0, :indent-list 0}] - (sut/parse-include-md - include-heading-0))) - (is - (= [{:uri "./with-heading-and-list.md", :indent-heading 1, :indent-list 1}] - (sut/parse-include-md - include-heading-list-1))) - (is - (= [{:uri "./with-heading-and-list.md", :indent-heading 0, :indent-list 0}] - (sut/parse-include-md - include-heading-list-0))) - (is - (= [{:uri "./simple.md", :indent-heading 0, :indent-list 0}] - (sut/parse-include-md - include-invalid-indent))) - (is - (= [{:uri "./with-heading-and-list.md", :indent-heading 2, :indent-list 3}] - (sut/parse-include-md - include-spaced-indent))) - (is - (= [{:uri "./with-heading-and-list.md", - :indent-heading 2, - :indent-list 3} - {:uri "./simple.md", :indent-heading 0, :indent-list 0}] - (sut/parse-include-md - multi))))) - -(s/defmethod resolver/do-resolve-md :test-mock +(s/defmethod resolve/do-resolve-md :test-mock [resolver uri :- s/Str] (cond @@ -90,7 +48,7 @@ more text.") (def system-under-test (component/system-map - :resolver (resolver/new-resolver :test-mock) + :resolver (resolve/new-resolver :test-mock) :includer (component/using (sut/new-includer) {:resolver :resolver}))) diff --git a/test/smeagol/test/include/parse.clj b/test/smeagol/test/include/parse.clj new file mode 100644 index 0000000..60a22bf --- /dev/null +++ b/test/smeagol/test/include/parse.clj @@ -0,0 +1,81 @@ +(ns smeagol.test.include.parse + (:require [clojure.test :refer :all] + [schema.core :as s] + [smeagol.include.parse :as sut])) + +(def include-simple + "# Heading1 +&[](./simple.md)") + +(def include-surounding-simple + "# Heading1 +Some surounding &[](./simple.md) text") + +(def include-heading-0 + "# Heading1 +&[:indent-heading 0](./with-heading.md)") + +(def include-heading-list-1 + "# Heading1 +&[:indent-heading 1 :indent-list 1](./with-heading-and-list.md)") + +(def include-heading-list-0 + "# Heading1 +&[:indent-list 0 :indent-heading 0](./with-heading-and-list.md)") + +(def include-invalid-indent + "# Heading1 +&[ invalid input should default to indent 0 ](./simple.md)") + +(def include-spaced-indent + "# Heading1 +&[ :indent-heading 2 :indent-list 33 ](./with-heading-and-list.md)") + +(def multi + "# Heading1 +&[ :indent-heading 2 :indent-list 33 ](./with-heading-and-list.md) +some text +&[](./simple.md) +more text.") + + +(deftest test-parse-include-md + (testing "parse include links" + (is + (= [] + (sut/parse-include-md "# Heading"))) + (is + (= [{:uri "./simple.md", :indent-heading 0, :indent-list 0}] + (sut/parse-include-md + include-simple))) + (is + (= [{:uri "./simple.md", :indent-heading 0, :indent-list 0}] + (sut/parse-include-md + include-surounding-simple))) + (is + (= [{:uri "./with-heading.md", :indent-heading 0, :indent-list 0}] + (sut/parse-include-md + include-heading-0))) + (is + (= [{:uri "./with-heading-and-list.md", :indent-heading 1, :indent-list 1}] + (sut/parse-include-md + include-heading-list-1))) + (is + (= [{:uri "./with-heading-and-list.md", :indent-heading 0, :indent-list 0}] + (sut/parse-include-md + include-heading-list-0))) + (is + (= [{:uri "./simple.md", :indent-heading 0, :indent-list 0}] + (sut/parse-include-md + include-invalid-indent))) + (is + (= [{:uri "./with-heading-and-list.md", :indent-heading 2, :indent-list 3}] + (sut/parse-include-md + include-spaced-indent))) + (is + (= [{:uri "./with-heading-and-list.md", + :indent-heading 2, + :indent-list 3} + {:uri "./simple.md", :indent-heading 0, :indent-list 0}] + (sut/parse-include-md + multi))))) From 78a534349b047c8695ecfeee432199960410e557 Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 18 May 2018 14:31:32 +0200 Subject: [PATCH 28/48] add the replacement parameter --- src/smeagol/include/parse.clj | 13 ++++++++----- test/smeagol/test/include/parse.clj | 28 +++++++++++++++++++--------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/smeagol/include/parse.clj b/src/smeagol/include/parse.clj index 0c4dbae..2212e0d 100644 --- a/src/smeagol/include/parse.clj +++ b/src/smeagol/include/parse.clj @@ -3,7 +3,8 @@ [schema.core :as s])) (def IncludeLink - {:uri s/Str + {:replace s/Str + :uri s/Str :indent-heading s/Num :indent-list s/Num}) @@ -27,7 +28,7 @@ (s/defn parse-include-link [md-src :- s/Str] - (re-seq #".*&\[\w*(.*)\w*\]\((.*)\).*" md-src)) + (re-seq #".*(&\[\w*(.*)\w*\]\((.*)\)).*" md-src)) (s/defn parse-include-md :- [IncludeLink] @@ -35,9 +36,11 @@ (vec (map (fn [parse-element] - (let [uri (nth parse-element 2) - indents-text (nth parse-element 1)] - {:uri uri + (let [replace (nth parse-element 1) + uri (nth parse-element 3) + indents-text (nth parse-element 2)] + {:replace replace + :uri uri :indent-heading (convert-indent-to-int (parse-indent-heading indents-text)) :indent-list (convert-indent-to-int (parse-indent-list indents-text))})) (parse-include-link md-src)))) diff --git a/test/smeagol/test/include/parse.clj b/test/smeagol/test/include/parse.clj index 60a22bf..af27abf 100644 --- a/test/smeagol/test/include/parse.clj +++ b/test/smeagol/test/include/parse.clj @@ -45,37 +45,47 @@ more text.") (= [] (sut/parse-include-md "# Heading"))) (is - (= [{:uri "./simple.md", :indent-heading 0, :indent-list 0}] + (= [{:replace "&[](./simple.md)" :uri "./simple.md", :indent-heading 0, :indent-list 0}] (sut/parse-include-md include-simple))) (is - (= [{:uri "./simple.md", :indent-heading 0, :indent-list 0}] + (= [{:replace "&[](./simple.md)" :uri "./simple.md", :indent-heading 0, :indent-list 0}] (sut/parse-include-md include-surounding-simple))) (is - (= [{:uri "./with-heading.md", :indent-heading 0, :indent-list 0}] + (= [{:replace "&[:indent-heading 0](./with-heading.md)" :uri "./with-heading.md", :indent-heading 0, :indent-list 0}] (sut/parse-include-md include-heading-0))) (is - (= [{:uri "./with-heading-and-list.md", :indent-heading 1, :indent-list 1}] + (= [{:replace + "&[:indent-heading 1 :indent-list 1](./with-heading-and-list.md)" + :uri "./with-heading-and-list.md", :indent-heading 1, :indent-list 1}] (sut/parse-include-md include-heading-list-1))) (is - (= [{:uri "./with-heading-and-list.md", :indent-heading 0, :indent-list 0}] + (= [{:replace + "&[:indent-list 0 :indent-heading 0](./with-heading-and-list.md)" + :uri "./with-heading-and-list.md", :indent-heading 0, :indent-list 0}] (sut/parse-include-md include-heading-list-0))) (is - (= [{:uri "./simple.md", :indent-heading 0, :indent-list 0}] + (= [{:replace + "&[ invalid input should default to indent 0 ](./simple.md)" + :uri "./simple.md", :indent-heading 0, :indent-list 0}] (sut/parse-include-md include-invalid-indent))) (is - (= [{:uri "./with-heading-and-list.md", :indent-heading 2, :indent-list 3}] + (= [{:replace + "&[ :indent-heading 2 :indent-list 33 ](./with-heading-and-list.md)" + :uri "./with-heading-and-list.md", :indent-heading 2, :indent-list 3}] (sut/parse-include-md include-spaced-indent))) (is - (= [{:uri "./with-heading-and-list.md", + (= [{:replace + "&[ :indent-heading 2 :indent-list 33 ](./with-heading-and-list.md)" + :uri "./with-heading-and-list.md", :indent-heading 2, :indent-list 3} - {:uri "./simple.md", :indent-heading 0, :indent-list 0}] + {:replace "&[](./simple.md)" :uri "./simple.md", :indent-heading 0, :indent-list 0}] (sut/parse-include-md multi))))) From 6768d71429e53aae58e26ed2e6a3db820e9e4d39 Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 18 May 2018 14:31:46 +0200 Subject: [PATCH 29/48] add replacement --- src/smeagol/include.clj | 38 ++++++++++++++++++++++++++++++----- test/smeagol/test/include.clj | 13 ++++++------ 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/smeagol/include.clj b/src/smeagol/include.clj index 14a97da..440f1ab 100644 --- a/src/smeagol/include.clj +++ b/src/smeagol/include.clj @@ -1,5 +1,6 @@ (ns smeagol.include (:require + [clojure.string :as cs] [schema.core :as s] [com.stuartsierra.component :as component] [smeagol.include.parse :as parse] @@ -11,15 +12,42 @@ (defprotocol IncludeMd (expand-include-md [includer md-src] - "return a markfown file content for given uri.")) + "return a markdown containing resolved includes")) + +(s/defn + do-expand-one-include :- s/Str + [includer :- Includer + include :- parse/IncludeLink + md-src :- s/Str] + (let [{:keys [uri replace]} include] + (cs/replace + md-src + (re-pattern (cs/escape + replace + {\[ "\\[" + \] "\\]" + \( "\\(" + \) "\\)"})) + (resolve/resolve-md (:resolver includer) uri)))) + ;indent + +(s/defn + do-expand-includes :- s/Str + [includer :- Includer + includes :- [parse/IncludeLink] + md-src :- s/Str] + (loop [loop-includes includes + result md-src] + (if (empty? loop-includes) + result + (recur + (rest loop-includes) + (do-expand-one-include includer (first loop-includes) result))))) (extend-type Includer IncludeMd (expand-include-md [includer md-src] - (let [includes (parse/parse-include-md md-src)] - ;resolve found includes - ;indent & integrate - md-src))) + (do-expand-includes includer (parse/parse-include-md md-src) md-src))) (s/defn new-includer diff --git a/test/smeagol/test/include.clj b/test/smeagol/test/include.clj index 45219e1..628ad75 100644 --- a/test/smeagol/test/include.clj +++ b/test/smeagol/test/include.clj @@ -47,11 +47,12 @@ more text.") (= uri "./simple.md") "Simple content.")) (def system-under-test - (component/system-map - :resolver (resolve/new-resolver :test-mock) - :includer (component/using - (sut/new-includer) - {:resolver :resolver}))) + (component/start + (component/system-map + :resolver (resolve/new-resolver :test-mock) + :includer (component/using + (sut/new-includer) + [:resolver])))) (deftest test-expand-include-md (testing "The whole integration of include" @@ -59,7 +60,7 @@ more text.") (= "# Heading" (sut/expand-include-md (:includer system-under-test) "# Heading"))) (is - (= "# Heading 1 + (= "# Heading1 Simple content." (sut/expand-include-md (:includer system-under-test) From 07342b5ac4387584097caecee7d05107cf9d3fa8 Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 18 May 2018 17:13:33 +0200 Subject: [PATCH 30/48] implemented includes-resolving for tests --- test/smeagol/test/include.clj | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/test/smeagol/test/include.clj b/test/smeagol/test/include.clj index 628ad75..dc477c9 100644 --- a/test/smeagol/test/include.clj +++ b/test/smeagol/test/include.clj @@ -44,7 +44,15 @@ more text.") [resolver uri :- s/Str] (cond - (= uri "./simple.md") "Simple content.")) + (= uri "./simple.md") "Simple content." + (= uri "./with-heading-and-list.md") "# Heading2 +some text +* List + +## Heading 3 +more text")) + + (def system-under-test (component/start @@ -64,4 +72,21 @@ more text.") Simple content." (sut/expand-include-md (:includer system-under-test) - include-simple))))) + include-simple))) + (is + (= "# Heading1 +Some surounding Simple content. text" + (sut/expand-include-md + (:includer system-under-test) + include-surounding-simple))) + (is + (= "# Heading1 +# Heading2 +some text +* List + +## Heading 3 +more text" + (sut/expand-include-md + (:includer system-under-test) + include-heading-list-0))))) From 12d4661db9844492d65847ffdc652da24f9178b4 Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 18 May 2018 17:17:15 +0200 Subject: [PATCH 31/48] expectation for header & list indent --- test/smeagol/test/include.clj | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test/smeagol/test/include.clj b/test/smeagol/test/include.clj index dc477c9..ff3e8e6 100644 --- a/test/smeagol/test/include.clj +++ b/test/smeagol/test/include.clj @@ -89,4 +89,18 @@ some text more text" (sut/expand-include-md (:includer system-under-test) - include-heading-list-0))))) + include-heading-list-0))) + (is + (= "# Heading1 +### Heading2 +some text + * List + +## Heading 3 +more text +some text +Simple content. +more text." + (sut/expand-include-md + (:includer system-under-test) + multi))))) From 535465c362ace052d311c64d1f3455aec0ecc0f6 Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 18 May 2018 20:47:15 +0200 Subject: [PATCH 32/48] implement indention --- src/smeagol/include.clj | 14 +++++--- src/smeagol/include/indent.clj | 54 ++++++++++++++++++++++++++++ test/smeagol/test/include.clj | 2 +- test/smeagol/test/include/indent.clj | 35 ++++++++++++++++++ 4 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 src/smeagol/include/indent.clj create mode 100644 test/smeagol/test/include/indent.clj diff --git a/src/smeagol/include.clj b/src/smeagol/include.clj index 440f1ab..41aaf99 100644 --- a/src/smeagol/include.clj +++ b/src/smeagol/include.clj @@ -4,7 +4,8 @@ [schema.core :as s] [com.stuartsierra.component :as component] [smeagol.include.parse :as parse] - [smeagol.include.resolve :as resolve])) + [smeagol.include.resolve :as resolve] + [smeagol.include.indent :as indent])) (s/defrecord Includer [resolver]) @@ -19,8 +20,8 @@ [includer :- Includer include :- parse/IncludeLink md-src :- s/Str] - (let [{:keys [uri replace]} include] - (cs/replace + (let [{:keys [uri replace indent-heading indent-list]} include] + (cs/replace-first md-src (re-pattern (cs/escape replace @@ -28,8 +29,11 @@ \] "\\]" \( "\\(" \) "\\)"})) - (resolve/resolve-md (:resolver includer) uri)))) - ;indent + (indent/do-indent-list + indent-list + (indent/do-indent-heading + indent-heading + (resolve/resolve-md (:resolver includer) uri)))))) (s/defn do-expand-includes :- s/Str diff --git a/src/smeagol/include/indent.clj b/src/smeagol/include/indent.clj new file mode 100644 index 0000000..6967d19 --- /dev/null +++ b/src/smeagol/include/indent.clj @@ -0,0 +1,54 @@ +(ns smeagol.include.indent + (:require + [clojure.string :as cs] + [schema.core :as s])) + +(s/defn + parse-list + [md-resolved :- s/Str] + (distinct + (into + (re-seq #"((^|\R? *)([\*\+-] ))" md-resolved) + (re-seq #"((^|\R? *)([0-9]+\. ))" md-resolved)))) + +(s/defn + parse-heading + [md-resolved :- s/Str] + (distinct + (re-seq #"((^|\R?)(#+ ))" md-resolved))) + +(s/defn + do-indent :- s/Str + [indent :- s/Num + indentor :- s/Str + elements + md-resolved :- s/Str] + (loop [result md-resolved + elements elements] + (if (empty? elements) + result + (let [element (first elements) + replace (nth element 1) + start (nth element 2) + end (nth element 3)] + (recur + (cs/replace + result + (re-pattern (cs/escape + replace + {\* "\\*" + \n "\\n"})) + (str start (apply str (repeat indent indentor)) end)) + (rest elements)))))) + +(s/defn + do-indent-heading :- s/Str + [indent :- s/Num + md-resolved :- s/Str] + (do-indent indent "#" (parse-heading md-resolved) md-resolved)) + +(s/defn + do-indent-list :- s/Str + [indent :- s/Num + md-resolved :- s/Str] + (do-indent indent " " (parse-list md-resolved) md-resolved)) diff --git a/test/smeagol/test/include.clj b/test/smeagol/test/include.clj index ff3e8e6..3a037f1 100644 --- a/test/smeagol/test/include.clj +++ b/test/smeagol/test/include.clj @@ -96,7 +96,7 @@ more text" some text * List -## Heading 3 +#### Heading 3 more text some text Simple content. diff --git a/test/smeagol/test/include/indent.clj b/test/smeagol/test/include/indent.clj new file mode 100644 index 0000000..b4ca363 --- /dev/null +++ b/test/smeagol/test/include/indent.clj @@ -0,0 +1,35 @@ +(ns smeagol.test.include.indent + (:require [clojure.test :refer :all] + [smeagol.include.indent :as sut])) + +(deftest test-parse-heading + (testing + (is (= '(["# " "# " "" "# "]) + (sut/parse-heading "# h1"))) + (is (= '(["\n# " "\n# " "\n" "# "]) + (sut/parse-heading "\n# h1"))))) + +(deftest test-indent-heading + (testing + (is (= "# h1" + (sut/do-indent-heading 0 "# h1"))) + (is (= "### h1" + (sut/do-indent-heading 2 "# h1"))) + (is (= "\n### h1" + (sut/do-indent-heading 2 "\n# h1"))))) + +(deftest test-parse-list + (testing + (is (= '([" * " " * " " " "* "]) + (sut/parse-list " * list"))) + (is (= '(["\n * " "\n * " "\n " "* "]) + (sut/parse-list "\n * list"))))) + +(deftest test-indent-list + (testing + (is (= " * list" + (sut/do-indent-list 0 " * list"))) + (is (= " * list" + (sut/do-indent-list 2 " * list"))) + (is (= "\n * list" + (sut/do-indent-list 2 "\n * list"))))) From 3668b26df13c5907dbbb1dac2cb160ea003514cd Mon Sep 17 00:00:00 2001 From: jem Date: Tue, 22 May 2018 16:59:43 +0200 Subject: [PATCH 33/48] add doc to namespaces --- src/smeagol/include.clj | 4 +++- src/smeagol/include/indent.clj | 6 +++++- src/smeagol/include/parse.clj | 6 +++++- src/smeagol/include/resolve.clj | 6 +++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/smeagol/include.clj b/src/smeagol/include.clj index 41aaf99..8f8a017 100644 --- a/src/smeagol/include.clj +++ b/src/smeagol/include.clj @@ -1,4 +1,6 @@ -(ns smeagol.include +(ns ^{:doc "Functions related to the include of markdown-paged in a given markdown." + :author "Michael Jerger"} + smeagol.include (:require [clojure.string :as cs] [schema.core :as s] diff --git a/src/smeagol/include/indent.clj b/src/smeagol/include/indent.clj index 6967d19..f92a69c 100644 --- a/src/smeagol/include/indent.clj +++ b/src/smeagol/include/indent.clj @@ -1,4 +1,8 @@ -(ns smeagol.include.indent +(ns ^{:doc "Functions related to the include of markdown-paged - handling the +list & heading indents of includes. This namespaces is implementation detail for +smeagol.include and not inteded for direct usage." + :author "Michael Jerger"} + smeagol.include.indent (:require [clojure.string :as cs] [schema.core :as s])) diff --git a/src/smeagol/include/parse.clj b/src/smeagol/include/parse.clj index 2212e0d..0016252 100644 --- a/src/smeagol/include/parse.clj +++ b/src/smeagol/include/parse.clj @@ -1,4 +1,8 @@ -(ns smeagol.include.parse +(ns ^{:doc "Functions related to the include of markdown-paged - parsing of +include links. This namespaces is implementation detail for +smeagol.include and not inteded for direct usage." + :author "Michael Jerger"} + smeagol.include.parse (:require [schema.core :as s])) diff --git a/src/smeagol/include/resolve.clj b/src/smeagol/include/resolve.clj index 13a67ce..95b0ec2 100644 --- a/src/smeagol/include/resolve.clj +++ b/src/smeagol/include/resolve.clj @@ -1,4 +1,8 @@ -(ns smeagol.include.resolve +(ns ^{:doc "Functions related to the include of markdown-paged - providing +a plugable load-content componet. This namespaces is implementation detail for +smeagol.include and not inteded for direct usage." + :author "Michael Jerger"} + smeagol.include.resolve (:require [schema.core :as s] [com.stuartsierra.component :as component])) From 7674a4c30593d86007ec2dd0961b6a6f3da6a8ba Mon Sep 17 00:00:00 2001 From: jem Date: Tue, 22 May 2018 18:01:22 +0200 Subject: [PATCH 34/48] stick system together --- src/smeagol/include/resolve.clj | 12 ++++++---- src/smeagol/include/resolve_local_file.clj | 27 ++++++++++++++++++++++ src/smeagol/routes/wiki.clj | 18 +++++++++++++-- 3 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 src/smeagol/include/resolve_local_file.clj diff --git a/src/smeagol/include/resolve.clj b/src/smeagol/include/resolve.clj index 95b0ec2..7a2b3b1 100644 --- a/src/smeagol/include/resolve.clj +++ b/src/smeagol/include/resolve.clj @@ -1,5 +1,5 @@ (ns ^{:doc "Functions related to the include of markdown-paged - providing -a plugable load-content componet. This namespaces is implementation detail for +a plugable load-content componet. This namespaces is implementation detail for smeagol.include and not inteded for direct usage." :author "Michael Jerger"} smeagol.include.resolve @@ -8,7 +8,8 @@ smeagol.include and not inteded for direct usage." [com.stuartsierra.component :as component])) (s/defrecord Resolver - [type :- s/Keyword]) + [type :- s/Keyword + local-base-dir :- s/Str]) ;As schema does'nt support s/defprotocol we use the dispatcher for annotation & validation. (s/defn dispatch-by-resolver-type :- s/Keyword @@ -38,5 +39,8 @@ smeagol.include and not inteded for direct usage." (s/defn new-resolver - [type :- s/Keyword] - (map->Resolver {:type type})) + ([type :- s/Keyword] + (map->Resolver {:type type :local-base-dir nil})) + ([type :- s/Keyword + local-base-dir :- s/Str] + (map->Resolver {:type type :local-base-dir local-base-dir}))) diff --git a/src/smeagol/include/resolve_local_file.clj b/src/smeagol/include/resolve_local_file.clj new file mode 100644 index 0000000..4daaac2 --- /dev/null +++ b/src/smeagol/include/resolve_local_file.clj @@ -0,0 +1,27 @@ +(ns ^{:doc "Functions related to the include of markdown-paged - providing +a plugable load-local-include-links componet. This namespaces is implementation detail for +smeagol.include and not inteded for direct usage." + :author "Michael Jerger"} + smeagol.include.resolve-local-file + (:require + [schema.core :as s] + [smeagol.include.resolve :as resolve] + [com.stuartsierra.component :as component] + [clojure.java.io :as cjio] + [taoensso.timbre :as timbre])) + +(s/defmethod resolve/do-resolve-md :local-file + [resolver + uri :- s/Str] + (let [file-name (uri) + file-path (cjio/file (:local-base-dir resolver) file-name) + exists? (.exists (clojure.java.io/as-file file-path))] + (cond exists? + (do + (timbre/info (format "Including page '%s' from file '%s'" uri file-path)) + (slurp file-path))))) + +(s/defn + new-resolver + [local-base-dir :- s/Str] + (resolve/new-resolver :local-file local-base-dir)) diff --git a/src/smeagol/routes/wiki.clj b/src/smeagol/routes/wiki.clj index fe80349..109a2cc 100644 --- a/src/smeagol/routes/wiki.clj +++ b/src/smeagol/routes/wiki.clj @@ -20,7 +20,10 @@ [smeagol.sanity :refer [show-sanity-check-error]] [smeagol.util :as util] [smeagol.uploads :as ul] - [taoensso.timbre :as timbre])) + [taoensso.timbre :as timbre] + [com.stuartsierra.component :as component] + [smeagol.include.resolve-local-file :as resolve] + [smeagol.include :as include])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; @@ -108,6 +111,14 @@ (edit-page request "stylesheet" ".css" "edit-css.html" "_edit-side-bar.md")) +(def md-include-system + (component/start + (component/system-map + :resolver (resolve/new-resolver util/content-dir) + :includer (component/using + (include/new-includer) + [:resolver])))) + (defn wiki-page "Render the markdown page specified in this `request`, if any. If none found, redirect to edit-page" [request] @@ -125,7 +136,10 @@ (merge (util/standard-params request) {:title page :page page - :content (md->html (slurp file-path)) + :content (md->html + (include/expand-include-md + (:includer md-include-system) + (slurp file-path))) :editable true}))) true (response/redirect (str "/edit?page=" page)))))) From 01c954fc2f1e404b6ce14e4777f43a97c0058193 Mon Sep 17 00:00:00 2001 From: jem Date: Tue, 22 May 2018 21:22:58 +0200 Subject: [PATCH 35/48] fix uri resolving --- src/smeagol/include/resolve_local_file.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smeagol/include/resolve_local_file.clj b/src/smeagol/include/resolve_local_file.clj index 4daaac2..c35e3e5 100644 --- a/src/smeagol/include/resolve_local_file.clj +++ b/src/smeagol/include/resolve_local_file.clj @@ -13,7 +13,7 @@ smeagol.include and not inteded for direct usage." (s/defmethod resolve/do-resolve-md :local-file [resolver uri :- s/Str] - (let [file-name (uri) + (let [file-name uri file-path (cjio/file (:local-base-dir resolver) file-name) exists? (.exists (clojure.java.io/as-file file-path))] (cond exists? From 778c0a84e24a94a29802c8e5957e9dadddde85af Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Thu, 24 May 2018 07:23:11 +0100 Subject: [PATCH 36/48] i18n --- resources/i18n/de-DE.edn | 143 ++++++++++++++++++++++++++++++++++++ resources/i18n/de.edn | 1 + resources/i18n/en-GB.edn | 2 +- resources/i18n/lt.edn | 1 + resources/i18n/lt_LT.edn | 143 ++++++++++++++++++++++++++++++++++++ resources/i18n/ru.edn | 1 + resources/i18n/ru_RU.edn | 144 +++++++++++++++++++++++++++++++++++++ resources/translations.edn | 0 8 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 resources/i18n/de-DE.edn create mode 120000 resources/i18n/de.edn create mode 120000 resources/i18n/lt.edn create mode 100644 resources/i18n/lt_LT.edn create mode 120000 resources/i18n/ru.edn create mode 100644 resources/i18n/ru_RU.edn create mode 100644 resources/translations.edn diff --git a/resources/i18n/de-DE.edn b/resources/i18n/de-DE.edn new file mode 100644 index 0000000..a7b8789 --- /dev/null +++ b/resources/i18n/de-DE.edn @@ -0,0 +1,143 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; +;;;; 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 +;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; en-GB.edn: English-language messages. +;;; This is essentially all the text in the chrome - that which isn't editable +;;; through the wiki itself; and the test in the sanity check report. + +;; ; ; ; ; ; ; ; ; ; +{:add-user-label "Add new user" ;; label for the add user link on edit users page + :change-pass-label "Change password!" + ;; text of the change password widget itself on the + ;; change password page + :change-pass-link "Change password" + ;; text of the change password link on the menu + :change-pass-prompt "To change your password" + ;; text of the change password widget prompt on the + ;; change password page + :change-col-hdr "Changes" ;; header for the changes column in history + :chpass-bad-match "Your proposed passwords don't match" + ;; error text if proposed passwords don't match + :chpass-fail "Your password was not changed" + ;; error text on fail other htan too short or bad match + :chpass-success "Your password was changed" + ;; confirmation text on password change + :chpass-too-short "You proposed password wasn't long enough: eight characters required" + ;; error text if proposed password is too short + :chpass-title-prefix "Change password for" + ;; prefix for title of change password page + :content-dir "The content directory" + ;; used in sanity check report + :content-dir-exists "The content directory exists" + ;; used in sanity check report + :content-dir-is-dir "The content directory is a directory" + ;; used in sanity check report + :cookies-about "About cookies" ;; about cookies text + :cookies-more "This website stores session information as a 'cookie' on your browser. This helps us show you the content you want to see. This cookie does not identify you, and cannot be read by other websites. It is deleted by your browser as soon as you leave this site. This website does not use any third party cookies, so your visit here cannot be tracked by other websites." + ;; more about cookies text + :default-page-title "Introduction" ;; title of the default page in this wiki + :del-col-hdr "Delete" ;; header for delete column on edit users page + :del-user-fail "Could not delete user" + ;; error message on failure to delete user + :del-user-success "Successfully deleted user" + ;; confirmation message on deletion of user + :diff-title-prefix "Changes since version" + ;; prefix for the header of the changes page + :does-not-exist "does not exist" + ;; (of a file or directory); used in sanity check report + :edit-col-hdr "Edit" ;; header for edit column on edit users page + :edit-page-link "Edit this page" + ;; text of the edit page link on the content frame + :edit-title-prefix "Edit" ;; prefix for title of edit content page + :edit-users-link "Edit users" ;; text of the edit users link on the menu + :edit-users-title "Select user to edit" + ;; title of edit users page + :email-prompt "Email address" ;; text of the email widget prompt on edit user page + :file-or-directory "File or directory" + ;; used in sanity check report + :file-summary-prompt "Description/what's changed" + ;; prompt for the file upload summary input + :file-upload-link-text "You may link to this file using a link of the form" + ;; Text introducing the link to an uploaded file + :file-upload-prompt "File to upload" ;; prompt string for the file upload widget + :file-upload-title "Upload a file" ;; title for the file upload page + :is-admin-prompt "Is administrator?" + :here "here" ;; used in sanity check report + :home-link "Home" ;; text of the home link on the menu + :is-not-directory "is not a directory" + ;; (of a file or directory) used in sanity check report + :is-not-readable "is not readable" + ;; (of a file or directory) used in sanity check report + :is-not-writable "is not writable" + ;; (of a file or directory) used in sanity check report + :login-label "Log in!" ;; text of the login widget on the login page + :login-link "Log in" ;; text of the login link on the menu + :login-prompt "To edit this wiki" + ;; text of the action widget prompt on the login page + :logout-label "Log out!" ;; text of the logout widget on the logout page + :logout-link "Log out" ;; text of the logout link on the menu + :logged-in-as "You are logged in as" + ;; text of the 'logged in as' label on the menu + :history-link "History" ;; text of the history link on the content frame + :history-title-prefix "History of" ;; prefix of the title on the history page + :new-pass-prompt "New password" ;; text of the new password widget prompt on the change + ;; password and edit user pages + :no-admin-users "There are no users in the 'passwd' file with administrative privileges" + ;; used in sanity check report + :old-pass-prompt "Your password" + ;; text of the old password widget prompt on the change + ;; password page, and password widget on login page + :password-file "the password ('passwd') file" + ;; used in sanity check report + :problems-found "problems were found" + ;; used in sanity check report + :rpt-pass-prompt "And again" ;; text of the new password widget prompt on the change + ;; password and edit user pages + :save-prompt "When you have finished editing" + ;; text of the save widget label on edit content + ;; and edit user page + :save-label "Save!" ;; text of the save widget itself + :save-user-fail "Failed to store user" + :save-user-success "Successfully stored user" + :see-documentation "For more information please see documentation " + ;; used in sanity check report + :smeagol-not-initialised + "Smeagol is not initialised correctly" + ;; title of the sanity check report + :smeagol-misconfiguration + "Smeagol has been unable to find some of the resources on which it depends, + possibly because of misconfiguration or missing environment variables." + ;; used in sanity check report + :user-lacks-field "User record in the passwd file lacks a field" + ;; used in sanity check report + :username-prompt "Username" ;; text of the username widget prompt on edit user page + ;; text of the is admin widget prompt on edit user page + :user-title-prefix "Edit user" ;; prefix for title of edit user page + :vers-col-hdr "Version" ;; header for the version column in history + :what-col-hdr "What" ;; header for the what column in history + :what-changed-prompt "What have you changed?" + ;; text of the summary widget prompt on edit + ;; content page + :when-col-hdr "When" ;; header for the when column in history + :your-uname-prompt "Your username" ;; text of the username widget prompt on the login page + } diff --git a/resources/i18n/de.edn b/resources/i18n/de.edn new file mode 120000 index 0000000..d74964e --- /dev/null +++ b/resources/i18n/de.edn @@ -0,0 +1 @@ +de-DE.edn \ No newline at end of file diff --git a/resources/i18n/en-GB.edn b/resources/i18n/en-GB.edn index a7b8789..64c164c 100644 --- a/resources/i18n/en-GB.edn +++ b/resources/i18n/en-GB.edn @@ -42,7 +42,7 @@ ;; error text on fail other htan too short or bad match :chpass-success "Your password was changed" ;; confirmation text on password change - :chpass-too-short "You proposed password wasn't long enough: eight characters required" + :chpass-too-short "Your proposed password wasn't long enough: eight characters required" ;; error text if proposed password is too short :chpass-title-prefix "Change password for" ;; prefix for title of change password page diff --git a/resources/i18n/lt.edn b/resources/i18n/lt.edn new file mode 120000 index 0000000..ef91fe5 --- /dev/null +++ b/resources/i18n/lt.edn @@ -0,0 +1 @@ +lt_LT.edn \ No newline at end of file diff --git a/resources/i18n/lt_LT.edn b/resources/i18n/lt_LT.edn new file mode 100644 index 0000000..13185d0 --- /dev/null +++ b/resources/i18n/lt_LT.edn @@ -0,0 +1,143 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; +;;;; 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. +;;;; +;;;; Lithuanian language translation contributed by and +;;;; Copyright (C) 2017 Soukyan Blackwood +;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; en-GB.edn: English-language messages. +;;; This is essentially all the text in the chrome - that which isn't editable +;;; through the wiki itself; and the test in the sanity check report. + +;; ; ; ; ; ; ; ; ; ; +{:add-user-label "Pridėti naują naudotoją" ;; label for the add user link on edit users page + :change-pass-label "Pakeiskite slaptažodį!" + ;; text of the change password widget itself on the + ;; change password page + :change-pass-link "Pakeiskite slaptažodį" + ;; text of the change password link on the menu + :change-pass-prompt "Pakeisti slaptažodį" + ;; text of the change password widget prompt on the + ;; change password page + :change-col-hdr "Pakeitimai" ;; header for the changes column in history + :chpass-bad-match "Jūsų siūlomi slaptažodžiai - nesutampa" + ;; error text if proposed passwords don't match + :chpass-fail "Jūsų slaptažodis nebuvo pakeistas" + ;; error text on fail other htan too short or bad match + :chpass-success "Jūsų slaptažodis buvo pakeistas" + ;; confirmation text on password change + :chpass-too-short "Jūsų siūlomas slaptožodis – per trumpas: reikia bent aštuonių ženklų" + ;; error text if proposed password is too short + :chpass-title-prefix "Pakeisti slaptažodį, dėl" + ;; prefix for title of change password page + :content-dir "Turinio katalogas" + ;; used in sanity check report + :content-dir-exists "Turinio katalogas egzistuoja" + ;; used in sanity check report + :content-dir-is-dir "Turinio katalogas yra katalogas" + ;; used in sanity check report + :cookies-about "Apie slapukus" ;; about cookies text + :cookies-more "Šis puslapis saugo jūsų sesijų informaciją jūsų naršyklėje “slapukų” forma. Tai mums leidžia jums rodyti tik tai, ką norite matyti. Slapukai neturi jokių jūsų identifikavimo duomenų ir kiti puslapiai negali jų “perskaityti”. Šie slapukai ištrinami iš karto, vos jūs išjungiate šį puslapį. Šis puslapis nenaudoja jokių trečiųjų asmenų slapukų, ir jūsų apsilankymas čia negali būti atsektas jokio kito puslapio." + ;; more about cookies text + :default-page-title "Pristatymas" ;; title of the default page in this wiki + :del-col-hdr "Ištrinti" ;; header for delete column on edit users page + :del-user-fail "Naudotojas negalėjo būti ištrintas" + ;; error message on failure to delete user + :del-user-success "Naudotojas sėkmingai ištrintas" + ;; confirmation message on deletion of user + :diff-title-prefix "Pakeitimai nuo versijos" + ;; prefix for the header of the changes page + :does-not-exist "neegzsituoja" + ;; (of a file or directory); used in sanity check report + :edit-col-hdr "Keisti" ;; header for edit column on edit users page + :edit-page-link "Keisti šį puslapį" + ;; text of the edit page link on the content frame + :edit-title-prefix "Keisti" ;; prefix for title of edit content page + :edit-users-link "Keisti naudotojus" ;; text of the edit users link on the menu + :edit-users-title "Pasirinkti naudotojus keitimui" + ;; title of edit users page + :email-prompt "el. Paštas" ;; text of the email widget prompt on edit user page + :file-or-directory "Failas ar katalogas" + ;; used in sanity check report + :file-summary-prompt "Aprašymas/kas pakeista" + ;; prompt for the file upload summary input + :file-upload-link-text "Galite nukreipti į šį failą naudodami formos nuorodą" + ;; Text introducing the link to an uploaded file + :file-upload-prompt "Failas įkėlimui" ;; prompt string for the file upload widget + :file-upload-title "Įkelti failą" ;; title for the file upload page + :is-admin-prompt "Administratorius?" + :here "čia" ;; used in sanity check report + :home-link "Pradinis" ;; text of the home link on the menu + :is-not-directory "ne katalogas" + ;; (of a file or directory) used in sanity check report + :is-not-readable "neperskaitomas" + ;; (of a file or directory) used in sanity check report + :is-not-writable "nerašomas" + ;; (of a file or directory) used in sanity check report + :login-label "Prisijunkite!" ;; text of the login widget on the login page + :login-link "Prisijunkite" ;; text of the login link on the menu + :login-prompt "Pakeisti šį viki" + ;; text of the action widget prompt on the login page + :logout-label "Atsijunkite!" ;; text of the logout widget on the logout page + :logout-link "Atsijunkite" ;; text of the logout link on the menu + :logged-in-as "Jūs prisijungęs, kaip" + ;; text of the 'logged in as' label on the menu + :history-link "Istorija" ;; text of the history link on the content frame + :history-title-prefix "Istorija apie" ;; prefix of the title on the history page + :new-pass-prompt "Naujas slaptažodis" ;; text of the new password widget prompt on the change + ;; password and edit user pages + :no-admin-users "Naudotojų ‘passwd’ faile su administatoriaus privilegijomis nėra" + ;; used in sanity check report + :old-pass-prompt "Jūsų slaptažodis" + ;; text of the old password widget prompt on the change + ;; password page, and password widget on login page + :password-file "slaptažodžio (‘passwd’) failas" + ;; used in sanity check report + :problems-found "rasta problemų" + ;; used in sanity check report + :rpt-pass-prompt "Ir dar kartą" ;; text of the new password widget prompt on the change + ;; password and edit user pages + :save-prompt "Kai baigsite redaguoti" + ;; text of the save widget label on edit content + ;; and edit user page + :save-label "Išsaugokite!" ;; text of the save widget itself + :save-user-fail "Nepavyko išsaugoti naudotojo" + :save-user-success "Naudotojas sėkmingai išsaugotas" + :see-documentation "Daugiau informacijos ieškokite dokumentacijoje " + ;; used in sanity check report + :smeagol-not-initialised + "Smygolas buvo blogai paleistas" + ;; title of the sanity check report + :smeagol-misconfiguration + "Smygolas nerado kai kurių jam reikalingų resursų, taip nutikti galėjo dėl neteisingų nustatymų, arba trūkstamų aplinkos kintamųjų" + ;; used in sanity check report + :user-lacks-field "Naudotojo passwd failo įraše trūksta laukelio" + ;; used in sanity check report + :username-prompt "Naudotojo vardas" ;; text of the username widget prompt on edit user page + ;; text of the is admin widget prompt on edit user page + :user-title-prefix "Pakeisti naudotoją" ;; prefix for title of edit user page + :vers-col-hdr "Versija" ;; header for the version column in history + :what-col-hdr "Kas" ;; header for the what column in history + :what-changed-prompt "Ką pakeitėte?" + ;; text of the summary widget prompt on edit + ;; content page + :when-col-hdr "Kada" ;; header for the when column in history + :your-uname-prompt "Jūsų naudotojo vardas" ;; text of the username widget prompt on the login page + } diff --git a/resources/i18n/ru.edn b/resources/i18n/ru.edn new file mode 120000 index 0000000..4a740ce --- /dev/null +++ b/resources/i18n/ru.edn @@ -0,0 +1 @@ +ru_RU.edn \ No newline at end of file diff --git a/resources/i18n/ru_RU.edn b/resources/i18n/ru_RU.edn new file mode 100644 index 0000000..73400d6 --- /dev/null +++ b/resources/i18n/ru_RU.edn @@ -0,0 +1,144 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; +;;;; 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. +;;;; +;;;; Russian language translation contributed by and +;;;; Copyright (C) 2017 Soukyan Blackwood +;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; en-GB.edn: English-language messages. +;;; This is essentially all the text in the chrome - that which isn't editable +;;; through the wiki itself; and the test in the sanity check report. + +;; ; ; ; ; ; ; ; ; ; +{:add-user-label "добавить нового пользователя" ;; label for the add user link on edit users page + :change-pass-label "изменить пароль!" + ;; text of the change password widget itself on the + ;; change password page + :change-pass-link "изменить пароль" + ;; text of the change password link on the menu + :change-pass-prompt "Чтобы изменить пароль" + ;; text of the change password widget prompt on the + ;; change password page + :change-col-hdr "изменения" ;; header for the changes column in history + :chpass-bad-match "Ваши предложенные пароли не совпадают" + ;; error text if proposed passwords don't match + :chpass-fail "Ваш пароль не был изменён" + ;; error text on fail other htan too short or bad match + :chpass-success "Ваш пароль был изменён" + ;; confirmation text on password change + :chpass-too-short "Вы предложили пароль недостаточно длины: требуется восемь символов" + ;; error text if proposed password is too short + :chpass-title-prefix "Изменить пароль для" + ;; prefix for title of change password page + :content-dir "Каталог содержимого" + ;; used in sanity check report + :content-dir-exists "Каталог содержимого существуе" + ;; used in sanity check report + :content-dir-is-dir "Каталог содержимого - это каталог" + ;; used in sanity check report + :cookies-about "Об кукисах" ;; about cookies text + :cookies-more "Этот сайт хранит информацию о сеансе как «cookie» в вашем браузере. Это поможет нам показать вам контент, который вы хотите увидеть. Этот файл cookie не идентифицирует вас и не может быть прочитан другими веб-сайтами. Он удаляется браузером, как только вы покидаете этот сайт. Этот веб-сайт не использует сторонние файлы cookie, поэтому ваш визит здесь не может быть отслежен другими веб-сайтами" + ;; more about cookies text + :default-page-title "представление" ;; title of the default page in this wiki + :del-col-hdr "Удалить" ;; header for delete column on edit users page + :del-user-fail "Не удалось удалить пользователя" + ;; error message on failure to delete user + :del-user-success "успешно удалён пользователь" + ;; confirmation message on deletion of user + :diff-title-prefix "Изменения с версии" + ;; prefix for the header of the changes page + :does-not-exist "не существует" + ;; (of a file or directory); used in sanity check report + :edit-col-hdr "редактировать" ;; header for edit column on edit users page + :edit-page-link "Редактировать эту страницу" + ;; text of the edit page link on the content frame + :edit-title-prefix "редактировать" ;; prefix for title of edit content page + :edit-users-link "Редактировать пользователей" ;; text of the edit users link on the menu + :edit-users-title "Выберите пользователя для редактирования" + ;; title of edit users page + :email-prompt "Адрес электронной почты" ;; text of the email widget prompt on edit user page + :file-or-directory "Файл или каталог" + ;; used in sanity check report + :file-summary-prompt "Описание / что изменилось" + ;; prompt for the file upload summary input + :file-upload-link-text "Вы можете ссылать этот файл, используя ссылку формы" + ;; Text introducing the link to an uploaded file + :file-upload-prompt "Файл для загрузки" ;; prompt string for the file upload widget + :file-upload-title "Загрузить файл" ;; title for the file upload page + :is-admin-prompt "Администратор?" + :here "здесь" ;; used in sanity check report + :home-link "Главная" ;; text of the home link on the menu + :is-not-directory "не является каталогом" + ;; (of a file or directory) used in sanity check report + :is-not-readable "не читаемый" + ;; (of a file or directory) used in sanity check report + :is-not-writable "недоступен для записи" + ;; (of a file or directory) used in sanity check report + :login-label "Вход!" ;; text of the login widget on the login page + :login-link "Вход" ;; text of the login link on the menu + :login-prompt "Чтобы отредактировать эту вики" + ;; text of the action widget prompt on the login page + :logout-label "Выйти!" ;; text of the logout widget on the logout page + :logout-link "Выйти" ;; text of the logout link on the menu + :logged-in-as "Вы вошли как" + ;; text of the 'logged in as' label on the menu + :history-link "история" ;; text of the history link on the content frame + :history-title-prefix "История об" ;; prefix of the title on the history page + :new-pass-prompt "Новый пароль" ;; text of the new password widget prompt on the change + ;; password and edit user pages + :no-admin-users "В файле 'passwd' нет пользователей с правами администратора" + ;; used in sanity check report + :old-pass-prompt "Ваш пароль" + ;; text of the old password widget prompt on the change + ;; password page, and password widget on login page + :password-file "файл пароля ('passwd')" + ;; used in sanity check report + :problems-found "проблемы были найдены" + ;; used in sanity check report + :rpt-pass-prompt "И опять" ;; text of the new password widget prompt on the change + ;; password and edit user pages + :save-prompt "Когда вы закончили редактирование" + ;; text of the save widget label on edit content + ;; and edit user page + :save-label "Сохранить!" ;; text of the save widget itself + :save-user-fail "Не удалось сохранить пользователя" + :save-user-success "Успешно сохранённый пользователь" + :see-documentation "для получения дополнительной информации смотрите документацию " + ;; used in sanity check report + :smeagol-not-initialised + "Смеаголь неправильно инициализирован" + ;; title of the sanity check report + :smeagol-misconfiguration + "Смеаголь не смог найти некоторые ресурсы, от которых это зависит, + возможно, из-за неправильной конфигурации или отсутствующих переменных среды." + ;; used in sanity check report + :user-lacks-field "В пользовательской записи в файле passwd отсутствует поле" + ;; used in sanity check report + :username-prompt "Имя пользователя" ;; text of the username widget prompt on edit user page + ;; text of the is admin widget prompt on edit user page + :user-title-prefix "Изменить пользователя" ;; prefix for title of edit user page + :vers-col-hdr "Версия" ;; header for the version column in history + :what-col-hdr "Что" ;; header for the what column in history + :what-changed-prompt "Что вы изменили?" + ;; text of the summary widget prompt on edit + ;; content page + :when-col-hdr "когда" ;; header for the when column in history + :your-uname-prompt "Ваш логин" ;; text of the username widget prompt on the login page + } diff --git a/resources/translations.edn b/resources/translations.edn new file mode 100644 index 0000000..e69de29 From 40f299b43d7c05a870a3848f508887ab4bb2c810 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Thu, 24 May 2018 07:26:39 +0100 Subject: [PATCH 37/48] Version 1.0.1 --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index efd7bc2..7e86d29 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject smeagol "1.0.1-SNAPSHOT" +(defproject smeagol "1.0.1" :description "A simple Git-backed Wiki inspired by Gollum" :url "https://github.com/simon-brooke/smeagol" :license {:name "GNU General Public License,version 2.0 or (at your option) any later version" From 05eafe603ff29a8144def4cb6a9111173cc457e7 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Thu, 24 May 2018 08:26:37 +0100 Subject: [PATCH 38/48] Minor: alphorder requirements, documentation spelling. --- project.clj | 6 +++--- src/smeagol/include/resolve.clj | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/project.clj b/project.clj index 375538d..8769cba 100644 --- a/project.clj +++ b/project.clj @@ -7,6 +7,7 @@ [clj-yaml "0.4.0"] [com.cemerick/url "0.1.1"] [com.fzakaria/slf4j-timbre "0.3.7"] + [com.stuartsierra/component "0.3.2"] [com.taoensso/encore "2.92.0"] [com.taoensso/timbre "4.10.0"] [com.taoensso/tower "3.0.2" :exclusions [com.taoensso/encore]] @@ -26,12 +27,11 @@ [org.slf4j/log4j-over-slf4j "1.7.25"] [org.slf4j/jul-to-slf4j "1.7.25"] [org.slf4j/jcl-over-slf4j "1.7.25"] + [prismatic/schema "1.1.9"] [prone "1.1.4"] [ring/ring-anti-forgery "1.1.0"] [ring-server "0.4.0"] - [selmer "1.11.0"] - [com.stuartsierra/component "0.3.2"] - [prismatic/schema "1.1.9"]] + [selmer "1.11.0"]] :repl-options {:init-ns smeagol.repl} diff --git a/src/smeagol/include/resolve.clj b/src/smeagol/include/resolve.clj index 7a2b3b1..266a276 100644 --- a/src/smeagol/include/resolve.clj +++ b/src/smeagol/include/resolve.clj @@ -11,7 +11,7 @@ smeagol.include and not inteded for direct usage." [type :- s/Keyword local-base-dir :- s/Str]) -;As schema does'nt support s/defprotocol we use the dispatcher for annotation & validation. +;As schema doesn't support s/defprotocol we use the dispatcher for annotation & validation. (s/defn dispatch-by-resolver-type :- s/Keyword "Dispatcher for different resolver implementations." [resolver :- Resolver @@ -19,7 +19,7 @@ smeagol.include and not inteded for direct usage." (:type resolver)) (defmulti do-resolve-md - "Multimethod return a markfown file content for given uri." + "Multimethod return a markdown file content for given uri." dispatch-by-resolver-type) (s/defmethod do-resolve-md :default [resolver :- Resolver @@ -29,7 +29,7 @@ smeagol.include and not inteded for direct usage." (defprotocol ResolveMd (resolve-md [resolver uri] - "return a markfown file content for given uru.")) + "return a markfown file content for given uri.")) (extend-type Resolver ResolveMd From f3456d819cbcd65ab8d1091539e31ffda8d55434 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Thu, 24 May 2018 08:28:37 +0100 Subject: [PATCH 39/48] Upversion to 1.0.2-SNAPSHOT --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 8769cba..1de6005 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject smeagol "1.0.1" +(defproject smeagol "1.0.2-SNAPSHOT" :description "A simple Git-backed Wiki inspired by Gollum" :url "https://github.com/simon-brooke/smeagol" :license {:name "GNU General Public License,version 2.0 or (at your option) any later version" From 7b284eb13fd95dd2a96b6cbb8a5be2ac808d2ae0 Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 25 May 2018 17:15:46 +0200 Subject: [PATCH 40/48] Added include doc --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 03cd9d1..46d38e1 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,17 @@ You can (if you're logged in) upload files, including images, using the **Upload ![Smeagol](http://vignette3.wikia.nocookie.net/lotr/images/e/e1/Gollum_Render.png/revision/latest?cb=20141218075509) +## Includes +You can include pages into the current page youre working on. To do so, you can add a include link: + +`&[:indent-heading s/Num :indent-list s/Num](relative or absolute uri s/Str)` + +Parameters semantics: + * uri: The page to include. At the moment only pages of the current wiki are allowed. A page called "PageToBeIncluded" will result in a uri "PageToBeIncluded.md". + * indent-heading: You can indent headings of included page to adjust the included content to your surrounding structure. Indents 0-9 are supported. + * indent-list: In Same manner you can indent lists of included page to adjust the included content to your surrounding structure. Indents 0-9 are supported. + Security warning: At the moment there is no check against directory traversal attack. So include feature may expose files outside of your wiki. + ## Advertisement If you like what you see here, I am available for work on open source Clojure projects. From 7e5b3d74dac2e0c675dcec024c544a6f36a2cbb0 Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 25 May 2018 17:19:33 +0200 Subject: [PATCH 41/48] spelling & format fixes for README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 46d38e1..2dfc62b 100644 --- a/README.md +++ b/README.md @@ -99,14 +99,15 @@ You can (if you're logged in) upload files, including images, using the **Upload ![Smeagol](http://vignette3.wikia.nocookie.net/lotr/images/e/e1/Gollum_Render.png/revision/latest?cb=20141218075509) ## Includes -You can include pages into the current page youre working on. To do so, you can add a include link: +You can include pages into the current page you're working on. To do so, you can add a include link: `&[:indent-heading s/Num :indent-list s/Num](relative or absolute uri s/Str)` Parameters semantics: - * uri: The page to include. At the moment only pages of the current wiki are allowed. A page called "PageToBeIncluded" will result in a uri "PageToBeIncluded.md". + * uri: The page to include. At the moment only pages from the current wiki are allowed. A page called "PageToBeIncluded" will result in a uri "PageToBeIncluded.md". * indent-heading: You can indent headings of included page to adjust the included content to your surrounding structure. Indents 0-9 are supported. * indent-list: In Same manner you can indent lists of included page to adjust the included content to your surrounding structure. Indents 0-9 are supported. + Security warning: At the moment there is no check against directory traversal attack. So include feature may expose files outside of your wiki. ## Advertisement From 77d77ed3343ccfd65f57576728b1c2e1af69a082 Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 25 May 2018 17:21:32 +0200 Subject: [PATCH 42/48] minor doc add in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2dfc62b..6cc0691 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ Parameters semantics: * indent-heading: You can indent headings of included page to adjust the included content to your surrounding structure. Indents 0-9 are supported. * indent-list: In Same manner you can indent lists of included page to adjust the included content to your surrounding structure. Indents 0-9 are supported. - Security warning: At the moment there is no check against directory traversal attack. So include feature may expose files outside of your wiki. + Security warning: At the moment there is no check against directory traversal attack. So include feature may expose files outside of your wiki content-dir. ## Advertisement If you like what you see here, I am available for work on open source Clojure projects. From 1136e792d4810fd9af8b443fdea6d6be4aeda79e Mon Sep 17 00:00:00 2001 From: jem Date: Tue, 8 Jan 2019 17:42:24 +0100 Subject: [PATCH 43/48] fix rings & noirs resource upload & serve location --- src/smeagol/middleware.clj | 14 ++++++++++++-- src/smeagol/routes/wiki.clj | 4 +++- src/smeagol/uploads.clj | 14 ++++++++------ 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/smeagol/middleware.clj b/src/smeagol/middleware.clj index 82ccb59..aa14cb2 100644 --- a/src/smeagol/middleware.clj +++ b/src/smeagol/middleware.clj @@ -6,7 +6,12 @@ [selmer.middleware :refer [wrap-error-page]] [prone.middleware :refer [wrap-exceptions]] [ring.middleware.anti-forgery :refer [wrap-anti-forgery]] - [noir-exception.core :refer [wrap-internal-error]])) + [ring.middleware.file :refer [wrap-file]] + [ring.middleware.resource :refer [wrap-resource]] + [ring.middleware.content-type :refer [wrap-content-type]] + [ring.middleware.not-modified :refer [wrap-not-modified]] + [noir-exception.core :refer [wrap-internal-error]] + [smeagol.util :as util])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; @@ -44,7 +49,12 @@ (def production-middleware - [#(wrap-internal-error % :log (fn [e] (timbre/error e)))]) + [#(wrap-internal-error % :log (fn [e] (timbre/error e))) + #(wrap-file % util/content-dir + {:index-files? false :prefer-handler? true}) + #(wrap-resource % "public") + #(wrap-content-type %) + #(wrap-not-modified %)]) (defn load-middleware [] diff --git a/src/smeagol/routes/wiki.clj b/src/smeagol/routes/wiki.clj index 467275d..1002b7b 100644 --- a/src/smeagol/routes/wiki.clj +++ b/src/smeagol/routes/wiki.clj @@ -52,6 +52,7 @@ "Process `source-text` and save it to the specified `file-path`, committing it to Git and finally redirecting to wiki-page." [params suffix request] + (timbre/trace (format "process-source: '%s'" request)) (let [source-text (:src params) page (:page params) file-name (str page suffix) @@ -122,6 +123,7 @@ (defn wiki-page "Render the markdown page specified in this `request`, if any. If none found, redirect to edit-page" [request] + (timbre/trace (format "wiki-page: '%s'" request)) (or (show-sanity-check-error) (let [params (keywordize-keys (:params request)) @@ -163,7 +165,7 @@ "Render a form to allow the upload of a file." [request] (let [params (keywordize-keys (:params request)) - data-path (str (io/resource-path) "/content/uploads/") + data-path (str util/content-dir "/content/uploads/") git-repo (hist/load-or-init-repo util/content-dir) upload (:upload params) uploaded (if upload (ul/store-upload params data-path)) diff --git a/src/smeagol/uploads.clj b/src/smeagol/uploads.clj index 27ddceb..cdac04a 100644 --- a/src/smeagol/uploads.clj +++ b/src/smeagol/uploads.clj @@ -56,9 +56,11 @@ filename (:filename upload)] (timbre/info (str "Storing upload file: " upload)) - (if tmp-file - (do - (.renameTo tmp-file - (File. (str path filename))) - filename) - (throw (Exception. "No file found?"))))) + (timbre/debug + (str "store-upload mv file: " tmp-file " to: " path filename)) + (if tmp-file + (do + (.renameTo tmp-file + (File. (str path filename))) + filename) + (throw (Exception. "No file found?"))))) From fad1fcfea5b1f0ad4dfff7473afeb3c2981854d7 Mon Sep 17 00:00:00 2001 From: jem Date: Tue, 8 Jan 2019 19:59:16 +0100 Subject: [PATCH 44/48] make start page configurable --- resources/config.edn | 4 ++-- src/smeagol/routes/wiki.clj | 2 +- src/smeagol/util.clj | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/resources/config.edn b/resources/config.edn index 0fcb152..80d0738 100644 --- a/resources/config.edn +++ b/resources/config.edn @@ -28,6 +28,7 @@ ;; ; ; ; ; ; ; ; ; ; { :content-dir "resources/public/content" + :start-page "README" ;; where content is served from. :default-locale "en-GB" ;; default language used for messages :formatters {"vega" smeagol.formatting/process-vega @@ -38,6 +39,5 @@ ;; :trace :debug :info :warn :error :fatal :passwd "resources/passwd" ;; where the password file is stored - :site-title "Smeagol" ;; overall title of the site, used in + :site-title "Smeagol"} ;; overall title of the site, used in ;; page headings -} diff --git a/src/smeagol/routes/wiki.clj b/src/smeagol/routes/wiki.clj index 467275d..91174b2 100644 --- a/src/smeagol/routes/wiki.clj +++ b/src/smeagol/routes/wiki.clj @@ -125,7 +125,7 @@ (or (show-sanity-check-error) (let [params (keywordize-keys (:params request)) - page (or (:page params) (util/get-message :default-page-title "Introduction" request)) + page (or (:page params) util/start-page (util/get-message :default-page-title "Introduction" request)) file-name (str page ".md") file-path (cjio/file util/content-dir file-name) exists? (.exists (clojure.java.io/as-file file-path))] diff --git a/src/smeagol/util.clj b/src/smeagol/util.clj index 015a5db..8ab537d 100644 --- a/src/smeagol/util.clj +++ b/src/smeagol/util.clj @@ -35,6 +35,9 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(def start-page + (:start-page config)) + (def content-dir (or (:content-dir config) From 3542ac914636fbf53a4d29fa079ab700fc3a38f4 Mon Sep 17 00:00:00 2001 From: Vlad Bokov Date: Fri, 18 Jan 2019 07:05:19 +0700 Subject: [PATCH 45/48] Prefer content-dir files over classpath (like /content/stylesheet.css) --- src/smeagol/handler.clj | 1 + src/smeagol/middleware.clj | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smeagol/handler.clj b/src/smeagol/handler.clj index d25e415..9cbaca5 100644 --- a/src/smeagol/handler.clj +++ b/src/smeagol/handler.clj @@ -97,6 +97,7 @@ [xss-protection?] (-> site-defaults (update-in [:session] merge session-defaults) + (dissoc :static) (assoc-in [:security :anti-forgery] xss-protection?))) diff --git a/src/smeagol/middleware.clj b/src/smeagol/middleware.clj index aa14cb2..92cfac0 100644 --- a/src/smeagol/middleware.clj +++ b/src/smeagol/middleware.clj @@ -50,9 +50,9 @@ (def production-middleware [#(wrap-internal-error % :log (fn [e] (timbre/error e))) + #(wrap-resource % "public") #(wrap-file % util/content-dir {:index-files? false :prefer-handler? true}) - #(wrap-resource % "public") #(wrap-content-type %) #(wrap-not-modified %)]) From 4f8c4b8925d3596ff42c2906958cbf21efbd1992 Mon Sep 17 00:00:00 2001 From: jem Date: Fri, 18 Jan 2019 15:06:33 +0100 Subject: [PATCH 46/48] fixed test - Now we are getting a 200 response again. --- resources/config.edn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/config.edn b/resources/config.edn index 80d0738..d5f7017 100644 --- a/resources/config.edn +++ b/resources/config.edn @@ -28,7 +28,7 @@ ;; ; ; ; ; ; ; ; ; ; { :content-dir "resources/public/content" - :start-page "README" + :start-page "Introduction" ;; where content is served from. :default-locale "en-GB" ;; default language used for messages :formatters {"vega" smeagol.formatting/process-vega From 5b785389b404ac8169191dfec3096afa54473c9b Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sat, 19 Jan 2019 17:20:50 +0000 Subject: [PATCH 47/48] Version 1.0.2 --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 49977fc..91a13a1 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject smeagol "1.0.2-SNAPSHOT" +(defproject smeagol "1.0.2" :description "A simple Git-backed Wiki inspired by Gollum" :url "https://github.com/simon-brooke/smeagol" :license {:name "GNU General Public License,version 2.0 or (at your option) any later version" From 8374432a168f01f8cba581d2dbfdcbd4f4d15730 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sat, 19 Jan 2019 17:46:33 +0000 Subject: [PATCH 48/48] Added change log --- resources/public/content/Change log.md | 7 +++++++ resources/public/content/_side-bar.md | 1 + 2 files changed, 8 insertions(+) create mode 100644 resources/public/content/Change log.md diff --git a/resources/public/content/Change log.md b/resources/public/content/Change log.md new file mode 100644 index 0000000..c948455 --- /dev/null +++ b/resources/public/content/Change log.md @@ -0,0 +1,7 @@ +# 1.0.2 +Two fixes contributed by a user: + +* [Configurable start page](https://github.com/journeyman-cc/smeagol/commit/b1eeecde1d0555e9b708807c63e28fac21de58c4) +* [Fixed uploads](https://github.com/journeyman-cc/smeagol/commit/1136e792d4810fd9af8b443fdea6d6be4aeda79e) + +Many thanks to [M Jerger](https://github.com/jerger) for these. \ No newline at end of file diff --git a/resources/public/content/_side-bar.md b/resources/public/content/_side-bar.md index a675893..ad01779 100644 --- a/resources/public/content/_side-bar.md +++ b/resources/public/content/_side-bar.md @@ -1,4 +1,5 @@ * [[Introduction]] +* [[Change log]] * [[User Documentation]] * [[Deploying Smeagol]] * [[Developing Smeagol]]