going somewhere
This commit is contained in:
1 parent
6e266c787b
commit
440206e924
15 files changed
+289
-46
No files matched your search
@@ -41,9 +41,28 @@
|
||||
(catch [:error-type :5XX] e (build-response request e)))))
|
||||
|
||||
|
||||
(defn get-all-users [conn]
|
||||
(fn [{{email :email} :route-params :as request}]
|
||||
(try+
|
||||
(timbre/info "getting user with email" email)
|
||||
(let [db (d/db conn)
|
||||
emails (d/q '[:find ?email
|
||||
:where [_ :skirmish.broker.user/email ?email]] db)
|
||||
xf (comp cat (map #(hash-map :email % :url (str "/api/1/users/" %))))]
|
||||
(build-response request
|
||||
(doall ((sequence xf emails)))))
|
||||
(catch [:error-type :4XX] e (build-response request e))
|
||||
(catch [:error-type :5XX] e (build-response request e)))))
|
||||
|
||||
(defn get-account [conn]
|
||||
(fn [email account]))
|
||||
|
||||
|
||||
(defn create-routes [conn]
|
||||
(routes
|
||||
(context "/api/1" []
|
||||
(POST "/users" [] (create-user conn))
|
||||
(GET "/users/:email" [email] (get-user conn)))
|
||||
(GET "/users" [] (get-all-users conn))
|
||||
(GET "/users/:email" [email] (get-user conn))
|
||||
(GET "/users/:email/accounts/:account" [email account] (get-account conn)))
|
||||
not-found-resp))
|
||||
@@ -47,30 +47,36 @@
|
||||
:db/valueType :db.type/keyword
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/unique :db.unique/identity
|
||||
:db/doc "The sec id."}
|
||||
:db/doc "The security id."}
|
||||
{
|
||||
:db/ident :skirmish.security/name
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The usual name of the security."}
|
||||
{
|
||||
:db/ident :skirmish.security/type
|
||||
:db/valueType :db.type/keyword
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/unique :db.unique/identity
|
||||
:db/doc "The type of security. For instance :equity or :currency."}
|
||||
{
|
||||
:db/ident :skirmish.security/description
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/unique :db.unique/identity
|
||||
:db/doc "The description of the currency. Please be verbose."}
|
||||
{
|
||||
:db/ident :skirmish.security/emitter
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/unique :db.unique/identity
|
||||
:db/doc "The public key of the emmiter. This is not yet supported."}
|
||||
{
|
||||
:db/ident :skirmish.security/number-of-decimal
|
||||
:db/valueType :db.type/long
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The number of decimal to show in the pretty printing."}
|
||||
{
|
||||
:db/ident :skirmish.security/symbol
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/unique :db.unique/identity
|
||||
:db/doc "The symbol of the security for pretty printing."}
|
||||
{
|
||||
:db/ident :skirmish.security/interest-rate
|
||||
@@ -108,7 +114,7 @@
|
||||
(defn create-connection [uri]
|
||||
(let [new-db? (d/create-database uri)
|
||||
conn (d/connect uri)]
|
||||
(when new-db?
|
||||
@(d/transact conn schema))
|
||||
;(when new-db?
|
||||
@(d/transact conn schema)
|
||||
conn))
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[slingshot.slingshot :refer [try+ throw+]]
|
||||
[compojure.route :refer [not-found]]
|
||||
[skirmish.exchange-gateway.exchange-gateway :refer [create-routes-for-exchange]]
|
||||
[skirmish.rest.util :refer [build-response get-body]]
|
||||
[skirmish.rest.util :refer [build-response get-body cors-middleware]]
|
||||
[skirmish.ledger.accounts]
|
||||
[datomic.api :as d]
|
||||
[taoensso.timbre :as timbre]
|
||||
@@ -21,7 +21,7 @@
|
||||
(defn get-account-body [request account sec]
|
||||
(if (nil? sec)
|
||||
(build-response request {:status 404})
|
||||
(let [sec-url (str "/api/1/securities/" (-> sec :skirmish.security/sec-id name))
|
||||
(let [sec-url (str "/api/1/ledger/securities/" (-> sec :skirmish.security/sec-id name))
|
||||
beautify-account { :amount (:skirmish.ledger/amount account)
|
||||
:sec-id (:skirmish.security/sec-id sec)
|
||||
:account-public-key (:skirmish.ledger/owner-public-key account)}
|
||||
@@ -63,21 +63,38 @@
|
||||
raw-securities
|
||||
(throw+ {:error-type :4XX :status 400 :body {:error "Invalid security format."}})))
|
||||
|
||||
(defn get-security-from-db [conn sec-id]
|
||||
(let [db (d/db conn)
|
||||
e (d/pull db '[*] [:skirmish.security/sec-id sec-id])
|
||||
{interest-rate :skirmish.security/interest-rate
|
||||
|
||||
(defn prettify-security [e db]
|
||||
(let [{interest-rate :skirmish.security/interest-rate
|
||||
description :skirmish.security/description
|
||||
id :db/id
|
||||
sec-id :skirmish.security/sec-id
|
||||
symbol :skirmish.security/symbol
|
||||
name :skirmish.security/name
|
||||
number-of-decimal :skirmish.security/number-of-decimal
|
||||
type_ :skirmish.security/type} e
|
||||
volume (d/q '[:find (sum ?a) .
|
||||
:where [?e :skirmish.ledger/amount ?a]
|
||||
[?e :skirmish.ledger/owner-public-key ?pk]]
|
||||
db)
|
||||
ret {:sec-id sec-id :interest-rate interest-rate :volume volume :type type_ :description description}]
|
||||
(if (nil? id)
|
||||
volume (d/q '[:find (sum ?amount) .
|
||||
:in $ ?id
|
||||
:where [?e :skirmish.ledger/sec ?id]
|
||||
[?e :skirmish.ledger/amount ?amount]]
|
||||
|
||||
db id)]
|
||||
{:sec-id sec-id
|
||||
:interest-rate interest-rate
|
||||
:volume (or volume 0)
|
||||
:name name
|
||||
:symbol symbol
|
||||
:number-of-decimal number-of-decimal
|
||||
:type type_
|
||||
:description description}))
|
||||
|
||||
(defn get-security-from-db [conn sec-id]
|
||||
(let [db (d/db conn)
|
||||
e (d/pull db '[*] [:skirmish.security/sec-id sec-id])]
|
||||
(println (str e))
|
||||
(if (-> e :db/id nil?)
|
||||
(throw+ {:error-type :4XX :status 404 :body {:error "Security not found."}})
|
||||
ret)))
|
||||
(prettify-security e db))))
|
||||
|
||||
(defn create-security [conn]
|
||||
"Create a fresh new security."
|
||||
@@ -156,11 +173,13 @@
|
||||
(let [securities (d/q '[:find ?pk :where [?e :skirmish.ledger/owner-public-key ?pk]] (d/db conn))]
|
||||
(build-response request (get-available-accounts-body securities)))))
|
||||
|
||||
|
||||
(defn get-api-description [request]
|
||||
(let [body [{:url "ledger/accounts" :name "accounts"}
|
||||
{:url "ledger/securities" :name "securities"}]]
|
||||
(build-response request body)))
|
||||
|
||||
|
||||
(defn create-routes-for-ledger [securities conn]
|
||||
(routes
|
||||
(context "/api/1/ledger" []
|
||||
@@ -181,4 +200,7 @@
|
||||
api-routes (create-routes-for-ledger (:securities config) conn)]
|
||||
|
||||
(timbre/info "Running skirmish.ledger.core server with config: " ledger-config)
|
||||
(run-server (api api-routes) ledger-config)))
|
||||
(run-server
|
||||
(-> api-routes api cors-middleware)
|
||||
ledger-config)))
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
(ns skirmish.routes)
|
||||
|
||||
(defn get-app-for [all-routes k]
|
||||
"An app consists on a name, a prefix and some routes."
|
||||
(let [app-name (-> k namespace keyword)
|
||||
app (first (filter #(= app-name (:name %)) all-routes))]
|
||||
app))
|
||||
|
||||
(defn- get-route-for [all-routes k]
|
||||
(let [app (get-app-for all-routes k)
|
||||
route-name (-> k name keyword)
|
||||
route (first (filter #(= route-name (:name %)) (:routes app)))]
|
||||
route))
|
||||
|
||||
(defn get-compojure-path [all-routes k]
|
||||
"Returns what compojure expects to have."
|
||||
(->> k (get-route-for all-routes) :path))
|
||||
|
||||
(defn replace-part [part params]
|
||||
(if (clojure.string/starts-with? part ":")
|
||||
(-> part (subs 1) keyword params)
|
||||
part))
|
||||
|
||||
(defn path-for [p params]
|
||||
(let [parts (clojure.string/split p #"/")]
|
||||
(clojure.string/join "/" (map #(replace-part % params) parts))))
|
||||
|
||||
|
||||
(defn get-context [all-routes c]
|
||||
(let [get-app #(get-app-for all-routes %)]
|
||||
(-> c
|
||||
name
|
||||
(keyword "some-name")
|
||||
get-app
|
||||
:path)))
|
||||
|
||||
|
||||
(defn get-path-for
|
||||
"Returns a link to a location by name."
|
||||
([all-routes k]
|
||||
(get-path-for all-routes k {}))
|
||||
([all-routes k params]
|
||||
(let [app (get-app-for all-routes k)
|
||||
route (get-route-for all-routes k)
|
||||
p (str (:path app) (:path route))]
|
||||
(path-for p params))))
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
(ns skirmish.wui-util)
|
||||
|
||||
(defn pp-number [n])
|
||||
@@ -0,0 +1,6 @@
|
||||
(ns skirmish.wui.components.face-value
|
||||
(:require [skirmish.wui.components.secunit :refer [secunit]]))
|
||||
|
||||
(defn face-value [amount sec-id]
|
||||
(when (= sec-id :dapm)
|
||||
(secunit amount sec-id)))
|
||||
@@ -1,24 +1,35 @@
|
||||
(ns skirmish.wui.components.portfolio-page
|
||||
(:require [reagent.core :refer [atom]]
|
||||
[cljs-http.client :as http]
|
||||
[skirmish.wui.components.face-value :refer [face-value]]
|
||||
[cljs.core.async :refer [<!] :refer-macros [go] :as async]
|
||||
[skirmish.wui.components.secunit :refer [secunit]]))
|
||||
|
||||
|
||||
(defn make-portfolio-summary-table [portfolio]
|
||||
[:table
|
||||
[:thead
|
||||
[:tr [:th "Security"] [:th "Amount"] [:th "Face Value"]]]
|
||||
[:tbody
|
||||
(for [sec-summary portfolio]
|
||||
[:tr {:key (:id sec-summary)}
|
||||
(for [{sec-summary :account} portfolio]
|
||||
[:tr {:key (:account-public-key sec-summary)}
|
||||
[:td (:sec-id sec-summary)]
|
||||
[:td [secunit (:sec-id sec-summary) (:amount sec-summary)]]
|
||||
[:td [secunit :dapm (:face-value sec-summary)]]])]])
|
||||
[:td [secunit (:amount sec-summary) (-> sec-summary :sec-id keyword)]]
|
||||
[:td [face-value (:amount sec-summary) (-> sec-summary :sec-id keyword)]]])]])
|
||||
|
||||
|
||||
(defn get-accounts-information [urls a-accounts]
|
||||
(go
|
||||
(let [ar (async/merge (map #(http/get % {:with-credentials? false}) urls))
|
||||
accounts (map :body (<! (async/into [] ar)))]
|
||||
(reset! a-accounts accounts))))
|
||||
|
||||
(defn shit [urls accounts]
|
||||
[:div.content
|
||||
[make-portfolio-summary-table accounts]])
|
||||
|
||||
|
||||
(defn page [{{accounts :skirmish.broker.user/accounts} :user}]
|
||||
(let [porfolio [{:id 12 :sec-id :foo :amount 100 :face-value 1265}
|
||||
{:id 54 :sec-id :toto :amount 100 :face-value 1265}
|
||||
{:id 66 :sec-id :foo :amount 100 :face-value 1265}]]
|
||||
[:div.content
|
||||
[:pre (str accounts)]
|
||||
(make-portfolio-summary-table porfolio)]))
|
||||
(let [urls (map :skirmish.broker.account/url accounts)
|
||||
a-accounts (atom [])]
|
||||
(get-accounts-information urls a-accounts)
|
||||
#(shit urls @a-accounts)))
|
||||
@@ -1,5 +1,25 @@
|
||||
(ns skirmish.wui.components.secunit)
|
||||
(ns skirmish.wui.components.secunit
|
||||
(:require [reagent.core :refer [atom]]
|
||||
[skirmish.wui.util :refer [pp-int]]
|
||||
[cljs-http.client :as http]
|
||||
[cljs.core.async :refer [<!] :refer-macros [go] :as async]))
|
||||
|
||||
(defn secunit [sec-id amount]
|
||||
(let [href (str "/securities/" sec-id)]
|
||||
[:a {:href href} (str amount)]))
|
||||
|
||||
(defn get-security-definition [sec sec-id]
|
||||
(go
|
||||
(let [url (str "http://localhost:1604/api/1/ledger/securities/" (name sec-id))
|
||||
resp (<! (http/get url {:with-credentials? false}))]
|
||||
(reset! sec (:body resp)))))
|
||||
|
||||
|
||||
(defn- pp-amount [amount sec]
|
||||
(when (seq sec)
|
||||
(let [{sec-id :sec-id number-of-decimal :number-of-decimal symbol :symbol} sec
|
||||
href (str "/securities/" sec-id)]
|
||||
[:a {:href href} (pp-int amount (or number-of-decimal 0)) " "
|
||||
(or symbol "")])))
|
||||
|
||||
(defn secunit [amount sec-id]
|
||||
(let [sec (atom {})]
|
||||
(get-security-definition sec sec-id)
|
||||
#(pp-amount amount @sec)))
|
||||
@@ -1,4 +1,41 @@
|
||||
(ns skirmish.wui.components.security-page)
|
||||
(ns skirmish.wui.components.security-page
|
||||
(:require [skirmish.wui.util :refer [pp-int]]
|
||||
[reagent.core :refer [atom]]
|
||||
[cljs-http.client :as http]
|
||||
[cljs.core.async :refer [<!] :refer-macros [go]]))
|
||||
|
||||
|
||||
(defn get-ledget-information [sec-info sec-id]
|
||||
(go
|
||||
(let [url (str "http://localhost:1604/api/1/ledger/securities/" (name sec-id))
|
||||
resp (<! (http/get url {:with-credentials? false}))]
|
||||
(reset! sec-info (:body resp)))))
|
||||
|
||||
|
||||
(defn create-ledger-table [sec-info]
|
||||
[:div
|
||||
[:h1 (:name sec-info)]
|
||||
[:cite (:description sec-info)]
|
||||
[:table
|
||||
[:tbody
|
||||
[:tr
|
||||
[:td "Security ID"] [:td (:sec-id sec-info)]]
|
||||
[:tr
|
||||
[:td "Type"] [:td (:type sec-info)]]
|
||||
[:tr
|
||||
[:td "Symbol"] [:td (:symbol sec-info)]]
|
||||
[:tr
|
||||
[:td "Interest Rate"] [:td (:interest-rate sec-info)]]
|
||||
[:tr
|
||||
[:td "Total Volume"] [:td (-> sec-info :volume (pp-int (:number-of-decimal sec-info)))]]]]])
|
||||
|
||||
|
||||
(defn ledger-table [sec-id]
|
||||
(let [sec-info (atom {})]
|
||||
(get-ledget-information sec-info sec-id)
|
||||
#(create-ledger-table @sec-info)))
|
||||
|
||||
|
||||
(defn page [state]
|
||||
[:h1 (str "this is a security page for " (:sec-id state))])
|
||||
[:div.content
|
||||
[ledger-table (:sec-id state)]])
|
||||
@@ -19,9 +19,16 @@
|
||||
[:li done "add the notion of 'accounts' in the server. An
|
||||
user should have many accounts; one for each security
|
||||
he owns"]
|
||||
[:li on-it "make the " [:a {:href "/portfolio"} "portfolio"] " page representing the use accounts"]
|
||||
[:li done "make the " [:a {:href "/portfolio"} "portfolio"] " page representing the use accounts"]
|
||||
[:li done "make a somewhat pretty " [:a {:href "/securities/dapm"} "security"] " page"]
|
||||
[:li done "create two stocks"]
|
||||
[:li on-it "add stocks to didier@gmail.com"]
|
||||
[:li on-it "make something for urls on the backend"]
|
||||
[:li "add a little bit of professionalism on top of the broker api"]
|
||||
[:li "make the api support transit and edn"]
|
||||
[:li "implements interest rate in ledger."]
|
||||
[:li "Make sure the ledger can have accounts"]
|
||||
[:li "when a new user logs in, he should receive some sort of money"]
|
||||
[:li "when a new user signs in, he should receive some sort of money"]
|
||||
[:li "\u22EE"]
|
||||
[:li "implement buy/sell securities."]]]
|
||||
|
||||
@@ -34,7 +41,6 @@
|
||||
[:ol
|
||||
[:li "Use ledger as source of through in each sub server."]
|
||||
[:li "Update web ui for integrating securities with ledger."]
|
||||
[:li "Create a basic broker that supports..."]
|
||||
[:li "Ledger should compute interest rate."]
|
||||
[:li "implement transactions in ledger."]
|
||||
[:li "implement escrow."]]]]])
|
||||
@@ -0,0 +1,29 @@
|
||||
(ns skirmish.wui.util)
|
||||
|
||||
(defn right-pad [s o n]
|
||||
"right pad s with o until length is greater or
|
||||
equal to n."
|
||||
(if (<= n (count s))
|
||||
s
|
||||
(recur (str s o) o n)))
|
||||
|
||||
(defn left-pad [s o n]
|
||||
"left pad s with o until length is greater or
|
||||
equal to n."
|
||||
(if (<= n (count s))
|
||||
s
|
||||
(recur (str o s) o n)))
|
||||
|
||||
(defn pp-int
|
||||
"returns the string representing n with the spaces at
|
||||
the proper place."
|
||||
([n]
|
||||
(cond
|
||||
(neg? n) (str "-" (pp-int (- n)))
|
||||
(< n 1000) (str n)
|
||||
:else (str (pp-int (quot n 1000)) " " (left-pad (str (mod n 1000)) "0" 3))))
|
||||
([n dec]
|
||||
(if (<= dec 0)
|
||||
(pp-int n)
|
||||
(let [i (int (Math/pow 10 dec))]
|
||||
(str (pp-int (quot n i)) "," (right-pad (str (mod n i)) "0" dec))))))
|
||||
Reference in new issue
Block a user