diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/chef/database/init.clj | 9 | ||||
-rw-r--r-- | src/chef/pages/admin.clj | 65 | ||||
-rw-r--r-- | src/chef/pages/admin/api.clj | 36 | ||||
-rw-r--r-- | src/chef/pages/admin/recipe_editor.clj | 61 | ||||
-rw-r--r-- | src/chef/routes.clj | 13 | ||||
-rw-r--r-- | src/chef/utils.clj | 21 |
6 files changed, 184 insertions, 21 deletions
diff --git a/src/chef/database/init.clj b/src/chef/database/init.clj index 7f23d27..ef4bd2f 100644 --- a/src/chef/database/init.clj +++ b/src/chef/database/init.clj @@ -7,9 +7,12 @@ :with-columns [[:id :integer :primary-key :autoincrement] [:name :text] [:question :text] - [:parent :integer]]})) ;TODO: create root category + [:parent :integer]]})) (jdbc/execute! db (sql/format {:create-table :recipes - :with-columns [[:id :integer :auto-increment :primary-key] + :with-columns [[:id :integer :primary-key :autoincrement] [:category :integer] [:title :text] - [:description :text]]}))) + [:unit :integer] + [:ingredients :text] + [:preparation :text] + [:thumbnail :text]]}))) diff --git a/src/chef/pages/admin.clj b/src/chef/pages/admin.clj index e38dac3..25f99a6 100644 --- a/src/chef/pages/admin.clj +++ b/src/chef/pages/admin.clj @@ -52,21 +52,60 @@ :where [:= :parent (:categories/id child)]}) (jdbc/execute! @cdb/db))))]]) +(defn- render-recipe-table-row [recipe] + (let [tr-id (str "recipe-" (:recipes/id recipe))] + [:tr {:id tr-id} + [:td + [:p (:recipes/title recipe)]] + [:td + (let [category (->> (sql/format {:select [:*] + :from [:categories] + :where [:= :id (:recipes/category recipe)]}) + (jdbc/execute! @cdb/db) + first)] + [:p (cutils/category-path category)])] + [:td + [:div + [:button {:class ["button" "primary"] + :onclick (str "window.open(\"/admin/recipe-editor/" + (:recipes/id recipe) + "\", \"\", \"width=500,height=500\")")} + "Bearbeiten"] + [:button {:class ["button error"] + :hx-trigger "click" + :hx-swap :none + :hx-delete (str "/api/admin/delete-recipe/" (:recipes/id recipe))} + "Löschen"]]]])) + (defn- render [] (cutils/gen-page "chef - Admin" - [:h1 "chef - Admin"] - [:h2 "Kategorien"] - [:ul - (render-category (first (->> (sql/format {:select [:*] - :from [:categories] - :where [:= :id -1]}) - (jdbc/execute! @cdb/db))) - (->> (sql/format {:select [:*] - :from [:categories] - :where [:and [:is :parent :null] [:> :id 0]]}) - (jdbc/execute! @cdb/db)))] - [:h2 "Rezepte"] - [:i "Coming soon..."])) + [:div {:style {:margin-left "1em"}} + [:h1 "chef - Admin"] + [:h2 "Kategorien"] + [:ul + (render-category (first (->> (sql/format {:select [:*] + :from [:categories] + :where [:= :id -1]}) + (jdbc/execute! @cdb/db))) + (->> (sql/format {:select [:*] + :from [:categories] + :where [:and [:is :parent :null] [:> :id 0]]}) + (jdbc/execute! @cdb/db)))] + [:h2 "Rezepte"] + [:table + [:tr + [:th "Titel"] + [:th "Kategorie"] + [:th "Aktionen"]] + (for [recipe (jdbc/execute! @cdb/db + (sql/format {:select [:*] + :from [:recipes]}))] + (render-recipe-table-row recipe))] + [:button {:class "button primary" + :hx-trigger "click" + :hx-swap :none + :hx-post "/api/admin/create-recipe"} + "Rezept erstellen"]])) (defn handler [req] (let [access-token (get-in req [:oauth2/access-tokens :auth]) diff --git a/src/chef/pages/admin/api.clj b/src/chef/pages/admin/api.clj index ff11672..8b2723a 100644 --- a/src/chef/pages/admin/api.clj +++ b/src/chef/pages/admin/api.clj @@ -37,7 +37,6 @@ :where [:= :id id]})) (delete-category-children! id) (-> (ruresp/response "Deleted.") - (ruresp/status 200) (ruresp/header "HX-Refresh" "true")))) (ruresp/bad-request "Bad request.")))) @@ -55,3 +54,38 @@ :where [:= :id id]}))) (ruresp/response "Updated.")) (ruresp/bad-request "Bad request.")))) + +(defn create-recipe [req] + (cutils/auth-only req + (jdbc/execute! @cdb/db + (sql/format {:insert-into [:recipes] + :values [{:title "New recipe"}]})) + (-> (ruresp/created "Created.") + (ruresp/header "HX-Refresh" "true")))) + +(defn delete-recipe [req] + (cutils/auth-only req + (if-let [id (try (Integer/parseInt (get-in req [:path-params :id])) + (catch Exception _ nil))] + (do (jdbc/execute! @cdb/db + (sql/format {:delete-from [:recipes] + :where [:= :id id]})) + (-> (ruresp/response "Deleted.") + (ruresp/header "HX-Refresh" "true"))) + (ruresp/bad-request "Bad request.")))) + +;;TODO: validate request +(defn edit-recipe [req] + (cutils/auth-only req + (if-let [id (try (Integer/parseInt (get-in req [:path-params :id])) + (catch Exception _ nil))] + (do (jdbc/execute! @cdb/db + (sql/format {:update :recipes + :set {:title (get-in req [:params "title"]) + :category (get-in req [:params "category"]) + :unit (get-in req [:params "ingredients-unit"]) + :ingredients (get-in req [:params "ingredients"]) + :preparation (get-in req [:params "preparation"])} + :where [:= :id id]})) + (ruresp/response "Saved.")) + (ruresp/bad-request "Bad request.")))) diff --git a/src/chef/pages/admin/recipe_editor.clj b/src/chef/pages/admin/recipe_editor.clj new file mode 100644 index 0000000..6afd591 --- /dev/null +++ b/src/chef/pages/admin/recipe_editor.clj @@ -0,0 +1,61 @@ +(ns chef.pages.admin.recipe-editor + (:require [hiccup2.core :as html] + [hiccup.util :as hutil] + [honey.sql :as sql] + [next.jdbc :as jdbc] + [chef.database :as cdb] + [ring.util.response :as ruresp] + [chef.utils :as cutils])) + +(defn render [recipe] + (cutils/gen-page "chef - Rezept bearbeiten" + [:div {:style {:margin-left "1em"}} + [:h1 "Rezept bearbeiten"] + [:form {:style {:width "50%"} + :hx-post (str "/api/admin/edit-recipe/" (:recipes/id recipe)) + :hx-swap "none"} + [:input {:type :text :name "title" :placeholder "Titel" + :value (:recipes/title recipe)}] + [:h2 "Kategorie"] + [:select {:name "category"} + (for [category (->> (sql/format {:select [:*] + :from [:categories]}) + (jdbc/execute! @cdb/db) + (filter #(pos? (:categories/id %))))] + [:option {:value (:categories/id category) + :selected (= (:categories/id category) (:recipes/category recipe))} + (cutils/category-path category)])] + [:h2 "Zutaten"] + [:div {:style {:display :flex}} + [:p {:style {:margin-right "0.5em"}} "Pro"] + [:select {:name "ingredients-unit" + :style {:height :fit-content + :padding "0.3em"}} + [:option {:value 0 :selected (= (:recipes/unit recipe) 0)} "Portion"] + [:option {:value 1 :selected (= (:recipes/unit recipe) 1)} "Person"]] + [:p ":"]] + [:textarea {:name "ingredients"} + (:recipes/ingredients recipe)] + ;; Regex: ([A-z0-9 ]*)=([0-9]*) ?([A-z]*) + [:p "(Je Zeile eine Zutat, in dem Format " [:code "[Beschreibung der Zutat]=[Menge als Zahl][Einheit der Menge]"] ".)"] + [:h2 "Zubereitung"] + [:textarea {:name "preparation"} + (:recipes/preparation recipe)] + [:button {:type :submit + :style {:margin-top "1em"}} "Speichern"]]] + [:script (hutil/raw-string "window.addEventListener(\"htmx:afterRequest\", () => window.close())")])) + +(defn handler [req] + (cutils/auth-only req + (if-let [id (try (Integer/parseInt (get-in req [:path-params :id])) + (catch Exception _ nil))] + (->> (sql/format {:select [:*] + :from [:recipes] + :where [:= :id id]}) + (jdbc/execute! @cdb/db) + first + render + html/html + str + ruresp/response) + (ruresp/bad-request "Bad request.")))) diff --git a/src/chef/routes.clj b/src/chef/routes.clj index a054b1d..9b16565 100644 --- a/src/chef/routes.clj +++ b/src/chef/routes.clj @@ -11,10 +11,13 @@ [chef.components.search :as ccsearch] - [chef.pages.admin.api :as cpaapi])) + [chef.pages.admin.api :as cpaapi] + [chef.pages.admin.recipe-editor :as cparecipe-editor])) (def router [["/" {:get {:handler cphome/handler}}] - ["/admin/" {:get {:handler cpadmin/handler}}] + ["/admin" + ["/" {:get {:handler cpadmin/handler}}] + ["/recipe-editor/:id" {:get {:handler cparecipe-editor/handler}}]] ["/static/*" (rring/create-resource-handler)] ["/components" @@ -24,7 +27,11 @@ ["/admin" ["/create-category" {:post {:handler cpaapi/create-category}}] ["/delete-category/:id" {:delete {:handler cpaapi/delete-category}}] - ["/edit-category/:id" {:post {:handler cpaapi/edit-category}}]]]]) + ["/edit-category/:id" {:post {:handler cpaapi/edit-category}}] + + ["/create-recipe" {:post {:handler cpaapi/create-recipe}}] + ["/delete-recipe/:id" {:delete {:handler cpaapi/delete-recipe}}] + ["/edit-recipe/:id" {:post {:handler cpaapi/edit-recipe}}]]]]) (def ring-handler (delay (-> router rring/router diff --git a/src/chef/utils.clj b/src/chef/utils.clj index f909c52..1ea5136 100644 --- a/src/chef/utils.clj +++ b/src/chef/utils.clj @@ -1,5 +1,9 @@ (ns chef.utils - (:require [ring.util.response :as ruresp])) + (:require [chef.database :as cdb] + [honey.sql :as sql] + [next.jdbc :as jdbc] + [ring.util.response :as ruresp] + [clojure.string :as cstr])) (defn gen-page [title & content] [:html @@ -16,3 +20,18 @@ ~(-> (ruresp/response "Unauthorized.") (ruresp/status 302) (ruresp/header "Location" "/auth")))) + +(defn category-path [category] + (cstr/join " > " + (loop [path (list) + category category] + (let [new-path (conj path (:categories/name category))] + (if (some? (:categories/parent category)) + (recur new-path + (->> {:select [:*] + :from [:categories] + :where [:= :id (:categories/parent category)]} + sql/format + (jdbc/execute! @cdb/db) + first)) + new-path))))) |