Seperate users

This commit is contained in:
Daniel O'Connell 2021-02-23 23:26:32 +01:00
parent d0a14bd1ab
commit 182e613deb
6 changed files with 81 additions and 66 deletions

View File

@ -9,22 +9,24 @@ CREATE TABLE users (
CREATE TABLE customers ( CREATE TABLE customers (
id SERIAL, id SERIAL,
name VARCHAR(512) UNIQUE, name VARCHAR(512),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted BOOLEAN, deleted BOOLEAN,
user_id INT, user_id INT,
PRIMARY KEY(id), PRIMARY KEY(id),
UNIQUE(name, user_id),
CONSTRAINT fk_users FOREIGN KEY(user_id) REFERENCES users(id) CONSTRAINT fk_users FOREIGN KEY(user_id) REFERENCES users(id)
); );
CREATE TABLE products ( CREATE TABLE products (
id SERIAL, id SERIAL,
name VARCHAR(512) UNIQUE, name VARCHAR(512),
amount NUMERIC, amount NUMERIC,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted BOOLEAN, deleted BOOLEAN,
user_id INT, user_id INT,
PRIMARY KEY(id), PRIMARY KEY(id),
UNIQUE(name, user_id),
CONSTRAINT fk_users FOREIGN KEY(user_id) REFERENCES users(id) CONSTRAINT fk_users FOREIGN KEY(user_id) REFERENCES users(id)
); );

View File

@ -4,17 +4,17 @@
[chicken-master.db :as db] [chicken-master.db :as db]
[chicken-master.orders :as orders])) [chicken-master.orders :as orders]))
(defn get-all [] (defn get-all [user-id]
(->> (sql/query db/db-uri ["select * from customers where deleted is null"]) (->> (sql/query db/db-uri ["select * from customers where deleted is null AND user_id = ?" user-id])
(map (fn [{:customers/keys [id name]}] {:id id :name name})))) (map (fn [{:customers/keys [id name]}] {:id id :name name}))))
(defn create! [name] (defn create! [user-id name]
(jdbc/execute! db/db-uri (jdbc/execute! db/db-uri
["INSERT INTO customers (name) VALUES(?) ON CONFLICT (name) DO UPDATE SET deleted = NULL" ["INSERT INTO customers (name, user_id) VALUES(?, ?) ON CONFLICT (name, user_id) DO UPDATE SET deleted = NULL"
name]) name user-id])
{:customers (get-all)}) {:customers (get-all user-id)})
(defn delete! [id] (defn delete! [user-id id]
(sql/update! db/db-uri :customers {:deleted true} {:id id}) (sql/update! db/db-uri :customers {:deleted true} {:id id :user_id user-id})
{:orders (orders/get-all) {:orders (orders/get-all user-id)
:customers (get-all)}) :customers (get-all user-id)})

View File

