migrated to API internally
This commit is contained in:
@@ -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`, `longURL`, `shortURL`, `statistics`, `status`.
|
will return a JSON object containing following self explaining fields: `note`, `longPath`, `shortPath`, `statistics`, `status`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
{
|
{
|
||||||
note: <markdown source>,
|
note: <markdown source>,
|
||||||
longURL: "http://notehub.org/2014/1/3/lorem-ipsum",
|
longPath: "/2014/1/3/lorem-ipsum",
|
||||||
shortURL: "http://notehub.org/0vrcp",
|
shortPath: "/0vrcp",
|
||||||
statistics: {
|
statistics: {
|
||||||
published: "2014-1-3",
|
published: "2014-1-3",
|
||||||
edited: "2014-1-12",
|
edited: "2014-1-12",
|
||||||
@@ -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`, `longURL`, `shortURL`, `status`.
|
The response of the server will contain the fields `noteID`, `longPath`, `shortPath`, `status`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
{
|
{
|
||||||
noteID: "2014/1/3/lorem-ipsum",
|
noteID: "2014/1/3/lorem-ipsum",
|
||||||
longURL: "http://notehub.org/2014/1/3/lorem-ipsum",
|
longPath: "/2014/1/3/lorem-ipsum",
|
||||||
shortURL: "http://notehub.org/0vrcp",
|
shortPath: "/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 `longURL`, `shortURL`, `status`.
|
The response of the server will contain the fields `longPath`, `shortPath`, `status`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
{
|
{
|
||||||
longURL: "http://notehub.org/2014/1/3/lorem-ipsum",
|
longPath: "/2014/1/3/lorem-ipsum",
|
||||||
shortURL: "http://notehub.org/0vrcp",
|
shortPath: "/0vrcp",
|
||||||
status: {
|
status: {
|
||||||
success: true,
|
success: true,
|
||||||
comment: "some server message"
|
comment: "some server message"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
page-title = Publish Markdown for Free
|
page-title = Pastebin for Markdown: Publish Your Markdown Anonymously
|
||||||
title = Free and Hassle-free Pastebin for Markdown Pages.
|
title = Free and Hassle-free Pastebin for Markdown Pages.
|
||||||
name = NoteHub
|
name = NoteHub
|
||||||
new-page = New Page
|
new-page = New Page
|
||||||
@@ -23,4 +23,4 @@ stats = statistics
|
|||||||
export = export
|
export = export
|
||||||
edit = edit
|
edit = edit
|
||||||
short-url = short url
|
short-url = short url
|
||||||
api-title = NoteHub API
|
api-title = API
|
||||||
|
|||||||
@@ -1,36 +1,24 @@
|
|||||||
var hash = function (input) {
|
|
||||||
var shortMod = function(i) { return i % 32767 };
|
|
||||||
var charCodes = input.split("")
|
|
||||||
.filter(function(c){ return c != "\n" && c != "\r" })
|
|
||||||
.map(function(c){ return c.charCodeAt(0) });
|
|
||||||
var h = 0;
|
|
||||||
for(var i in charCodes)
|
|
||||||
h = shortMod(h + shortMod(charCodes[i] * (h % 2 != 0 ? 16381 ^ i : 16381 & i)));
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
var $ = function(id){ return document.getElementById(id); }
|
var $ = function(id){ return document.getElementById(id); }
|
||||||
var iosDetected = navigator.userAgent.match("(iPad|iPod|iPhone)");
|
var iosDetected = navigator.userAgent.match("(iPad|iPod|iPhone)");
|
||||||
var timer = null;
|
var timer = null;
|
||||||
var timerDelay = iosDetected ? 800 : 400;
|
var timerDelay = iosDetected ? 800 : 400;
|
||||||
var show = function(elem) { elem.style.display = "block" }
|
var show = function(elem) { elem.style.display = "block" }
|
||||||
var $draft, $action, $preview, $password, $plain_password, $input_elems, $dashed_line, updatePreview;
|
var $note, $action, $preview, $plain_password, $input_elems, $dashed_line, updatePreview;
|
||||||
|
|
||||||
function md2html(input){
|
function md2html(input){
|
||||||
return marked(input);
|
return marked(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadPage() {
|
function loadPage() {
|
||||||
$draft = $("draft");
|
$note = $("note");
|
||||||
$action = $("action");
|
$action = $("action");
|
||||||
$preview = $("preview");
|
$preview = $("preview");
|
||||||
$password = $("password");
|
|
||||||
$plain_password = $("plain-password");
|
$plain_password = $("plain-password");
|
||||||
$input_elems = $("input-elems");
|
$input_elems = $("input-elems");
|
||||||
$dashed_line = $("dashed-line");
|
$dashed_line = $("dashed-line");
|
||||||
updatePreview = function(){
|
updatePreview = function(){
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
var content = $draft.value;
|
var content = $note.value;
|
||||||
var delay = Math.min(timerDelay, timerDelay * (content.length / 400));
|
var delay = Math.min(timerDelay, timerDelay * (content.length / 400));
|
||||||
timer = setTimeout(function(){
|
timer = setTimeout(function(){
|
||||||
show($dashed_line);
|
show($dashed_line);
|
||||||
@@ -39,14 +27,14 @@ function loadPage() {
|
|||||||
}, delay);
|
}, delay);
|
||||||
};
|
};
|
||||||
if($action){
|
if($action){
|
||||||
if($action.value == "update") updatePreview(); else $draft.value = "";
|
if($action.value == "update") updatePreview(); else $note.value = "";
|
||||||
$draft.onkeyup = updatePreview;
|
$note.onkeyup = updatePreview;
|
||||||
$("publish-button").onclick = function(e) {
|
$("publish-button").onclick = function(e) {
|
||||||
if($plain_password.value != "") $password.value = md5($plain_password.value);
|
if($plain_password.value != "") $("password").value = md5($plain_password.value);
|
||||||
$plain_password.value = null;
|
$plain_password.value = null;
|
||||||
$("session-value").value = hash($draft.value + $("session-key").value);
|
$("signature").value = md5($("session").value + $note.value);
|
||||||
}
|
}
|
||||||
if(iosDetected) $draft.className += " ui-border"; else $draft.focus();
|
if(iosDetected) $note.className += " ui-border"; else $note.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
var mdDocs = document.getElementsByClassName("markdown");
|
var mdDocs = document.getElementsByClassName("markdown");
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
max-title-length = 40
|
max-title-length = 40
|
||||||
|
domain = http://notehub.org/
|
||||||
|
|||||||
+19
-23
@@ -7,9 +7,9 @@
|
|||||||
:only [replace blank? lower-case split-lines]])
|
:only [replace blank? lower-case split-lines]])
|
||||||
(:require [NoteHub.storage :as storage]))
|
(:require [NoteHub.storage :as storage]))
|
||||||
|
|
||||||
(def api-version "1.0")
|
(def version "1.0")
|
||||||
|
|
||||||
(def domain "http://notehub.org/")
|
(def domain (get-setting :domain))
|
||||||
|
|
||||||
; Concatenates all fields to a string
|
; Concatenates all fields to a string
|
||||||
(defn build-key
|
(defn build-key
|
||||||
@@ -28,10 +28,10 @@
|
|||||||
([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- getURL [noteID & description]
|
(defn- getPath [noteID & description]
|
||||||
(if description
|
(if description
|
||||||
(str domain (storage/get-short-url noteID))
|
(str "/" (storage/get-short-url noteID))
|
||||||
(str domain (sreplace noteID #" " "/"))))
|
(str "/" (sreplace noteID #" " "/"))))
|
||||||
|
|
||||||
(let [md5Instance (java.security.MessageDigest/getInstance "MD5")]
|
(let [md5Instance (java.security.MessageDigest/getInstance "MD5")]
|
||||||
(defn get-signature
|
(defn get-signature
|
||||||
@@ -43,13 +43,13 @@
|
|||||||
(.toString (new java.math.BigInteger 1 (.digest md5Instance)) 16)))))
|
(.toString (new java.math.BigInteger 1 (.digest md5Instance)) 16)))))
|
||||||
|
|
||||||
(defn get-note [noteID]
|
(defn get-note [noteID]
|
||||||
{:note (storage/get-note noteID)
|
(if (storage/note-exists? noteID)
|
||||||
:longURL (getURL noteID)
|
{:note (storage/get-note noteID)
|
||||||
:shortURL (getURL noteID :short)
|
:longPath (getPath noteID)
|
||||||
:statistics (storage/get-note-statistics noteID)
|
:shortPath (getPath noteID :short)
|
||||||
:status (if (storage/note-exists? noteID)
|
:statistics (storage/get-note-statistics noteID)
|
||||||
(create-response true)
|
:status (create-response true)}
|
||||||
(create-response false "noteID '%s' unknown" noteID))})
|
(create-response false "noteID '%s' unknown" noteID)))
|
||||||
|
|
||||||
(defn post-note
|
(defn post-note
|
||||||
([note pid signature] (post-note note pid signature nil))
|
([note pid signature] (post-note note pid signature nil))
|
||||||
@@ -76,12 +76,10 @@
|
|||||||
(do
|
(do
|
||||||
(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 (getURL noteID)
|
:shortPath (getPath noteID :short)
|
||||||
:shortURL (getURL noteID :short)
|
:status (create-response true)}))
|
||||||
:status (create-response true)
|
|
||||||
}))
|
|
||||||
{:status (create-response false (first errors))}))))
|
{:status (create-response false (first errors))}))))
|
||||||
|
|
||||||
|
|
||||||
@@ -97,9 +95,7 @@
|
|||||||
(if (empty? errors)
|
(if (empty? errors)
|
||||||
(do
|
(do
|
||||||
(storage/edit-note noteID note)
|
(storage/edit-note noteID note)
|
||||||
{
|
{:longPath (getPath noteID)
|
||||||
:longURL (getURL noteID)
|
:shortPath (getPath noteID :short)
|
||||||
:shortURL (getURL noteID :short)
|
:status (create-response true)})
|
||||||
:status (create-response true)
|
|
||||||
})
|
|
||||||
{:status (create-response false (first errors))})))
|
{:status (create-response false (first errors))})))
|
||||||
|
|||||||
@@ -6,6 +6,5 @@
|
|||||||
(defn -main [& m]
|
(defn -main [& m]
|
||||||
(let [mode (keyword (or (first m) :prod))
|
(let [mode (keyword (or (first m) :prod))
|
||||||
port (Integer. (get (System/getenv) "PORT" "8080"))]
|
port (Integer. (get (System/getenv) "PORT" "8080"))]
|
||||||
(server/start port {:mode mode
|
(server/start port {:mode mode :ns 'NoteHub})))
|
||||||
:ns 'NoteHub})))
|
|
||||||
|
|
||||||
|
|||||||
+4
-14
@@ -40,28 +40,18 @@
|
|||||||
(defn get-psk [pid]
|
(defn get-psk [pid]
|
||||||
(redis/hget db publisher pid))
|
(redis/hget db publisher pid))
|
||||||
|
|
||||||
(defn create-session
|
(defn create-session []
|
||||||
[]
|
|
||||||
(let [token (encrypt (str (rand-int Integer/MAX_VALUE)))]
|
(let [token (encrypt (str (rand-int Integer/MAX_VALUE)))]
|
||||||
(do (redis/sadd db sessions token)
|
(do (redis/sadd db sessions token)
|
||||||
token)))
|
token)))
|
||||||
|
|
||||||
(defn invalidate-session
|
(defn invalidate-session [token]
|
||||||
[token]
|
|
||||||
; Jedis is buggy & returns an NPE for token == nil
|
; Jedis is buggy & returns an NPE for token == nil
|
||||||
(when token
|
(when token
|
||||||
(let [was-valid (redis/sismember db sessions token)]
|
(let [was-valid (redis/sismember db sessions token)]
|
||||||
(do (redis/srem db sessions token)
|
(do (redis/srem db sessions token)
|
||||||
was-valid))))
|
was-valid))))
|
||||||
|
|
||||||
; TODO: deprecated
|
|
||||||
(defn update-note
|
|
||||||
[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 edit-note
|
(defn edit-note
|
||||||
[noteID text]
|
[noteID text]
|
||||||
(do
|
(do
|
||||||
@@ -97,8 +87,8 @@
|
|||||||
"Return views, publishing and editing timestamp"
|
"Return views, publishing and editing timestamp"
|
||||||
[noteID]
|
[noteID]
|
||||||
{ :views (redis/hget db views noteID)
|
{ :views (redis/hget db views noteID)
|
||||||
:published (redis/hget db published noteID)
|
:published (redis/hget db published noteID)
|
||||||
:edited (redis/hget db edited noteID) })
|
:edited (redis/hget db edited noteID) })
|
||||||
|
|
||||||
(defn note-exists?
|
(defn note-exists?
|
||||||
[noteID]
|
[noteID]
|
||||||
|
|||||||
+50
-75
@@ -4,12 +4,12 @@
|
|||||||
[NoteHub.storage :as storage]
|
[NoteHub.storage :as storage]
|
||||||
[cheshire.core :refer :all])
|
[cheshire.core :refer :all])
|
||||||
(:use
|
(:use
|
||||||
[NoteHub.storage] ; TODO: delete this
|
|
||||||
[NoteHub.settings]
|
[NoteHub.settings]
|
||||||
[NoteHub.views.common]
|
[NoteHub.views.common]
|
||||||
[clojure.string :rename {replace sreplace}
|
[clojure.string :rename {replace sreplace}
|
||||||
:only [escape split replace blank? split-lines lower-case]]
|
:only [escape split replace blank? split-lines lower-case]]
|
||||||
[clojure.core.incubator :only [-?>]]
|
[clojure.core.incubator :only [-?>]]
|
||||||
|
[noir.util.crypt :only [encrypt]]
|
||||||
[hiccup.form]
|
[hiccup.form]
|
||||||
[hiccup.core]
|
[hiccup.core]
|
||||||
[hiccup.element]
|
[hiccup.element]
|
||||||
@@ -17,21 +17,8 @@
|
|||||||
[noir.core :only [defpage defpartial]]
|
[noir.core :only [defpage defpartial]]
|
||||||
[noir.statuses]))
|
[noir.statuses]))
|
||||||
|
|
||||||
(defn get-hash
|
(when-not (storage/valid-publisher? api/domain)
|
||||||
"A simple hash-function, which computes a hash from the text field
|
(storage/register-publisher api/domain))
|
||||||
content and given session number. It is intended to be used as a spam
|
|
||||||
protection / captcha alternative. (Probably doesn't work for UTF-16)"
|
|
||||||
[s]
|
|
||||||
(let [short-mod #(mod % 32767)
|
|
||||||
char-codes (map #(.codePointAt % 0) (remove #(contains? #{"\n" "\r"} %) (map str s)))
|
|
||||||
zip-with-index (map list char-codes (range))]
|
|
||||||
(reduce
|
|
||||||
#(short-mod (+ %
|
|
||||||
(short-mod (* (first %2)
|
|
||||||
((if (odd? %)
|
|
||||||
bit-xor
|
|
||||||
bit-and) 16381 (second %2))))))
|
|
||||||
0 zip-with-index)))
|
|
||||||
|
|
||||||
; 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
|
||||||
@@ -70,15 +57,19 @@
|
|||||||
[:div.central-element.helvetica {:style "margin-bottom: 3em"}
|
[:div.central-element.helvetica {:style "margin-bottom: 3em"}
|
||||||
(form-to {:autocomplete :off} [:post form-url]
|
(form-to {:autocomplete :off} [:post form-url]
|
||||||
(hidden-field :action command)
|
(hidden-field :action command)
|
||||||
|
(hidden-field :version api/version)
|
||||||
(hidden-field :password)
|
(hidden-field :password)
|
||||||
fields
|
fields
|
||||||
(text-area {:class :max-width} :draft 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))])])))
|
||||||
|
|
||||||
|
(defn generate-session []
|
||||||
|
(encrypt (str (rand-int Integer/MAX_VALUE))))
|
||||||
|
|
||||||
; Routes
|
; Routes
|
||||||
; ======
|
; ======
|
||||||
|
|
||||||
@@ -98,24 +89,10 @@
|
|||||||
; 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
|
||||||
(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)))))
|
||||||
|
|
||||||
; 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
|
|
||||||
(html (hidden-field :key noteID))
|
|
||||||
(:note (api/get-note noteID)) :enter-passwd)))
|
|
||||||
|
|
||||||
; New Note Page
|
|
||||||
(defpage "/new" {}
|
|
||||||
(input-form "/post-note" :publish
|
|
||||||
(html (hidden-field :session-key (create-session))
|
|
||||||
(hidden-field {:id :session-value} :session-value))
|
|
||||||
(get-message :loading) :set-passwd))
|
|
||||||
|
|
||||||
; Provides Markdown of the specified note
|
; Provides Markdown of the specified note
|
||||||
(defpage "/:year/:month/:day/:title/export" {:keys [year month day title]}
|
(defpage "/:year/:month/:day/:title/export" {:keys [year month day title]}
|
||||||
(when-let [md-text (:note (api/get-note (api/build-key [year month day] title)))]
|
(when-let [md-text (:note (api/get-note (api/build-key [year month day] title)))]
|
||||||
@@ -137,53 +114,55 @@
|
|||||||
[:td (get-message :article-views)]
|
[:td (get-message :article-views)]
|
||||||
[:td (:views stats)]]])))
|
[:td (:views stats)]]])))
|
||||||
|
|
||||||
; Updates a note
|
|
||||||
(defpage [:post "/update-note"] {:keys [key draft password]}
|
|
||||||
(if (update-note key draft password)
|
|
||||||
(redirect (apply url (split key #" ")))
|
|
||||||
(response 403)))
|
|
||||||
|
|
||||||
; New Note Posting — the most "complex" function in the entire app ;)
|
|
||||||
(defpage [:post "/post-note"] {:keys [draft password session-key session-value]}
|
|
||||||
; first we collect all info needed to evaluate the validity of the note creation request
|
|
||||||
(let [valid-session (invalidate-session session-key) ; was the note posted from a newly generated form?
|
|
||||||
valid-draft (not (blank? draft)) ; has the note a meaningful content?
|
|
||||||
; is the hash code correct?
|
|
||||||
valid-hash (try
|
|
||||||
(= (Short/parseShort session-value)
|
|
||||||
(get-hash (str draft session-key)))
|
|
||||||
(catch Exception e nil))]
|
|
||||||
; check whether the new note can be added
|
|
||||||
(if (and valid-session valid-draft valid-hash)
|
|
||||||
; 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;
|
|
||||||
; if not, append "-n", where "n" is the next free number
|
|
||||||
(let [[year month day] (api/get-date)
|
|
||||||
untrimmed-line (filter #(or (= \- %) (Character/isLetterOrDigit %))
|
|
||||||
(-> draft 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)
|
|
||||||
; TODO: replace to ccs/take when it gets fixed
|
|
||||||
proposed-title (apply str (take max-length title-uncut))
|
|
||||||
date [year month day]
|
|
||||||
title (first (drop-while #(note-exists? (api/build-key date %))
|
|
||||||
(cons proposed-title
|
|
||||||
(map #(str proposed-title "-" (+ 2 %)) (range)))))]
|
|
||||||
(do
|
|
||||||
(add-note (api/build-key date title) draft password)
|
|
||||||
(redirect (url year month day title))))
|
|
||||||
(response 400))))
|
|
||||||
|
|
||||||
; Resolving of a short url
|
; Resolving of a short url
|
||||||
(defpage "/:short-url" {:keys [short-url]}
|
(defpage "/:short-url" {:keys [short-url]}
|
||||||
(when-let [params (resolve-url short-url)]
|
(when-let [params (storage/resolve-url short-url)]
|
||||||
(let [{:keys [year month day title]} params
|
(let [{:keys [year month day title]} params
|
||||||
rest-params (dissoc params :year :month :day :title)
|
rest-params (dissoc params :year :month :day :title)
|
||||||
core-url (url year month day title)
|
core-url (url year month day title)
|
||||||
long-url (if (empty? rest-params) core-url (util/url core-url rest-params))]
|
long-url (if (empty? rest-params) core-url (util/url core-url rest-params))]
|
||||||
(redirect long-url))))
|
(redirect long-url))))
|
||||||
|
|
||||||
|
; New Note Page
|
||||||
|
(defpage "/new" {}
|
||||||
|
(input-form "/post-note" :publish
|
||||||
|
(html (hidden-field :session (storage/create-session))
|
||||||
|
(hidden-field {:id :signature} :signature))
|
||||||
|
(get-message :loading) :set-passwd))
|
||||||
|
|
||||||
|
; 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
|
||||||
|
(html (hidden-field :noteID noteID))
|
||||||
|
(:note (api/get-note noteID)) :enter-passwd)))
|
||||||
|
|
||||||
|
; Creates New Note from Web
|
||||||
|
(defpage [:post "/post-note"] {:keys [session note signature password version]}
|
||||||
|
(if (= signature (api/get-signature session note))
|
||||||
|
(let [pid api/domain
|
||||||
|
psk (storage/get-psk pid)]
|
||||||
|
(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))
|
||||||
|
(response 400)))
|
||||||
|
(response 500)))
|
||||||
|
(response 400)))
|
||||||
|
|
||||||
|
; Updates a note
|
||||||
|
(defpage [:post "/update-note"] {:keys [noteID note password version]}
|
||||||
|
(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))
|
||||||
|
password)]
|
||||||
|
(if (get-in resp [:status :success])
|
||||||
|
(redirect (:longPath resp))
|
||||||
|
(response 403)))
|
||||||
|
(response 500))))
|
||||||
|
|
||||||
; Here lives the API
|
; Here lives the API
|
||||||
|
|
||||||
(defpage "/api" args
|
(defpage "/api" args
|
||||||
@@ -199,7 +178,3 @@
|
|||||||
(defpage [:put "/api/note"] {:keys [version noteID note pid signature password]}
|
(defpage [:put "/api/note"] {:keys [version noteID note pid signature password]}
|
||||||
(generate-string (api/update-note noteID note pid signature password)))
|
(generate-string (api/update-note noteID note pid signature password)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 domain (apply str (interpose "/" (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"))
|
||||||
(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 (= (:longURL post-response) (:longURL get-response) note-url))
|
(is (= (:longPath post-response) (:longPath get-response) note-url))
|
||||||
(is (= (:shortURL post-response) (:shortURL get-response)))
|
(is (= (:shortPath post-response) (:shortPath 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])))))
|
||||||
|
|||||||
@@ -43,11 +43,7 @@
|
|||||||
test-note))
|
test-note))
|
||||||
(is (valid-password? (build-key date test-title) "12345qwert"))
|
(is (valid-password? (build-key date test-title) "12345qwert"))
|
||||||
(is (= (do
|
(is (= (do
|
||||||
(update-note (build-key date test-title) "update" "12345qwert")
|
(edit-note (build-key date test-title) "update")
|
||||||
(get-note (build-key date test-title)))
|
|
||||||
"update"))
|
|
||||||
(is (= (do
|
|
||||||
(update-note (build-key date test-title) "not authorized" "44444")
|
|
||||||
(get-note (build-key date test-title)))
|
(get-note (build-key date test-title)))
|
||||||
"update")))
|
"update")))
|
||||||
(testing "of the note access"
|
(testing "of the note access"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
(ns NoteHub.test.views.pages
|
(ns NoteHub.test.views.pages
|
||||||
(:use [NoteHub.views.pages]
|
(:use [NoteHub.views.pages]
|
||||||
[NoteHub.api :only [build-key get-date]]
|
[NoteHub.api :only [build-key get-signature get-date]]
|
||||||
[noir.util.test]
|
[noir.util.test]
|
||||||
[NoteHub.views.common :only [url]]
|
[NoteHub.views.common :only [url]]
|
||||||
[NoteHub.storage]
|
[NoteHub.storage]
|
||||||
@@ -38,9 +38,9 @@
|
|||||||
(is (has-status
|
(is (has-status
|
||||||
(send-request
|
(send-request
|
||||||
[:post "/post-note"]
|
[:post "/post-note"]
|
||||||
{:session-key session-key
|
{:session session-key
|
||||||
:draft test-note
|
:note test-note
|
||||||
:session-value (str (get-hash (str test-note session-key)))}) 302))
|
:signature (get-signature session-key test-note)}) 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)))
|
||||||
@@ -51,35 +51,33 @@
|
|||||||
(deftest note-update
|
(deftest note-update
|
||||||
(let [session-key (create-session)
|
(let [session-key (create-session)
|
||||||
date (get-date)
|
date (get-date)
|
||||||
title "test-note"
|
title "this-is-a-test-note"
|
||||||
[year month day] date]
|
[year month day] date
|
||||||
|
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-key session-key
|
{:session session-key
|
||||||
:draft "test note"
|
:note test-note
|
||||||
:password "qwerty"
|
:password "qwerty"
|
||||||
:session-value (str (get-hash (str "test note" session-key)))}) 302))
|
:signature hash}) 302))
|
||||||
(is (note-exists? (build-key date title)))
|
(is (note-exists? (build-key date title)))
|
||||||
(is (substring? "test note"
|
(is (substring? "test note" ((send-request (url year month day title)) :body)))
|
||||||
((send-request (url year month day title)) :body)))
|
|
||||||
(is (has-status
|
(is (has-status
|
||||||
(send-request
|
(send-request
|
||||||
[:post "/update-note"]
|
[:post "/update-note"]
|
||||||
{:key (build-key [year month day] title)
|
{:noteID (build-key [year month day] title)
|
||||||
:draft "WRONG pass"
|
:note "WRONG pass"
|
||||||
:password "qwerty1" }) 403))
|
:password "qwerty1" }) 403))
|
||||||
(is (substring? "test note"
|
(is (substring? "test note" ((send-request (url year month day title)) :body)))
|
||||||
((send-request (url year month day title)) :body)))
|
|
||||||
(is (has-status
|
(is (has-status
|
||||||
(send-request
|
(send-request
|
||||||
[:post "/update-note"]
|
[:post "/update-note"]
|
||||||
{:key (build-key [year month day] title)
|
{:noteID (build-key [year month day] title)
|
||||||
:draft "UPDATED CONTENT"
|
:note "UPDATED CONTENT 123"
|
||||||
:password "qwerty" }) 302))
|
:password "qwerty" }) 302))
|
||||||
(is (substring? "UPDATED CONTENT"
|
(is (substring? "UPDATED CONTENT" ((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))))))))
|
||||||
@@ -100,13 +98,3 @@
|
|||||||
(is (has-status (send-request (url 2012 6 3 "some-title" "export")) 200) "accessing test note's export")
|
(is (has-status (send-request (url 2012 6 3 "some-title" "export")) 200) "accessing test note's export")
|
||||||
(is (has-status (send-request (url 2012 6 3 "some-title" "stats")) 200) "accessing test note's stats")
|
(is (has-status (send-request (url 2012 6 3 "some-title" "stats")) 200) "accessing test note's stats")
|
||||||
(is (has-status (send-request "/") 200) "accessing landing page"))))
|
(is (has-status (send-request "/") 200) "accessing landing page"))))
|
||||||
|
|
||||||
(deftest hash-function
|
|
||||||
(testing "Self-made hash function"
|
|
||||||
(testing "for correct hashes"
|
|
||||||
(is (= 0 (get-hash "")))
|
|
||||||
(is (= 6178 (get-hash "test тест")))
|
|
||||||
(is (= 6178 (get-hash (str "test\n \rтест"))))
|
|
||||||
(is (= 274 (get-hash "Hello world!"))))
|
|
||||||
(testing "for a wrong hash"
|
|
||||||
(is (not= 6178 (get-hash "wrong hash"))))))
|
|
||||||
|
|||||||
Reference in New Issue
Block a user