Browse Source

renamed paths to urls back

master
Christian Mueller 12 years ago
parent
commit
99ac828ba3
  1. 20
      API.md
  2. 2
      settings
  3. 30
      src/NoteHub/api.clj
  4. 20
      src/NoteHub/views/pages.clj
  5. 16
      test/NoteHub/test/api.clj
  6. 44
      test/NoteHub/test/views/pages.clj

20
API.md

@ -26,14 +26,14 @@ Parameter | Explanation | Type
`noteID` | Note-ID | **required** `noteID` | Note-ID | **required**
`version` | Used API version | **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: Example:
{ {
note: <markdown source>, note: <markdown source>,
longPath: "/2014/1/3/lorem-ipsum", longURL: "http://notehub.org/2014/1/3/lorem-ipsum",
shortPath: "/0vrcp", shortURL: "http://notehub.org/0vrcp",
statistics: { statistics: {
published: "2014-1-3", published: "2014-1-3",
edited: "2014-1-12", 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. 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 ## 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 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: Example:
{ {
noteID: "2014/1/3/lorem-ipsum", noteID: "2014/1/3/lorem-ipsum",
longPath: "/2014/1/3/lorem-ipsum", longURL: "http://notehub.org/2014/1/3/lorem-ipsum",
shortPath: "/0vrcp", shortURL: "http://notehub.org/0vrcp",
status: { status: {
success: true, success: true,
comment: "some server message" comment: "some server message"
@ -109,13 +109,13 @@ The Signature is the MD5 hash of the following string concatenation:
pid + psk + noteID + note + password 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: Example:
{ {
longPath: "/2014/1/3/lorem-ipsum", longURL: "http://notehub.org/2014/1/3/lorem-ipsum",
shortPath: "/0vrcp", shortURL: "http://notehub.org/0vrcp",
status: { status: {
success: true, success: true,
comment: "some server message" comment: "some server message"

2
settings

@ -1,2 +1,2 @@
max-title-length = 40 max-title-length = 40
domain = http://notehub.org/ domain = http://notehub.org

30
src/NoteHub/api.clj

@ -1,11 +1,11 @@
(ns NoteHub.api (ns NoteHub.api
(:import (:import
[java.util Calendar]) [java.util Calendar])
(:use (:use
[NoteHub.settings] [NoteHub.settings]
[clojure.string :rename {replace sreplace} [clojure.string :rename {replace sreplace}
:only [replace blank? lower-case split-lines split]]) :only [replace blank? lower-case split-lines split]])
(:require (:require
[ring.util.codec] [ring.util.codec]
[NoteHub.storage :as storage])) [NoteHub.storage :as storage]))
@ -20,7 +20,7 @@
(println)) (println))
; Concatenates all fields to a string ; Concatenates all fields to a string
(defn build-key (defn build-key
"Returns a storage-key for the given note coordinates" "Returns a storage-key for the given note coordinates"
[[year month day] title] [[year month day] title]
(print-str year month day title)) (print-str year month day title))
@ -28,7 +28,7 @@
(defn get-date (defn get-date
"Returns today's 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})) {Calendar/YEAR 0, Calendar/MONTH 1, Calendar/DAY_OF_MONTH 0}))
(defn- create-response (defn- create-response
@ -36,12 +36,12 @@
([success message & params] ([success message & params]
(assoc (create-response success) :message (apply format message params)))) (assoc (create-response success) :message (apply format message params))))
(defn- getPath [noteID & description] (defn- get-path [noteID & description]
(if description (if description
(str "/" (storage/get-short-url noteID)) (str "/" (storage/get-short-url noteID))
(let [[year month day title] (split noteID #" ")] (let [[year month day title] (split noteID #" ")]
(apply str (interpose "/" (apply str (interpose "/"
[year month day (ring.util.codec/url-encode title)]))))) [domain year month day (ring.util.codec/url-encode title)])))))
(let [md5Instance (java.security.MessageDigest/getInstance "MD5")] (let [md5Instance (java.security.MessageDigest/getInstance "MD5")]
(defn get-signature (defn get-signature
@ -55,8 +55,8 @@
(defn get-note [noteID] (defn get-note [noteID]
(if (storage/note-exists? noteID) (if (storage/note-exists? noteID)
{:note (storage/get-note noteID) {:note (storage/get-note noteID)
:longPath (getPath noteID) :longURL (get-path noteID)
:shortPath (getPath noteID :short) :shortURL (get-path noteID :short)
:statistics (storage/get-note-statistics noteID) :statistics (storage/get-note-statistics noteID)
:status (create-response true)} :status (create-response true)}
(create-response false "noteID '%s' unknown" noteID))) (create-response false "noteID '%s' unknown" noteID)))
@ -73,13 +73,13 @@
(when (blank? note) "note is empty")])] (when (blank? note) "note is empty")])]
(if (empty? errors) (if (empty? errors)
(let [[year month day] (get-date) (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)) (-> note split-lines 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)
max-length (get-setting :max-title-length #(Integer/parseInt %) 80) max-length (get-setting :max-title-length #(Integer/parseInt %) 80)
proposed-title (apply str (take max-length title-uncut)) 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 %)) title (first (drop-while #(storage/note-exists? (build-key date %))
(cons proposed-title (cons proposed-title
(map #(str proposed-title "-" (+ 2 %)) (range))))) (map #(str proposed-title "-" (+ 2 %)) (range)))))
@ -88,8 +88,8 @@
(storage/add-note noteID note password) (storage/add-note noteID note password)
(storage/create-short-url noteID) (storage/create-short-url noteID)
{:noteID noteID {:noteID noteID
:longPath (getPath noteID) :longURL (get-path noteID)
:shortPath (getPath noteID :short) :shortURL (get-path noteID :short)
:status (create-response true)})) :status (create-response true)}))
{:status (create-response false (first errors))})))) {:status (create-response false (first errors))}))))
@ -107,7 +107,7 @@
(if (empty? errors) (if (empty? errors)
(do (do
(storage/edit-note noteID note) (storage/edit-note noteID note)
{:longPath (getPath noteID) {:longURL (get-path noteID)
:shortPath (getPath noteID :short) :shortURL (get-path noteID :short)
:status (create-response true)}) :status (create-response true)})
{:status (create-response false (first errors))}))) {:status (create-response false (first errors))})))

20
src/NoteHub/views/pages.clj

@ -34,10 +34,10 @@
; Converts given markdown to html and wraps with the main layout ; Converts given markdown to html and wraps with the main layout
(defn- wrap [short-url params md-text] (defn- wrap [short-url params md-text]
(when md-text (when md-text
(layout params (params :title) (layout params (params :title)
[:article.bottom-space.markdown md-text] [:article.bottom-space.markdown md-text]
(let [links (map #(link-to (let [links (map #(link-to
(if (= :short-url %) (if (= :short-url %)
(url short-url) (url short-url)
(str (params :title) "/" (name %))) (str (params :title) "/" (name %)))
@ -62,7 +62,7 @@
fields fields
(text-area {:class :max-width} :note content) (text-area {:class :max-width} :note content)
[:fieldset#input-elems {:class css-class} [: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) :plain-password)
(submit-button {:class "button ui-elem" (submit-button {:class "button ui-elem"
:id :publish-button} (get-message command))])]))) :id :publish-button} (get-message command))])])))
@ -82,13 +82,13 @@
[:br] [:br]
[:a.landing-button {:href "/new" :style "color: white"} (get-message :new-page)]] [:a.landing-button {:href "/new" :style "color: white"} (get-message :new-page)]]
[:div#dashed-line] [:div#dashed-line]
[:article.helvetica.bottom-space.markdown {:style "font-size: 1em"} [:article.helvetica.bottom-space.markdown {:style "font-size: 1em"}
(slurp "LANDING.md")] (slurp "LANDING.md")]
[:div.centered.helvetica.markdown (get-message :footer)])) [:div.centered.helvetica.markdown (get-message :footer)]))
; Displays the note ; Displays the note
(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
(storage/create-short-url params) (storage/create-short-url params)
(select-keys params [:title :theme :header-font :text-font]) (select-keys params [:title :theme :header-font :text-font])
(:note (api/get-note (api/build-key [year month day] title))))) (:note (api/get-note (api/build-key [year month day] title)))))
@ -133,7 +133,7 @@
; Update Note Page ; Update Note Page
(defpage "/:year/:month/:day/:title/edit" {:keys [year month day title]} (defpage "/:year/:month/:day/:title/edit" {:keys [year month day title]}
(let [noteID (api/build-key [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)) (html (hidden-field :noteID noteID))
(:note (api/get-note noteID)) :enter-passwd))) (:note (api/get-note noteID)) :enter-passwd)))
@ -145,7 +145,7 @@
(if (storage/valid-publisher? pid) (if (storage/valid-publisher? pid)
(let [resp (api/post-note note pid (api/get-signature (str pid psk note)) password)] (let [resp (api/post-note note pid (api/get-signature (str pid psk note)) password)]
(if (get-in resp [:status :success]) (if (get-in resp [:status :success])
(redirect (:longPath resp)) (redirect (:longURL resp))
(response 400))) (response 400)))
(response 500))) (response 500)))
(response 400))) (response 400)))
@ -155,11 +155,11 @@
(let [pid api/domain (let [pid api/domain
psk (storage/get-psk pid)] psk (storage/get-psk pid)]
(if (storage/valid-publisher? pid) (if (storage/valid-publisher? pid)
(let [resp (api/update-note noteID note pid (let [resp (api/update-note noteID note pid
(api/get-signature (str pid psk noteID note password)) (api/get-signature (str pid psk noteID note password))
password)] password)]
(if (get-in resp [:status :success]) (if (get-in resp [:status :success])
(redirect (:longPath resp)) (redirect (:longURL resp))
(response 403))) (response 403)))
(response 500)))) (response 500))))

