diff --git a/ChangeLog.md b/ChangeLog.md index c57624c..64e95d4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,6 +1,17 @@ ## Changes between 1.0.0-beta6 and 1.0.0-beta7 -No changes yet. +### ring.session.store implementation + +Monger now features a [Ring session store](https://github.com/mmcgrana/ring/blob/master/ring-core/src/ring/middleware/session/store.clj) implementation. To use it, require `monger.ring.session-store` and use +`monger.ring.session-store/monger-store` function like so: + +``` clojure +(ns my.service + (:use monger.ring.session-store)) + +(let [store (monger-store "web_sessions")] + ...) +``` diff --git a/project.clj b/project.clj index 1c585d6..053ba01 100644 --- a/project.clj +++ b/project.clj @@ -21,12 +21,13 @@ :1.5 {:dependencies [[org.clojure/clojure "1.5.0-master-SNAPSHOT"]]} :dev {:resource-paths ["test/resources"] :dependencies [[clj-time "0.4.2" :exclusions [org.clojure/clojure]] - [org.clojure/data.json "0.1.2" :exclusions [org.clojure/clojure]] - [org.clojure/tools.cli "0.2.1" :exclusions [org.clojure/clojure]] - [org.clojure/core.cache "0.5.0" :exclusions [org.clojure/clojure]]]}} + [org.clojure/data.json "0.1.2" :exclusions [org.clojure/clojure]] + [org.clojure/tools.cli "0.2.1" :exclusions [org.clojure/clojure]] + [org.clojure/core.cache "0.5.0" :exclusions [org.clojure/clojure]] + [ring/ring-core "1.1.0"]]}} :aliases {"all" ["with-profile" "dev:dev,1.4:dev,1.5"]} :repositories {"sonatype" {:url "http://oss.sonatype.org/content/repositories/releases" - :snapshots false, + :snapshots false :releases {:checksum :fail :update :always}} "sonatype-snapshots" {:url "http://oss.sonatype.org/content/repositories/snapshots" :snapshots true diff --git a/src/monger/ring/session_store.clj b/src/monger/ring/session_store.clj new file mode 100644 index 0000000..ef08e39 --- /dev/null +++ b/src/monger/ring/session_store.clj @@ -0,0 +1,46 @@ +(ns monger.ring.session-store + (:require [ring.middleware.session.store :as ringstore] + [monger.collection :as mc]) + (:use monger.conversion) + (:import [java.util UUID Date])) + +;; +;; Implementation +;; + +(def ^{:const true} + default-session-store-collection "web_sessions") + + + + +;; +;; API +;; + +(defrecord MongoDBSessionStore [^String collection-name]) + +(extend-protocol ringstore/SessionStore + MongoDBSessionStore + + (read-session [store key] + (if-let [m (and key + (mc/find-one-as-map (.collection-name store) {:_id key}))] + m + {})) + + (write-session [store key data] + (let [key (or key (str (UUID/randomUUID)))] + (mc/save (.collection-name store) (assoc data :date (Date.) :_id key)) + key)) + + (delete-session [store key] + (mc/remove-by-id (.collection-name store) key) + nil)) + + +(defn monger-store + ([] + (MongoDBSessionStore. default-session-store-collection)) + ([^String s] + (MongoDBSessionStore. s))) \ No newline at end of file diff --git a/test/monger/test/ring/session_store_test.clj b/test/monger/test/ring/session_store_test.clj new file mode 100644 index 0000000..799d50d --- /dev/null +++ b/test/monger/test/ring/session_store_test.clj @@ -0,0 +1,54 @@ +(ns monger.test.ring.session-store-test + (:require [monger core util] + [monger.collection :as mc] + [monger.test.helper :as helper]) + (:use clojure.test + ring.middleware.session.store + monger.ring.session-store)) + + +(helper/connect!) + +(defn purge-sessions + [f] + (mc/remove "web_sessions") + (mc/remove "sessions") + (f) + (mc/remove "web_sessions") + (mc/remove "sessions")) + +(use-fixtures :each purge-sessions) + + +(deftest test-reading-a-session-that-does-not-exist + (let [store (monger-store)] + (is (= {} (read-session store "a-missing-key-1228277"))))) + + +(deftest test-reading-a-session-that-does-exist + (let [store (monger-store) + sk (write-session store nil {:library "Monger"}) + m (read-session store sk)] + (is sk) + (is (and (:_id m) (:date m))) + (is (= (dissoc m :_id :date) + {:library "Monger"})))) + + +(deftest test-updating-a-session + (let [store (monger-store "sessions") + sk1 (write-session store nil {:library "Monger"}) + sk2 (write-session store sk1 {:library "Ring"}) + m (read-session store sk2)] + (is (and sk1 sk2)) + (is (and (:_id m) (:date m))) + (is (= sk1 sk2)) + (is (= (dissoc m :_id :date) + {:library "Ring"})))) + + +(deftest test-deleting-a-session + (let [store (monger-store "sessions") + sk (write-session store nil {:library "Monger"})] + (is (nil? (delete-session store sk))) + (is (= {} (read-session store sk)))))