documentation added + more sophisticated settings file reader
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
(ns NoteHub.crossover.lib
|
(ns NoteHub.crossover.lib
|
||||||
(:refer-clojure :exclude [hash]))
|
(:refer-clojure :exclude [hash]))
|
||||||
|
|
||||||
; very simple hash function %)
|
(defn hash
|
||||||
; (doesn't work for UTF-16!)
|
"A simple hash-function, which computes a hash from the text field
|
||||||
(defn hash [f s]
|
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)
|
(let [short-mod #(mod % 32767)
|
||||||
char-codes (map f
|
char-codes (map f
|
||||||
(filter #(not (contains? #{"\n" "\r"} %)) (map str s)))]
|
(filter #(not (contains? #{"\n" "\r"} %)) (map str s)))]
|
||||||
|
|||||||
@@ -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)))
|
||||||
+23
-9
@@ -1,24 +1,32 @@
|
|||||||
(ns NoteHub.storage
|
(ns NoteHub.storage
|
||||||
(:use [NoteHub.config])
|
(:use [NoteHub.settings]
|
||||||
|
[noir.options :only [dev-mode?]])
|
||||||
(:require [clj-redis.client :as redis]))
|
(:require [clj-redis.client :as redis]))
|
||||||
|
|
||||||
|
; Initialize the data base
|
||||||
(def db
|
(def db
|
||||||
(redis/init
|
(redis/init
|
||||||
(when noir.options/dev-mode?
|
(when dev-mode?
|
||||||
{:url (config-map :db-url)})))
|
{:url (get-setting :db-url)})))
|
||||||
|
|
||||||
|
; DB hierarchy levels
|
||||||
(def note "note")
|
(def note "note")
|
||||||
|
|
||||||
(def views "views")
|
(def views "views")
|
||||||
|
|
||||||
|
|
||||||
|
; Concatenates all fields to a string
|
||||||
(defn- build-key [[year month day] title]
|
(defn- build-key [[year month day] title]
|
||||||
(print-str 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)]
|
(let [key (build-key date title)]
|
||||||
(redis/hset db note key text)))
|
(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)
|
(let [key (build-key date title)
|
||||||
text (redis/hget db note key)]
|
text (redis/hget db note key)]
|
||||||
(when text
|
(when text
|
||||||
@@ -26,13 +34,19 @@
|
|||||||
(redis/hincrby db views key 1)
|
(redis/hincrby db views key 1)
|
||||||
text))))
|
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)))
|
(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)))
|
(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)]
|
(let [key (build-key date title)]
|
||||||
(do
|
(do
|
||||||
(redis/hdel db views key)
|
(redis/hdel db views key)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
[hiccup.page :only [include-js html5]]
|
[hiccup.page :only [include-js html5]]
|
||||||
[hiccup.element :only [javascript-tag]]))
|
[hiccup.element :only [javascript-tag]]))
|
||||||
|
|
||||||
|
; Creates the main html layout
|
||||||
(defpartial generate-layout
|
(defpartial generate-layout
|
||||||
[params title & content]
|
[params title & content]
|
||||||
(html5
|
(html5
|
||||||
@@ -28,8 +29,9 @@
|
|||||||
(include-js "/cljs/main.js")]
|
(include-js "/cljs/main.js")]
|
||||||
[:body content])))
|
[:body content])))
|
||||||
|
|
||||||
(defn layout [& args]
|
(defn layout
|
||||||
|
"Generates the main html layout"
|
||||||
|
[& args]
|
||||||
(if (map? (first args))
|
(if (map? (first args))
|
||||||
(apply generate-layout args)
|
(apply generate-layout args)
|
||||||
(apply generate-layout {} args)))
|
(apply generate-layout {} args)))
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
(ns NoteHub.views.css-generator
|
(ns NoteHub.views.css-generator
|
||||||
(:use [cssgen]
|
(:use [cssgen]
|
||||||
|
[NoteHub.settings]
|
||||||
[cssgen.types]))
|
[cssgen.types]))
|
||||||
|
|
||||||
(defn gen-fontlist [& fonts]
|
(defn- gen-fontlist [& fonts]
|
||||||
(apply str
|
(apply str
|
||||||
(interpose ","
|
(interpose ","
|
||||||
(map #(str "'" % "'")
|
(map #(str "'" % "'")
|
||||||
(filter identity fonts)))))
|
(filter identity fonts)))))
|
||||||
|
|
||||||
|
; CSS Mixins
|
||||||
(def page-width
|
(def page-width
|
||||||
(mixin
|
(mixin
|
||||||
:width :800px))
|
:width (get-setting :page-width :800px keyword)))
|
||||||
|
|
||||||
(def helvetica-neue
|
(def helvetica-neue
|
||||||
(mixin
|
(mixin
|
||||||
@@ -20,6 +22,7 @@
|
|||||||
"Arial"
|
"Arial"
|
||||||
"Lucida Grande"
|
"Lucida Grande"
|
||||||
"sans-serif")))
|
"sans-serif")))
|
||||||
|
|
||||||
(def central-element
|
(def central-element
|
||||||
(mixin
|
(mixin
|
||||||
page-width
|
page-width
|
||||||
@@ -28,7 +31,8 @@
|
|||||||
:margin-left "auto"
|
:margin-left "auto"
|
||||||
:margin-right "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
|
(get-in {:dark {:background :#333
|
||||||
:foreground :#ccc
|
:foreground :#ccc
|
||||||
:background-halftone :#444
|
:background-halftone :#444
|
||||||
@@ -38,7 +42,9 @@
|
|||||||
:background-halftone :#efefef
|
:background-halftone :#efefef
|
||||||
:foreground-halftone :#888 }} [theme tone]))
|
: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)
|
(let [theme (params :theme)
|
||||||
theme (if theme (keyword theme) :default)
|
theme (if theme (keyword theme) :default)
|
||||||
header-fonts (gen-fontlist (params :header-font) "Noticia Text" "PT Serif" "Georgia")
|
header-fonts (gen-fontlist (params :header-font) "Noticia Text" "PT Serif" "Georgia")
|
||||||
|
|||||||
+22
-16
@@ -3,6 +3,7 @@
|
|||||||
(:require [NoteHub.crossover.lib :as lib])
|
(:require [NoteHub.crossover.lib :as lib])
|
||||||
(:use
|
(:use
|
||||||
[NoteHub.storage]
|
[NoteHub.storage]
|
||||||
|
[NoteHub.settings]
|
||||||
[clojure.string :rename {replace sreplace} :only [split replace lower-case]]
|
[clojure.string :rename {replace sreplace} :only [split replace lower-case]]
|
||||||
[clojure.core.incubator :only [-?>]]
|
[clojure.core.incubator :only [-?>]]
|
||||||
[hiccup.form]
|
[hiccup.form]
|
||||||
@@ -16,23 +17,22 @@
|
|||||||
[java.util Calendar]
|
[java.util Calendar]
|
||||||
[org.pegdown PegDownProcessor]))
|
[org.pegdown PegDownProcessor]))
|
||||||
|
|
||||||
; Fix a maximal title length used in the link
|
|
||||||
(def max-title-length 80)
|
|
||||||
|
|
||||||
; Markdown -> HTML mapper
|
; Markdown -> HTML mapper
|
||||||
(defn md-to-html [md-text]
|
(defn md-to-html [md-text]
|
||||||
(.markdownToHtml (PegDownProcessor.) 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)))]
|
(let [k (encrypt (str (rand-int Integer/MAX_VALUE)))]
|
||||||
(do (flash-put! k true)
|
(do (flash-put! k true)
|
||||||
(print-str k))))
|
(print-str k))))
|
||||||
|
|
||||||
; This function answers to a corresponding AJAX request
|
; Converts given markdwon to html and wraps with layout
|
||||||
(defremote get-preview-md [session-key md]
|
(defn- wrap [params md-text]
|
||||||
(when (flash-get session-key)
|
(if md-text
|
||||||
{:session-key (get-flash-key)
|
(let [title (-?> md-text (split #"\n") first (sreplace #"[_\*#]" ""))]
|
||||||
:preview (md-to-html md)}))
|
(common/layout params title [:article (md-to-html md-text)]))
|
||||||
|
(status 404 (get-page 404))))
|
||||||
|
|
||||||
; Template for the error sites
|
; Template for the error sites
|
||||||
(defn page-setter [code message]
|
(defn page-setter [code message]
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
[:article
|
[:article
|
||||||
[:h1 message]])))
|
[:h1 message]])))
|
||||||
|
|
||||||
|
; Sets a message for each corresponding HTTP status
|
||||||
(page-setter 404 "Nothing Found.")
|
(page-setter 404 "Nothing Found.")
|
||||||
(page-setter 400 "Bad request.")
|
(page-setter 400 "Bad request.")
|
||||||
(page-setter 500 "OMG, Server Exploded.")
|
(page-setter 500 "OMG, Server Exploded.")
|
||||||
@@ -48,6 +49,13 @@
|
|||||||
; Routes
|
; 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
|
; Landing Page
|
||||||
(defpage "/" {}
|
(defpage "/" {}
|
||||||
(common/layout "Free Markdown Hosting"
|
(common/layout "Free Markdown Hosting"
|
||||||
@@ -74,21 +82,18 @@
|
|||||||
[:div#preview-start-line.hidden]
|
[:div#preview-start-line.hidden]
|
||||||
[:article#preview]))
|
[:article#preview]))
|
||||||
|
|
||||||
(defn wrap [params md-text]
|
; Display the note
|
||||||
(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))))
|
|
||||||
|
|
||||||
(defpage "/:year/:month/:day/:title" {:keys [year month day title theme header-font text-font] :as params}
|
(defpage "/:year/:month/:day/:title" {:keys [year month day title theme header-font text-font] :as params}
|
||||||
(wrap
|
(wrap
|
||||||
(select-keys params [:theme :header-font :text-font])
|
(select-keys params [:theme :header-font :text-font])
|
||||||
(get-note [year month day] title)))
|
(get-note [year month day] title)))
|
||||||
|
|
||||||
|
; Provides Markdown of the specified note
|
||||||
(defpage "/:year/:month/:day/:title/export" {:keys [year month day title]}
|
(defpage "/:year/:month/:day/:title/export" {:keys [year month day title]}
|
||||||
(let [md-text (get-note [year month day] title)]
|
(let [md-text (get-note [year month day] title)]
|
||||||
(if md-text md-text (status 404 (get-page 404)))))
|
(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]}
|
(defpage "/:year/:month/:day/:title/stat" {:keys [year month day title]}
|
||||||
(let [views (get-views [year month day] title)]
|
(let [views (get-views [year month day] title)]
|
||||||
(if views
|
(if views
|
||||||
@@ -119,7 +124,8 @@
|
|||||||
(-> draft (split #"\n") first (sreplace " " "-") lower-case))
|
(-> draft (split #"\n") first (sreplace " " "-") lower-case))
|
||||||
trim (fn [s] (apply str (drop-while #(= \- %) s)))
|
trim (fn [s] (apply str (drop-while #(= \- %) s)))
|
||||||
title-uncut (-> untrimmed-line trim reverse trim reverse)
|
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]
|
date [year month day]
|
||||||
title (first (drop-while #(note-exists? date %)
|
title (first (drop-while #(note-exists? date %)
|
||||||
(cons proposed-title
|
(cons proposed-title
|
||||||
|
|||||||
Reference in New Issue
Block a user