This commit is contained in:
Daniel O'Connell 2021-03-01 22:40:46 +01:00
parent 182e613deb
commit 38053bbdb2
13 changed files with 136 additions and 79 deletions

7
config/prod/config.edn Normal file
View File

@ -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"}
}

13
infra/chickens.service Normal file
View File

@ -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

35
infra/nginx/chickens.conf Normal file
View File

@ -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
}

View File

@ -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))

View File

@ -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)))

View File

@ -9,11 +9,12 @@
(into {})))
(defn products-map [tx products]
(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 {})))
(into {}))))
(defn update! [user-id new-products]
(jdbc/with-transaction [tx db/db-uri]

View File

@ -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))

View File

@ -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 edit-order []
(html/modal
:order-edit
(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 @(re-frame/subscribe [::subs/order-edit-who])
customers @(re-frame/subscribe [::subs/available-customers])]
(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 @(re-frame/subscribe [::subs/order-edit-notes])})
[prod/products-edit @(re-frame/subscribe [::subs/order-edit-products])]]
{:default (:notes @state)})
[prod/products-edit (:products @state) :available-prods available-prods]])))
(defn edit-order []
(html/modal
:order-edit
[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)

View File

@ -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]]
@ -97,14 +97,13 @@
(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)))))
[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

View File

@ -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"]]]]))

View File

@ -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}

View File

@ -29,7 +29,7 @@
[:h2 "Magazyn"]
[stock-form @(re-frame/subscribe [::subs/available-products])]]
;; On success
(fn [form]
:on-submit (fn [form]
(->> form
(reduce-kv #(if-let [val (prod/num-or-nil %3)]
(assoc %1 (keyword %2) val)

View File

@ -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)))