plumbed through child add/delete subcommands

This commit is contained in:
Stephen McQuay 2015-08-09 15:38:35 -07:00
parent 8e5f559567
commit 5957437ded
5 changed files with 107 additions and 53 deletions

43
children/db.go Normal file
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
}

View File

@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"log"
"net/http" "net/http"
"os" "os"
"strconv" "strconv"
@ -10,12 +9,14 @@ import (
"github.com/bgentry/speakeasy" "github.com/bgentry/speakeasy"
"mcquay.me/allowances" "mcquay.me/allowances"
"mcquay.me/allowances/children"
) )
const usage = `allowances app const usage = `allowances app
subcommands: subcommands:
pw -- manage password file pw -- manage password file
child -- manage children
serve -- serve webapp serve -- serve webapp
` `
@ -26,6 +27,13 @@ subcommands:
test <passes.json> test <passes.json>
` `
const childUsage = `allowances child
subcommands:
add <children.json> <child name> <child name> ...
delete <children.json> <child name> <child name> ...
`
func main() { func main() {
if len(os.Args) < 2 { if len(os.Args) < 2 {
fmt.Fprintf(os.Stderr, usage) fmt.Fprintf(os.Stderr, usage)
@ -74,6 +82,41 @@ func main() {
fmt.Fprintf(os.Stderr, "%s\n", pwUsage) fmt.Fprintf(os.Stderr, "%s\n", pwUsage)
os.Exit(1) 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": case "serve":
sm := http.NewServeMux() sm := http.NewServeMux()
dbfile := os.Getenv("DB") dbfile := os.Getenv("DB")
@ -93,7 +136,6 @@ func main() {
port = p port = p
} }
addr := fmt.Sprintf(":%d", port) addr := fmt.Sprintf(":%d", port)
log.Printf("%+v", addr)
err = http.ListenAndServe(addr, sm) err = http.ListenAndServe(addr, sm)
if err != nil { if err != nil {
panic(err) panic(err)

35
db.go
View File

@ -2,18 +2,20 @@ package allowances
import ( import (
"encoding/json" "encoding/json"
"io/ioutil"
"log"
"os" "os"
"sync" "sync"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"mcquay.me/fs"
) )
var dbMutex sync.RWMutex
func GetHashes(filename string) (Passes, bool, error) { func GetHashes(filename string) (Passes, bool, error) {
r := []string{} r := []string{}
exists := false exists := false
if !Exists(filename) { if !fs.Exists(filename) {
return r, exists, nil return r, exists, nil
} }
exists = true exists = true
@ -59,30 +61,3 @@ func (p Passes) Check(attempt string) (bool, error) {
} }
return false, nil 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
}

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
}

View File

@ -9,6 +9,8 @@ import (
"strings" "strings"
"github.com/gorilla/sessions" "github.com/gorilla/sessions"
"mcquay.me/allowances/children"
"mcquay.me/fs"
) )
func init() { func init() {
@ -28,7 +30,8 @@ func NewFailure(msg string) *failure {
} }
type Allowances struct { type Allowances struct {
db string db children.DB
dbfile string
hashes Passes hashes Passes
store *sessions.CookieStore store *sessions.CookieStore
} }
@ -47,11 +50,16 @@ func NewAllowances(sm *http.ServeMux, dbfile, passfile, staticFiles string) (*Al
return nil, err return nil, err
} }
if !Exists(dbfile) { if !fs.Exists(dbfile) {
return nil, fmt.Errorf("child db file doesn't exist: %q", 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{ r := &Allowances{
db: dbfile, db: db,
dbfile: dbfile,
hashes: hashes, hashes: hashes,
store: sessions.NewCookieStore([]byte("hello world")), 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 { 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": a.db})
tmpls["home"].Execute(w, map[string]interface{}{"children": children})
return nil return nil
} }
@ -102,12 +109,11 @@ func (a *Allowances) add(w http.ResponseWriter, req *http.Request, uid string) e
if err != nil { if err != nil {
return fmt.Errorf("couldn't parse a dollar amount: %v", err) return fmt.Errorf("couldn't parse a dollar amount: %v", err)
} }
children := loadChildren(a.db) a.db[child] += amount
children[child] += amount a.db.Save(a.dbfile)
defer dumpChildren(a.db, children)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
b, err := json.Marshal(map[string]interface{}{ b, err := json.Marshal(map[string]interface{}{
"amount": dollarize(children[child]), "amount": dollarize(a.db[child]),
"name": child, "name": child,
}) })
if err != nil { if err != nil {