Browse Source

plumbed through child add/delete subcommands

master
Stephen McQuay 4 years ago
parent
commit
5957437ded
5 changed files with 107 additions and 53 deletions
  1. +43
    -0
      children/db.go
  2. +44
    -2
      cmd/allowances/main.go
  3. +5
    -30
      db.go
  4. +0
    -12
      fs.go
  5. +15
    -9
      handlers.go

+ 43
- 0
children/db.go View File

@@ -0,0 +1,43 @@
package children

import (
"encoding/json"
"errors"
"os"
"sync"

"mcquay.me/fs"
)

var mut sync.Mutex

type DB map[string]int

func Load(filename string) (children DB, err error) {
db := DB{}
if !fs.Exists(filename) {
return db, errors.New("db file doesn't exist")
}
f, err := os.Open(filename)
if err != nil {
return nil, err
}
if err := json.NewDecoder(f).Decode(&db); err != nil {
return nil, err
}
return db, nil
}

func (db DB) Save(filename string) error {
mut.Lock()
defer mut.Unlock()
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
if err := json.NewEncoder(f).Encode(db); err != nil {
return err
}
return nil
}

+ 44
- 2
cmd/allowances/main.go View File

@@ -2,7 +2,6 @@ package main

import (
"fmt"
"log"
"net/http"
"os"
"strconv"
@@ -10,12 +9,14 @@ import (
"github.com/bgentry/speakeasy"

"mcquay.me/allowances"
"mcquay.me/allowances/children"
)

const usage = `allowances app

subcommands:
pw -- manage password file
child -- manage children
serve -- serve webapp
`

@@ -26,6 +27,13 @@ subcommands:
test <passes.json>
`

const childUsage = `allowances child

subcommands:
add <children.json> <child name> <child name> ...
delete <children.json> <child name> <child name> ...
`

func main() {
if len(os.Args) < 2 {
fmt.Fprintf(os.Stderr, usage)
@@ -74,6 +82,41 @@ func main() {
fmt.Fprintf(os.Stderr, "%s\n", pwUsage)
os.Exit(1)
}
case "child":
childCmd := os.Args[2:]
if len(childCmd) < 3 {
fmt.Fprintf(os.Stderr, "%s\n", childUsage)
os.Exit(1)
}
switch childCmd[0] {
case "add":
dbfile := os.Args[3]
names := os.Args[4:]
db, err := children.Load(dbfile)
if err != nil {
fmt.Fprintf(os.Stderr, "problem loading children db: %s\n", pwUsage)
os.Exit(1)
}
for _, name := range names {
db[name] = 0
}
db.Save(dbfile)
case "delete", "del":
dbfile := os.Args[3]
names := os.Args[4:]
db, err := children.Load(dbfile)
if err != nil {
fmt.Fprintf(os.Stderr, "problem loading children db: %s\n", pwUsage)
os.Exit(1)
}
for _, name := range names {
delete(db, name)
}
db.Save(dbfile)
default:
fmt.Fprintf(os.Stderr, "%s\n", pwUsage)
os.Exit(1)
}
case "serve":
sm := http.NewServeMux()
dbfile := os.Getenv("DB")
@@ -93,7 +136,6 @@ func main() {
port = p
}
addr := fmt.Sprintf(":%d", port)
log.Printf("%+v", addr)
err = http.ListenAndServe(addr, sm)
if err != nil {
panic(err)

+ 5
- 30
db.go View File

@@ -2,18 +2,20 @@ package allowances

import (
"encoding/json"
"io/ioutil"
"log"
"os"
"sync"

"golang.org/x/crypto/bcrypt"

"mcquay.me/fs"
)

var dbMutex sync.RWMutex

func GetHashes(filename string) (Passes, bool, error) {
r := []string{}
exists := false
if !Exists(filename) {
if !fs.Exists(filename) {
return r, exists, nil
}
exists = true
@@ -59,30 +61,3 @@ func (p Passes) Check(attempt string) (bool, error) {
}
return false, nil
}

var dbMutex = sync.RWMutex{}

func loadChildren(filename string) (children map[string]int) {
dbMutex.RLock()
defer dbMutex.RUnlock()
b, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatal(err)
}
err = json.Unmarshal(b, &children)
if err != nil {
log.Fatal(err)
}
return
}

func dumpChildren(filename string, children map[string]int) {
dbMutex.Lock()
defer dbMutex.Unlock()
b, err := json.Marshal(children)
err = ioutil.WriteFile(filename, b, 0644)
if err != nil {
log.Fatal("serious issue writing children db file", err)
}
return
}

+ 0
- 12
fs.go View File

@@ -1,12 +0,0 @@
package allowances

import "os"

func Exists(path string) bool {
if _, err := os.Stat(path); err != nil {
return false
} else if os.IsNotExist(err) {
return false
}
return true
}

+ 15
- 9
handlers.go View File

@@ -9,6 +9,8 @@ import (
"strings"

"github.com/gorilla/sessions"
"mcquay.me/allowances/children"
"mcquay.me/fs"
)

func init() {
@@ -28,7 +30,8 @@ func NewFailure(msg string) *failure {
}

type Allowances struct {
db string
db children.DB
dbfile string
hashes Passes
store *sessions.CookieStore
}
@@ -47,11 +50,16 @@ func NewAllowances(sm *http.ServeMux, dbfile, passfile, staticFiles string) (*Al
return nil, err
}

if !Exists(dbfile) {
if !fs.Exists(dbfile) {
return nil, fmt.Errorf("child db file doesn't exist: %q", dbfile)
}
db, err := children.Load(dbfile)
if err != nil {
return nil, err
}
r := &Allowances{
db: dbfile,
db: db,
dbfile: dbfile,
hashes: hashes,
store: sessions.NewCookieStore([]byte("hello world")),
}
@@ -60,8 +68,7 @@ func NewAllowances(sm *http.ServeMux, dbfile, passfile, staticFiles string) (*Al
}

func (a *Allowances) home(w http.ResponseWriter, req *http.Request, uid string) error {
children := loadChildren(a.db)
tmpls["home"].Execute(w, map[string]interface{}{"children": children})
tmpls["home"].Execute(w, map[string]interface{}{"children": a.db})
return nil
}

@@ -102,12 +109,11 @@ func (a *Allowances) add(w http.ResponseWriter, req *http.Request, uid string) e
if err != nil {
return fmt.Errorf("couldn't parse a dollar amount: %v", err)
}
children := loadChildren(a.db)
children[child] += amount
defer dumpChildren(a.db, children)
a.db[child] += amount
a.db.Save(a.dbfile)
w.Header().Set("Content-Type", "application/json")
b, err := json.Marshal(map[string]interface{}{
"amount": dollarize(children[child]),
"amount": dollarize(a.db[child]),
"name": child,
})
if err != nil {

Loading…
Cancel
Save