summaryrefslogtreecommitdiff
path: root/system/db
diff options
context:
space:
mode:
authorSteve Manuel <nilslice@gmail.com>2016-10-31 01:06:36 -0700
committerSteve Manuel <nilslice@gmail.com>2016-10-31 01:06:36 -0700
commit76f1af6aad8de62f3df540767e713959c3385c01 (patch)
tree5cb9c7184b94be344492d8fd89c7709a14ccaee9 /system/db
parent519c5b44d0b36e1f61cb0228889401fa1e33357e (diff)
parent12cd2d10d79b7b8f0666c7f3f145e773f6edaac5 (diff)
Merge branch 'ponzu-dev'
Diffstat (limited to 'system/db')
-rw-r--r--system/db/content.go124
-rw-r--r--system/db/init.go18
-rw-r--r--system/db/user.go114
3 files changed, 197 insertions, 59 deletions
diff --git a/system/db/content.go b/system/db/content.go
index 2d6e8ea..bd1ee4b 100644
--- a/system/db/content.go
+++ b/system/db/content.go
@@ -38,13 +38,20 @@ func SetContent(target string, data url.Values) (int, error) {
}
func update(ns, id string, data url.Values) (int, error) {
+ var specifier string // i.e. _pending, _sorted, etc.
+ if strings.Contains(ns, "_") {
+ spec := strings.Split(ns, "_")
+ ns = spec[0]
+ specifier = "_" + spec[1]
+ }
+
cid, err := strconv.Atoi(id)
if err != nil {
return 0, err
}
err = store.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte(ns))
+ b, err := tx.CreateBucketIfNotExists([]byte(ns + specifier))
if err != nil {
return err
}
@@ -65,15 +72,24 @@ func update(ns, id string, data url.Values) (int, error) {
return 0, nil
}
- go SortContent(ns)
+ if specifier == "" {
+ go SortContent(ns)
+ }
return cid, nil
}
func insert(ns string, data url.Values) (int, error) {
var effectedID int
+ var specifier string // i.e. _pending, _sorted, etc.
+ if strings.Contains(ns, "_") {
+ spec := strings.Split(ns, "_")
+ ns = spec[0]
+ specifier = "_" + spec[1]
+ }
+
err := store.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte(ns))
+ b, err := tx.CreateBucketIfNotExists([]byte(ns + specifier))
if err != nil {
return err
}
@@ -89,7 +105,7 @@ func insert(ns string, data url.Values) (int, error) {
if err != nil {
return err
}
- data.Add("id", cid)
+ data.Set("id", cid)
j, err := postToJSON(ns, data)
if err != nil {
@@ -107,40 +123,11 @@ func insert(ns string, data url.Values) (int, error) {
return 0, err
}
- go SortContent(ns)
-
- return effectedID, nil
-}
-
-func postToJSON(ns string, data url.Values) ([]byte, error) {
- // find the content type and decode values into it
- t, ok := content.Types[ns]
- if !ok {
- return nil, fmt.Errorf(content.ErrTypeNotRegistered, ns)
- }
- post := t()
-
- dec := schema.NewDecoder()
- dec.SetAliasTag("json") // allows simpler struct tagging when creating a content type
- dec.IgnoreUnknownKeys(true) // will skip over form values submitted, but not in struct
- err := dec.Decode(post, data)
- if err != nil {
- return nil, err
- }
-
- slug, err := manager.Slug(post.(editor.Editable))
- if err != nil {
- return nil, err
- }
- post.(editor.Editable).SetSlug(slug)
-
- // marshall content struct to json for db storage
- j, err := json.Marshal(post)
- if err != nil {
- return nil, err
+ if specifier == "" {
+ go SortContent(ns)
}
- return j, nil
+ return effectedID, nil
}
// DeleteContent removes an item from the database. Deleting a non-existent item
@@ -153,7 +140,6 @@ func DeleteContent(target string) error {
tx.Bucket([]byte(ns)).Delete([]byte(id))
return nil
})
-
if err != nil {
return err
}
@@ -178,7 +164,7 @@ func Content(target string) ([]byte, error) {
b := tx.Bucket([]byte(ns))
_, err := val.Write(b.Get([]byte(id)))
if err != nil {
- fmt.Println(err)
+ log.Println(err)
return err
}
@@ -197,8 +183,12 @@ func ContentAll(namespace string) [][]byte {
store.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(namespace))
- len := b.Stats().KeyN
- posts = make([][]byte, 0, len)
+ if b == nil {
+ return nil
+ }
+
+ numKeys := b.Stats().KeyN
+ posts = make([][]byte, 0, numKeys)
b.ForEach(func(k, v []byte) error {
posts = append(posts, v)
@@ -216,10 +206,15 @@ func ContentAll(namespace string) [][]byte {
// in descending order, from most recent to least recent
// Should be called from a goroutine after SetContent is successful
func SortContent(namespace string) {
+ // only sort main content types i.e. Post
+ if strings.Contains(namespace, "_") {
+ return
+ }
+
all := ContentAll(namespace)
var posts sortablePosts
- // decode each (json) into Editable
+ // decode each (json) into type to then sort
for i := range all {
j := all[i]
post := content.Types[namespace]()
@@ -238,18 +233,14 @@ func SortContent(namespace string) {
// store in <namespace>_sorted bucket, first delete existing
err := store.Update(func(tx *bolt.Tx) error {
- err := tx.DeleteBucket([]byte(namespace + "_sorted"))
+ bname := []byte(namespace + "_sorted")
+ err := tx.DeleteBucket(bname)
if err != nil {
return err
}
- b, err := tx.CreateBucket([]byte(namespace + "_sorted"))
+ b, err := tx.CreateBucketIfNotExists(bname)
if err != nil {
- err := tx.Rollback()
- if err != nil {
- return err
- }
-
return err
}
@@ -263,11 +254,6 @@ func SortContent(namespace string) {
cid := fmt.Sprintf("%d:%d", i, posts[i].Time())
err = b.Put([]byte(cid), j)
if err != nil {
- err := tx.Rollback()
- if err != nil {
- return err
- }
-
return err
}
}
@@ -293,3 +279,35 @@ func (s sortablePosts) Less(i, j int) bool {
func (s sortablePosts) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
+
+func postToJSON(ns string, data url.Values) ([]byte, error) {
+ // find the content type and decode values into it
+ ns = strings.TrimSuffix(ns, "_external")
+ t, ok := content.Types[ns]
+ if !ok {
+ return nil, fmt.Errorf(content.ErrTypeNotRegistered, ns)
+ }
+ post := t()
+
+ dec := schema.NewDecoder()
+ dec.SetAliasTag("json") // allows simpler struct tagging when creating a content type
+ dec.IgnoreUnknownKeys(true) // will skip over form values submitted, but not in struct
+ err := dec.Decode(post, data)
+ if err != nil {
+ return nil, err
+ }
+
+ slug, err := manager.Slug(post.(editor.Editable))
+ if err != nil {
+ return nil, err
+ }
+ post.(editor.Editable).SetSlug(slug)
+
+ // marshall content struct to json for db storage
+ j, err := json.Marshal(post)
+ if err != nil {
+ return nil, err
+ }
+
+ return j, nil
+}
diff --git a/system/db/init.go b/system/db/init.go
index 1a5ed25..63804e1 100644
--- a/system/db/init.go
+++ b/system/db/init.go
@@ -13,12 +13,21 @@ import (
var store *bolt.DB
+// Close exports the abillity to close our db file. Should be called with defer
+// after call to Init() from the same place.
+func Close() {
+ err := store.Close()
+ if err != nil {
+ log.Println(err)
+ }
+}
+
// Init creates a db connection, initializes db with required info, sets secrets
func Init() {
var err error
- store, err = bolt.Open("store.db", 0666, nil)
+ store, err = bolt.Open("system.db", 0666, nil)
if err != nil {
- log.Fatal(err)
+ log.Fatalln(err)
}
err = store.Update(func(tx *bolt.Tx) error {
@@ -67,10 +76,9 @@ func Init() {
return nil
})
if err != nil {
- log.Fatal("Coudn't initialize db with buckets.", err)
+ log.Fatalln("Coudn't initialize db with buckets.", err)
}
- // sort all content into type_sorted buckets
go func() {
for t := range content.Types {
SortContent(t)
@@ -99,7 +107,7 @@ func SystemInitComplete() bool {
})
if err != nil {
complete = false
- log.Fatal(err)
+ log.Fatalln(err)
}
return complete
diff --git a/system/db/user.go b/system/db/user.go
index a3a0be3..d2dc3a9 100644
--- a/system/db/user.go
+++ b/system/db/user.go
@@ -4,15 +4,21 @@ import (
"bytes"
"encoding/json"
"errors"
+ "fmt"
+ "net/http"
"github.com/bosssauce/ponzu/system/admin/user"
"github.com/boltdb/bolt"
+ "github.com/nilslice/jwt"
)
// ErrUserExists is used for the db to report to admin user of existing user
var ErrUserExists = errors.New("Error. User exists.")
+// ErrNoUserExists is used for the db to report to admin user of non-existing user
+var ErrNoUserExists = errors.New("Error. No user exists.")
+
// SetUser sets key:value pairs in the db for user settings
func SetUser(usr *user.User) (int, error) {
err := store.Update(func(tx *bolt.Tx) error {
@@ -38,7 +44,7 @@ func SetUser(usr *user.User) (int, error) {
return err
}
- err = users.Put([]byte(usr.Email), j)
+ err = users.Put(email, j)
if err != nil {
return err
}
@@ -52,6 +58,65 @@ func SetUser(usr *user.User) (int, error) {
return usr.ID, nil
}
+// UpdateUser sets key:value pairs in the db for existing user settings
+func UpdateUser(usr, updatedUsr *user.User) error {
+ err := store.Update(func(tx *bolt.Tx) error {
+ users := tx.Bucket([]byte("_users"))
+
+ // check if user is found by email, fail if nil
+ exists := users.Get([]byte(usr.Email))
+ if exists == nil {
+ return ErrNoUserExists
+ }
+
+ // marshal User to json and put into bucket
+ j, err := json.Marshal(updatedUsr)
+ if err != nil {
+ return err
+ }
+
+ err = users.Put([]byte(updatedUsr.Email), j)
+ if err != nil {
+ return err
+ }
+
+ // if email address was changed, delete the old record of former
+ // user with original email address
+ if usr.Email != updatedUsr.Email {
+ err = users.Delete([]byte(usr.Email))
+ if err != nil {
+ return err
+ }
+
+ }
+
+ return nil
+ })
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// DeleteUser deletes a user from the db by email
+func DeleteUser(email string) error {
+ err := store.Update(func(tx *bolt.Tx) error {
+ b := tx.Bucket([]byte("_users"))
+ err := b.Delete([]byte(email))
+ if err != nil {
+ return err
+ }
+
+ return nil
+ })
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
// User gets the user by email from the db
func User(email string) ([]byte, error) {
val := &bytes.Buffer{}
@@ -72,3 +137,50 @@ func User(email string) ([]byte, error) {
return val.Bytes(), nil
}
+
+// UserAll returns all users from the db
+func UserAll() ([][]byte, error) {
+ var users [][]byte
+ err := store.View(func(tx *bolt.Tx) error {
+ b := tx.Bucket([]byte("_users"))
+ err := b.ForEach(func(k, v []byte) error {
+ users = append(users, v)
+ return nil
+ })
+ if err != nil {
+ return err
+ }
+
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return users, nil
+}
+
+// CurrentUser extracts the user from the request data and returns the current user from the db
+func CurrentUser(req *http.Request) ([]byte, error) {
+ if !user.IsValid(req) {
+ return nil, fmt.Errorf("Error. Invalid User.")
+ }
+
+ token, err := req.Cookie("_token")
+ if err != nil {
+ return nil, err
+ }
+
+ claims := jwt.GetClaims(token.Value)
+ email, ok := claims["user"]
+ if !ok {
+ return nil, fmt.Errorf("Error. No user data found in request token.")
+ }
+
+ usr, err := User(email.(string))
+ if err != nil {
+ return nil, err
+ }
+
+ return usr, nil
+}