moving to compojure; api done
This commit is contained in:
+5
-14
@@ -1,15 +1,15 @@
|
||||
(ns NoteHub.api
|
||||
(ns notehub.api
|
||||
(:import
|
||||
[java.util Calendar])
|
||||
(:use
|
||||
[NoteHub.settings]
|
||||
[notehub.settings]
|
||||
[ring.util.codec :only [url-encode]]
|
||||
[clojure.string :rename {replace sreplace}
|
||||
:only [replace blank? lower-case split-lines split]])
|
||||
(:require
|
||||
[ring.util.codec]
|
||||
[hiccup.util :as util]
|
||||
[NoteHub.storage :as storage]))
|
||||
[notehub.storage :as storage]))
|
||||
|
||||
(def version "1.1")
|
||||
|
||||
@@ -60,15 +60,6 @@
|
||||
(str domain "/" (storage/create-short-url token {:year year :month month :day day :title title}))
|
||||
(str domain (url year month day title))))))
|
||||
|
||||
(let [md5Instance (java.security.MessageDigest/getInstance "MD5")]
|
||||
(defn get-signature
|
||||
"Returns the MD5 hash for the concatenation of all passed parameters"
|
||||
[& args]
|
||||
(let [input (sreplace (apply str args) #"[\r\n]" "")]
|
||||
(do (.reset md5Instance)
|
||||
(.update md5Instance (.getBytes input))
|
||||
(.toString (new java.math.BigInteger 1 (.digest md5Instance)) 16)))))
|
||||
|
||||
(defn get-note [noteID]
|
||||
(if (storage/note-exists? noteID)
|
||||
(let [note (storage/get-note noteID)]
|
||||
@@ -87,7 +78,7 @@
|
||||
;(log "post-note: %s" {:pid pid :signature signature :password password :note note})
|
||||
(let [errors (filter identity
|
||||
[(when-not (storage/valid-publisher? pid) "pid invalid")
|
||||
(when-not (= signature (get-signature pid (storage/get-psk pid) note))
|
||||
(when-not (= signature (storage/sign pid (storage/get-psk pid) note))
|
||||
"signature invalid")
|
||||
(when (blank? note) "note is empty")])]
|
||||
(if (empty? errors)
|
||||
@@ -121,7 +112,7 @@
|
||||
;(log "update-note: %s" {:pid pid :noteID noteID :signature signature :password password :note note})
|
||||
(let [errors (filter identity
|
||||
[(when-not (storage/valid-publisher? pid) "pid invalid")
|
||||
(when-not (= signature (get-signature pid (storage/get-psk pid) noteID note password))
|
||||
(when-not (= signature (storage/sign pid (storage/get-psk pid) noteID note password))
|
||||
"signature invalid")
|
||||
(when (blank? note) "note is empty")
|
||||
(when-not (storage/valid-password? noteID password) "password invalid")])]
|
||||
|
||||
@@ -1,28 +1,24 @@
|
||||
(ns NoteHub.views.pages
|
||||
(:require [hiccup.util :as util]
|
||||
[NoteHub.api :as api]
|
||||
[NoteHub.storage :as storage]
|
||||
[cheshire.core :refer :all])
|
||||
(:use
|
||||
[NoteHub.settings]
|
||||
[clojure.string :rename {replace sreplace}
|
||||
:only [escape split replace blank? split-lines lower-case]]
|
||||
[clojure.core.incubator :only [-?>]]
|
||||
[noir.util.crypt :only [encrypt]]
|
||||
[hiccup.form]
|
||||
[hiccup.core]
|
||||
[hiccup.element]
|
||||
[hiccup.util :only [escape-html]]
|
||||
[hiccup.page :only [include-js html5]]
|
||||
[noir.response :only [redirect status content-type]]
|
||||
[noir.core :only [defpage defpartial]]
|
||||
[noir.statuses]))
|
||||
(ns notehub.handler
|
||||
(:use compojure.core
|
||||
[notehub.settings]
|
||||
[clojure.string :rename {replace sreplace}
|
||||
:only [escape split replace blank? split-lines lower-case]]
|
||||
[clojure.core.incubator :only [-?>]]
|
||||
[hiccup.form]
|
||||
[hiccup.core]
|
||||
[hiccup.element]
|
||||
[hiccup.util :only [escape-html]]
|
||||
[hiccup.page :only [include-js html5]])
|
||||
(:require [compojure.handler :as handler]
|
||||
[compojure.route :as route]
|
||||
[hiccup.util :as util]
|
||||
[notehub.api :as api]
|
||||
[notehub.storage :as storage]
|
||||
[cheshire.core :refer :all]))
|
||||
|
||||
(when-not (storage/valid-publisher? "NoteHub")
|
||||
(storage/register-publisher "NoteHub"))
|
||||
|
||||
; Creates the main html layout
|
||||
(defpartial layout
|
||||
(defn layout
|
||||
[title & content]
|
||||
(html5
|
||||
[:head
|
||||
@@ -40,6 +36,32 @@
|
||||
(if-not (get-setting :dev-mode) (include-js "/js/google-analytics.js"))]
|
||||
[:body {:onload "onLoad()"} content]))
|
||||
|
||||
|
||||
(defn md-node
|
||||
"Returns an HTML element with a textarea inside
|
||||
containing the markdown text (to keep all chars unescaped)"
|
||||
([cls input] (md-node cls {} input))
|
||||
([cls opts input]
|
||||
[(keyword (str (name cls) ".markdown")) opts
|
||||
[:textarea input]]))
|
||||
|
||||
#_ (
|
||||
|
||||
; ######## OLD CODE START
|
||||
|
||||
(ns NoteHub.views.pages
|
||||
(:require )
|
||||
(:use
|
||||
|
||||
|
||||
[noir.response :only [redirect status content-type]]
|
||||
[noir.core :only [defpage defpartial]]
|
||||
[noir.statuses]
|
||||
[noir.util.crypt :only [encrypt]]))
|
||||
|
||||
(when-not (storage/valid-publisher? "NoteHub")
|
||||
(storage/register-publisher "NoteHub"))
|
||||
|
||||
(defn sanitize
|
||||
"Breakes all usages of <script> & <iframe>"
|
||||
[input]
|
||||
@@ -80,13 +102,6 @@
|
||||
(defn generate-session []
|
||||
(encrypt (str (rand-int Integer/MAX_VALUE))))
|
||||
|
||||
(defn md-node
|
||||
"Returns an HTML element with a textarea inside
|
||||
containing the markdown text (to keep all chars unescaped)"
|
||||
([cls input] (md-node cls {} input))
|
||||
([cls opts input]
|
||||
[(keyword (str (name cls) ".markdown")) opts
|
||||
[:textarea input]]))
|
||||
|
||||
; Routes
|
||||
; ======
|
||||
@@ -135,13 +150,6 @@
|
||||
[:tr [:td (str (get-message %) ":")] [:td (% stats)]])
|
||||
[:published :edited :publisher :views])])))
|
||||
|
||||
(defpage "/:short-url" {:keys [short-url]}
|
||||
(when-let [params (storage/resolve-url short-url)]
|
||||
(let [{:keys [year month day title]} params
|
||||
rest-params (dissoc params :year :month :day :title)
|
||||
core-url (api/url year month day title)
|
||||
long-url (if (empty? rest-params) core-url (util/url core-url rest-params))]
|
||||
(redirect long-url))))
|
||||
|
||||
(defpage "/:year/:month/:day/:title/edit" {:keys [year month day title]}
|
||||
(let [noteID (api/build-key [year month day] title)]
|
||||
@@ -181,23 +189,48 @@
|
||||
(response 403)))
|
||||
(response 500))))
|
||||
|
||||
; Here lives the API
|
||||
; ###### END OLD CODE
|
||||
)
|
||||
|
||||
(defpage "/api" args
|
||||
(layout (get-message :api-title)
|
||||
(md-node :article (slurp "API.md"))))
|
||||
(defn redirect [url]
|
||||
{:status 302
|
||||
:headers {"Location" (str url)}
|
||||
:body ""})
|
||||
|
||||
(defpage [:get "/api/note"] {:keys [version noteID]}
|
||||
(generate-string (api/get-note noteID)))
|
||||
(defroutes api-routes
|
||||
|
||||
(defpage [:post "/api/note"] {:keys [version note pid signature password] :as params}
|
||||
(generate-string
|
||||
(api/post-note
|
||||
note
|
||||
pid
|
||||
signature
|
||||
{:params (dissoc params :version :note :pid :signature :password)
|
||||
:password password})))
|
||||
(GET "/" [] (layout (get-message :api-title)
|
||||
(md-node :article (slurp "API.md"))))
|
||||
|
||||
(defpage [:put "/api/note"] {:keys [version noteID note pid signature password]}
|
||||
(generate-string (api/update-note noteID note pid signature password)))
|
||||
(GET "/note" [version noteID]
|
||||
(generate-string (api/get-note noteID)))
|
||||
|
||||
(POST "/note" {params :params}
|
||||
(generate-string
|
||||
(api/post-note
|
||||
(:note params)
|
||||
(:pid params)
|
||||
(:signature params)
|
||||
{:params (dissoc params :version :note :pid :signature :password)
|
||||
:password (:password params)})))
|
||||
|
||||
(PUT "/note" [version noteID note pid signature password]
|
||||
(generate-string (api/update-note noteID note pid signature password))))
|
||||
|
||||
(defroutes app-routes
|
||||
(context "/api" [] api-routes)
|
||||
(GET "/" [] "Hello World")
|
||||
|
||||
(GET "/:short-url" [short-url]
|
||||
(when-let [params (storage/resolve-url short-url)]
|
||||
(let [{:keys [year month day title]} params
|
||||
rest-params (dissoc params :year :month :day :title)
|
||||
core-url (api/url year month day title)
|
||||
long-url (if (empty? rest-params) core-url (util/url core-url rest-params))]
|
||||
(redirect long-url))))
|
||||
|
||||
(route/resources "/resources")
|
||||
(route/not-found "Not Found"))
|
||||
|
||||
(def app
|
||||
(handler/site app-routes))
|
||||
@@ -1,10 +0,0 @@
|
||||
(ns NoteHub.server
|
||||
(:require [noir.server :as server]))
|
||||
|
||||
(server/load-views "src/NoteHub/views/")
|
||||
|
||||
(defn -main [& m]
|
||||
(let [mode (keyword (or (first m) :prod))
|
||||
port (Integer. (get (System/getenv) "PORT" "8080"))]
|
||||
(server/start port {:mode mode :ns 'NoteHub})))
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
(ns NoteHub.settings
|
||||
(ns notehub.settings
|
||||
(:refer-clojure :exclude [replace reverse])
|
||||
(:use [clojure.string]))
|
||||
|
||||
; Loads and parses any file with each line consisting a key and
|
||||
; Loads and parses any file with each line consisting a key and
|
||||
; a value separated by a "=", and returns a corresponding key-value map.
|
||||
(defn- get-pairs-map [file]
|
||||
(let [file-content (slurp file)
|
||||
pairs (map #(map trim (split % #"=" 2))
|
||||
pairs (map #(map trim (split % #"=" 2))
|
||||
(remove blank? (split-lines file-content)))]
|
||||
(apply hash-map
|
||||
(apply hash-map
|
||||
(mapcat #(list (keyword (first %)) (second %)) pairs))))
|
||||
|
||||
; Loads the setting file to a map
|
||||
@@ -24,7 +24,7 @@
|
||||
(messages-map key))
|
||||
|
||||
(defn get-setting
|
||||
"Takes a settings key, a converter function and a default value, and returns a corresponding
|
||||
"Takes a settings key, a converter function and a default value, and returns a corresponding
|
||||
setting 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 type.
|
||||
This function is not applied to the specified default value!
|
||||
@@ -33,10 +33,10 @@
|
||||
(let [converter (first more)
|
||||
default (second more)
|
||||
value (settings-map key)
|
||||
; Through this hack we can read security-critical settings from (previously
|
||||
; Through this hack we can read security-critical settings from (previously
|
||||
; set) shell variables without commiting their content to CVS
|
||||
value (if value value
|
||||
(System/getenv
|
||||
(System/getenv
|
||||
(upper-case
|
||||
(replace (name key) #"-" ""))))]
|
||||
(if value
|
||||
|
||||
+14
-6
@@ -1,11 +1,19 @@
|
||||
(ns NoteHub.storage
|
||||
(:use [NoteHub.settings]
|
||||
[clojure.string :only (blank?)]
|
||||
[noir.util.crypt :only [encrypt]])
|
||||
(ns notehub.storage
|
||||
(:use [notehub.settings]
|
||||
[clojure.string :only (blank? replace) :rename {replace sreplace}])
|
||||
(:require [taoensso.carmine :as car :refer (wcar)]))
|
||||
|
||||
(def conn {:pool {} :spec {:uri (get-setting :db-url)}})
|
||||
|
||||
(let [md5Instance (java.security.MessageDigest/getInstance "MD5")]
|
||||
(defn sign
|
||||
"Returns the MD5 hash for the concatenation of all passed parameters"
|
||||
[& args]
|
||||
(let [input (sreplace (apply str args) #"[\r\n]" "")]
|
||||
(do (.reset md5Instance)
|
||||
(.update md5Instance (.getBytes input))
|
||||
(.toString (new java.math.BigInteger 1 (.digest md5Instance)) 16)))))
|
||||
|
||||
(defmacro redis [cmd & body]
|
||||
`(car/wcar conn
|
||||
(~(symbol "car" (name cmd))
|
||||
@@ -20,7 +28,7 @@
|
||||
(defn register-publisher [pid]
|
||||
"Returns nil if given PID exists or a PSK otherwise"
|
||||
(when (not (valid-publisher? pid))
|
||||
(let [psk (encrypt (str (rand-int Integer/MAX_VALUE) pid))]
|
||||
(let [psk (sign (str (rand-int Integer/MAX_VALUE) pid))]
|
||||
(redis :hset :publisher-key pid psk)
|
||||
psk)))
|
||||
|
||||
@@ -31,7 +39,7 @@
|
||||
(redis :hget :publisher-key pid))
|
||||
|
||||
(defn create-session []
|
||||
(let [token (encrypt (str (rand-int Integer/MAX_VALUE)))]
|
||||
(let [token (sign (str (rand-int Integer/MAX_VALUE)))]
|
||||
(redis :sadd :sessions token)
|
||||
token))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user