|
- #|
-
- src/web/construct-decks.lisp
-
- Web Routes For Construct Decks
-
- TODO Pick one: /construct/ or /construct/ ?
-
- Features Requsted:
-
- - DONE Card Names
- - DONE Card Prices - I think we'll need to wire this up to the
- YGO-CC-ITEM. That requires rewriting that component to use the new
- YGO-SET instead of the CSV.
- - DONE Sort by Price - Honestly having trouble sorting this junk lmao!
- - Show only YGO-SET-ITEMS with inventory - see constructed-decks.lisp<models>
-
-
- |#
-
- (in-package #:cl-deck-builder2.web)
-
- (defparameter *current-constructed-deck* nil)
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defun render-construct-deck (id tpl)
- (with-logged-in-user
- (let ((deck (first
- (select-constructed-decks
- (sxql:where (:= :id id))))))
- (when deck
- (render-with-env tpl
- (list :active "/construct"
- :deck deck
- :id (mito:object-id deck)
- :name (cl-deck-builder2.models.constructed-decks::deck-name-of deck)
- :saved-deck-list (select-constructed-decks)))))))
-
- ;; I think this takes a CAR and a CDR pair of YGO-SET ID and VARIANT ID
- ;; I'm pretty sure it's supposed to be finding YGO-SET-ITEMs though
- (defun selected-sets-to-deck-listing (cards)
- (let ((lst '()))
- (with-connection (db)
- (with-transaction
- (dolist (card cards (reverse lst))
- (destructuring-bind (set variant)
- card
- (let* ((set-id (cdr set))
- (variant-id (cdr variant))
- (set-item (first (ygo-select-set-item set-id variant-id)))
- (set (first (ygo-set (sxql:where (:= :id set-id)))))
- (variant (mito:find-dao 'variant-condition :id variant-id)))
- (with-slots ((passcode-id cl-deck-builder2.models.ygoprodeck.classes::passcode-id))
- set
- (push (list :deck-set set
- :condition variant
- :set-item set-item
- :card (ygo-card-by-passcode passcode-id))
- lst)))))))))
-
- ;; XXX Where does this go? What does this accomplish?
- (defun select-deck-as-plist (id)
- (let ((lst '()))
- (dolist (itm (retrieve-dao 'deck-item :deck-id id) (reverse lst))
- (push (list :deck-item itm) lst))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defun default-constructed-deck-is-valid-to-pull ()
- (valid-pull-p
- (deck-to-pull-set-items-qty-as-alist *current-constructed-deck*)
- (deck-to-pull-desired-qty-as-alist *current-constructed-deck*)))
-
- (defun default-constructed-deck-invalid-qtys ()
- (find-any-invalid-qtys
- (deck-to-pull-set-items-qty-as-alist *current-constructed-deck*)
- (deck-to-pull-desired-qty-as-alist *current-constructed-deck*)))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defun store-combined-deck-as-current (original-deck selected-listing)
- (setf *current-constructed-deck*
- (loop for original in (reverse original-deck)
- for selected in selected-listing
- collect (apply #'make-instance 'constructed-deck-intermediate (append original selected)))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; We have to actually pull the inventory.
- ;; This is the old code but it's written for YDK-DECK object so maybe I'll write one for CONSTRUCTED-DECK-INTERMEDIATE.
- (defun pull-from-inventory (cdi-items)
- "Attempt to find inventory stock for every card in this deck, and if we are able to secure it, construct and insert a new PULLED-DECK into the database."
- (let ((counts (deck-to-pull-desired-qty-as-alist cdi-items)))
- (dolist (row counts)
- (decf (qty-of (car row)) (cdr row))
- ;; Update each one and save - wrapping this in a transaction causes issues with pulling multiple items.
- (save-dao (car row)))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defroute ("/construct" :method :GET) ()
- "Constructed Deck View Main Route. Login Required."
- (v:info :construct "GET /construct")
-
- (with-logged-in-user
- (render-with-env #P"construct/index.html"
- (list :active "/construct"
- :saved-deck-list (select-constructed-decks)))))
-
- (defroute ("/construct/:id/view" :method :GET) (&key id)
- "Constructed Deck View deck by ID Route. Login Required."
- (v:info :construct "GET /construct/~d" id)
-
- (with-logged-in-user
- (render-construct-deck id #P"construct/index.html")))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defroute ("/construct/ygo-set-item" :method :GET) (&key _parsed)
- "Find the YGO-SET-ITEM associated with the |SET-ID| and |VARIANT-ID|
-
- TODO This needs a rewrite as it currently actually accepts multiple
- CARDs and operates on their component |SET-ID| and |VARIANT-ID| which
- is really not optimal. Ideally we should be handling this all in bulk
- with better routes."
- (v:info :cards "GET /cards/ygo-set-items ~a" _parsed)
-
- (with-logged-in-user
- (alexandria:if-let ((cards (query-param "cards" _parsed)))
- (dolist (card cards)
- (let ((|set-id| (query-param "set-id" card))
- (|variant-id| (query-param "variant-id" card)))
- (handler-case
- (ratify:with-parsed-forms
- ((:integer |set-id|)
- (:integer |variant-id|))
- (return
- (render-with-env #P"cards/variant-results.html"
- (list :id (gensym)
- :item (find |variant-id|
- (select-ygo-cc-item-variants |set-id|)
- :key (alexandria:compose #'mito:object-id #'variant-of))))))
- (ratify:combined-error (e)
- (flash-error (format nil "/cards/ygo-set-items => ~d:~d ~a~%" |set-id| |variant-id| e)))))))))
-
-
- (defroute ("/construct/:id/select-sets" :method :GET) (&key id)
- "Select the YDK-SET for the corresponding PASSCODEs. Use Deck ID from the deck builder."
- (v:info :construct "GET /construct/~d/select-sets" id)
-
- (with-logged-in-user
- (with-connection (db)
- (let* ((cards (mito:retrieve-dao 'deck-item :deck-id id))
- (sets (mapcar (alexandria:compose #'ygo-card-sets #'deck-passcode-of) cards))
- (variants (select-variant-condition)))
- (render-with-env #P"construct/select-sets.html"
- (list :sets (reverse sets)
- :deck-id id
- :variants variants))))))
-
- (defroute ("/construct/:id/select-sets" :method :POST) (&key id _parsed)
- "Constructed Decks Select Sets POST Route - Attempt to SUBTRACT-DESIRED-FROM-SET-ITEM-QTY-AS-ALIST, and if VALID-PULL-P, call PULL-FROM-INVENTORY. Otherwise, FLASH-ERROR to the user about Insufficient Inventory."
- (v:info :construct "POST /construct/~d/select-sets ~a" id _parsed)
-
- (with-logged-in-user
- (alexandria:if-let ((cards (query-param "cards" _parsed)))
- (let ((original-deck (select-deck-as-plist id))
- (selected-listing (selected-sets-to-deck-listing cards)))
-
- ;; Store the current constructed deck template
- (store-combined-deck-as-current original-deck selected-listing)
-
- ;; See if there are any issues with the current inventory
- (if (default-constructed-deck-is-valid-to-pull)
- (progn
- ;; Decrement the stock from the YGO-SET-ITEM
- (pull-from-inventory *current-constructed-deck*)
- ;; Create a new CONSTRUCTED-DECK based on *CURRENT-CONSTRUCTED-DECK*
- (cdi-pull-from-inventory *current-constructed-deck*)
- (flash-message (_ "Deck constructed!"))
- (render-with-env #P"construct/constructed-deck-list.html"
- (list :original-deck original-deck
- :deck-id id
- :total-price nil
- :table *current-constructed-deck*)))
- (let ((err (default-constructed-deck-invalid-qtys)))
- (with-connection (db)
- (flash-error (format nil (_ "Insufficient Inventory: <a href=\"/cards/by-passcode/~a\" target=\"_blank\">~a</a>")
- ;; TODO all this nesting again...
- (ygo-passcode-of err)
- (ygo-passcode-of err))))
- (redirect (format nil "/construct/~d/select-sets" id))))))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defroute ("/construct/:id/deconstruct" :method :POST) (&key id _parsed)
- "Deconstruct deck. That is, increment the QTY of the the contents to of the CONSTRUCTED-DECK-AS-CDI-LIST."
- (v:info :construct "POST /construct/~d/deconstruct ~a" id _parsed)
-
- (with-logged-in-user
- (return-to-inventory
- (constructed-deck-as-cdi-list id)))
-
- (_ "Ok!"))
-
- (defroute ("/construct/:id/selected-sets" :method :GET) (&key id _parsed)
- "Query CONSTRUCTED-DECK ID for the YGO-SET-ITEMS it contains. We use CONSTRUCTED-DECK-AS-CDI-LIST again."
- (v:info :construct "GET /construct/~d/selected-sets ~a" id _parsed)
-
- (with-logged-in-user
- (let ((table (constructed-deck-as-cdi-list id)))
- (render-with-env #P"construct/constructed-deck-list.html"
- (list :table table)))))
-
- (defroute ("/construct/:id/update" :method :POST) (&key id |name| |sell-price| |sold| _parsed)
- "Update a CONSTRUCTED-DECK by ID"
- (v:info :construct "POST /construct/~d/update ~a" id _parsed)
-
- (with-logged-in-user
- (let ((found (find-dao 'constructed-deck :id id)))
- (when found
- (when |name| (setf (deck-name-of found) |name|))
- (when |sell-price| (setf (deck-sell-price-of found) |sell-price|))
- (when (string= |sold| "on") (setf (deck-sold found) 1))
- (update-dao found)
- (flash-message (_ "Deck Updated"))
- (redirect (format nil "/construct/~d/view" id))))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- ;; This one looks like: Get all the cards in a deck id 13 and query all the sets using YGO-CARD-SETS
-
- ;; (let* ((cards (retrieve-dao 'deck-item :deck-id 13))
- ;; (all-sets (mapcar #'deck-passcode-of cards)))
- ;; (mapcar #'cl-deck-builder2.models.ygoprodeck.methods::ygo-card-sets
- ;; (reverse all-sets)))
-
- ;; (with-connection (db)
- ;; (with-transaction
- ;; (let ((v (mito:find-dao 'cl-deck-builder2.models.ygoprodeck.fields::variant-condition :name "Near Mint")))
- ;; (mapcar (lambda (set)
- ;; (mito:find-dao 'cl-deck-builder2.models.ygoprodeck.classes::ygo-set-item
- ;; :item set
- ;; :variant v))
- ;; *))))
|