16
test/NoteHub/test/api.clj

@ -1,5 +1,5 @@
(ns NoteHub.test.api (ns NoteHub.test.api
(:require (:require
[cheshire.core :refer :all] [cheshire.core :refer :all]
[NoteHub.storage :as storage]) [NoteHub.storage :as storage])
(:use [NoteHub.api] (:use [NoteHub.api]
@ -10,7 +10,7 @@
(def pid "somePlugin") (def pid "somePlugin")
(def pid2 "somePlugin2") (def pid2 "somePlugin2")
(def note-title (str (apply print-str (get-date)) " hello-world-this-is-a-test-note")) (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)))) (defn substring? [a b] (not (= nil (re-matches (re-pattern (str "(?s).*" a ".*")) b))))
(defmacro isnt [arg] `(is (not ~arg))) (defmacro isnt [arg] `(is (not ~arg)))
@ -43,8 +43,8 @@
(is (:success (:status post-response))) (is (:success (:status post-response)))
(is (:success (:status get-response))) (is (:success (:status get-response)))
(is (= note (:note get-response))) (is (= note (:note get-response)))
(is (= (:longPath post-response) (:longPath get-response) note-url)) (is (= (:longURL post-response) (:longURL get-response) note-url))
(is (= (:shortPath post-response) (:shortPath get-response))) (is (= (:shortURL post-response) (:shortURL get-response)))
(is (= "1" (get-in get-response [:statistics :views]))) (is (= "1" (get-in get-response [:statistics :views])))
(isnt (get-in get-response [:statistics :edited])) (isnt (get-in get-response [:statistics :edited]))
(is (= "2" (get-in (get-note (:noteID post-response)) [:statistics :views]))))) (is (= "2" (get-in (get-note (:noteID post-response)) [:statistics :views])))))
@ -74,12 +74,12 @@
(isnt (:success (:status update-response))) (isnt (:success (:status update-response)))
(is (= "signature invalid" (:message (:status update-response))))) (is (= "signature invalid" (:message (:status update-response)))))
(is (= note (:note (get-note note-id)))) (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")] (get-signature pid psk note-id new-note "passwd") "passwd")]
(is (= { :success true } (:status update-response))) (is (= { :success true } (:status update-response)))
(isnt (= nil (get-in (get-note note-id) [:statistics :edited]))) (isnt (= nil (get-in (get-note note-id) [:statistics :edited])))
(is (= new-note (:note (get-note note-id))))) (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")] (get-signature pid psk note-id "aaa" "pass") "pass")]
(isnt (:success (:status update-response))) (isnt (:success (:status update-response)))
(is (= "password invalid" (:message (:status update-response))))) (is (= "password invalid" (:message (:status update-response)))))
@ -99,7 +99,7 @@
(is (get-in body ["status" "success"])) (is (get-in body ["status" "success"]))
(is (= note ((parse-string (is (= note ((parse-string
(:body (send-request [:get "/api/note"] {:version "1.0" :noteID noteID}))) "note"))) (:body (send-request [:get "/api/note"] {:version "1.0" :noteID noteID}))) "note")))
(is (do (is (do
(storage/delete-note noteID) (storage/delete-note noteID)
(not (storage/note-exists? noteID))))))) (not (storage/note-exists? noteID)))))))
@ -148,6 +148,6 @@
(is (substring? "UPDATED CONTENT" (is (substring? "UPDATED CONTENT"
((parse-string ((parse-string
(:body (send-request [:get "/api/note"] {:version "1.0" :noteID noteID}))) "note"))) (:body (send-request [:get "/api/note"] {:version "1.0" :noteID noteID}))) "note")))
(is (do (is (do
(storage/delete-note noteID) (storage/delete-note noteID)
(not (storage/note-exists? noteID))))))) (not (storage/note-exists? noteID)))))))

