diff --git a/config/prod/config.edn b/config/prod/config.edn new file mode 100644 index 0000000..37293b5 --- /dev/null +++ b/config/prod/config.edn @@ -0,0 +1,7 @@ +{;; Networking settings + :port 8000 + :allow-origin ["http://91.218.78.71" "https://mruwnik.github.io"] + + ;; db settings + :db-uri {:jdbcUrl "jdbc:postgresql://localhost/chickens"} + } diff --git a/infra/chickens.service b/infra/chickens.service new file mode 100644 index 0000000..361c7ce --- /dev/null +++ b/infra/chickens.service @@ -0,0 +1,13 @@ +[Unit] +Description=Chicken master +After=postgresql.service + +[Service] +ExecStart=/usr/bin/java -Dconfig="/home/dan/chicken-master/config.edn" -jar /home/dan/chicken-master/target/chicken-master.jar +Type=simple +Restart=always +RestartSec=1 +User=root + +[Install] +WantedBy=multi-user.target diff --git a/infra/nginx/chickens.conf b/infra/nginx/chickens.conf new file mode 100644 index 0000000..6ee18bd --- /dev/null +++ b/infra/nginx/chickens.conf @@ -0,0 +1,35 @@ +server { + + server_name chickens.ahiru.pl + + access_log /var/log/nginx/reverse-access.log; + error_log /var/log/nginx/reverse-error.log; + + location / { + proxy_pass http://127.0.0.1:8000; + } + + listen [::]:443 ssl ipv6only=on; # managed by Certbot + listen 443 ssl; # managed by Certbot + ssl_certificate /etc/letsencrypt/live/chickens.ahiru.pl/fullchain.pem; # managed by Certbot + ssl_certificate_key /etc/letsencrypt/live/chickens.ahiru.pl/privkey.pem; # managed by Certbot + include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot + +} +server { + if ($host = chickens.ahiru.pl) { + return 301 https://$host$request_uri; + } # managed by Certbot + + + listen 80; + listen [::]:80; + + server_name chickens.ahiru.pl + + access_log /var/log/nginx/reverse-access.log; + return 404; # managed by Certbot + + +} diff --git a/src/clj/chicken_master/handler.clj b/src/clj/chicken_master/handler.clj index 7afd314..00b0197 100644 --- a/src/clj/chicken_master/handler.clj +++ b/src/clj/chicken_master/handler.clj @@ -23,9 +23,9 @@ (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) as-edn)) + (some->> body (products/update! basic-authentication) (assoc {} :products) as-edn)) -(defn get-orders [user-id] (as-edn {:orders (orders/get-all user-id)})) +(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)) diff --git a/src/clj/chicken_master/orders.clj b/src/clj/chicken_master/orders.clj index c59f255..66cfba9 100644 --- a/src/clj/chicken_master/orders.clj +++ b/src/clj/chicken_master/orders.clj @@ -43,7 +43,7 @@ (defn get-order [tx user-id id] (first (get-orders tx "WHERE o.id = ? AND o.user_id = ?" [id user-id]))) -(defn get-all [user-id] (get-orders db/db-uri "WHERE o.user_id = ?" [user-id])) +(defn get-all [user-id] (group-by :day (get-orders db/db-uri "WHERE o.user_id = ?" [user-id]))) (defn- orders-for-days [tx user-id & days] (let [days (remove nil? days)] @@ -51,18 +51,11 @@ (map t/inst->timestamp) (map jdbc.types/as-date) (into [user-id]) - (get-orders tx (str "WHERE o.user_id = ? AND o.order_date::date IN " (db/psql-list days)))))) - -(defn- orders-between [tx user-id from to] - (get-orders - tx - "WHERE o.order_date::date >= ? AND o.order_date::date <= ? AND o.user_id = ?" - [(some-> from t/inst->timestamp jdbc.types/as-date) - (some-> to t/inst->timestamp jdbc.types/as-date) - user-id])) + (get-orders tx (str "WHERE o.user_id = ? AND o.order_date::date IN " (db/psql-list days))) + (group-by :day) + (merge (reduce #(assoc %1 (t/format-date %2) {}) {} days))))) (defn replace! [user-id {:keys [who products] :as order}] - (prn order) (jdbc/with-transaction [tx db/db-uri] (let [customer-id (or (:id who) (:customers/id (db/get-by-id tx user-id :customers (:name who) :name))) diff --git a/src/clj/chicken_master/products.clj b/src/clj/chicken_master/products.clj index 412029d..828f0c7 100644 --- a/src/clj/chicken_master/products.clj +++ b/src/clj/chicken_master/products.clj @@ -9,11 +9,12 @@ (into {}))) (defn products-map [tx products] - (->> (map name (keys products)) - (into [(str "SELECT id, name from products where name IN " (db/psql-list (keys products)))]) - (sql/query tx) - (map #(vector (:products/name %) (:products/id %))) - (into {}))) + (when (seq products) + (->> (map name (keys products)) + (into [(str "SELECT id, name from products where name IN " (db/psql-list (keys products)))]) + (sql/query tx) + (map #(vector (:products/name %) (:products/id %))) + (into {})))) (defn update! [user-id new-products] (jdbc/with-transaction [tx db/db-uri] diff --git a/src/clj/chicken_master/time.clj b/src/clj/chicken_master/time.clj index 684701c..adc5030 100644 --- a/src/clj/chicken_master/time.clj +++ b/src/clj/chicken_master/time.clj @@ -1,11 +1,17 @@ (ns chicken-master.time (:import [java.time Instant LocalDate ZoneOffset] + [java.time.format DateTimeFormatter] [java.sql Timestamp])) (defn parse-date [date] (-> date (LocalDate/parse) (.atStartOfDay) (.toInstant ZoneOffset/UTC))) +(defn format-date [date] + (-> DateTimeFormatter/ISO_LOCAL_DATE + (.withZone ZoneOffset/UTC) + (.format date))) + (defn inst->timestamp [inst] (Timestamp/from inst)) (defn now [] (Instant/now)) diff --git a/src/cljs/chicken_master/calendar.cljs b/src/cljs/chicken_master/calendar.cljs index 442eb58..4f1bcf9 100644 --- a/src/cljs/chicken_master/calendar.cljs +++ b/src/cljs/chicken_master/calendar.cljs @@ -1,6 +1,7 @@ (ns chicken-master.calendar (:require [re-frame.core :as re-frame] + [reagent.core :as reagent] [chicken-master.subs :as subs] [chicken-master.html :as html] [chicken-master.products :as prod] @@ -19,22 +20,28 @@ :notes notes :products (prod/collect-products (remove (comp #{"who" "notes"} first) raw-values))}) +(defn order-form [order] + (let [state (reagent/atom (or order{})) + customers @(re-frame/subscribe [::subs/available-customers]) + available-prods @(re-frame/subscribe [::subs/available-products])] + (fn [] + [:div + (let [who (:who @state)] + [:div + (html/input :who "kto" {:required true :default (:name who) :list :customers}) + (into [:datalist {:id :customers}] + (for [cust customers] [:option {:value (:name cust) :id (:id cust)}])) + [:input {:id :who-id :name :who-id :type :hidden :value (or (:id who) "")}]]) + (html/input :notes "notka" + {:default (:notes @state)}) + [prod/products-edit (:products @state) :available-prods available-prods]]))) + (defn edit-order [] (html/modal :order-edit - [:div - (let [who @(re-frame/subscribe [::subs/order-edit-who]) - customers @(re-frame/subscribe [::subs/available-customers])] - [:div - (html/input :who "kto" {:required true :default (:name who) :list :customers}) - (into [:datalist {:id :customers}] - (for [cust customers] [:option {:value (:name cust) :id (:id cust)}])) - [:input {:id :who-id :name :who-id :type :hidden :value (or (:id who) "")}]]) - (html/input :notes "notka" - {:default @(re-frame/subscribe [::subs/order-edit-notes])}) - [prod/products-edit @(re-frame/subscribe [::subs/order-edit-products])]] + [order-form @(re-frame/subscribe [::subs/editted-order])] ;; On success - (fn [form] (re-frame/dispatch [::event/save-order (format-raw-order form)])))) + :on-submit (fn [form] (re-frame/dispatch [::event/save-order (format-raw-order form)])))) (defn format-order [settings {:keys [id who day hour notes products state]}] [:div {:class [:order state] :key (gensym) diff --git a/src/cljs/chicken_master/events.cljs b/src/cljs/chicken_master/events.cljs index a38647c..ae7ba97 100644 --- a/src/cljs/chicken_master/events.cljs +++ b/src/cljs/chicken_master/events.cljs @@ -47,11 +47,6 @@ (when (js/confirm msg) {:fx [[:dispatch (into [on-confirm-event] params)]]}))) -(re-frame/reg-event-fx - ::remove-order - (fn [_ [_ id]] - {:http-xhrio (http-request :delete (str "orders/" id))})) - (re-frame/reg-event-db ::failed-request (fn [db [_ response]] @@ -59,6 +54,11 @@ (js/alert "Wystąpił błąd") (assoc db :loading? false))) +(re-frame/reg-event-fx + ::remove-order + (fn [_ [_ id]] + {:http-xhrio (http-request :delete (str "orders/" id))})) + (re-frame/reg-event-fx ::move-order (fn [{{orders :orders start-date :start-date} :db} [_ id day]] @@ -91,20 +91,19 @@ (fn [{{order :order-edit} :db} [_ form]] {:dispatch [::hide-modal :order-edit] :http-xhrio (http-post (str "orders") - (merge - (select-keys order [:id :day :hour :state]) - (select-keys form [:id :day :hour :state :who :notes :products])))})) + (merge + (select-keys order [:id :day :hour :state]) + (select-keys form [:id :day :hour :state :who :notes :products])))})) (re-frame/reg-event-db ::process-fetched-days - (fn [db [_ orders]] + (fn [db [_ days]] (-> db (assoc :loading? nil) (update :current-days (fn [current-days] - (let [days (group-by :day orders)] - (for [[day orders] current-days] - [day (if (contains? days day) (days day) orders)])))) - (update :orders #(reduce (fn [m cust] (assoc m (:id cust) cust)) % orders))))) + (for [[day orders] current-days] + [day (if (contains? days day) (days day) orders)]))) + (update :orders #(reduce (fn [m order] (assoc m (:id order) order)) % (mapcat second days)))))) (re-frame/reg-event-fx ::scroll-weeks @@ -131,7 +130,7 @@ ::fetch-orders (fn [_ [_ from to]] {:dispatch [::start-loading] - :http-xhrio (http-get "orders" {} ::process-stock)})) + :http-xhrio (http-request :get "orders")})) ;; Customers events (re-frame/reg-event-fx @@ -170,12 +169,11 @@ (defn assoc-if [coll key val] (if val (assoc coll key val) coll)) (re-frame/reg-event-fx ::process-stock - (fn [{db :db} [_ {:keys [products customers orders]}]] + (fn [{db :db} [_ {:keys [products customers]}]] {:db (-> db (assoc-if :products products) - (assoc-if :customers customers) - (assoc-if :orders (some->> orders (into {} (map #(vector (:id %) %)))))) - :dispatch [::scroll-weeks 0] + (assoc-if :customers customers)) + :dispatch [::stop-loading] })) (re-frame/reg-event-fx @@ -183,7 +181,7 @@ (fn [_ [_ products]] {:fx [[:dispatch [::hide-modal :stock]] [:dispatch [::start-loading]]] - :http-xhrio (http-request :post "products" :body products :on-sucess ::process-stock)})) + :http-xhrio (http-request :post "products" :body products :on-success ::process-stock)})) ;; Settings diff --git a/src/cljs/chicken_master/html.cljs b/src/cljs/chicken_master/html.cljs index b44a769..e62e0dc 100644 --- a/src/cljs/chicken_master/html.cljs +++ b/src/cljs/chicken_master/html.cljs @@ -39,7 +39,8 @@ content [:div {:class :form-buttons} [:button {:type :button :on-click #(re-frame/dispatch [::event/hide-modal modal-id])} "ok"]]]]) - ([modal-id content on-submit] + ([modal-id content & {:keys [on-submit submit-text] + :or {submit-text "ok"}}] [:div {:class :popup :on-click #(re-frame/dispatch [::event/hide-modal modal-id])} [:form {:action "#" :class :popup-content @@ -50,7 +51,7 @@ (re-frame/dispatch [::event/hide-modal modal-id])))} content [:div {:class :form-buttons} - [:button "ok"] + [:button submit-text] [:button {:type :button :on-click #(re-frame/dispatch [::event/hide-modal modal-id])} "anuluj"]]]])) diff --git a/src/cljs/chicken_master/products.cljs b/src/cljs/chicken_master/products.cljs index 5d1f4d3..37c56f0 100644 --- a/src/cljs/chicken_master/products.cljs +++ b/src/cljs/chicken_master/products.cljs @@ -40,36 +40,34 @@ [:div {:class :product-item-edit :key (gensym)} [:div {:class :input-item} ;; [:label {:for :product} "co"] - [:select {:name (str "product-" id) :id :product :defaultValue (some-> what name) + [:select {:name (str "product-" id) :id :product :defaultValue (or (some-> what name) "-") :on-change #(let [prod (-> % .-target .-value keyword)] (if-not (= prod :-) (swap! state assoc prod (+ (@state prod) (@state what)))) - (swap! state dissoc what) - )} - (for [product (-> available (conj what) sort vec (conj nil))] - [:option {:key (gensym) :value product} (if product (name product) "-")])] - ] + (swap! state dissoc what))} + (for [product (->> available (concat [what]) (remove nil?) sort vec)] + [:option {:key (gensym) :value product} (name product)]) + [:option {:key (gensym) :value nil} "-"]]] (number-input (str "amount-" id) nil (@state what) - #(swap! state assoc what (-> % .-target .-value num-or-nil))) - ])) + #(swap! state assoc what (-> % .-target .-value num-or-nil)))])) (defn products-edit [selected-prods & {:keys [available-prods getter-fn] :or {available-prods @(re-frame/subscribe [::subs/available-products])}}] - (let [state (reagent/atom (or selected-prods {}))] + (let [state (reagent/atom (or selected-prods {})) + all-product-names (-> available-prods keys set)] (fn [] - (let [available (remove (partial get @state) (keys available-prods)) - products (->> @state - keys - sort + (let [available (remove (partial get @state) all-product-names) + product-names (if (seq available) + (conj (->> @state (map first) vec) nil) + (map first @state)) + products (->> product-names (map (partial product-item available state)) - (into [:div {:class :product-items-edit}])) - products (conj products (product-item available state nil))] + (into [:div {:class :product-items-edit}]))] (if getter-fn (conj products [:button {:type :button :on-click #(getter-fn (dissoc @state nil))} "ok"]) - products - ))))) + products))))) (defn format-product [settings [product amount]] [:div {:key (gensym) :class :product} diff --git a/src/cljs/chicken_master/stock.cljs b/src/cljs/chicken_master/stock.cljs index 23600ca..c78109d 100644 --- a/src/cljs/chicken_master/stock.cljs +++ b/src/cljs/chicken_master/stock.cljs @@ -29,11 +29,11 @@ [:h2 "Magazyn"] [stock-form @(re-frame/subscribe [::subs/available-products])]] ;; On success - (fn [form] - (->> form - (reduce-kv #(if-let [val (prod/num-or-nil %3)] - (assoc %1 (keyword %2) val) - %1) - {}) - (conj [::event/save-stock]) - re-frame/dispatch)))) + :on-submit (fn [form] + (->> form + (reduce-kv #(if-let [val (prod/num-or-nil %3)] + (assoc %1 (keyword %2) val) + %1) + {}) + (conj [::event/save-stock]) + re-frame/dispatch)))) diff --git a/src/cljs/chicken_master/subs.cljs b/src/cljs/chicken_master/subs.cljs index c396f94..a40665c 100644 --- a/src/cljs/chicken_master/subs.cljs +++ b/src/cljs/chicken_master/subs.cljs @@ -14,8 +14,6 @@ (re-frame/reg-sub ::show-customers-modal (fn [db] (-> db :clients :show))) (re-frame/reg-sub ::show-settings-modal (fn [db] (-> db :settings :show))) -(re-frame/reg-sub ::order-edit-who (fn [db] (-> db :order-edit :who))) -(re-frame/reg-sub ::order-edit-notes (fn [db] (-> db :order-edit :notes))) -(re-frame/reg-sub ::order-edit-products (fn [db] (-> db :order-edit :products))) +(re-frame/reg-sub ::editted-order (fn [db] (:order-edit db))) (re-frame/reg-sub ::current-days (fn [db] (:current-days db)))