diff --git a/src/clj/chicken_master/api.clj b/src/clj/chicken_master/api.clj new file mode 100644 index 0000000..9962717 --- /dev/null +++ b/src/clj/chicken_master/api.clj @@ -0,0 +1,49 @@ +(ns chicken-master.api + (:require [chicken-master.orders :as orders] + [chicken-master.customers :as customers] + [chicken-master.products :as products] + [clojure.edn :as edn] + [compojure.core :refer [GET POST PUT DELETE defroutes]])) + +(defn as-edn [resp] + {:headers {"Content-Type" "application/edn"} + :body resp}) + +(defn get-customers [user-id] (as-edn (customers/get-all user-id))) +(defn add-customer [{:keys [body basic-authentication]}] + (as-edn (some->> body :name (customers/create! basic-authentication)))) +(defn delete-customer [user-id id] (->> id edn/read-string (customers/delete! user-id) as-edn)) + +(defn get-products [user-id] (as-edn (products/get-all user-id))) +(defn save-products [{:keys [body basic-authentication]}] + (some->> body (products/update! basic-authentication) (assoc {} :products) as-edn)) + +(defn get-orders [user-id] (as-edn (orders/get-all user-id))) +(defn update-order [request] + (let [user-id (:basic-authentication request) + id (some-> request :route-params :id (Integer/parseInt)) + order (-> request :body (update :id #(or % id)))] + (as-edn (orders/replace! user-id order)))) + +(defn delete-order [user-id id] (->> id edn/read-string (orders/delete! user-id) as-edn)) +(defn set-order-state [user-id id status] (as-edn (orders/change-state! user-id (edn/read-string id) status))) + +(defn get-stock [user-id] + (as-edn + {:customers (:body (get-customers user-id)) + :products (:body (get-products user-id))})) + +(defroutes all-routes + (GET "/stock" [:as {user-id :basic-authentication}] (get-stock user-id)) + (GET "/customers" [:as {user-id :basic-authentication}] (get-customers user-id)) + (POST "/customers" request (add-customer request)) + (DELETE "/customers/:id" [id :as {user-id :basic-authentication}] (delete-customer user-id id)) + + (GET "/products" request (get-products request)) + (POST "/products" request (save-products request)) + + (GET "/orders" [:as {user-id :basic-authentication}] (get-orders user-id)) + (POST "/orders" request (update-order request)) + (PUT "/orders/:id" request (update-order request)) + (DELETE "/orders/:id" [id :as {user-id :basic-authentication}] (delete-order user-id id)) + (POST "/orders/:id/:status" [id status :as {user-id :basic-authentication}] (set-order-state user-id id status))) diff --git a/src/clj/chicken_master/handler.clj b/src/clj/chicken_master/handler.clj index 00b0197..5e30aaa 100644 --- a/src/clj/chicken_master/handler.clj +++ b/src/clj/chicken_master/handler.clj @@ -1,64 +1,15 @@ (ns chicken-master.handler (:require [chicken-master.db :as db] - [chicken-master.orders :as orders] - [chicken-master.customers :as customers] - [chicken-master.products :as products] + [chicken-master.api :as endpoints] [clojure.edn :as edn] [config.core :refer [env]] - [compojure.core :refer [GET POST PUT DELETE defroutes]] + [compojure.core :refer [GET defroutes routes]] [compojure.route :refer [resources not-found]] [compojure.handler :refer [api]] [ring.util.response :refer [resource-response]] [ring.middleware.basic-authentication :refer [wrap-basic-authentication]] [ring.middleware.cors :refer [wrap-cors]])) -(defn as-edn [resp] - {:headers {"Content-Type" "application/edn"} - :body resp}) - -(defn get-customers [user-id] (as-edn (customers/get-all user-id))) -(defn add-customer [{:keys [body basic-authentication]}] - (as-edn (some->> body :name (customers/create! basic-authentication)))) -(defn delete-customer [user-id id] (->> id edn/read-string (customers/delete! user-id) as-edn)) - -(defn get-products [user-id] (as-edn (products/get-all user-id))) -(defn save-products [{:keys [body basic-authentication]}] - (some->> body (products/update! basic-authentication) (assoc {} :products) as-edn)) - -(defn get-orders [user-id] (as-edn (orders/get-all user-id))) -(defn update-order [request] - (let [user-id (:basic-authentication request) - id (some-> request :route-params :id (Integer/parseInt)) - order (-> request :body (update :id #(or % id)))] - (as-edn (orders/replace! user-id order)))) - -(defn delete-order [user-id id] (->> id edn/read-string (orders/delete! user-id) as-edn)) -(defn set-order-state [user-id id status] (as-edn (orders/change-state! user-id (edn/read-string id) status))) - -(defn get-stock [user-id] - (as-edn - {:customers (:body (get-customers user-id)) - :products (:body (get-products user-id))})) - -(defroutes routes - (GET "/stock" [:as {user-id :basic-authentication}] (get-stock user-id)) - (GET "/customers" [:as {user-id :basic-authentication}] (get-customers user-id)) - (POST "/customers" request (add-customer request)) - (DELETE "/customers/:id" [id :as {user-id :basic-authentication}] (delete-customer user-id id)) - - (GET "/products" request (get-products request)) - (POST "/products" request (save-products request)) - - (GET "/orders" [:as {user-id :basic-authentication}] (get-orders user-id)) - (POST "/orders" request (update-order request)) - (PUT "/orders/:id" request (update-order request)) - (DELETE "/orders/:id" [id :as {user-id :basic-authentication}] (delete-order user-id id)) - (POST "/orders/:id/:status" [id status :as {user-id :basic-authentication}] (set-order-state user-id id status)) - - (GET "/" [] (resource-response "index.html" {:root "public"})) - (resources "/") - (not-found "not found")) - (defn- handle-edn [response] (if (= (get-in response [:headers "Content-Type"]) "application/edn") (update response :body pr-str) @@ -82,10 +33,17 @@ (defn authenticated? [name pass] (db/valid-user? name pass)) -(def handler (-> routes - (wrap-basic-authentication authenticated?) - (wrap-cors :access-control-allow-origin (map re-pattern (env :allow-origin)) - :access-control-allow-methods [:get :put :post :delete :options]) - api - wrap-edn-request - wrap-edn-response)) +(defroutes base-routes + (GET "/" [] (resource-response "index.html" {:root "public"})) + (resources "/") + (not-found "not found")) + +(def handler (routes + (-> endpoints/all-routes + (wrap-basic-authentication authenticated?) + (wrap-cors :access-control-allow-origin (map re-pattern (env :allow-origin)) + :access-control-allow-methods [:get :put :post :delete :options]) + api + wrap-edn-request + wrap-edn-response) + base-routes)) diff --git a/src/cljs/chicken_master/config.cljs b/src/cljs/chicken_master/config.cljs index d3aab48..af137e1 100644 --- a/src/cljs/chicken_master/config.cljs +++ b/src/cljs/chicken_master/config.cljs @@ -65,6 +65,8 @@ (defn settings-options [] [:div [:h3 "Ustawienia wyglądu kalendarza"] + [:button {:type :button :on-click #(set-item! :bearer-token nil)} "wyloguj"] + (input :first-day-offset "o ile dni przesunąć niedziele w lewo" {:type :number :max 7 :min 0 :parser #(js/parseInt %)}) (input :day-names "skróty nazw dni tygodnia" diff --git a/src/cljs/chicken_master/db.cljs b/src/cljs/chicken_master/db.cljs index fd61722..2a332a0 100644 --- a/src/cljs/chicken_master/db.cljs +++ b/src/cljs/chicken_master/db.cljs @@ -25,6 +25,7 @@ ;; :current-days [{:day (google.date "2020-01-01") :orders []}] ;; :customers [] + ;; :bearer-token "user-token" ::clients {:show nil} ; customers edit modal :stock {:show nil} :products {:eggs 22 :milk 32 :cabbage 54 :carrots 11 :cows 32 :ants 21} diff --git a/src/cljs/chicken_master/events.cljs b/src/cljs/chicken_master/events.cljs index ae7ba97..137eef2 100644 --- a/src/cljs/chicken_master/events.cljs +++ b/src/cljs/chicken_master/events.cljs @@ -3,9 +3,10 @@ [re-frame.core :as re-frame] [chicken-master.db :as db] [chicken-master.time :as time] - [chicken-master.config :refer [settings default-settings]] + [chicken-master.config :refer [settings default-settings set-item!]] [day8.re-frame.http-fx] - [ajax.edn :as edn])) + [ajax.edn :as edn] + [goog.crypt.base64 :as b64])) (defn http-request [method endpoint & {:keys [params body on-success on-failure] :or {on-success ::process-fetched-days @@ -13,7 +14,7 @@ {:method method :uri (str (settings :backend-url) endpoint) :headers {"Content-Type" "application/edn" - "authorization" "Basic c2lsb2E6a3JhY2g="} + "authorization" (str "Basic " (some-> js/window (.-localStorage) (.getItem :bearer-token)))} :format (edn/edn-request-format) :body (some-> body pr-str) :params params @@ -21,6 +22,7 @@ :on-success [on-success] :on-failure [on-failure]}) + (defn http-get [endpoint params on-success] (http-request :get endpoint :params params :on-success on-success)) @@ -31,8 +33,17 @@ ::initialize-db (fn [_ _] (time/update-settings default-settings) - {:db (assoc db/default-db :settings default-settings) - :fx [[:dispatch [::show-from-date (time/iso-date (time/today))]] + (let [user (some-> js/window (.-localStorage) (.getItem :bearer-token))] + {:db (assoc db/default-db + :settings default-settings + :current-user user) + :dispatch [(when user ::load-db)]}))) + +(re-frame/reg-event-fx + ::load-db + (fn [_ _] + (time/update-settings default-settings) + {:fx [[:dispatch [::show-from-date (time/iso-date (time/today))]] [:dispatch [::start-loading]] [:dispatch [::fetch-stock]] [:dispatch [::fetch-orders]]]})) @@ -52,7 +63,9 @@ (fn [db [_ response]] (.error js/console (str response)) (js/alert "Wystąpił błąd") - (assoc db :loading? false))) + (-> db + (assoc :loading? false) + (update :current-user #(when-not (= (:status response) 401) %))))) (re-frame/reg-event-fx ::remove-order @@ -191,6 +204,14 @@ (assoc-in db [:settings :show] true))) +(re-frame/reg-event-fx + ::set-user + (fn [{db :db} [_ user]] + (set-item! :bearer-token (b64/encodeString (str (user "name") ":" (user "password")))) + {:db (assoc db :current-user (b64/encodeString (str (user "name") ":" (user "password")))) + :dispatch [::load-db]})) + + (comment (re-frame/dispatch-sync [::show-stock]) (re-frame/dispatch-sync [::update-product-stock :eggs 2]) diff --git a/src/cljs/chicken_master/html.cljs b/src/cljs/chicken_master/html.cljs index e62e0dc..ef74a4b 100644 --- a/src/cljs/chicken_master/html.cljs +++ b/src/cljs/chicken_master/html.cljs @@ -39,8 +39,9 @@ content [:div {:class :form-buttons} [:button {:type :button :on-click #(re-frame/dispatch [::event/hide-modal modal-id])} "ok"]]]]) - ([modal-id content & {:keys [on-submit submit-text] - :or {submit-text "ok"}}] + ([modal-id content & {:keys [on-submit submit-text show-cancel] + :or {submit-text "ok" + show-cancel true}}] [:div {:class :popup :on-click #(re-frame/dispatch [::event/hide-modal modal-id])} [:form {:action "#" :class :popup-content @@ -52,7 +53,8 @@ content [:div {:class :form-buttons} [:button submit-text] - [:button {:type :button :on-click #(re-frame/dispatch [::event/hide-modal modal-id])} "anuluj"]]]])) + (when show-cancel + [:button {:type :button :on-click #(re-frame/dispatch [::event/hide-modal modal-id])} "anuluj"])]]])) (comment diff --git a/src/cljs/chicken_master/subs.cljs b/src/cljs/chicken_master/subs.cljs index a40665c..13af447 100644 --- a/src/cljs/chicken_master/subs.cljs +++ b/src/cljs/chicken_master/subs.cljs @@ -2,6 +2,7 @@ (:require [re-frame.core :as re-frame])) (re-frame/reg-sub ::name (fn [db] (:name db))) +(re-frame/reg-sub ::current-user (fn [db] (:current-user db))) (re-frame/reg-sub ::settings (fn [db] (:settings db))) (re-frame/reg-sub ::loading? (fn [db] (:loading? db))) diff --git a/src/cljs/chicken_master/views.cljs b/src/cljs/chicken_master/views.cljs index e0ca60a..978736e 100644 --- a/src/cljs/chicken_master/views.cljs +++ b/src/cljs/chicken_master/views.cljs @@ -12,7 +12,23 @@ (defn show-settings [] (html/modal :settings (settings-options))) -(defn main-panel [] +(defn login-screen [] + [:div + (html/modal + :login + [:div + [:div + [:label {:for :name} "nazwa użytkownika"] + [:br] + [:input {:id :name :name :name}]] + [:div + [:label {:for :name} "hasło"] + [:br] + [:input {:id :password :name :password :type :password}]]] + :on-submit #(re-frame/dispatch [::event/set-user %]) + :show-cancel nil)]) + +(defn app [] [:div {:class :full-height} [:div {:class [:loader-container (if-not @(re-frame/subscribe [::subs/loading?]) :hidden)]} [:div {:class :loader}]] @@ -36,3 +52,8 @@ (cal/calendar @(re-frame/subscribe [::subs/current-days]) @(re-frame/subscribe [::subs/settings])) [:button {:id :scroll-down-button :class [:menu-button :scroll-button] :on-click #(re-frame/dispatch [::event/scroll-weeks 2])} "v"] ]) + +(defn main-panel [] + (if @(re-frame/subscribe [::subs/current-user]) + (app) + (login-screen)))