From f15cf2fe5ac1eda5037e09276839f0b5a33fbffd Mon Sep 17 00:00:00 2001 From: arunvm Date: Tue, 28 Aug 2018 11:50:12 +0530 Subject: [PATCH 1/5] Implemented query to fetch user and get posts --- jsonstore/jsonstore.go | 82 +++++++++++++++++++++++++++++++++++++++++- mint.go | 5 +-- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/jsonstore/jsonstore.go b/jsonstore/jsonstore.go index 3ce7baa..753d697 100644 --- a/jsonstore/jsonstore.go +++ b/jsonstore/jsonstore.go @@ -13,7 +13,7 @@ import ( "strings" "time" - "mint/code" + "github.com/Hashnode/mint/code" "github.com/tendermint/abci/types" "golang.org/x/crypto/ed25519" @@ -87,6 +87,27 @@ func byteToHex(input []byte) string { return hexValue } +func getPosts(db *mgo.Database, sortBy string, searchConfig map[string]interface{}) ([]interface{}, error) { + var posts []interface{} + var user User + + err := db.C("posts").Find(searchConfig).Sort("-" + sortBy).All(&posts) + if err != nil { + panic(err) + } + + for i := range posts { + err = db.C("users").Find(bson.M{"_id": posts[i].(bson.M)["author"].(bson.ObjectId)}).One(&user) + if err != nil { + panic(err) + } + + posts[i].(bson.M)["author"] = user + } + + return posts, nil +} + func findTotalDocuments(db *mgo.Database) int64 { collections := [5]string{"posts", "comments", "users", "userpostvotes", "usercommentvotes"} var sum int64 @@ -522,5 +543,64 @@ func (app *JSONStoreApplication) Commit() types.ResponseCommit { // Query ... Query the blockchain. Unimplemented as of now. func (app *JSONStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { + var temp interface{} + var user User + var t map[string]interface{} + + if reqQuery.Data != nil { + err := json.Unmarshal(reqQuery.Data, &temp) + if err != nil { + panic(err) + } + + t = temp.(map[string]interface{}) + } + + switch reqQuery.Path { + case "/fetch-user": + err := db.C("users").Find(bson.M{"publicKey": t["publicKey"].(string)}).One(&user) + if err != nil { + resQuery.Log = err.Error() + break + } + + resData, err := json.Marshal(user) + if err != nil { + resQuery.Log = err.Error() + break + } + resQuery.Value = resData + case "/get-posts": + + searchConfig := make(map[string]interface{}) + + searchConfig["spam"] = false + if val, ok := t["type"]; ok { + if val.(string) == "askUH" || val.(string) == "showUH" { + searchConfig[val.(string)] = true + } else { + resQuery.Log = "type field can only have values 'showUH' or 'askUH'" + break + } + } + + if t["sortBy"].(string) != "score" && t["sortBy"].(string) != "date" { + resQuery.Log = "sortBy field can only have values 'score' or 'date'" + break + } + + posts, err := getPosts(db, t["sortBy"].(string), searchConfig) + if err != nil { + panic(err) + } + + resData, err := json.Marshal(posts) + if err != nil { + resQuery.Log = err.Error() + break + } + resQuery.Value = resData + } + return } diff --git a/mint.go b/mint.go index 115fdf8..e4a14a6 100644 --- a/mint.go +++ b/mint.go @@ -1,9 +1,10 @@ package main import ( - "mint/jsonstore" "os" + "github.com/Hashnode/mint/jsonstore" + "github.com/tendermint/abci/server" "github.com/tendermint/abci/types" mgo "gopkg.in/mgo.v2" @@ -38,7 +39,7 @@ func initJSONStore() error { app = jsonstore.NewJSONStoreApplication(db) // Start the listener - srv, err := server.NewServer("tcp://0.0.0.0:46658", "socket", app) + srv, err := server.NewServer("tcp://0.0.0.0:26658", "socket", app) if err != nil { return err } From 00cf40b85757b70891d5d346bc1f9cafa102e2f3 Mon Sep 17 00:00:00 2001 From: arunvm Date: Tue, 28 Aug 2018 21:59:56 +0530 Subject: [PATCH 2/5] Implemented query for retrieveing post upvote status,comments and comment upvote status --- jsonstore/jsonstore.go | 87 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/jsonstore/jsonstore.go b/jsonstore/jsonstore.go index 753d697..9e362a1 100644 --- a/jsonstore/jsonstore.go +++ b/jsonstore/jsonstore.go @@ -11,6 +11,7 @@ import ( "regexp" "strconv" "strings" + "sync" "time" "github.com/Hashnode/mint/code" @@ -600,6 +601,92 @@ func (app *JSONStoreApplication) Query(reqQuery types.RequestQuery) (resQuery ty break } resQuery.Value = resData + case "/get-upvote-status": + var wg sync.WaitGroup + var status map[string]interface{} + + status = make(map[string]interface{}) + + err := db.C("users").Find(bson.M{"publicKey": t["publicKey"].(string)}).One(&user) + if err != nil { + panic(err) + } + + for _, postID := range t["postIds"].([]interface{}) { + wg.Add(1) + go func(postID string) { + defer wg.Done() + count, err := db.C("userpostvotes").Find(bson.M{"postID": bson.ObjectIdHex(postID), "userID": user.ID}).Count() + if err != nil { + panic(err) + } + + if count > 0 { + status[postID] = true + } + }(postID.(string)) + } + + wg.Wait() + resData, err := json.Marshal(status) + if err != nil { + resQuery.Log = err.Error() + break + } + resQuery.Value = resData + case "/comment": + var comment map[string]interface{} + err := db.C("comments").Find(bson.M{"_id": bson.ObjectIdHex(t["id"].(string))}).One(&comment) + if err != nil { + panic(err) + } + + err = db.C("users").Find(bson.M{"_id": comment["author"].(bson.ObjectId)}).One(&user) + if err != nil { + panic(err) + } + + comment["author"] = user + + resData, err := json.Marshal(comment) + if err != nil { + resQuery.Log = err.Error() + break + } + resQuery.Value = resData + case "/get-comment-upvote-status": + var wg sync.WaitGroup + var status map[string]interface{} + + status = make(map[string]interface{}) + + err := db.C("users").Find(bson.M{"publicKey": t["publicKey"].(string)}).One(&user) + if err != nil { + panic(err) + } + + for _, commentID := range t["commentIds"].([]interface{}) { + wg.Add(1) + go func(commentID string) { + defer wg.Done() + count, err := db.C("usercommentvotes").Find(bson.M{"commentID": bson.ObjectIdHex(commentID), "userID": user.ID}).Count() + if err != nil { + panic(err) + } + + if count > 0 { + status[commentID] = true + } + }(commentID.(string)) + } + + wg.Wait() + resData, err := json.Marshal(status) + if err != nil { + resQuery.Log = err.Error() + break + } + resQuery.Value = resData } return From a50f84bed60291e15558cdc5c4291daa12574e7b Mon Sep 17 00:00:00 2001 From: arunvm Date: Fri, 31 Aug 2018 18:43:15 +0530 Subject: [PATCH 3/5] Implemented query to get a single post and its comments --- jsonstore/jsonstore.go | 61 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/jsonstore/jsonstore.go b/jsonstore/jsonstore.go index 9e362a1..861a14f 100644 --- a/jsonstore/jsonstore.go +++ b/jsonstore/jsonstore.go @@ -548,15 +548,13 @@ func (app *JSONStoreApplication) Query(reqQuery types.RequestQuery) (resQuery ty var user User var t map[string]interface{} - if reqQuery.Data != nil { - err := json.Unmarshal(reqQuery.Data, &temp) - if err != nil { - panic(err) - } - - t = temp.(map[string]interface{}) + err := json.Unmarshal(reqQuery.Data, &temp) + if err != nil { + panic(err) } + t = temp.(map[string]interface{}) + switch reqQuery.Path { case "/fetch-user": err := db.C("users").Find(bson.M{"publicKey": t["publicKey"].(string)}).One(&user) @@ -687,6 +685,55 @@ func (app *JSONStoreApplication) Query(reqQuery types.RequestQuery) (resQuery ty break } resQuery.Value = resData + case "/post": + var wg sync.WaitGroup + var post map[string]interface{} + var user User + var comments []map[string]interface{} + + post = make(map[string]interface{}) + + err := db.C("posts").Find(bson.M{"_id": bson.ObjectIdHex(t["id"].(string))}).One(&post) + if err != nil { + panic(err) + } + + err = db.C("users").Find(bson.M{"_id": post["author"].(bson.ObjectId)}).One(&user) + if err != nil { + panic(err) + } + + post["author"] = user + + err = db.C("comments").Find(bson.M{"postID": bson.ObjectIdHex(t["id"].(string))}).All(&comments) + if err != nil { + panic(err) + } + + for i := range comments { + wg.Add(1) + go func(i int) { + defer wg.Done() + var user User + err = db.C("users").Find(bson.M{"_id": comments[i]["author"].(bson.ObjectId)}).One(&user) + if err != nil { + panic(err) + } + + comments[i]["author"] = user + }(i) + } + + post["comments"] = comments + + wg.Wait() + resData, err := json.Marshal(post) + if err != nil { + resQuery.Log = err.Error() + break + } + resQuery.Value = resData + } return From 76fd629bd11f8edd0ea12b9c5760082f039d1b56 Mon Sep 17 00:00:00 2001 From: arunvm Date: Sun, 2 Sep 2018 21:08:38 +0530 Subject: [PATCH 4/5] Refactored code --- jsonstore/helper.go | 57 ++++++++++++++++++ jsonstore/jsonstore.go | 133 ++++++----------------------------------- jsonstore/types.go | 63 +++++++++++++++++++ 3 files changed, 138 insertions(+), 115 deletions(-) create mode 100644 jsonstore/helper.go create mode 100644 jsonstore/types.go diff --git a/jsonstore/helper.go b/jsonstore/helper.go new file mode 100644 index 0000000..17ed2f4 --- /dev/null +++ b/jsonstore/helper.go @@ -0,0 +1,57 @@ +package jsonstore + +import ( + "fmt" + "math" + "time" + + mgo "gopkg.in/mgo.v2" + "gopkg.in/mgo.v2/bson" +) + +func byteToHex(input []byte) string { + var hexValue string + for _, v := range input { + hexValue += fmt.Sprintf("%02x", v) + } + return hexValue +} + +func getPosts(db *mgo.Database, sortBy string, searchConfig map[string]interface{}) ([]interface{}, error) { + var posts []interface{} + var user User + + err := db.C("posts").Find(searchConfig).Sort("-" + sortBy).All(&posts) + if err != nil { + panic(err) + } + + for i := range posts { + err = db.C("users").Find(bson.M{"_id": posts[i].(bson.M)["author"].(bson.ObjectId)}).One(&user) + if err != nil { + panic(err) + } + + posts[i].(bson.M)["author"] = user + } + + return posts, nil +} + +func findTotalDocuments(db *mgo.Database) int64 { + collections := [5]string{"posts", "comments", "users", "userpostvotes", "usercommentvotes"} + var sum int64 + + for _, collection := range collections { + count, _ := db.C(collection).Find(nil).Count() + sum += int64(count) + } + + return sum +} + +func hotScore(votes int, date time.Time) float64 { + gravity := 1.8 + hoursAge := float64(date.Unix() * 3600) + return float64(votes-1) / math.Pow(hoursAge+2, gravity) +} diff --git a/jsonstore/jsonstore.go b/jsonstore/jsonstore.go index 861a14f..81b4830 100644 --- a/jsonstore/jsonstore.go +++ b/jsonstore/jsonstore.go @@ -6,7 +6,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "math" "net/url" "regexp" "strconv" @@ -25,108 +24,6 @@ import ( var _ types.Application = (*JSONStoreApplication)(nil) var db *mgo.Database -// Post ... -type Post struct { - ID bson.ObjectId `bson:"_id" json:"_id"` - Title string `bson:"title" json:"title"` - URL string `bson:"url" json:"url"` - Text string `bson:"text" json:"text"` - Author bson.ObjectId `bson:"author" json:"author"` - Upvotes int `bson:"upvotes" json:"upvotes"` - Date time.Time `bson:"date" json:"date"` - Score float64 `bson:"score" json:"score"` - NumComments int `bson:"numComments" json:"numComments"` - AskUH bool `bson:"askUH" json:"askUH"` - ShowUH bool `bson:"showUH" json:"showUH"` - Spam bool `bson:"spam" json:"spam"` -} - -// Comment ... -type Comment struct { - ID bson.ObjectId `bson:"_id" json:"_id"` - Content string `bson:"content" json:"content"` - Author bson.ObjectId `bson:"author" json:"author"` - Upvotes int `bson:"upvotes" json:"upvotes"` - Score float64 `bson:"score" json:"score"` - Date time.Time - PostID bson.ObjectId `bson:"postID" json:"postID"` - ParentCommentID bson.ObjectId `bson:"parentCommentId,omitempty" json:"parentCommentId"` -} - -// User ... -type User struct { - ID bson.ObjectId `bson:"_id" json:"_id"` - Name string `bson:"name" json:"name"` - Username string `bson:"username" json:"username"` - PublicKey string `bson:"publicKey" json:"publicKey"` -} - -// UserPostVote ... -type UserPostVote struct { - ID bson.ObjectId `bson:"_id" json:"_id"` - UserID bson.ObjectId `bson:"userID" json:"userID"` - PostID bson.ObjectId `bson:"postID" json:"postID"` -} - -// UserCommentVote ... -type UserCommentVote struct { - ID bson.ObjectId `bson:"_id" json:"_id"` - UserID bson.ObjectId `bson:"userID" json:"userID"` - CommentID bson.ObjectId `bson:"commentID" json:"commentID"` -} - -// JSONStoreApplication ... -type JSONStoreApplication struct { - types.BaseApplication -} - -func byteToHex(input []byte) string { - var hexValue string - for _, v := range input { - hexValue += fmt.Sprintf("%02x", v) - } - return hexValue -} - -func getPosts(db *mgo.Database, sortBy string, searchConfig map[string]interface{}) ([]interface{}, error) { - var posts []interface{} - var user User - - err := db.C("posts").Find(searchConfig).Sort("-" + sortBy).All(&posts) - if err != nil { - panic(err) - } - - for i := range posts { - err = db.C("users").Find(bson.M{"_id": posts[i].(bson.M)["author"].(bson.ObjectId)}).One(&user) - if err != nil { - panic(err) - } - - posts[i].(bson.M)["author"] = user - } - - return posts, nil -} - -func findTotalDocuments(db *mgo.Database) int64 { - collections := [5]string{"posts", "comments", "users", "userpostvotes", "usercommentvotes"} - var sum int64 - - for _, collection := range collections { - count, _ := db.C(collection).Find(nil).Count() - sum += int64(count) - } - - return sum -} - -func hotScore(votes int, date time.Time) float64 { - gravity := 1.8 - hoursAge := float64(date.Unix() * 3600) - return float64(votes-1) / math.Pow(hoursAge+2, gravity) -} - // FindTimeFromObjectID ... Convert ObjectID string to Time func FindTimeFromObjectID(id string) time.Time { ts, _ := strconv.ParseInt(id[0:8], 16, 64) @@ -559,14 +456,16 @@ func (app *JSONStoreApplication) Query(reqQuery types.RequestQuery) (resQuery ty case "/fetch-user": err := db.C("users").Find(bson.M{"publicKey": t["publicKey"].(string)}).One(&user) if err != nil { - resQuery.Log = err.Error() - break + panic(err) + // resQuery.Log = err.Error() + // break } resData, err := json.Marshal(user) if err != nil { - resQuery.Log = err.Error() - break + panic(err) + // resQuery.Log = err.Error() + // break } resQuery.Value = resData case "/get-posts": @@ -595,8 +494,9 @@ func (app *JSONStoreApplication) Query(reqQuery types.RequestQuery) (resQuery ty resData, err := json.Marshal(posts) if err != nil { - resQuery.Log = err.Error() - break + panic(err) + // resQuery.Log = err.Error() + // break } resQuery.Value = resData case "/get-upvote-status": @@ -648,8 +548,9 @@ func (app *JSONStoreApplication) Query(reqQuery types.RequestQuery) (resQuery ty resData, err := json.Marshal(comment) if err != nil { - resQuery.Log = err.Error() - break + panic(err) + // resQuery.Log = err.Error() + // break } resQuery.Value = resData case "/get-comment-upvote-status": @@ -681,8 +582,9 @@ func (app *JSONStoreApplication) Query(reqQuery types.RequestQuery) (resQuery ty wg.Wait() resData, err := json.Marshal(status) if err != nil { - resQuery.Log = err.Error() - break + panic(err) + // resQuery.Log = err.Error() + // break } resQuery.Value = resData case "/post": @@ -729,8 +631,9 @@ func (app *JSONStoreApplication) Query(reqQuery types.RequestQuery) (resQuery ty wg.Wait() resData, err := json.Marshal(post) if err != nil { - resQuery.Log = err.Error() - break + panic(err) + // resQuery.Log = err.Error() + // break } resQuery.Value = resData diff --git a/jsonstore/types.go b/jsonstore/types.go new file mode 100644 index 0000000..bac7549 --- /dev/null +++ b/jsonstore/types.go @@ -0,0 +1,63 @@ +package jsonstore + +import ( + "time" + + "github.com/tendermint/abci/types" + "gopkg.in/mgo.v2/bson" +) + +// Post ... +type Post struct { + ID bson.ObjectId `bson:"_id" json:"_id"` + Title string `bson:"title" json:"title"` + URL string `bson:"url" json:"url"` + Text string `bson:"text" json:"text"` + Author bson.ObjectId `bson:"author" json:"author"` + Upvotes int `bson:"upvotes" json:"upvotes"` + Date time.Time `bson:"date" json:"date"` + Score float64 `bson:"score" json:"score"` + NumComments int `bson:"numComments" json:"numComments"` + AskUH bool `bson:"askUH" json:"askUH"` + ShowUH bool `bson:"showUH" json:"showUH"` + Spam bool `bson:"spam" json:"spam"` +} + +// Comment ... +type Comment struct { + ID bson.ObjectId `bson:"_id" json:"_id"` + Content string `bson:"content" json:"content"` + Author bson.ObjectId `bson:"author" json:"author"` + Upvotes int `bson:"upvotes" json:"upvotes"` + Score float64 `bson:"score" json:"score"` + Date time.Time + PostID bson.ObjectId `bson:"postID" json:"postID"` + ParentCommentID bson.ObjectId `bson:"parentCommentId,omitempty" json:"parentCommentId"` +} + +// User ... +type User struct { + ID bson.ObjectId `bson:"_id" json:"_id"` + Name string `bson:"name" json:"name"` + Username string `bson:"username" json:"username"` + PublicKey string `bson:"publicKey" json:"publicKey"` +} + +// UserPostVote ... +type UserPostVote struct { + ID bson.ObjectId `bson:"_id" json:"_id"` + UserID bson.ObjectId `bson:"userID" json:"userID"` + PostID bson.ObjectId `bson:"postID" json:"postID"` +} + +// UserCommentVote ... +type UserCommentVote struct { + ID bson.ObjectId `bson:"_id" json:"_id"` + UserID bson.ObjectId `bson:"userID" json:"userID"` + CommentID bson.ObjectId `bson:"commentID" json:"commentID"` +} + +// JSONStoreApplication ... +type JSONStoreApplication struct { + types.BaseApplication +} From d72df94407c390fda75a04f81d7ca2150fd59745 Mon Sep 17 00:00:00 2001 From: arunvm Date: Thu, 6 Sep 2018 12:14:51 +0530 Subject: [PATCH 5/5] Refactored code --- jsonstore/helper.go | 7 +++++++ jsonstore/jsonstore.go | 8 -------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/jsonstore/helper.go b/jsonstore/helper.go index 17ed2f4..29a8827 100644 --- a/jsonstore/helper.go +++ b/jsonstore/helper.go @@ -3,6 +3,7 @@ package jsonstore import ( "fmt" "math" + "strconv" "time" mgo "gopkg.in/mgo.v2" @@ -55,3 +56,9 @@ func hotScore(votes int, date time.Time) float64 { hoursAge := float64(date.Unix() * 3600) return float64(votes-1) / math.Pow(hoursAge+2, gravity) } + +// FindTimeFromObjectID ... Convert ObjectID string to Time +func FindTimeFromObjectID(id string) time.Time { + ts, _ := strconv.ParseInt(id[0:8], 16, 64) + return time.Unix(ts, 0) +} diff --git a/jsonstore/jsonstore.go b/jsonstore/jsonstore.go index 81b4830..655f63d 100644 --- a/jsonstore/jsonstore.go +++ b/jsonstore/jsonstore.go @@ -8,10 +8,8 @@ import ( "fmt" "net/url" "regexp" - "strconv" "strings" "sync" - "time" "github.com/Hashnode/mint/code" @@ -24,12 +22,6 @@ import ( var _ types.Application = (*JSONStoreApplication)(nil) var db *mgo.Database -// FindTimeFromObjectID ... Convert ObjectID string to Time -func FindTimeFromObjectID(id string) time.Time { - ts, _ := strconv.ParseInt(id[0:8], 16, 64) - return time.Unix(ts, 0) -} - // NewJSONStoreApplication ... func NewJSONStoreApplication(dbCopy *mgo.Database) *JSONStoreApplication { db = dbCopy