| (in-package :forms) |
|
|
| (defclass file-form-field (form-field) |
| ((multiple :initarg :multiple-p |
| :accessor multiple-p |
| :initform nil |
| :documentation "If this fields handles multiple file uploads") |
| (path :initarg :path |
| :accessor file-path |
| :initform nil) |
| (file-name :initarg :file-name |
| :accessor file-name |
| :initform nil) |
| (content-type :initarg :content-type |
| :accessor file-content-type |
| :initform nil) |
| (upload-handler :initarg :upload-handler |
| :accessor upload-handler |
| :initform nil |
| :documentation "Function that handles the file upload") |
| (accept :initarg :accept |
| :accessor file-accept |
| :type (or null string) |
| :initform nil |
| :documentation "Files accepted. See https://www.w3schools.com/tags/att_input_accept.asp")) |
| (:documentation "A file input field")) |
|
|
| (defmethod field-read-from-request ((field file-form-field) form parameters) |
| (let ((fvalue |
| (cdr (assoc (field-request-name field form) parameters :test #'string=)))) |
| (if (and fvalue (listp fvalue)) |
| (destructuring-bind (path file-name content-type) fvalue |
| (setf (file-path field) path) |
| (setf (file-name field) file-name) |
| (setf (file-content-type field) content-type) |
| (when (upload-handler field) |
| (funcall (upload-handler field) field))) |
| |
| (progn |
| (warn "CL-FORMS: Could not read file field file: ~a." field) |
| (when (not (equalp (form-enctype form) "multipart/form-data")) |
| (warn "CL-FORMS: Encoding type in forms should be set to 'multipart/form-data' for file uploads.")))) |
| |
| (setf (field-value field) fvalue))) |
|
|
| (defmethod make-form-field ((field-type (eql :file)) &rest args) |
| (apply #'make-instance 'file-form-field args)) |
|
|
| |
|
|
| (defclass stateful-file-field (forms::file-form-field) |
| ((download-link :initarg :download-link |
| :type (or null string symbol function) |
| :initform nil |
| :documentation "Function to generate the download link to the file")) |
| (:documentation "An stateful file field is a file field that mantains its value (the uploaded file data) and renders the the uploaded file download link and a file upload widget")) |
|
|
| (defmethod download-link ((field stateful-file-field)) |
| (with-slots (download-link) field |
| (if (stringp download-link) |
| download-link |
| (funcall download-link field)))) |
|
|
| (defmethod forms::field-read-from-request ((field stateful-file-field) form parameters) |
| (let ((fvalue |
| (cdr (assoc (forms::field-request-name field form) parameters :test #'string=)))) |
| (if (and fvalue (listp fvalue)) |
| |
| (destructuring-bind (path file-name content-type) fvalue |
| (setf (forms::file-path field) path) |
| (setf (forms::file-name field) file-name) |
| (setf (forms::file-content-type field) content-type) |
| (when (forms::upload-handler field) |
| (funcall (forms::upload-handler field) field))) |
| |
| (let ((file-info |
| (cdr (assoc (format nil "~A.info" (forms::field-request-name field form)) parameters :test #'string=)))) |
| (when file-info |
| (let ((finfo (read-from-string (base64:base64-string-to-string file-info)))) |
| (setf (forms::file-path field) (getf finfo :path) |
| (forms::file-name field) (getf finfo :file-name) |
| (forms::file-content-type field) (getf finfo :content-type)))))))) |
|
|
| (defmethod forms::make-form-field ((field-type (eql :stateful-file)) &rest args) |
| (apply #'make-instance 'stateful-file-field args)) |
|
|