diff options
author | Tom Willemse | 2013-06-30 22:38:05 +0200 |
---|---|---|
committer | Tom Willemse | 2013-07-01 00:01:48 +0200 |
commit | a9935738595c7fcbf78696a67d9e31b45830297f (patch) | |
tree | b8c1a46d3ee8280af3dc46129975dcff8c628a5e /scrumli.lisp | |
download | scrumli-a9935738595c7fcbf78696a67d9e31b45830297f.tar.gz scrumli-a9935738595c7fcbf78696a67d9e31b45830297f.zip |
Initial commit
Diffstat (limited to 'scrumli.lisp')
-rw-r--r-- | scrumli.lisp | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/scrumli.lisp b/scrumli.lisp new file mode 100644 index 0000000..39a7039 --- /dev/null +++ b/scrumli.lisp @@ -0,0 +1,153 @@ +(in-package #:scrumli) + +(defvar *scrumli-host* "http://localhost:8080" + "The host currently running Scrumli. Used by Mozilla Persona.") + +(defvar *scrumelo-bootstrap-css-location* + "http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.no-icons.min.css" + "The location of the twitter bootstrap CSS file.") + +(defvar *scrumelo-bootstrap-js-location* + "http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js" + "The location of the twitter bootstrap JS file.") + +(defvar *scrumelo-font-awesome-css-location* + "http://netdna.bootstrapcdn.com/font-awesome/3.1.1/css/font-awesome.min.css" + "The location of the font awesome CSS file.") + +(defvar *scrumelo-jquery-js-location* + "http://code.jquery.com/jquery-2.0.0.min.js" + "The location of the jQuery JS file.") + +(defvar *scrumelo-react-js-location* + "http://cdnjs.cloudflare.com/ajax/libs/react/0.3.2/react.min.js" + "The location of the React JS file.") + +(defvar *scrumelo-jsxtransformer-js-location* + "http://cdnjs.cloudflare.com/ajax/libs/react/0.3.2/JSXTransformer.js" + "The location of the JSX Transformer JS file.") + +(defun logged-in-p () + (hunchentoot:session-value :username)) + +(define-route main ("") + (if (logged-in-p) + (<:html + (<:head (<:title "Hello!") + (<:link :href *scrumelo-bootstrap-css-location* + :rel "stylesheet" :type "text/css") + (<:link :href *scrumelo-font-awesome-css-location* + :rel "stylesheet" :type "text/css") + (<:script :type "text/javascript" + :src *scrumelo-bootstrap-js-location*) + (<:script :type "text/javascript" + :src *scrumelo-jquery-js-location*) + (<:script :type "text/javascript" + :src *scrumelo-react-js-location*) + (<:script :type "text/javascript" + :src *scrumelo-jsxtransformer-js-location*)) + (<:body + (<:a :href "/logout" "Logout") " " + (hunchentoot:session-value :username) + (<:div :class "container" + (<:h1 "Backlog") + (<:div :id "content") + (<:script :type "text/jsx" :src "js/main.js")))) + (redirect 'login-page))) + +(define-route react-ui ("js/main.js" + :content-type "application/ecmascript") + (merge-pathnames "js/main.js" *static-directory*)) + +(define-route login-js ("js/login.js" + :content-type "application/ecmascript") + (merge-pathnames "js/login.js" *static-directory*)) + +(define-route stories-json ("stories" :content-type "text/json") + (if (logged-in-p) + (with-output-to-string (out) + (encode-json (get-all-stories) out)) + 403)) + +(define-route stories-new ("stories/new" :method :post) + (if (logged-in-p) + (let ((role (hunchentoot:post-parameter "role")) + (necessity (hunchentoot:post-parameter "necessity")) + (title (hunchentoot:post-parameter "headline")) + (content (hunchentoot:post-parameter "content"))) + (format t "~s;~s;~s;~s;~s~%" role necessity title content + (hunchentoot:session-value :username)) + (post-story role necessity title content + (hunchentoot:session-value :username)) + 200) + 403)) + +(define-route stories-state ("stories/state" :method :post) + (if (logged-in-p) + (let* ((id (hunchentoot:post-parameter "id")) + (current-state (story-get-state id))) + (story-set-state id (ecase (intern current-state :scrumli) + (todo "DOING") + (doing "DONE") + (done "TODO"))) + 200) + 403)) + +(define-route stories-priority ("stories/:dir" :method :post) + (if (logged-in-p) + (let* ((id (hunchentoot:post-parameter "id"))) + (story-change-priority id (intern (string-upcase dir) :keyword)) + 200) + 403)) + +(define-route login-page ("login") + (if (not (logged-in-p)) + (<:html :lang "en" + (<:head (<:meta :charset "utf-8") + (<:title "Login") + (<:script :src "https://login.persona.org/include.js") + (<:script :src "/js/login.js")) + (<:body + (<:form :id "login-form" :method "POST" :action "" + (<:input :id "assertion-field" :type "hidden" + :name "assertion" :value "")) + (<:p (<:a :href "javascript:login()" "Login")))) + (redirect 'main))) + +(define-route logout-page ("logout") + (if (logged-in-p) + (progn + (setf (hunchentoot:session-value :username) nil))) + (redirect 'login-page)) + +(defun json-to-string (obj) + (with-output-to-string (out) + (encode-json obj out))) + +(defun verify-credentials (audience assertion) + (let ((response + (http-request "https://verifier.login.persona.org/verify" + :method :post :content-type "application/json" + :content (json-to-string + `(("assertion" . ,assertion) + ("audience" . ,audience))) + :want-stream t))) + (decode-json response))) + +(define-route login-page/post ("login" :method :post) + (let ((result (verify-credentials + *scrumli-host* + (hunchentoot:post-parameter "assertion")))) + (if (equal (cdr (assoc :status result)) "okay") + (progn + (hunchentoot:start-session) + (setf (hunchentoot:session-value :username) + (cdr (assoc :email result))) + (redirect 'main)) + 403))) + +(define-route scrumelo-story ("stories/:id") + (if (logged-in-p) + (with-output-to-string (out) + (encode-json (get-story id) out)) + 403)) |