Refactor file/dir operations

This commit is contained in:
Marcus Kammer 2024-06-12 22:24:00 +02:00
parent 6c754876e7
commit e8b6d97b83
Signed by: marcuskammer
GPG key ID: C374817BE285268F
8 changed files with 98 additions and 81 deletions

View file

@ -10,6 +10,7 @@
((:module "src" ((:module "src"
:components :components
((:file "package") ((:file "package")
(:file "fileops")
(:file "app") (:file "app")
(:file "survey"))) (:file "survey")))

75
src/fileops.lisp Normal file
View file

@ -0,0 +1,75 @@
(in-package :ml-survey)
(defun base-dir ()
(let ((os (uiop:detect-os)))
(cond ((eq os :os-windows)
(format nil "~a/" (uiop:getenv "LOCALAPPDATA")))
((eq os :os-unix)
(format nil "~a" (uiop:merge-pathnames*
".local/share/"
(format nil
"~a/"
(uiop:getenv "HOME")))))
((eq os :os-macos)
(format nil "~a" (uiop:merge-pathnames*
"Library/Application Support/"
(format nil
"~a/"
(uiop:getenv "HOME")))))
(t (error "Unsupported OS")))))
(defun app-dir ()
(uiop:merge-pathnames* "ml-survey/" (base-dir)))
(defun data-dir ()
(uiop:merge-pathnames* "data/surveys/" (app-dir)))
(defun ensure-data-dir ()
(let ((data-dir (data-dir)))
(ensure-directories-exist (data-dir))
data-dir))
(defun ensure-file-exist (pathname)
"Ensure that a file specified by PATHNAME exists, create it if it doesn't."
(unless (uiop:file-exists-p pathname)
(with-open-file (stream pathname
:direction :output
:if-exists :overwrite
:if-does-not-exist :create)
(format stream "")))
pathname)
(defun ensure-data-file-exist (survey-id questionnaire-id)
(let ((path (format nil "~a~a/~a.lisp"
(ensure-data-dir)
survey-id
questionnaire-id)))
(ensure-directories-exist path)
(ensure-file-exist path)))
(defun make-db-file (file)
"Prepare and ensure a database file at FILE-STR path."
(check-type file string)
(let ((path (uiop:merge-pathnames* file (ensure-data-dir))))
(ensure-file-exist path)))
(defun load-response (db)
(check-type db (or string pathname))
(with-open-file (stream db
:direction :input
:if-does-not-exist :create)
(if (= (file-length stream) 0)
(list)
(read stream))))
(defun store-response (db responses)
(check-type db (or string pathname))
(check-type responses list)
(with-open-file (stream db
:direction :output
:if-exists :supersede)
(prin1 responses stream)))

View file

@ -1,37 +1,5 @@
(in-package :ml-survey/handlers) (in-package :ml-survey/handlers)
(defun base-dir ()
(let ((os (uiop:detect-os)))
(cond ((eq os :os-windows)
(format nil "~a/" (uiop:getenv "LOCALAPPDATA")))
((eq os :os-unix)
(format nil "~a" (uiop:merge-pathnames*
".local/share/"
(format nil
"~a/"
(uiop:getenv "HOME")))))
((eq os :os-macos)
(format nil "~a" (uiop:merge-pathnames*
"Library/Application Support/"
(format nil
"~a/"
(uiop:getenv "HOME")))))
(t (error "Unsupported OS")))))
(defun app-dir ()
(uiop:merge-pathnames* "ml-survey/" (base-dir)))
(defun data-dir ()
(uiop:merge-pathnames* "data/surveys/" (app-dir)))
(defun ensure-data-dir ()
(let ((data-dir (data-dir)))
(ensure-directories-exist (data-dir))
data-dir))
(defun split-uri (uri) (defun split-uri (uri)
(check-type uri string) (check-type uri string)
(remove-if #'string-empty-p (remove-if #'string-empty-p
@ -56,50 +24,6 @@
(local-time:now) (local-time:now)
:format '((:hour 2) ":" (:min 2) ":" (:sec 2)))) :format '((:hour 2) ":" (:min 2) ":" (:sec 2))))
(defun ensure-file-exist (pathname)
"Ensure that a file specified by PATHNAME exists, create it if it doesn't."
(unless (uiop:file-exists-p pathname)
(with-open-file (stream pathname
:direction :output
:if-exists :overwrite
:if-does-not-exist :create)
(format stream "")))
pathname)
(defun ensure-data-file-exist (survey-id questionnaire-id)
(let ((path (format nil "~a~a/~a.lisp"
(ensure-data-dir)
survey-id
questionnaire-id)))
(ensure-directories-exist path)
(ensure-file-exist path)))
(defun make-db-file (file)
"Prepare and ensure a database file at FILE-STR path."
(check-type file string)
(let ((path (uiop:merge-pathnames* file (ensure-data-dir))))
(ensure-file-exist path)))
(defun make-surveys-db-file ()
(make-db-file "surveys-db.lisp"))
(defun load-response (db)
(check-type db (or string pathname))
(with-open-file (stream db
:direction :input
:if-does-not-exist :create)
(if (= (file-length stream) 0)
(list)
(read stream))))
(defun store-response (db responses)
(check-type db (or string pathname))
(check-type responses list)
(with-open-file (stream db
:direction :output
:if-exists :supersede)
(prin1 responses stream)))
(defun generate-uuid () (defun generate-uuid ()
(parse-integer (format nil "~A~A~A" (parse-integer (format nil "~A~A~A"
(sb-posix:getpid) (sb-posix:getpid)

View file

@ -9,4 +9,10 @@
#:content-type* #:content-type*
#:request-uri #:request-uri
#:request-uri* #:request-uri*
#:*request*)) #:*request*)
(:import-from #:ml-survey
#:ensure-data-dir
#:ensure-data-file-exist
#:store-response
#:load-response
#:make-surveys-db-file))

View file

@ -20,20 +20,20 @@
(defun process-questionnaire-get (lang s) (defun process-questionnaire-get (lang s)
(check-type lang string) (check-type lang string)
(check-type s survey) (check-type s ml-survey:survey)
(setf *html-lang* lang) (setf *html-lang* lang)
(funcall (choose-sus-form lang) (survey-id s))) (funcall (choose-sus-form lang) (ml-survey:survey-id s)))
(defun process-questionnaire-post (request s) (defun process-questionnaire-post (request s)
(let ((post-params (post-parameters* request)) (let ((post-params (post-parameters* request))
(questionnaire-id (generate-uuid))) (questionnaire-id (generate-uuid)))
(store-response (ensure-data-file-exist (survey-id s) (store-response (ensure-data-file-exist (ml-survey:survey-id s)
questionnaire-id) questionnaire-id)
post-params) post-params)
(ml-survey/views:questionnaire-submit))) (ml-survey/views:questionnaire-submit)))
(define-easy-handler (questionnaire :uri #'questionnaire-uri) (lang) (define-easy-handler (questionnaire :uri #'questionnaire-uri) (lang)
(let ((s (make-instance 'survey :id (get-survey-id (request-uri*))))) (let ((s (make-instance 'ml-survey:survey :id (get-survey-id (request-uri*)))))
(cond ((eq (hunchentoot:request-method*) :get) (cond ((eq (hunchentoot:request-method*) :get)
(process-questionnaire-get lang s)) (process-questionnaire-get lang s))
((eq (hunchentoot:request-method*) :post) ((eq (hunchentoot:request-method*) :post)

View file

@ -8,6 +8,11 @@
#:survey-data-dir-p #:survey-data-dir-p
#:survey-data-dir-files #:survey-data-dir-files
#:survey-html #:survey-html
#:ensure-data-dir
#:ensure-data-file-exist
#:store-response
#:load-response
#:make-surveys-db-file
#:start #:start
#:*app* #:*app*
#:set-default-directory #:set-default-directory

View file

@ -1,3 +1,8 @@
(in-package :ml-survey)
(defun make-surveys-db-file ()
(make-db-file "surveys-db.lisp"))
(defclass survey () (defclass survey ()
((id :initarg :id :reader survey-id) ((id :initarg :id :reader survey-id)
(data-dir :initarg :data-dir :reader survey-data-dir) (data-dir :initarg :data-dir :reader survey-data-dir)

View file

@ -1,6 +1,7 @@
(in-package :ml-survey/views) (in-package :ml-survey/views)
(defun survey (survey &optional results) (defun survey (survey &optional results)
(check-type survey ml-survey:survey)
"Generates the view to show the survey created." "Generates the view to show the survey created."
(with-page (:title "Survey Details") (with-page (:title "Survey Details")
(navbar-en) (navbar-en)