diff options
author | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2009-11-29 00:27:23 +0100 |
---|---|---|
committer | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2009-11-29 00:27:23 +0100 |
commit | 268267c9e45351322ec61800f5b9900d83f40a24 (patch) | |
tree | e78bae16dcef5d664f78b0749330d73a96472a8c /logikorr.lisp | |
parent | 55ca2cac7bb7df1c5c0ccd4063729f8659a0b020 (diff) |
Beginning of a rewrite in Clojure for use on the Google App Engine.
Diffstat (limited to 'logikorr.lisp')
-rw-r--r-- | logikorr.lisp | 273 |
1 files changed, 0 insertions, 273 deletions
diff --git a/logikorr.lisp b/logikorr.lisp deleted file mode 100644 index 013ef59..0000000 --- a/logikorr.lisp +++ /dev/null @@ -1,273 +0,0 @@ -;;; Copyright 2009, Matthias Andreas Benkard. - -(defpackage :logikorr-ht - (:use #:hunchentoot #:common-lisp #:json #:cl-who)) - -(in-package #:logikorr-ht) - -(defstruct student - (id -1 :type integer) - (score #() :type vector) - (last-name "" :type (or string null)) - (first-name "" :type (or string null))) - -(defparameter *directory* (asdf:component-pathname (asdf:find-system '#:logikorr))) -(defparameter *in-locked-context-p* nil) - -(defvar *students* nil) -(defvar *database* nil) -(defvar *database-directory* (merge-pathnames #p"data/" *directory*)) -(defvar *lock* (merge-pathnames #p".mulk-db-lock" *database-directory*)) - -(defvar *password-file* (merge-pathnames #p"password.txt" *directory*)) -(defvar *password* - (with-open-file (in *password-file* :direction :input) - (read-line in))) - -(setq *hunchentoot-default-external-format* - (flexi-streams:make-external-format :utf-8)) - -(defun find-and-initialise-database () - (let* ((files (directory (merge-pathnames #p"*.txt" *database-directory*))) - (sorted-files (sort files #'> - :key (lambda (x) - (parse-integer (pathname-name x)))))) - (setq *database* (first sorted-files)))) - -(defun make-new-revision () - (find-and-initialise-database) - (let* ((name (pathname-name *database*)) - (number (parse-integer name)) - (new-path (merge-pathnames (make-pathname :name (format nil "~D" (1+ number))) - *database*))) - (find-students) - (write-database-to-file new-path) - (setq *database* new-path) - (1+ number))) - -(defmacro with-authentication (() &body body) - `(call-with-authentication (lambda () ,@body))) - -(defun call-with-authentication (thunk) - (multiple-value-bind (name password) - (authorization) - (if (and (string= name "logik") (string= password *password*)) - (funcall thunk) - (progn - (require-authorization "Logik-Ergebniseingabe"))))) - -(defmacro with-data-lock (() &body body) - `(call-with-data-lock (lambda () ,@body))) - -(defun call-with-data-lock (thunk) - (cond (*in-locked-context-p* - (funcall thunk)) - (t - (let (lock) - (unwind-protect - (progn - (loop until (setq lock (open *lock* :direction :output :if-exists nil :if-does-not-exist :create))) - (let ((*in-locked-context-p* t)) (funcall thunk))) - (progn (ignore-errors (delete-file *lock*)) - (ignore-errors (close lock)))))))) - - -(defun find-students () - (find-and-initialise-database) - (with-data-lock () - (setq - *students* - (with-open-file (in *database* :external-format :utf-8) - (loop for line = (read-line in nil nil nil) - with id = 0 - while line - unless (equal (remove #\Space line) "") - collect (let* ((name line) - (score-line (read-line in t)) - (score (read-from-string score-line)) - (comma (position #\, name)) - (last-name (if comma (subseq name 0 comma) nil)) - (first-name (if comma (subseq name (+ comma 2)) name))) - (make-student :id id - :score (make-array (list (length score)) - :initial-contents score - :adjustable t - :fill-pointer t) - :last-name last-name - :first-name first-name)) - and do (incf id)))))) - -(define-easy-handler (show-main-page :uri "/") () - (with-authentication () - (let ((students (find-students))) - (ignore-errors (setf (header-out :content-type) "text/html; charset=UTF-8")) - (with-html-output-to-string (html) - (:html - (:head - (:title "Logik I: Korrekturergebnisse") - (:script :type "text/javascript" - :src "js/prototype.js") - (:script :type "text/javascript" - :src "js/scriptaculous.js") - (:link :type "text/css" :rel "stylesheet" :href "style.css") - (:script :type "text/javascript" :src "http://yui.yahooapis.com/3.0.0/build/yui/yui-min.js") - (:script :type "text/javascript" :src "logikorr.js") - (:script :type "text/javascript" :src "logikorr-completion-data.js")) - (:body - (:h1 "Logik I: Korrekturergebnisse") - (:h2 "Neue Ergebnisse") - (:form (:button :type "button" :id "make-revision" - (esc "Aktuelle Version sichern")) - (:div :id "new-version-label" :style "display: inline; color: #070")) - (:table :id "ergebnisse") - (:h2 "Bestehende Ergebnisse") - (:table - (:tr - (:th "ID") (:th "Punkte") (:th "Nachname") (:th "Vorname")) - (dolist (student students) - (with-slots (id score last-name first-name) student - (htm (:tr (:td (str id)) - (:td (str score)) - (:td (esc last-name)) - (:td (esc first-name))))))))))))) - - -(define-easy-handler (logikorr.js :uri "/logikorr.js") () - (handle-static-file (relpath "logikorr.js"))) - -(define-easy-handler (logikorr-completion-data.js :uri "/logikorr-completion-data.js") () - (with-authentication () - (ignore-errors (setf (header-out :content-type) "text/javascript; charset=UTF-8")) - (format nil "~%autocompleteList = ~A" - (json:encode-json-to-string (mapcar (lambda (x) (unsplit-name (student-first-name x) (student-last-name x))) - (find-students)))))) - - -(define-easy-handler (style.css :uri "/style.css") () - (setf (header-out :content-type) "text/css; charset=UTF-8") - "body { - z-index: 0; -} - -div.autocomplete { - position:absolute; - width:350px; - background-color:white; - border:1px solid #888; - margin:0; - padding:0; - z-index: 100; -} -div.autocomplete ul { - list-style-type:none; - margin:0; - padding:0; -} -div.autocomplete ul li.selected { background-color: #ffb;} -div.autocomplete ul li { - list-style-type:none; - display:block; - margin:0; - padding:2px; - height:32px; - cursor:pointer; -}") - -(defun relpath (path) - (merge-pathnames path *directory*)) - -(define-easy-handler (s1.js :uri "/js/builder.js") () - (handle-static-file (relpath "js/builder.js"))) - -(define-easy-handler (s2.js :uri "/js/scriptaculous.js") () - (handle-static-file (relpath "js/scriptaculous.js"))) - -(define-easy-handler (s3.js :uri "/js/controls.js") () - (handle-static-file (relpath "js/controls.js"))) - -(define-easy-handler (s4.js :uri "/js/dragdrop.js") () - (handle-static-file (relpath "js/dragdrop.js"))) - -(define-easy-handler (s5.js :uri "/js/effects.js") () - (handle-static-file (relpath "js/effects.js"))) - -(define-easy-handler (s6.js :uri "/js/prototype.js") () - (handle-static-file (relpath "js/prototype.js"))) - -(define-easy-handler (scriptaculous.js :uri "/js/scriptaculous.js") () - (handle-static-file (relpath "js/scriptaculous.js"))) - -(define-easy-handler (s8.js :uri "/js/slider.js") () - (handle-static-file (relpath "js/slider.js"))) - -(define-easy-handler (s9.js :uri "/js/sound.js") () - (handle-static-file (relpath "js/sound.js"))) - -(define-easy-handler (s10.js :uri "/js/unittest.js") () - (handle-static-file (relpath "js/unittest.js"))) - -(defun unsplit-name (first last) - (if last - (format nil "~A, ~A" last first) - first)) - -(defun find-student-by-name (name) - (dolist (student (find-students)) - (when (string= name (unsplit-name (student-first-name student) - (student-last-name student))) - (return-from find-student-by-name student)))) - -(defun find-student-by-id (id) - (find id (find-students) :key #'student-id)) - -(define-easy-handler (find-student :uri "/find-student") (name) - (with-authentication () - (let ((student (find-student-by-name name))) - (setf (header-out :content-type) "text/json; charset=UTF-8") - (with-slots (id first-name last-name score) student - (with-output-to-string (*standard-output*) - (json:encode-json-plist - (list :id id - :first-name first-name - :last-name last-name - :score score))))))) - -(define-easy-handler (update-student-score :uri "/update-student-score") - (id score-number score) - (with-authentication () - (with-data-lock () - (let ((student (find-student-by-id (parse-integer id))) - (index (parse-integer score-number))) - (loop while (<= (length (student-score student)) index) - do (vector-push-extend 0 (student-score student))) - (setf (elt (student-score student) index) - (let ((*read-eval* nil)) - (let ((score (read-from-string score))) - (check-type score number) - score)))) - (write-database))) - "\"OK\"") - -(define-easy-handler (create-new-revision :uri "/make-new-revision") - () - (with-authentication () - (format nil "~D" (make-new-revision)))) - -(defun write-database () - (find-and-initialise-database) - (write-database-to-file *database*)) - -(defun write-database-to-file (file) - (with-data-lock () - (unless *students* - (return-from write-database-to-file)) - (with-open-file (out file :external-format :utf-8 :direction :output :if-exists :new-version #+(or) :supersede) - (dolist (student *students*) - (if (student-last-name student) - (format out "~&~A, ~A" (student-last-name student) (student-first-name student)) - (format out "~&~A" (student-first-name student))) - (format out "~&(~{~3S~^ ~} )" (coerce (student-score student) 'list)) - (format out "~%~%"))))) - -(defun start-logikorr () - (start (make-instance 'acceptor :port 8080))) |