MVP w UI
parent
a901e41d25
commit
ea83759be2
22
ledger.go
22
ledger.go
|
|
@ -52,9 +52,17 @@ func (ledger Ledger) SetTransactions(transactions []Transaction) error {
|
|||
return os.Rename(f.Name(), ledger.path)
|
||||
}
|
||||
|
||||
func (ledger Ledger) LossyBalances() (Balances, error) {
|
||||
return ledger.balances(true)
|
||||
}
|
||||
|
||||
func (ledger Ledger) Balances() (Balances, error) {
|
||||
return ledger.balances(false)
|
||||
}
|
||||
|
||||
func (ledger Ledger) balances(lossy bool) (Balances, error) {
|
||||
transactions, err := ledger.Transactions()
|
||||
if err != nil {
|
||||
if !lossy && err != nil {
|
||||
return nil, err
|
||||
}
|
||||
balances := make(Balances)
|
||||
|
|
@ -65,14 +73,22 @@ func (ledger Ledger) Balances() (Balances, error) {
|
|||
return balances, nil
|
||||
}
|
||||
|
||||
func (ledger Ledger) LossyTransactions() ([]Transaction, error) {
|
||||
return ledger.transactions(true)
|
||||
}
|
||||
|
||||
func (ledger Ledger) Transactions() ([]Transaction, error) {
|
||||
return ledger.transactions(false)
|
||||
}
|
||||
|
||||
func (ledger Ledger) transactions(lossy bool) ([]Transaction, error) {
|
||||
f, err := ledger.open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
transactions := make([]Transaction, 0)
|
||||
for err == nil {
|
||||
for (!lossy && err == nil) || (lossy && err != io.EOF) {
|
||||
var transaction Transaction
|
||||
transaction, err = readTransaction(f)
|
||||
if err == io.EOF {
|
||||
|
|
@ -82,7 +98,7 @@ func (ledger Ledger) Transactions() ([]Transaction, error) {
|
|||
err = fmt.Errorf("error parsing transaction #%d: %v", len(transactions), err)
|
||||
}
|
||||
}
|
||||
if err == io.EOF {
|
||||
if err == io.EOF || lossy {
|
||||
err = nil
|
||||
}
|
||||
return transactions, err
|
||||
|
|
|
|||
3
main.go
3
main.go
|
|
@ -9,6 +9,7 @@ import (
|
|||
func main() {
|
||||
as := args.NewArgSet()
|
||||
as.Append(args.INT, "p", "port to listen on", "8101")
|
||||
as.Append(args.BOOL, "debug", "debug mode", false)
|
||||
as.Append(args.STRING, "f", "file to abuse", "/tmp/ledger-ui.dat")
|
||||
if err := as.Parse(); err != nil {
|
||||
panic(err)
|
||||
|
|
@ -17,7 +18,7 @@ func main() {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := http.ListenAndServe(":"+fmt.Sprint(as.GetInt("p")), Server{ledger: ledger}); err != nil {
|
||||
if err := http.ListenAndServe(":"+fmt.Sprint(as.GetInt("p")), Server{ledger: ledger, debug: as.GetBool("debug")}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,8 +113,8 @@
|
|||
}
|
||||
zachsPayment = (x) => setRowKeyValue(x, "Payer", "AssetAccount:Zach")
|
||||
belsPayment = (x) => setRowKeyValue(x, "Payer", "AssetAccount:Bel")
|
||||
zachsCharge = (x) => setRowKeyValue(x, "Payee", "DebtAccount:Zach")
|
||||
belsCharge = (x) => setRowKeyValue(x, "belsCharge", "DebtAccount:Bel")
|
||||
zachsCharge = (x) => setRowKeyValue(x, "Payee", "AssetAccount:Zach")
|
||||
belsCharge = (x) => setRowKeyValue(x, "Payee", "AssetAccount:Bel")
|
||||
function http(method, remote, callback, body) {
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
|
|
|
|||
38
server.go
38
server.go
|
|
@ -2,7 +2,9 @@ package main
|
|||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
|
@ -12,6 +14,7 @@ var index string
|
|||
|
||||
type Server struct {
|
||||
ledger Ledger
|
||||
debug bool
|
||||
}
|
||||
|
||||
func (server Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -24,19 +27,50 @@ func (server Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
case "GET/api/balances":
|
||||
server.getBalances(w, r)
|
||||
default:
|
||||
fmt.Fprint(w, index)
|
||||
if server.debug {
|
||||
b, _ := ioutil.ReadFile("./public/index.html")
|
||||
w.Write(b)
|
||||
} else {
|
||||
fmt.Fprint(w, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (server Server) err(w http.ResponseWriter, r *http.Request, err error) {
|
||||
log.Println(r.Method, r.URL.Path, err)
|
||||
http.Error(w, fmt.Sprint(err.Error()), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func (server Server) getTransactions(w http.ResponseWriter, r *http.Request) {
|
||||
transactions, err := server.ledger.Transactions()
|
||||
if err != nil {
|
||||
|
||||
server.err(w, r, err)
|
||||
return
|
||||
}
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{"Transactions": transactions})
|
||||
}
|
||||
|
||||
func (server Server) putTransactions(w http.ResponseWriter, r *http.Request) {
|
||||
var request struct {
|
||||
IDX int `json:"idx"`
|
||||
Transaction
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||||
server.err(w, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.ledger.SetTransaction(request.IDX, request.Transaction); err != nil {
|
||||
server.err(w, r, err)
|
||||
return
|
||||
}
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{"ok": true})
|
||||
}
|
||||
|
||||
func (server Server) getBalances(w http.ResponseWriter, r *http.Request) {
|
||||
balances, err := server.ledger.Balances()
|
||||
if err != nil {
|
||||
server.err(w, r, err)
|
||||
return
|
||||
}
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{"Balances": balances})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
2021-01-01 groceries
|
||||
Withdrawal:Target $10
|
||||
AssetAccount:Chase:8824
|
||||
2021-01-05 bel vidya
|
||||
Withdrawal:Target $1
|
||||
AssetAccount:Chase:8824
|
||||
2021-01-06 qt vidya
|
||||
Withdrawal:Target $100
|
||||
AssetAccount:Chase:8824
|
||||
2021-01-07 bel payment
|
||||
AssetAccount:Chase:8824 $1
|
||||
AssetAccount:Payment
|
||||
2021-01-08 qt payment
|
||||
AssetAccount:Chase:8824 $100
|
||||
AssetAccount:Payment
|
||||
2021-01-09 bel grocery payment
|
||||
AssetAccount:Chase:8824 $5
|
||||
AssetAccount:Payment
|
||||
2021-01-10 qt grocery payment
|
||||
AssetAccount:Chase:8824 $5
|
||||
AssetAccount:Payment
|
||||
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
|
|
@ -75,16 +76,25 @@ func words(b []byte) [][]byte {
|
|||
}
|
||||
|
||||
func (transaction *Transaction) readDate(lines [][]byte) error {
|
||||
if len(lines) < 1 || len(words(lines[0])) < 1 {
|
||||
return errors.New("stub")
|
||||
}
|
||||
transaction.Date = string(words(lines[0])[0])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (transaction *Transaction) readDescription(lines [][]byte) error {
|
||||
if len(lines) < 1 || len(words(lines[0])) < 1 {
|
||||
return errors.New("stub")
|
||||
}
|
||||
transaction.Description = string(bytes.Join(words(lines[0])[1:], []byte(" ")))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (transaction *Transaction) readAmount(lines [][]byte) error {
|
||||
if len(lines) < 2 || len(words(lines[1])) < 2 {
|
||||
return errors.New("stub")
|
||||
}
|
||||
amount := string(words(lines[1])[1])
|
||||
f, err := strconv.ParseFloat(strings.Trim(amount, "$"), 32)
|
||||
transaction.Amount = float32(f)
|
||||
|
|
@ -92,6 +102,9 @@ func (transaction *Transaction) readAmount(lines [][]byte) error {
|
|||
}
|
||||
|
||||
func (transaction *Transaction) readPayerPayee(lines [][]byte) error {
|
||||
if len(lines) < 3 || len(words(lines[1])) < 1 || len(words(lines[2])) < 1 {
|
||||
return errors.New("stub")
|
||||
}
|
||||
payer := string(words(lines[1])[0])
|
||||
payee := string(words(lines[2])[0])
|
||||
if transaction.Amount >= 0 {
|
||||
|
|
@ -108,7 +121,7 @@ func (transaction *Transaction) readPayerPayee(lines [][]byte) error {
|
|||
|
||||
func (transaction Transaction) Marshal() string {
|
||||
return fmt.Sprintf(
|
||||
"%-25s%s\n%25s%-50s$%.2f\n%25s%s",
|
||||
"%-25s%s\n%25s%-49s $%.2f\n%25s%s",
|
||||
transaction.Date,
|
||||
transaction.Description,
|
||||
"",
|
||||
|
|
|
|||
Loading…
Reference in New Issue