diff --git a/handlers/check.go b/handlers/check.go index b18f0ee..9f7ec6c 100644 --- a/handlers/check.go +++ b/handlers/check.go @@ -80,18 +80,32 @@ func CheckHandler(w http.ResponseWriter, r *http.Request) { // is this a new repo? if so, increase the count in the high scores bucket later isNewRepo := false + var oldRepoBytes []byte err = db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(RepoBucket)) if b == nil { return fmt.Errorf("repo bucket not found") } - isNewRepo = b.Get([]byte(repo)) == nil + oldRepoBytes = b.Get([]byte(repo)) return nil }) if err != nil { log.Println(err) } + // get the old score and store it for stats updating + var oldScore *float64 + if isNewRepo = oldRepoBytes == nil; !isNewRepo { + oldRepo := checksResp{} + err = json.Unmarshal(oldRepoBytes, &oldRepo) + if err != nil { + log.Println("ERROR: could not unmarshal json:", err) + http.Error(w, err.Error(), 500) + return + } + oldScore = &oldRepo.Average + } + // if this is a new repo, or the user force-refreshed, update the cache if isNewRepo || forceRefresh { err = db.Update(func(tx *bolt.Tx) error { @@ -122,7 +136,12 @@ func CheckHandler(w http.ResponseWriter, r *http.Request) { } } - return updateHighScores(mb, resp, repo) + err = updateHighScores(mb, resp, repo) + if err != nil { + return err + } + + return updateStats(mb, resp, repo, oldScore) }) if err != nil { @@ -200,6 +219,31 @@ func updateHighScores(mb *bolt.Bucket, resp checksResp, repo string) error { return nil } +func updateStats(mb *bolt.Bucket, resp checksResp, repo string, oldScore *float64) error { + scores := make([]int, 101, 101) + statsBytes := mb.Get([]byte("stats")) + if statsBytes == nil { + statsBytes, _ = json.Marshal(scores) + } + err := json.Unmarshal(statsBytes, &scores) + if err != nil { + return err + } + scores[int(resp.Average*100)]++ + if oldScore != nil { + scores[int(*oldScore*100)]-- + } + newStats, err := json.Marshal(scores) + if err != nil { + return err + } + err = mb.Put([]byte("stats"), newStats) + if err != nil { + return err + } + return nil +} + func updateReposCount(mb *bolt.Bucket, resp checksResp, repo string) (err error) { log.Printf("New repo %q, adding to repo count...", repo) totalInt := 0 diff --git a/handlers/high_scores.go b/handlers/high_scores.go index 2323ca2..b74c9de 100644 --- a/handlers/high_scores.go +++ b/handlers/high_scores.go @@ -31,7 +31,7 @@ func HighScoresHandler(w http.ResponseWriter, r *http.Request) { } defer db.Close() - count, scores := 0, &scoreHeap{} + count, scores, stats := 0, &scoreHeap{}, make([]int, 101, 101) err = db.View(func(tx *bolt.Tx) error { hsb := tx.Bucket([]byte(MetaBucket)) if hsb == nil { @@ -46,6 +46,15 @@ func HighScoresHandler(w http.ResponseWriter, r *http.Request) { } json.Unmarshal(scoreBytes, scores) + statsBytes := hsb.Get([]byte("stats")) + if statsBytes == nil { + statsBytes, err = json.Marshal(stats) + if err != nil { + return err + } + } + json.Unmarshal(statsBytes, &stats) + heap.Init(scores) total := hsb.Get([]byte("total_repos")) @@ -72,6 +81,7 @@ func HighScoresHandler(w http.ResponseWriter, r *http.Request) { t.Execute(w, map[string]interface{}{ "HighScores": sortedScores, + "Stats": stats, "Count": humanize.Comma(int64(count)), "google_analytics_key": googleAnalyticsKey, }) diff --git a/tools/migrate_repo_names.go b/tools/names/migrate_repo_names.go similarity index 100% rename from tools/migrate_repo_names.go rename to tools/names/migrate_repo_names.go diff --git a/tools/scores/init_repo_scores.go b/tools/scores/init_repo_scores.go new file mode 100644 index 0000000..9b46c11 --- /dev/null +++ b/tools/scores/init_repo_scores.go @@ -0,0 +1,75 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "time" + + "github.com/boltdb/bolt" + "github.com/gojp/goreportcard/handlers" +) + +const ( + dbPath string = "goreportcard.db" + repoBucket string = "repos" + metaBucket string = "meta" +) + +type checksResp struct { + Repo string `json:"repo"` + Average float64 `json:"average"` +} + +func main() { + db, err := bolt.Open(handlers.DBPath, 0600, &bolt.Options{Timeout: 1 * time.Second}) + if err != nil { + log.Fatal(err) + } + defer db.Close() + stats := make([]int, 101, 101) + err = db.Update(func(tx *bolt.Tx) error { + rb := tx.Bucket([]byte(repoBucket)) + if rb == nil { + return fmt.Errorf("repo bucket not found") + } + rb.ForEach(func(k, v []byte) error { + resp := checksResp{} + err := json.Unmarshal(v, &resp) + if err != nil { + return err + } + log.Printf("%s - %.2f", resp.Repo, resp.Average*100) + stats[int(resp.Average*100)]++ + return nil + }) + + // finally update the stats + mb := tx.Bucket([]byte(metaBucket)) + if mb == nil { + return fmt.Errorf("meta bucket not found") + } + var statsBytes []byte + statsBytes, err = json.Marshal(stats) + if err != nil { + return err + } + log.Printf("Stats: %v", stats) + err = mb.Put([]byte("stats"), statsBytes) + if err != nil { + return err + } + + tResp := mb.Get([]byte("stats")) + tStats := []int{} + err = json.Unmarshal(tResp, &tStats) + if err != nil { + return err + } + log.Printf("Stats Confirmation: %v", tStats) + return nil + }) + if err != nil { + log.Fatal(err) + } +}