Yu-Gi-Oh! Deck Building and Card Inventory Management web interface written in Common Lisp, utilizing HTMX.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

172 lignes
6.1KB

  1. #|
  2. src/web/label-maker.lisp
  3. Label Maker Front-End
  4. https://www.uline.com/product/detail/s-20247/store-fixtures/price-tag-insert-cards-1-1-4-x-2
  5. Supports arbitrary number of labels.
  6. Currently tested with LABELS-LENGTH set to 32 (ULINE S-20247) or 30 (Avery 5160).
  7. We generate a LaTeX file then use PDFLaTeX to produce a pdf in
  8. GENERATE-LABELS-FOR-ATTACHMENT-ID.
  9. The barcodes are generated by ZXingWriter.
  10. TODO A lot of functionality that resides in the web interface needs to be moved to the model interface:
  11. - public-relative-pathname
  12. - generate-labels
  13. - generate-labels-for-attachment
  14. - generate-labels-for-attachment-id
  15. - *current-label-class*
  16. |#
  17. (in-package #:cl-user)
  18. (defpackage #:cl-deck-builder2.web.label-maker
  19. (:use #:cl
  20. #:cl-deck-builder2.models.label-maker)
  21. (:import-from #:caveman2
  22. #:<app>
  23. #:defroute
  24. #:redirect
  25. #:clear-routing-rules)
  26. (:import-from #:cl-deck-builder2.i18n
  27. #:_)
  28. (:import-from #:cl-deck-builder2.toolkit
  29. #:query-param
  30. #:random-pathname-name)
  31. (:import-from #:cl-deck-builder2.web
  32. #:flash-error
  33. #:flash-message
  34. #:render-with-env
  35. #:render-markdown-file)
  36. (:import-from #:cl-deck-builder2.web.query
  37. #:select-attachment-by-id)
  38. (:import-from #:cl-deck-builder2.models.attachment
  39. #:attachment-valid-p
  40. #:create-attachment)
  41. (:import-from #:cl-deck-builder2.config
  42. #:*public-directory*
  43. #:*static-directory*
  44. #:*template-directory*)
  45. (:local-nicknames (#:v #:org.shirakumo.verbose))
  46. (:export #:*web*))
  47. (in-package #:cl-deck-builder2.web.label-maker)
  48. (defclass <web> (<app>) ())
  49. (defvar *web* (make-instance '<web>))
  50. (clear-routing-rules *web*)
  51. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  52. (defparameter *base-pathspec* #P"/tmp/labels/")
  53. (defparameter *current-label-class* 'latex-label-uline-s-20247
  54. "The most recently used class for making labels.
  55. The idea was you could select the types of labels from a select box on the Label Maker page.")
  56. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  57. (defun public-relative-pathname (pathspec)
  58. "PROBE-FILE on PATHSPEC in *PUBLIC-DIRECTORY*.
  59. TODO I think this is duplicate code from TOOLKIT.PATHS."
  60. (probe-file
  61. (merge-pathnames
  62. pathspec
  63. cl-deck-builder2.config:*public-directory*)))
  64. ;; TODO All of this needs to be rewritten in some kind of pipeline form.
  65. (defun generate-labels (output &key (class 'latex-label-uline-s-20247) csv pdf tex)
  66. "Create output with RENDER-PAGE."
  67. (ensure-directories-exist *base-pathspec*)
  68. (let ((page (make-instance class :csv csv)))
  69. (with-open-file (s tex
  70. :if-exists :supersede
  71. :direction :output)
  72. (format s "~a" (render-page page))))
  73. (uiop:delete-file-if-exists (probe-file #P"~/public/labels.pdf"))
  74. (if (inferior-shell:run
  75. `(and
  76. (cd "/tmp/labels/")
  77. (pdflatex ,tex)
  78. (mv ,pdf ,output)))
  79. output))
  80. ;; TODO ENOUGH-PATHNAME
  81. ;; TODO rewrite this using defclass like we did for CARDINFO
  82. (defun generate-labels-for-attachment (path file-key)
  83. (generate-labels (make-pathname :name file-key
  84. :type "pdf"
  85. :directory (namestring *public-directory*))
  86. :class *current-label-class*
  87. :csv path
  88. :tex #P"/tmp/labels/labels.tex"
  89. :pdf #P"/tmp/labels/labels.pdf"))
  90. (defun generate-labels-for-attachment-id (id)
  91. (let ((found (select-attachment-by-id id)))
  92. (when found
  93. (generate-labels-for-attachment
  94. (public-relative-pathname
  95. (;; Trim leading "/"
  96. subseq
  97. (namestring (mito-attachment:file-url found)) 1))
  98. (pathname-name
  99. (mito-attachment:file-key found))))))
  100. (defun label-maker-process-files (files)
  101. "Process FILES with ATTACHMENT-VALID-P, CREATE-ATTACHMENT, then GENERATE-LABELS-FOR-ATTACHMENT-ID."
  102. (dolist (file files)
  103. (if (attachment-valid-p file)
  104. (destructuring-bind (content filename content-type)
  105. file
  106. (setf filename (random-pathname-name :type (pathname-type filename)))
  107. (let ((success (create-attachment content filename content-type)))
  108. (if success
  109. (progn
  110. ;; Create ATTACHMENT was successful
  111. (generate-labels-for-attachment-id (mito:object-id success))
  112. (flash-message (format nil (_ "Success! Download link: <a href=\"/public/~a.pdf\">labels.pdf</a>")
  113. (pathname-name
  114. (mito-attachment:file-key success)))))
  115. (flash-error (_ "Something went wrong. Try again?")))))
  116. (flash-error (_ "Invalid upload.")))))
  117. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  118. (defroute ("/" :method :GET) ()
  119. "Label Maker Main Route."
  120. (render-with-env #P"label-maker.html"
  121. `(:active "/label-maker")))
  122. (defroute ("/instructions" :method :GET) ()
  123. "Display Label Maker Instructions using RENDER-MARKDOWN-FILE."
  124. (render-markdown-file
  125. (asdf:system-relative-pathname :cl-deck-builder2 "doc/label-maker.md")))
  126. (defroute ("/" :method :POST) (&key _parsed)
  127. "Label Maker POST route.
  128. TODO Parameters: FILES A list of CSV files to process. CLASS the class of label you wish to generate. May be one of LATEX-LABEL-ULINE-S-20247 or LATEX-LABEL-AVERY-5160."
  129. (v:info :label-maker "POST /label-maker => ~a" _parsed)
  130. (let ((files (query-param "files" _parsed))
  131. (class (query-param "class" _parsed)))
  132. ;; Check the CLASS parameter
  133. (setf *current-label-class*
  134. (find-class
  135. (cond ((string= class "latex-label-uline-s-20247") 'latex-label-uline-s-20247)
  136. (t 'latex-label-avery-5160))))
  137. (if files
  138. (label-maker-process-files files)
  139. (flash-error (_ "No files.")))
  140. (redirect "/label-maker")))