summaryrefslogtreecommitdiff
path: root/src/chef
diff options
context:
space:
mode:
Diffstat (limited to 'src/chef')
-rw-r--r--src/chef/database/init.clj9
-rw-r--r--src/chef/pages/admin.clj65
-rw-r--r--src/chef/pages/admin/api.clj36
-rw-r--r--src/chef/pages/admin/recipe_editor.clj61
-rw-r--r--src/chef/routes.clj13
-rw-r--r--src/chef/utils.clj21
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)))))