@ -15,9 +15,15 @@
["INSERT INTO users (name, password) VALUES (?, crypt(?, gen_salt('bf')))" name passwd])) ["INSERT INTO users (name, password) VALUES (?, crypt(?, gen_salt('bf')))" name passwd]))
(defn valid-user? [name passwd] (defn valid-user? [name passwd]
(jdbc/execute-one! (:users/id (jdbc/execute-one!
db-uri db-uri
[" SELECT * FROM users WHERE name = ? AND password = crypt(?, password)" name passwd])) ["SELECT * FROM users WHERE name = ? AND password = crypt(?, password)" name passwd])))
(defn get-by-id
([tx user-id table id] (get-by-id tx user-id table id :id))
([tx user-id table id id-column]
(jdbc/execute-one! tx [(str "SELECT * from " (name table) " WHERE " (name id-column) " = ? AND user_id = ?")
id user-id])))
(comment (comment
(create-user "siloa" "krach") (create-user "siloa" "krach")

View File

@ -16,41 +16,44 @@
{:headers {"Content-Type" "application/edn"} {:headers {"Content-Type" "application/edn"}
:body resp}) :body resp})
(defn get-customers [] (as-edn (customers/get-all))) (defn get-customers [user-id] (as-edn (customers/get-all user-id)))
(defn add-customer [request] (as-edn (some-> request :body :name customers/create!))) (defn add-customer [{:keys [body basic-authentication]}]
(defn delete-customer [id] (as-edn (customers/delete! (edn/read-string id)))) (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 [_] (as-edn (products/get-all))) (defn get-products [user-id] (as-edn (products/get-all user-id)))
(defn save-products [request] (as-edn (some-> request :body products/update!))) (defn save-products [{:keys [body basic-authentication]}]
(some->> body (products/update! basic-authentication) as-edn))
(defn get-orders [params] (as-edn {:orders (orders/get-all)})) (defn get-orders [user-id] (as-edn {:orders (orders/get-all user-id)}))
(defn update-order [request] (defn update-order [request]
(let [id (some-> request :route-params :id (Integer/parseInt)) (let [user-id (:basic-authentication request)
id (some-> request :route-params :id (Integer/parseInt))
order (-> request :body (update :id #(or % id)))] order (-> request :body (update :id #(or % id)))]
(as-edn (orders/replace! order)))) (as-edn (orders/replace! user-id order))))
(defn delete-order [id] (as-edn (orders/delete! (edn/read-string id)))) (defn delete-order [user-id id] (->> id edn/read-string (orders/delete! user-id) as-edn))
(defn set-order-state [id status] (as-edn (orders/change-state! (edn/read-string id) status))) (defn set-order-state [user-id id status] (as-edn (orders/change-state! user-id (edn/read-string id) status)))
(defn get-stock [params] (defn get-stock [user-id]
(as-edn (as-edn
{:customers (:body (get-customers)) {:customers (:body (get-customers user-id))
:products (:body (get-products params))})) :products (:body (get-products user-id))}))
(defroutes routes (defroutes routes
(GET "/stock" {params :query-params} (get-stock params)) (GET "/stock" [:as {user-id :basic-authentication}] (get-stock user-id))
(GET "/customers" [] (get-customers)) (GET "/customers" [:as {user-id :basic-authentication}] (get-customers user-id))
(POST "/customers" request (add-customer request)) (POST "/customers" request (add-customer request))
(DELETE "/customers/:id" [id] (delete-customer id)) (DELETE "/customers/:id" [id :as {user-id :basic-authentication}] (delete-customer user-id id))
(GET "/products" request (get-products request)) (GET "/products" request (get-products request))
(POST "/products" request (save-products request)) (POST "/products" request (save-products request))
(GET "/orders" {params :query-params} (get-orders params)) (GET "/orders" [:as {user-id :basic-authentication}] (get-orders user-id))
(POST "/orders" request (update-order request)) (POST "/orders" request (update-order request))
(PUT "/orders/:id" request (update-order request)) (PUT "/orders/:id" request (update-order request))
(DELETE "/orders/:id" [id] (delete-order id)) (DELETE "/orders/:id" [id :as {user-id :basic-authentication}] (delete-order user-id id))
(POST "/orders/:id/:status" [id status] (set-order-state id status)) (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"})) (GET "/" [] (resource-response "index.html" {:root "public"}))
(resources "/") (resources "/")

View File

@ -6,14 +6,15 @@
[chicken-master.products :as products] [chicken-master.products :as products]
[chicken-master.time :as t])) [chicken-master.time :as t]))
(defn- upsert-order! [tx user-id {:keys [id day state notes]}] (defn- upsert-order! [tx user-id customer-id {:keys [id day state notes]}]
(let [order {:customer_id user-id (let [order {:customer_id customer-id
:notes notes :notes notes
:status (some-> state name jdbc.types/as-other) :status (some-> state name jdbc.types/as-other)
:order_date (some-> day t/parse-date t/inst->timestamp)}] :order_date (some-> day t/parse-date t/inst->timestamp)}]
(if id (if (db/get-by-id tx user-id :orders id)
(do (sql/update! tx :orders order {:id id}) id) (do (sql/update! tx :orders order {:id id}) id)
(:orders/id (sql/insert! tx :orders order))))) (:orders/id (sql/insert! tx :orders (assoc order :user_id user-id))))))
(defn- structure-order [items] (defn- structure-order [items]
{:id (-> items first :orders/id) {:id (-> items first :orders/id)
@ -39,32 +40,35 @@
vals vals
(map structure-order))) (map structure-order)))
(defn get-order [tx id] (defn get-order [tx user-id id]
(first (get-orders tx "WHERE o.id = ?" [id]))) (first (get-orders tx "WHERE o.id = ? AND o.user_id = ?" [id user-id])))
(defn get-all [] (get-orders db/db-uri nil [])) (defn get-all [user-id] (get-orders db/db-uri "WHERE o.user_id = ?" [user-id]))
(defn- orders-for-days [tx & days] (defn- orders-for-days [tx user-id & days]
(let [days (remove nil? days)] (let [days (remove nil? days)]
(->> days (->> days
(map t/inst->timestamp) (map t/inst->timestamp)
(map jdbc.types/as-date) (map jdbc.types/as-date)
(get-orders tx (str "WHERE o.order_date::date IN " (db/psql-list days)))))) (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 from to] (defn- orders-between [tx user-id from to]
(get-orders (get-orders
tx tx
"WHERE o.order_date::date >= ? AND o.order_date::date <= ?" "WHERE o.order_date::date >= ? AND o.order_date::date <= ? AND o.user_id = ?"
[(some-> from t/inst->timestamp jdbc.types/as-date) [(some-> from t/inst->timestamp jdbc.types/as-date)
(some-> to t/inst->timestamp jdbc.types/as-date)])) (some-> to t/inst->timestamp jdbc.types/as-date)
user-id]))
(defn replace! [{:keys [who products] :as order}] (defn replace! [user-id {:keys [who products] :as order}]
(prn order)
(jdbc/with-transaction [tx db/db-uri] (jdbc/with-transaction [tx db/db-uri]
(let [user-id (or (:id who) (let [customer-id (or (:id who)
(:customers/id (sql/get-by-id tx :customers (:name who) :name {}))) (:customers/id (db/get-by-id tx user-id :customers (:name who) :name)))
products-map (products/products-map tx products) products-map (products/products-map tx products)
previous-day (some->> order :id (sql/get-by-id tx :orders) :orders/order_date (.toInstant)) previous-day (some->> order :id (db/get-by-id tx user-id :orders) :orders/order_date (.toInstant))
order-id (upsert-order! tx user-id order)] order-id (upsert-order! tx user-id customer-id order)]
(sql/delete! tx :order_products {:order_id order-id}) (sql/delete! tx :order_products {:order_id order-id})
(sql/insert-multi! tx :order_products (sql/insert-multi! tx :order_products
[:order_id :product_id :amount] [:order_id :product_id :amount]
@ -72,21 +76,21 @@
:let [product-id (-> n name products-map)] :let [product-id (-> n name products-map)]
:when product-id] :when product-id]
[order-id product-id amount])) [order-id product-id amount]))
(orders-for-days tx previous-day (some-> order :day t/parse-date))))) (orders-for-days tx user-id previous-day (some-> order :day t/parse-date)))))
(defn delete! [id] (defn delete! [user-id id]
(jdbc/with-transaction [tx db/db-uri] (jdbc/with-transaction [tx db/db-uri]
(let [day (some->> id (sql/get-by-id tx :orders) :orders/order_date (.toInstant))] (let [day (some->> id (db/get-by-id tx user-id :orders) :orders/order_date (.toInstant))]
(sql/delete! tx :orders {:id id}) (sql/delete! tx :orders {:id id :user_id user-id})
(when day (orders-for-days tx day))))) (when day (orders-for-days tx user-id day)))))
(defn change-state! (defn change-state!
"Update the state of the given order and also modify the number of products available: "Update the state of the given order and also modify the number of products available:
* when `fulfilled` decrement the number of products * when `fulfilled` decrement the number of products
* when `waiting` increment the number (as this means a previously fulfilled order has been returned)" * when `waiting` increment the number (as this means a previously fulfilled order has been returned)"
[id state] [user-id id state]
(jdbc/with-transaction [tx db/db-uri] (jdbc/with-transaction [tx db/db-uri]
(let [order (get-order tx id) (let [order (get-order tx user-id id)
operator (condp = state operator (condp = state
"fulfilled" "-" "fulfilled" "-"
"waiting" "+")] "waiting" "+")]
@ -96,4 +100,4 @@
[(str "UPDATE products SET amount = amount " operator " ? WHERE name = ?") [(str "UPDATE products SET amount = amount " operator " ? WHERE name = ?")
amount (name prod)])) amount (name prod)]))
(sql/update! tx :orders {:status (jdbc.types/as-other state)} {:id id})) (sql/update! tx :orders {:status (jdbc.types/as-other state)} {:id id}))
(orders-for-days tx (-> order :day t/parse-date))))) (orders-for-days tx user-id (-> order :day t/parse-date)))))

