Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m2s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
96 lines
2.6 KiB
Plaintext
96 lines
2.6 KiB
Plaintext
;; lib/dream/demos/todo.sx — CRUD todo list with forms + CSRF (todo.ml).
|
|
;; An in-memory store holds items; add/toggle/delete go through POST forms guarded
|
|
;; by the CSRF middleware. Wires session -> csrf -> router.
|
|
|
|
(define
|
|
dream-todo-store
|
|
(fn () (let ((items (list)) (next-id 0)) {:all (fn () items) :add (fn (text) (begin (set! next-id (+ next-id 1)) (set! items (concat items (list {:id next-id :text text :done false}))) next-id)) :delete (fn (id) (set! items (filter (fn (it) (not (= (get it :id) id))) items))) :toggle (fn (id) (set! items (map (fn (it) (if (= (get it :id) id) (assoc it :done (not (get it :done))) it)) items)))})))
|
|
|
|
(define
|
|
dr/todo-render
|
|
(fn
|
|
(store req)
|
|
(str
|
|
"<ul>"
|
|
(reduce
|
|
(fn
|
|
(acc it)
|
|
(str
|
|
acc
|
|
"<li>"
|
|
(if (get it :done) "[x] " "[ ] ")
|
|
(get it :text)
|
|
"</li>"))
|
|
""
|
|
((get store :all)))
|
|
"</ul>"
|
|
"<form method=\"post\" action=\"/add\">"
|
|
(dream-csrf-tag req)
|
|
"<input name=\"text\"><button>Add</button></form>")))
|
|
|
|
(define
|
|
dream-todo-index
|
|
(fn (store) (fn (req) (dream-html (dr/todo-render store req)))))
|
|
|
|
(define
|
|
dream-todo-add
|
|
(fn
|
|
(store)
|
|
(fn
|
|
(req)
|
|
(let
|
|
((r (dream-form req)))
|
|
(if
|
|
(dream-ok? r)
|
|
(begin
|
|
((get store :add) (get (dream-ok-value r) "text"))
|
|
(dream-redirect "/"))
|
|
(dream-html-status
|
|
403
|
|
(str "Rejected: " (dream-err-reason r))))))))
|
|
|
|
(define
|
|
dream-todo-toggle
|
|
(fn
|
|
(store)
|
|
(fn
|
|
(req)
|
|
(let
|
|
((r (dream-form req)))
|
|
(if
|
|
(dream-ok? r)
|
|
(begin
|
|
((get store :toggle) (parse-int (dream-param req "id")))
|
|
(dream-redirect "/"))
|
|
(dream-html-status 403 "Rejected"))))))
|
|
|
|
(define
|
|
dream-todo-delete
|
|
(fn
|
|
(store)
|
|
(fn
|
|
(req)
|
|
(let
|
|
((r (dream-form req)))
|
|
(if
|
|
(dream-ok? r)
|
|
(begin
|
|
((get store :delete) (parse-int (dream-param req "id")))
|
|
(dream-redirect "/"))
|
|
(dream-html-status 403 "Rejected"))))))
|
|
|
|
(define
|
|
dream-todo-app-with
|
|
(fn
|
|
(store backend secret)
|
|
((dream-sessions backend)
|
|
((dream-csrf secret)
|
|
(dream-router
|
|
(list
|
|
(dream-get "/" (dream-todo-index store))
|
|
(dream-post "/add" (dream-todo-add store))
|
|
(dream-post "/toggle/:id" (dream-todo-toggle store))
|
|
(dream-post "/delete/:id" (dream-todo-delete store))))))))
|
|
|
|
;; entry: (dream-run (dream-todo-app-with (dream-todo-store) (dream-memory-sessions) "change-me"))
|