diff --git a/src/NoteHub/crossover/lib.clj b/src/NoteHub/crossover/lib.clj index 95fb5bc..86900cf 100644 --- a/src/NoteHub/crossover/lib.clj +++ b/src/NoteHub/crossover/lib.clj @@ -1,9 +1,11 @@ (ns NoteHub.crossover.lib (:refer-clojure :exclude [hash])) -; very simple hash function %) -; (doesn't work for UTF-16!) -(defn hash [f s] +(defn hash + "A simple hash-function, which computes a hash from the text field + content and given session number. It is intended to be used as a spam + protection / captcha alternative. (Probably doesn't work for URF-16)" + [f s] (let [short-mod #(mod % 32767) char-codes (map f (filter #(not (contains? #{"\n" "\r"} %)) (map str s)))] diff --git a/src/NoteHub/settings.clj b/src/NoteHub/settings.clj new file mode 100644 index 0000000..734f12a --- /dev/null +++ b/src/NoteHub/settings.clj @@ -0,0 +1,18 @@ +(ns NoteHub.settings + (:require [clojure.string :as cs])) + +(defn get-setting + "Takes a settings key, a default value and a converter function and returns a corresponding + settings value. The default value is returned back when no setting value was found. + The converter function can be provided to convert the setting from string to a needed format." + [key & more] + (let [default (first more) + converter (second more) + file-content (slurp "settings") + lines (cs/split file-content #"\n") + pairs (map #(map cs/trim %) (map #(cs/split % #"=") lines)) + config-map (apply hash-map (mapcat #(list (keyword (first %)) (second %)) pairs)) + value (config-map key)] + (if value + (if (fn? converter) (converter value) value) + default))) diff --git a/src/NoteHub/storage.clj b/src/NoteHub/storage.clj index 1c26c71..3672c9f 100644 --- a/src/NoteHub/storage.clj +++ b/src/NoteHub/storage.clj @@ -1,24 +1,32 @@ (ns NoteHub.storage - (:use [NoteHub.config]) + (:use [NoteHub.settings] + [noir.options :only [dev-mode?]]) (:require [clj-redis.client :as redis])) +; Initialize the data base (def db (redis/init - (when noir.options/dev-mode? - {:url (config-map :db-url)}))) + (when dev-mode? + {:url (get-setting :db-url)}))) +; DB hierarchy levels (def note "note") - (def views "views") + +; Concatenates all fields to a string (defn- build-key [[year month day] title] (print-str year month day title)) -(defn set-note [date title text] +(defn set-note + "Creates a note with the given title and text in the given date namespace" + [date title text] (let [key (build-key date title)] (redis/hset db note key text))) -(defn get-note [date title] +(defn get-note + "Gets the note from the given date namespaces for the specified title" + [date title] (let [key (build-key date title) text (redis/hget db note key)] (when text @@ -26,13 +34,19 @@ (redis/hincrby db views key 1) text)))) -(defn get-views [date title] +(defn get-views + "Returns the number of views for the specified date and note title" + [date title] (redis/hget db views (build-key date title))) -(defn note-exists? [date title] +(defn note-exists? + "Returns true if the note with the specified title and date exists" + [date title] (redis/hexists db note (build-key date title))) -(defn delete-note [date title] +(defn delete-note + "Deletes the note with the specified coordinates" + [date title] (let [key (build-key date title)] (do (redis/hdel db views key) diff --git a/src/NoteHub/views/common.clj b/src/NoteHub/views/common.clj index 2ba837b..8c29706 100644 --- a/src/NoteHub/views/common.clj +++ b/src/NoteHub/views/common.clj @@ -5,6 +5,7 @@ [hiccup.page :only [include-js html5]] [hiccup.element :only [javascript-tag]])) +; Creates the main html layout (defpartial generate-layout [params title & content] (html5 @@ -28,8 +29,9 @@ (include-js "/cljs/main.js")] [:body content]))) -(defn layout [& args] +(defn layout + "Generates the main html layout" + [& args] (if (map? (first args)) (apply generate-layout args) (apply generate-layout {} args))) - diff --git a/src/NoteHub/views/css_generator.clj b/src/NoteHub/views/css_generator.clj index b271886..0535b90 100644 --- a/src/NoteHub/views/css_generator.clj +++ b/src/NoteHub/views/css_generator.clj @@ -1,16 +1,18 @@ (ns NoteHub.views.css-generator (:use [cssgen] + [NoteHub.settings] [cssgen.types])) -(defn gen-fontlist [& fonts] +(defn- gen-fontlist [& fonts] (apply str (interpose "," (map #(str "'" % "'") (filter identity fonts))))) +; CSS Mixins (def page-width (mixin - :width :800px)) + :width (get-setting :page-width :800px keyword))) (def helvetica-neue (mixin @@ -20,6 +22,7 @@ "Arial" "Lucida Grande" "sans-serif"))) + (def central-element (mixin page-width @@ -28,7 +31,8 @@ :margin-left "auto" :margin-right "auto")) -(defn color [theme tone] +; Resolves the theme name & tone parameter to a concrete color +(defn- color [theme tone] (get-in {:dark {:background :#333 :foreground :#ccc :background-halftone :#444 @@ -38,7 +42,9 @@ :background-halftone :#efefef :foreground-halftone :#888 }} [theme tone])) -(defn global-css [params] +(defn global-css + "Generates the entire CSS rules of the app" + [params] (let [theme (params :theme) theme (if theme (keyword theme) :default) header-fonts (gen-fontlist (params :header-font) "Noticia Text" "PT Serif" "Georgia") diff --git a/src/NoteHub/views/pages.clj b/src/NoteHub/views/pages.clj index 5c12451..4988e12 100644 --- a/src/NoteHub/views/pages.clj +++ b/src/NoteHub/views/pages.clj @@ -3,6 +3,7 @@ (:require [NoteHub.crossover.lib :as lib]) (:use [NoteHub.storage] + [NoteHub.settings] [clojure.string :rename {replace sreplace} :only [split replace lower-case]] [clojure.core.incubator :only [-?>]] [hiccup.form] @@ -16,23 +17,22 @@ [java.util Calendar] [org.pegdown PegDownProcessor])) -; Fix a maximal title length used in the link -(def max-title-length 80) - ; Markdown -> HTML mapper (defn md-to-html [md-text] (.markdownToHtml (PegDownProcessor.) md-text)) -(defn get-flash-key [] +; Creates a random session number +(defn- get-flash-key [] (let [k (encrypt (str (rand-int Integer/MAX_VALUE)))] (do (flash-put! k true) (print-str k)))) -; This function answers to a corresponding AJAX request -(defremote get-preview-md [session-key md] - (when (flash-get session-key) - {:session-key (get-flash-key) - :preview (md-to-html md)})) +; Converts given markdwon to html and wraps with layout +(defn- wrap [params md-text] + (if md-text + (let [title (-?> md-text (split #"\n") first (sreplace #"[_\*#]" ""))] + (common/layout params title [:article (md-to-html md-text)])) + (status 404 (get-page 404)))) ; Template for the error sites (defn page-setter [code message] @@ -41,6 +41,7 @@ [:article [:h1 message]]))) +; Sets a message for each corresponding HTTP status (page-setter 404 "Nothing Found.") (page-setter 400 "Bad request.") (page-setter 500 "OMG, Server Exploded.") @@ -48,6 +49,13 @@ ; Routes ; ====== +; This function answers to a AJAX request: it gets a sesion key and markdown text. +; IT return html version of the provided markdown and a new session key +(defremote get-preview-md [session-key md] + (when (flash-get session-key) + {:session-key (get-flash-key) + :preview (md-to-html md)})) + ; Landing Page (defpage "/" {} (common/layout "Free Markdown Hosting" @@ -74,21 +82,18 @@ [:div#preview-start-line.hidden] [:article#preview])) -(defn wrap [params md-text] - (if md-text - (let [title (-?> md-text (split #"\n") first (sreplace #"[_\*#]" ""))] - (common/layout params title [:article (md-to-html md-text)])) - (status 404 (get-page 404)))) - +; Display the note (defpage "/:year/:month/:day/:title" {:keys [year month day title theme header-font text-font] :as params} (wrap (select-keys params [:theme :header-font :text-font]) (get-note [year month day] title))) +; Provides Markdown of the specified note (defpage "/:year/:month/:day/:title/export" {:keys [year month day title]} (let [md-text (get-note [year month day] title)] (if md-text md-text (status 404 (get-page 404))))) +; Provides the number of views of the specified note (defpage "/:year/:month/:day/:title/stat" {:keys [year month day title]} (let [views (get-views [year month day] title)] (if views @@ -119,7 +124,8 @@ (-> draft (split #"\n") first (sreplace " " "-") lower-case)) trim (fn [s] (apply str (drop-while #(= \- %) s))) title-uncut (-> untrimmed-line trim reverse trim reverse) - proposed-title (apply str (take max-title-length title-uncut)) + proposed-title (apply str (take (get-setting :max-title-length 80 #(Integer/parseInt %)) + title-uncut)) date [year month day] title (first (drop-while #(note-exists? date %) (cons proposed-title