View File

@ -3,8 +3,8 @@
[next.jdbc.sql :as sql] [next.jdbc.sql :as sql]
[chicken-master.db :as db])) [chicken-master.db :as db]))
(defn get-all [] (defn get-all [user-id]
(->> (sql/query db/db-uri ["select * from products where deleted is null"]) (->> (sql/query db/db-uri ["select * from products where deleted is null and user_id = ?" user-id])
(map (fn [{:products/keys [name amount]}] [(keyword name) amount])) (map (fn [{:products/keys [name amount]}] [(keyword name) amount]))
(into {}))) (into {})))
@ -15,15 +15,15 @@
(map #(vector (:products/name %) (:products/id %))) (map #(vector (:products/name %) (:products/id %)))
(into {}))) (into {})))
(defn update! [new-products] (defn update! [user-id new-products]
(jdbc/with-transaction [tx db/db-uri] (jdbc/with-transaction [tx db/db-uri]
(doseq [[prod amount] new-products] (doseq [[prod amount] new-products]
(jdbc/execute! tx (jdbc/execute! tx
["INSERT INTO products (name, amount) VALUES(?, ?) ["INSERT INTO products (name, amount, user_id) VALUES(?, ?, ?)
ON CONFLICT (name) DO UPDATE SET amount = EXCLUDED.amount, deleted = NULL" ON CONFLICT (name, user_id) DO UPDATE SET amount = EXCLUDED.amount, deleted = NULL"
(name prod) amount])) (name prod) amount user-id]))
(sql/update! tx :products (sql/update! tx :products
{:deleted true} {:deleted true}
(into [(str "name NOT IN " (db/psql-list (keys new-products)))] (into [(str "name NOT IN " (db/psql-list (keys new-products)))]
(->> new-products keys (map name))))) (->> new-products keys (map name)))))
(get-all)) (get-all user-id))