44
test/NoteHub/test/views/pages.clj

@ -35,18 +35,18 @@
title "this-is-a-test-note" title "this-is-a-test-note"
[year month day] date] [year month day] date]
(testing "Note creation" (testing "Note creation"
(is (has-status (let [resp (send-request
(send-request [:post "/post-note"]
[:post "/post-note"] {:session session-key
{:session session-key :note test-note
:note test-note :signature (get-signature session-key test-note)})]
:signature (get-signature session-key test-note)}) 302)) (is (has-status resp 302))
(is (note-exists? (build-key date title))) (is (note-exists? (build-key date title)))
(is (substring? "Hello _world_" (is (substring? "Hello _world_"
((send-request (url year month day title)) :body))) ((send-request (url year month day title)) :body)))
(is (do (is (do
(delete-note (build-key date title)) (delete-note (build-key date title))
(not (note-exists? (build-key date title)))))))) (not (note-exists? (build-key date title)))))))))
(deftest note-creation-utf (deftest note-creation-utf
(let [session-key (create-session) (let [session-key (create-session)
@ -55,15 +55,15 @@
note "# Радуга\nкаждый охотник желает знать, где сидят фазаны." note "# Радуга\nкаждый охотник желает знать, где сидят фазаны."
[year month day] date] [year month day] date]
(testing "Note creation with UTF8 symbols" (testing "Note creation with UTF8 symbols"
(is (has-status (is (has-status
(send-request (send-request
[:post "/post-note"] [:post "/post-note"]
{:session session-key {:session session-key
:note note :note note
:signature (get-signature session-key note)}) 302)) :signature (get-signature session-key note)}) 302))
(is (note-exists? (build-key date title))) (is (note-exists? (build-key date title)))
(is (substring? "знать" ((send-request (url year month day title)) :body))) (is (substring? "знать" ((send-request (url year month day title)) :body)))
(is (do (is (do
(delete-note (build-key date title)) (delete-note (build-key date title))
(not (note-exists? (build-key date title)))))))) (not (note-exists? (build-key date title))))))))
@ -74,8 +74,8 @@
[year month day] date [year month day] date
hash (get-signature session-key test-note)] hash (get-signature session-key test-note)]
(testing "Note update" (testing "Note update"
(is (has-status (is (has-status
(send-request (send-request
[:post "/post-note"] [:post "/post-note"]
{:session session-key {:session session-key
:note test-note :note test-note
@ -83,21 +83,21 @@
:signature hash}) 302)) :signature hash}) 302))
(is (note-exists? (build-key date title))) (is (note-exists? (build-key date title)))
(is (substring? "test note" ((send-request (url year month day title)) :body))) (is (substring? "test note" ((send-request (url year month day title)) :body)))
(is (has-status (is (has-status
(send-request (send-request
[:post "/update-note"] [:post "/update-note"]
{:noteID (build-key [year month day] title) {:noteID (build-key [year month day] title)
:note "WRONG pass" :note "WRONG pass"
:password "qwerty1" }) 403)) :password "qwerty1" }) 403))
(is (substring? "test note" ((send-request (url year month day title)) :body))) (is (substring? "test note" ((send-request (url year month day title)) :body)))
(is (has-status (is (has-status
(send-request (send-request
[:post "/update-note"] [:post "/update-note"]
{:noteID (build-key [year month day] title) {:noteID (build-key [year month day] title)
:note "UPDATED CONTENT 123" :note "UPDATED CONTENT 123"
:password "qwerty" }) 302)) :password "qwerty" }) 302))
(is (substring? "UPDATED CONTENT" ((send-request (url year month day title)) :body))) (is (substring? "UPDATED CONTENT" ((send-request (url year month day title)) :body)))
(is (do (is (do
(delete-note (build-key date title)) (delete-note (build-key date title))
(not (note-exists? (build-key date title)))))))) (not (note-exists? (build-key date title))))))))

Loading…
Cancel
Save