diff --git a/API.md b/API.md index 6c3c813..47a96a0 100644 --- a/API.md +++ b/API.md @@ -26,14 +26,14 @@ Parameter | Explanation | Type `noteID` | Note-ID | **required** `version` | Used API version | **required** -will return a JSON object containing following self explaining fields: `note`, `longPath`, `shortPath`, `statistics`, `status`. +will return a JSON object containing following self explaining fields: `note`, `longURL`, `shortURL`, `statistics`, `status`. Example: { note: , - longPath: "/2014/1/3/lorem-ipsum", - shortPath: "/0vrcp", + longURL: "http://notehub.org/2014/1/3/lorem-ipsum", + shortURL: "http://notehub.org/0vrcp", statistics: { published: "2014-1-3", edited: "2014-1-12", @@ -47,7 +47,7 @@ Example: Hence, the status of the request can be evaluated by reading of the property `status.success`. The field `status.comment`might contain an error message, a warning or any other comments from the server. -The note ID is a string, containing the date of publishing and a few first words of the note (usually the title), e.g.: `"2014 1 3 lorem-ipsum"`. This ID will be generated by NoteHub automatically. +The note ID is a string, containing the date of publishing and a few first words of the note (usually the title), e.g.: `"2014 1 3 lorem-ipsum"`. This ID will be generated by NoteHub automatically. ## Note Creation @@ -71,14 +71,14 @@ The Signature is the MD5 hash of the following string concatenation: The signature serves as a proof, that the request is authentic and will be issued by the publisher corresponding to the provided PID. -The response of the server will contain the fields `noteID`, `longPath`, `shortPath`, `status`. +The response of the server will contain the fields `noteID`, `longURL`, `shortURL`, `status`. Example: { noteID: "2014/1/3/lorem-ipsum", - longPath: "/2014/1/3/lorem-ipsum", - shortPath: "/0vrcp", + longURL: "http://notehub.org/2014/1/3/lorem-ipsum", + shortURL: "http://notehub.org/0vrcp", status: { success: true, comment: "some server message" @@ -109,13 +109,13 @@ The Signature is the MD5 hash of the following string concatenation: pid + psk + noteID + note + password -The response of the server will contain the fields `longPath`, `shortPath`, `status`. +The response of the server will contain the fields `longURL`, `shortURL`, `status`. Example: { - longPath: "/2014/1/3/lorem-ipsum", - shortPath: "/0vrcp", + longURL: "http://notehub.org/2014/1/3/lorem-ipsum", + shortURL: "http://notehub.org/0vrcp", status: { success: true, comment: "some server message" diff --git a/settings b/settings index 70b3e6f..f2b0c79 100644 --- a/settings +++ b/settings @@ -1,2 +1,2 @@ max-title-length = 40 -domain = http://notehub.org/ +domain = http://notehub.org diff --git a/src/NoteHub/api.clj b/src/NoteHub/api.clj index 28eadd1..0af480f 100644 --- a/src/NoteHub/api.clj +++ b/src/NoteHub/api.clj @@ -1,11 +1,11 @@ (ns NoteHub.api - (:import + (:import [java.util Calendar]) (:use [NoteHub.settings] [clojure.string :rename {replace sreplace} :only [replace blank? lower-case split-lines split]]) - (:require + (:require [ring.util.codec] [NoteHub.storage :as storage])) @@ -20,7 +20,7 @@ (println)) ; Concatenates all fields to a string -(defn build-key +(defn build-key "Returns a storage-key for the given note coordinates" [[year month day] title] (print-str year month day title)) @@ -28,7 +28,7 @@ (defn get-date "Returns today's date" [] - (map #(+ (second %) (.get (Calendar/getInstance) (first %))) + (map #(+ (second %) (.get (Calendar/getInstance) (first %))) {Calendar/YEAR 0, Calendar/MONTH 1, Calendar/DAY_OF_MONTH 0})) (defn- create-response @@ -36,12 +36,12 @@ ([success message & params] (assoc (create-response success) :message (apply format message params)))) -(defn- getPath [noteID & description] +(defn- get-path [noteID & description] (if description (str "/" (storage/get-short-url noteID)) (let [[year month day title] (split noteID #" ")] - (apply str (interpose "/" - [year month day (ring.util.codec/url-encode title)]))))) + (apply str (interpose "/" + [domain year month day (ring.util.codec/url-encode title)]))))) (let [md5Instance (java.security.MessageDigest/getInstance "MD5")] (defn get-signature @@ -55,8 +55,8 @@ (defn get-note [noteID] (if (storage/note-exists? noteID) {:note (storage/get-note noteID) - :longPath (getPath noteID) - :shortPath (getPath noteID :short) + :longURL (get-path noteID) + :shortURL (get-path noteID :short) :statistics (storage/get-note-statistics noteID) :status (create-response true)} (create-response false "noteID '%s' unknown" noteID))) @@ -73,13 +73,13 @@ (when (blank? note) "note is empty")])] (if (empty? errors) (let [[year month day] (get-date) - untrimmed-line (filter #(or (= \- %) (Character/isLetterOrDigit %)) + untrimmed-line (filter #(or (= \- %) (Character/isLetterOrDigit %)) (-> note split-lines first (sreplace " " "-") lower-case)) trim (fn [s] (apply str (drop-while #(= \- %) s))) title-uncut (-> untrimmed-line trim reverse trim reverse) max-length (get-setting :max-title-length #(Integer/parseInt %) 80) proposed-title (apply str (take max-length title-uncut)) - date [year month day] + date [year month day] title (first (drop-while #(storage/note-exists? (build-key date %)) (cons proposed-title (map #(str proposed-title "-" (+ 2 %)) (range))))) @@ -88,8 +88,8 @@ (storage/add-note noteID note password) (storage/create-short-url noteID) {:noteID noteID - :longPath (getPath noteID) - :shortPath (getPath noteID :short) + :longURL (get-path noteID) + :shortURL (get-path noteID :short) :status (create-response true)})) {:status (create-response false (first errors))})))) @@ -107,7 +107,7 @@ (if (empty? errors) (do (storage/edit-note noteID note) - {:longPath (getPath noteID) - :shortPath (getPath noteID :short) + {:longURL (get-path noteID) + :shortURL (get-path noteID :short) :status (create-response true)}) {:status (create-response false (first errors))}))) diff --git a/src/NoteHub/views/pages.clj b/src/NoteHub/views/pages.clj index 5bdce6e..8c3d4bd 100644 --- a/src/NoteHub/views/pages.clj +++ b/src/NoteHub/views/pages.clj @@ -34,10 +34,10 @@ ; Converts given markdown to html and wraps with the main layout (defn- wrap [short-url params md-text] - (when md-text + (when md-text (layout params (params :title) [:article.bottom-space.markdown md-text] - (let [links (map #(link-to + (let [links (map #(link-to (if (= :short-url %) (url short-url) (str (params :title) "/" (name %))) @@ -62,7 +62,7 @@ fields (text-area {:class :max-width} :note content) [:fieldset#input-elems {:class css-class} - (text-field {:class "ui-elem" :placeholder (get-message passwd-msg)} + (text-field {:class "ui-elem" :placeholder (get-message passwd-msg)} :plain-password) (submit-button {:class "button ui-elem" :id :publish-button} (get-message command))])]))) @@ -82,13 +82,13 @@ [:br] [:a.landing-button {:href "/new" :style "color: white"} (get-message :new-page)]] [:div#dashed-line] - [:article.helvetica.bottom-space.markdown {:style "font-size: 1em"} + [:article.helvetica.bottom-space.markdown {:style "font-size: 1em"} (slurp "LANDING.md")] [:div.centered.helvetica.markdown (get-message :footer)])) ; Displays the note (defpage "/:year/:month/:day/:title" {:keys [year month day title theme header-font text-font] :as params} - (wrap + (wrap (storage/create-short-url params) (select-keys params [:title :theme :header-font :text-font]) (:note (api/get-note (api/build-key [year month day] title))))) @@ -133,7 +133,7 @@ ; Update Note Page (defpage "/:year/:month/:day/:title/edit" {:keys [year month day title]} (let [noteID (api/build-key [year month day] title)] - (input-form "/update-note" :update + (input-form "/update-note" :update (html (hidden-field :noteID noteID)) (:note (api/get-note noteID)) :enter-passwd))) @@ -145,7 +145,7 @@ (if (storage/valid-publisher? pid) (let [resp (api/post-note note pid (api/get-signature (str pid psk note)) password)] (if (get-in resp [:status :success]) - (redirect (:longPath resp)) + (redirect (:longURL resp)) (response 400))) (response 500))) (response 400))) @@ -155,11 +155,11 @@ (let [pid api/domain psk (storage/get-psk pid)] (if (storage/valid-publisher? pid) - (let [resp (api/update-note noteID note pid - (api/get-signature (str pid psk noteID note password)) + (let [resp (api/update-note noteID note pid + (api/get-signature (str pid psk noteID note password)) password)] (if (get-in resp [:status :success]) - (redirect (:longPath resp)) + (redirect (:longURL resp)) (response 403))) (response 500)))) diff --git a/test/NoteHub/test/api.clj b/test/NoteHub/test/api.clj index a454a61..29dc872 100644 --- a/test/NoteHub/test/api.clj +++ b/test/NoteHub/test/api.clj @@ -1,5 +1,5 @@ (ns NoteHub.test.api - (:require + (:require [cheshire.core :refer :all] [NoteHub.storage :as storage]) (:use [NoteHub.api] @@ -10,7 +10,7 @@ (def pid "somePlugin") (def pid2 "somePlugin2") (def note-title (str (apply print-str (get-date)) " hello-world-this-is-a-test-note")) -(def note-url (str (apply str (interpose "/" (get-date))) "/hello-world-this-is-a-test-note")) +(def note-url (str (apply str domain "/" (interpose "/" (get-date))) "/hello-world-this-is-a-test-note")) (defn substring? [a b] (not (= nil (re-matches (re-pattern (str "(?s).*" a ".*")) b)))) (defmacro isnt [arg] `(is (not ~arg))) @@ -43,8 +43,8 @@ (is (:success (:status post-response))) (is (:success (:status get-response))) (is (= note (:note get-response))) - (is (= (:longPath post-response) (:longPath get-response) note-url)) - (is (= (:shortPath post-response) (:shortPath get-response))) + (is (= (:longURL post-response) (:longURL get-response) note-url)) + (is (= (:shortURL post-response) (:shortURL get-response))) (is (= "1" (get-in get-response [:statistics :views]))) (isnt (get-in get-response [:statistics :edited])) (is (= "2" (get-in (get-note (:noteID post-response)) [:statistics :views]))))) @@ -74,12 +74,12 @@ (isnt (:success (:status update-response))) (is (= "signature invalid" (:message (:status update-response))))) (is (= note (:note (get-note note-id)))) - (let [update-response (update-note note-id new-note pid + (let [update-response (update-note note-id new-note pid (get-signature pid psk note-id new-note "passwd") "passwd")] (is (= { :success true } (:status update-response))) (isnt (= nil (get-in (get-note note-id) [:statistics :edited]))) (is (= new-note (:note (get-note note-id))))) - (let [update-response (update-note note-id "aaa" pid + (let [update-response (update-note note-id "aaa" pid (get-signature pid psk note-id "aaa" "pass") "pass")] (isnt (:success (:status update-response))) (is (= "password invalid" (:message (:status update-response))))) @@ -99,7 +99,7 @@ (is (get-in body ["status" "success"])) (is (= note ((parse-string (:body (send-request [:get "/api/note"] {:version "1.0" :noteID noteID}))) "note"))) - (is (do + (is (do (storage/delete-note noteID) (not (storage/note-exists? noteID))))))) @@ -148,6 +148,6 @@ (is (substring? "UPDATED CONTENT" ((parse-string (:body (send-request [:get "/api/note"] {:version "1.0" :noteID noteID}))) "note"))) - (is (do + (is (do (storage/delete-note noteID) (not (storage/note-exists? noteID))))))) diff --git a/test/NoteHub/test/views/pages.clj b/test/NoteHub/test/views/pages.clj index a3bc278..7d3c7d8 100644 --- a/test/NoteHub/test/views/pages.clj +++ b/test/NoteHub/test/views/pages.clj @@ -35,18 +35,18 @@ title "this-is-a-test-note" [year month day] date] (testing "Note creation" - (is (has-status - (send-request - [:post "/post-note"] - {:session session-key - :note test-note - :signature (get-signature session-key test-note)}) 302)) - (is (note-exists? (build-key date title))) - (is (substring? "Hello _world_" - ((send-request (url year month day title)) :body))) - (is (do - (delete-note (build-key date title)) - (not (note-exists? (build-key date title)))))))) + (let [resp (send-request + [:post "/post-note"] + {:session session-key + :note test-note + :signature (get-signature session-key test-note)})] + (is (has-status resp 302)) + (is (note-exists? (build-key date title))) + (is (substring? "Hello _world_" + ((send-request (url year month day title)) :body))) + (is (do + (delete-note (build-key date title)) + (not (note-exists? (build-key date title))))))))) (deftest note-creation-utf (let [session-key (create-session) @@ -55,15 +55,15 @@ note "# Радуга\nкаждый охотник желает знать, где сидят фазаны." [year month day] date] (testing "Note creation with UTF8 symbols" - (is (has-status - (send-request + (is (has-status + (send-request [:post "/post-note"] {:session session-key :note note :signature (get-signature session-key note)}) 302)) (is (note-exists? (build-key date title))) (is (substring? "знать" ((send-request (url year month day title)) :body))) - (is (do + (is (do (delete-note (build-key date title)) (not (note-exists? (build-key date title)))))))) @@ -74,8 +74,8 @@ [year month day] date hash (get-signature session-key test-note)] (testing "Note update" - (is (has-status - (send-request + (is (has-status + (send-request [:post "/post-note"] {:session session-key :note test-note @@ -83,21 +83,21 @@ :signature hash}) 302)) (is (note-exists? (build-key date title))) (is (substring? "test note" ((send-request (url year month day title)) :body))) - (is (has-status - (send-request + (is (has-status + (send-request [:post "/update-note"] {:noteID (build-key [year month day] title) :note "WRONG pass" :password "qwerty1" }) 403)) (is (substring? "test note" ((send-request (url year month day title)) :body))) - (is (has-status - (send-request + (is (has-status + (send-request [:post "/update-note"] {:noteID (build-key [year month day] title) :note "UPDATED CONTENT 123" :password "qwerty" }) 302)) (is (substring? "UPDATED CONTENT" ((send-request (url year month day title)) :body))) - (is (do + (is (do (delete-note (build-key date title)) (not (note-exists? (build-key date title))))))))