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 (
"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)

35
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
}

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"
"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 {