Browse Source

session tokens stored in redis now; tests extended

master
Christian Mueller 14 years ago
parent
commit
0fcf4742e3
  1. 4
      src-cljs/main.cljs
  2. 16
      src/NoteHub/storage.clj
  3. 25
      src/NoteHub/views/pages.clj
  4. 14
      test/NoteHub/test/storage.clj
  5. 51
      test/NoteHub/test/views/pages.clj

4
src-cljs/main.cljs

@ -32,13 +32,11 @@
(.click ($ :#preview-button) (.click ($ :#preview-button)
(fn [e] (fn [e]
(xhr [:post "/preview"] (xhr [:post "/preview"]
{:session-key (val $session-key) {:draft (val $draft)}
:draft (val $draft)}
(fn [json-map] (fn [json-map]
(let [m (js->clj (JSON/parse json-map))] (let [m (js->clj (JSON/parse json-map))]
(do (do
(inner $preview (m "preview")) (inner $preview (m "preview"))
(val $session-key (m "session-key"))
(show $preview-start-line) (show $preview-start-line)
(scroll-to $preview-start-line))))))) (scroll-to $preview-start-line)))))))

16
src/NoteHub/storage.clj

@ -1,5 +1,6 @@
(ns NoteHub.storage (ns NoteHub.storage
(:use [NoteHub.settings] (:use [NoteHub.settings]
[noir.util.crypt :only [encrypt]]
[noir.options :only [dev-mode?]]) [noir.options :only [dev-mode?]])
(:require [clj-redis.client :as redis])) (:require [clj-redis.client :as redis]))
@ -12,11 +13,26 @@
; DB hierarchy levels ; DB hierarchy levels
(def note "note") (def note "note")
(def views "views") (def views "views")
(def sessions "sessions")
; Concatenates all fields to a string ; 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 create-session
"Creates a random session token"
[]
(let [token (encrypt (str (rand-int Integer/MAX_VALUE)))]
(do (redis/sadd db sessions token) token)))
(defn invalidate-session
"Invalidates given session"
[token]
; Jedis is buggy & returns an NPE for token == nil
(when token
(let [was-valid (redis/sismember db sessions token)]
(do (redis/srem db sessions token) was-valid))))
(defn set-note (defn set-note
"Creates a note with the given title and text in the given date namespace" "Creates a note with the given title and text in the given date namespace"
[date title text] [date title text]

25
src/NoteHub/views/pages.clj

@ -11,10 +11,8 @@
[ring.util.codec :only [url-encode]] [ring.util.codec :only [url-encode]]
[hiccup.core] [hiccup.core]
[hiccup.util :only [escape-html]] [hiccup.util :only [escape-html]]
[noir.session :only [flash-put! flash-get]]
[noir.response :only [redirect status]] [noir.response :only [redirect status]]
[noir.core :only [defpage render]] [noir.core :only [defpage render]]
[noir.util.crypt :only [encrypt]]
[cheshire.core] [cheshire.core]
[noir.statuses]) [noir.statuses])
(:import (:import
@ -29,12 +27,6 @@
(defn md-to-html [md-text] (defn md-to-html [md-text]
(.markdownToHtml md-processor md-text)) (.markdownToHtml md-processor md-text))
; Creates a random session token
(defn- get-flash-key []
(let [k (encrypt (str (rand-int Integer/MAX_VALUE)))]
(do (flash-put! k true)
(print-str k))))
; Sets a custom message for each needed HTTP status. ; Sets a custom message for each needed HTTP status.
; The message to be assigned is extracted with a dynamically generated key ; The message to be assigned is extracted with a dynamically generated key
(doseq [code [400 404 500]] (doseq [code [400 404 500]]
@ -54,16 +46,20 @@
(layout params title [:article (md-to-html md-text)])) (layout params title [:article (md-to-html md-text)]))
(status 404 (get-page 404)))) (status 404 (get-page 404))))
(defn get-date
"Returns today's date"
[]
(map #(+ (second %) (.get (Calendar/getInstance) (first %)))
{Calendar/YEAR 0, Calendar/MONTH 1, Calendar/DAY_OF_MONTH 0}))
; Routes ; Routes
; ====== ; ======
; This function answers to an AJAX request: it gets a session key and a markdown text. ; This function answers to an AJAX request: it gets a session key and a markdown text.
; It returns the html code of the provided markdown and a new session key. ; It returns the html code of the provided markdown and a new session key.
(defpage [:post "/preview"] {:keys [session-key draft]} (defpage [:post "/preview"] {:keys [session-key draft]}
(when (flash-get session-key)
(generate-string (generate-string
{:session-key (get-flash-key) {:preview (md-to-html draft)}))
:preview (md-to-html draft)})))
; Landing Page ; Landing Page
(defpage "/" {} (defpage "/" {}
@ -90,7 +86,7 @@
(layout {:js true} (get-message :new-note) (layout {:js true} (get-message :new-note)
[:div.central-element [:div.central-element
(form-to [:post "/post-note"] (form-to [:post "/post-note"]
(hidden-field :session-key (get-flash-key)) (hidden-field :session-key (create-session))
(hidden-field {:id :session-value} :session-value) (hidden-field {:id :session-value} :session-value)
(text-area {:class :max-width} :draft (get-message :loading)) (text-area {:class :max-width} :draft (get-message :loading))
[:div#buttons.hidden [:div#buttons.hidden
@ -130,7 +126,7 @@
; New Note Posting — the most "complex" function in the entire app ;) ; New Note Posting — the most "complex" function in the entire app ;)
(defpage [:post "/post-note"] {:keys [draft session-key session-value]} (defpage [:post "/post-note"] {:keys [draft session-key session-value]}
; first we collect all info needed to evaluate the validity of the note creation request ; first we collect all info needed to evaluate the validity of the note creation request
(let [valid-session (flash-get session-key) ; was the note posted from a newly generated form? (let [valid-session (invalidate-session session-key) ; was the note posted from a newly generated form?
valid-draft (not (ccs/blank? draft)) ; has the note a meaningful content? valid-draft (not (ccs/blank? draft)) ; has the note a meaningful content?
; is the hash code correct? ; is the hash code correct?
valid-hash (try valid-hash (try
@ -142,8 +138,7 @@
; if yes, we compute the current date, extract a title string from the text, ; if yes, we compute the current date, extract a title string from the text,
; which will be a part of the url and look whether this title is free today; ; which will be a part of the url and look whether this title is free today;
; if not, append "-n", where "n" is the next free number ; if not, append "-n", where "n" is the next free number
(let [[year month day] (map #(+ (second %) (.get (Calendar/getInstance) (first %))) (let [[year month day] (get-date)
{Calendar/YEAR 0, Calendar/MONTH 1, Calendar/DAY_OF_MONTH 0})
untrimmed-line (filter #(or (= \- %) (Character/isLetterOrDigit %)) untrimmed-line (filter #(or (= \- %) (Character/isLetterOrDigit %))
(-> draft ccs/split-lines first (sreplace " " "-") lower-case)) (-> draft ccs/split-lines first (sreplace " " "-") lower-case))
trim (fn [s] (apply str (drop-while #(= \- %) s))) trim (fn [s] (apply str (drop-while #(= \- %) s)))

14
test/NoteHub/test/storage.clj

@ -5,7 +5,8 @@
(def test-title "Some title.") (def test-title "Some title.")
(def test-note "This is a test note.") (def test-note "This is a test note.")
(testing "Storage" (deftest storage
(testing "Storage"
(testing "of correct note creation" (testing "of correct note creation"
(is (= (do (is (= (do
(set-note date test-title test-note) (set-note date test-title test-note)
@ -18,10 +19,19 @@
"2"))) "2")))
(testing "of the note access" (testing "of the note access"
(is (not= (get-note date test-title) "any text"))) (is (not= (get-note date test-title) "any text")))
(testing "session management"
(let [s1 (create-session)
s2 (create-session)
s3 (create-session)]
(is (invalidate-session s1))
(is (not (invalidate-session (str s1 s2))))
(is (invalidate-session s2))
(is (not (invalidate-session "wrongtoken")))
(is (invalidate-session s3))))
(testing "of note existence" (testing "of note existence"
(is (note-exists? date test-title)) (is (note-exists? date test-title))
(is (not (do (is (not (do
(delete-note date test-title) (delete-note date test-title)
(note-exists? date test-title)))) (note-exists? date test-title))))
(is (not (note-exists? [2013 06 03] test-title))) (is (not (note-exists? [2013 06 03] test-title)))
(is (not (note-exists? date "some title"))))) (is (not (note-exists? date "some title"))))))

51
test/NoteHub/test/views/pages.clj

@ -1,13 +1,15 @@
(ns NoteHub.test.views.pages (ns NoteHub.test.views.pages
(:require [NoteHub.crossover.lib :as lib])
(:use [NoteHub.views.pages] (:use [NoteHub.views.pages]
[noir.util.test] [noir.util.test]
[clojure.contrib.string :only [substring?]]
[NoteHub.views.common :only [url]] [NoteHub.views.common :only [url]]
[NoteHub.storage] [NoteHub.storage]
[clojure.test])) [clojure.test]))
(def date [2012 6 3]) (def date [2012 6 3])
(def test-title "some-title") (def test-title "some-title")
(def test-note "# This is a test note.\nHello _world_.") (def test-note "# This is a test note.\nHello _world_. Motörhead, тест.")
(defn create-testnote-fixture [f] (defn create-testnote-fixture [f]
(set-note date test-title test-note) (set-note date test-title test-note)
@ -29,22 +31,43 @@
(md-to-html "#_hellö_ __world__\ntest `code`"))))) (md-to-html "#_hellö_ __world__\ntest `code`")))))
(deftest export-test (deftest export-test
(testing "Markdown export" (testing "Markdown export"
(has-body (send-request (url 2012 6 3 "some-title" "export")) test-note))) (is (has-body (send-request (url 2012 6 3 "some-title" "export")) test-note))))
(deftest note-creation
(let [session-key (create-session)
date (get-date)
; TODO: replace note generation by a function from pages.clj
title "this-is-a-test-note"
[year month day] date]
(testing "Note creation"
(is (has-status
(send-request
[:post "/post-note"]
{:session-key session-key
:draft test-note
:session-value (str (lib/hash #(.codePointAt % 0)
(str test-note session-key)))}) 302))
(is (note-exists? date title))
(is (substring? "Hello <em>world</em>"
((send-request (url year month day title)) :body)))
(is (do
(delete-note date title)
(not (note-exists? date title)))))))
(deftest requests (deftest requests
(testing "HTTP Status" (testing "HTTP Status"
(testing "of a wrong access" (testing "of a wrong access"
(has-status (send-request "/wrong-page") 404) (is (has-status (send-request "/wrong-page") 404))
(has-status (send-request (url 2012 6 3 "lol" "stat")) 404) (is (has-status (send-request (url 2012 6 3 "lol" "stat")) 404))
(has-status (send-request (url 2012 6 3 "lol" "export")) 404) (is (has-status (send-request (url 2012 6 3 "lol" "export")) 404))
(has-status (send-request (url 2012 6 3 "lol")) 404) (is (has-status (send-request (url 2012 6 3 "lol")) 404))
(has-status (send-request (url 2012 6 4 "wrong-title")) 404)) (is (has-status (send-request (url 2012 6 4 "wrong-title")) 404)))
(testing "of corrupt note-post" (testing "of corrupt note-post"
(has-status (send-request [:post "/post-note"]) 400)) (is (has-status (send-request [:post "/post-note"]) 400)))
(testing "valid accesses" (testing "valid accesses"
(has-status (send-request "/new") 200) (is (has-status (send-request "/new") 200))
(has-status (send-request (url 2012 6 3 "some-title")) 200) (is (has-status (send-request (url 2012 6 3 "some-title")) 200))
(has-status (send-request (url 2012 6 3 "some-title" "export")) 200) (is (has-status (send-request (url 2012 6 3 "some-title" "export")) 200))
(has-status (send-request (url 2012 6 3 "some-title" "stat")) 200) (is (has-status (send-request (url 2012 6 3 "some-title" "stat")) 200))
(has-status (send-request (url 2012 6 3 "some-title")) 200) (is (has-status (send-request (url 2012 6 3 "some-title")) 200))
(has-status (send-request "/") 200)))) (is (has-status (send-request "/") 200)))))

Loading…
Cancel
Save