first api version implemented

This commit is contained in:
Christian Mueller
2014-01-05 22:34:42 +01:00
parent dfb3a1c934
commit f39ae0a593
8 changed files with 157 additions and 53 deletions
+88 -9
View File
@@ -1,12 +1,37 @@
(ns NoteHub.api
(:require [NoteHub.storage :as persistance]))
(:import
[java.util Calendar])
(:use
[NoteHub.settings]
[clojure.string :rename {replace sreplace}
:only [replace blank? lower-case split-lines]])
(:require [NoteHub.storage :as storage]))
(def api-version "1.0")
(def domain "http://notehub.org/")
; Concatenates all fields to a string
(defn build-key
"Returns a storage-key for the given note coordinates"
[[year month day] title]
(print-str year month day title))
(defn get-date
"Returns today's date"
[]
(map #(+ (second %) (.get (Calendar/getInstance) (first %)))
{Calendar/YEAR 0, Calendar/MONTH 1, Calendar/DAY_OF_MONTH 0}))
(defn- create-response
([success] { :success success })
([success message]
(assoc (create-response success) :message message)))
([success message & params]
(assoc (create-response success) :message (apply format message params))))
(defn- getURL [noteID description]
(if (description)
(str domain (storage/get-short-url noteID))
(str domain (sreplace noteID #" " "/"))))
(let [md5Instance (java.security.MessageDigest/getInstance "MD5")]
(defn get-signature
@@ -17,9 +42,63 @@
(.update md5Instance (.getBytes input))
(.toString (new java.math.BigInteger 1 (.digest md5Instance)) 16)))))
(defn get-note [noteID])
(defn post-note [& args])
(defn update-note [& args])
(defn register-publisher [& args])
(defn revoke-publisher [& args])
(defn valid-publisher? [& args])
(defn get-note [noteID]
{:note (storage/get-note noteID)
:longURL (getURL noteID)
:shortURL (getURL noteID :short)
:statistics (storage/get-note-statistics noteID)
:status (if (storage/note-exists? noteID)
(create-response true)
(create-response false "noteID '%s' unknown" noteID))})
(defn post-note
([note pid signature] (post-note note pid signature nil))
([note pid signature password]
(let [errors (filter identity
(lazy-seq
[(when-not (storage/valid-publisher? pid) "pid invalid")
(when-not (= signature
(get-signature pid (storage/get-psk pid) note))
"signature invalid")
(when (blank? note) "note is empty")]))]
(if (empty? errors)
(let [[year month day] (get-date)
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]
title (first (drop-while #(storage/note-exists? (build-key date %))
(cons proposed-title
(map #(str proposed-title "-" (+ 2 %)) (range)))))
noteID (build-key date title)]
(do
(storage/add-note noteID note password)
(storage/create-short-url noteID)
{
:noteID noteID
:longURL (getURL noteID)
:shortURL (getURL noteID :short)
:status (create-response true)
}))
{:status (create-response false (first errors))}))))
(defn update-note [noteID note pid signature password]
(let [errors (filter identity
(lazy-seq
[(when-not (storage/valid-publisher? pid) "pid invalid")
(when-not (= signature
(get-signature pid (storage/get-psk pid) noteID note password))
"signature invalid")
(when (blank? note) "note is empty")
(when-not (storage/update-note noteID note password) "password invalid")]))]
(if (empty? errors)
{
:longURL (getURL noteID)
:shortURL (getURL noteID :short)
:status (create-response true)
}
{:status (create-response false (first errors))})))
+42 -11
View File
@@ -11,12 +11,34 @@
(when-not (dev-mode?)
{:url (get-setting :db-url)})))
(defn get-current-date []
(str (java.util.Date.)))
; DB hierarchy levels
(def note "note")
(def published "published")
(def edited "edited")
(def views "views")
(def password "password")
(def sessions "sessions")
(def short-url "short-url")
(def publisher "publisher")
(defn valid-publisher? [pid]
(redis/hexists db publisher pid))
(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))
_ (redis/hset db publisher pid psk)]
psk)))
(defn revoke-publisher [pid]
(redis/hdel db publisher pid))
(defn get-psk [pid]
(redis/hget db publisher pid))
(defn create-session
[]
@@ -36,6 +58,7 @@
[noteID text passwd]
(let [stored-password (redis/hget db password noteID)]
(when (and stored-password (= passwd stored-password))
(redis/hset db edited noteID (get-current-date))
(redis/hset db note noteID text))))
(defn add-note
@@ -43,6 +66,7 @@
([noteID text passwd]
(do
(redis/hset db note noteID text)
(redis/hset db published noteID (get-current-date))
(when (not (blank? passwd))
(redis/hset db password noteID passwd)))))
@@ -55,17 +79,21 @@
text))))
(defn get-note-views
"Returns the number of views for the specified noteID"
[noteID]
(redis/hget db views noteID))
(defn get-note-statistics
"Return views, publishing and editing timestamp"
[noteID]
{ :view (redis/hget db views noteID)
:published (redis/hget db published noteID)
:edited (redis/hget db edited noteID) })
(defn note-exists?
"Returns true if the note with the specified noteID"
[noteID]
(redis/hexists db note noteID))
(defn delete-note
"Deletes the note with the specified coordinates"
[noteID]
(doseq [kw [password views note]]
; TODO: delete short url by looking for the title
@@ -76,6 +104,9 @@
[url]
(redis/hexists db short-url url))
(defn get-short-url [noteID]
(redis/hget db short-url noteID))
(defn resolve-url
"Resolves short url by providing all metadata of the request"
[url]
@@ -92,12 +123,12 @@
(redis/hdel db short-url value))))
(defn create-short-url
"Creates a short url for the given request metadata or extracts
"Creates a short url for the given request metadata or noteID or extracts
one if it was already created"
[metadata]
(let [request (str (into (sorted-map) metadata))]
(if (short-url-exists? request)
(redis/hget db short-url request)
[arg]
(let [key (if (map? arg) (str (into (sorted-map) arg)) arg)]
(if (short-url-exists? key)
(redis/hget db short-url key)
(let [hash-stream (partition 5 (repeatedly #(rand-int 36)))
hash-to-string (fn [hash]
(apply str
@@ -108,8 +139,8 @@
(remove short-url-exists?
(map hash-to-string hash-stream)))]
(do
; we create two mappings: request params -> short url and back,
; we create two mappings: key params -> short url and back,
; s.t. we can later easily check whether a short url already exists
(redis/hset db short-url url request)
(redis/hset db short-url request url)
(redis/hset db short-url url key)
(redis/hset db short-url key url)
url)))))
+3 -16
View File
@@ -1,7 +1,8 @@
(ns NoteHub.views.pages
(:require [hiccup.util :as util])
(:use
[NoteHub.storage]
[NoteHub.storage] ; TODO: delete this
[NoteHub.api :only [build-key get-date]]
[NoteHub.settings]
[NoteHub.views.common]
[clojure.string :rename {replace sreplace}
@@ -12,15 +13,7 @@
[hiccup.element]
[noir.response :only [redirect status content-type]]
[noir.core :only [defpage defpartial]]
[noir.statuses])
(:import
[java.util Calendar]))
; Concatenates all fields to a string
(defn build-key
"Returns a storage-key for the given note coordinates"
[[year month day] title]
(print-str year month day title))
[noir.statuses]))
(defn get-hash
"A simple hash-function, which computes a hash from the text field
@@ -66,12 +59,6 @@
links (interpose separator links)]
[:div#panel (map identity links)]))))
(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
; ======