Skip to content

Commit

Permalink
Merge pull request stakwork#2190 from stakwork/feat/new_hunter_metrics
Browse files Browse the repository at this point in the history
Feat: added newhunters, and newhuntersbyperiod metrics
  • Loading branch information
humansinstitute authored Dec 16, 2024
2 parents ae3f0b4 + a7ea620 commit c4eb948
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 22 deletions.
2 changes: 2 additions & 0 deletions db/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,6 @@ type Database interface {
GetTicketsWithoutGroup() ([]Tickets, error)
UpdateTicketsWithoutGroup(ticket Tickets) error
ProcessUpdateTicketsWithoutGroup()
GetNewHunters(r PaymentDateRange) int64
TotalPeopleByPeriod(r PaymentDateRange) int64
}
33 changes: 33 additions & 0 deletions db/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"math"
"net/http"
"strings"
"time"

"github.com/stakwork/sphinx-tribes/utils"
)
Expand All @@ -17,6 +18,38 @@ func (db database) TotalPeopleByDateRange(r PaymentDateRange) int64 {
return count
}

func (db database) TotalPeopleByPeriod(r PaymentDateRange) int64 {
var count int64

// convert timestamp string to int64
timestamp, err := utils.ConvertStringToInt(r.StartDate)
if err != nil {
fmt.Println("Error parsing date:", err)
}

// Convert the timestamp to a time.Time object
t := time.Unix(int64(timestamp), 0)

// Format the time as a human-readable string
formattedTime := t.Format("2006-01-02 15:04:05")

db.db.Model(&Person{}).Where("created < ?", formattedTime).Count(&count)
return count
}

func (db database) GetNewHunters(r PaymentDateRange) int64 {
var totalCount int64
var newHunters int64 = 0
var huntersByPeriod int64 = db.TotalPeopleByPeriod(r)

db.db.Model(&Person{}).Count(&totalCount)

if huntersByPeriod > 0 && totalCount > huntersByPeriod {
newHunters = totalCount - huntersByPeriod
}
return newHunters
}

func (db database) TotalWorkspacesByDateRange(r PaymentDateRange) int64 {
var count int64
db.db.Model(&Organization{}).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate).Count(&count)
Expand Down
2 changes: 2 additions & 0 deletions db/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,8 @@ type BountyMetrics struct {
AverageCompleted uint `json:"average_completed"`
UniqueHuntersPaid int64 `json:"unique_hunters_paid"`
NewHuntersPaid int64 `json:"new_hunters_paid"`
NewHunters int64 `json:"new_hunters"`
NewHuntersByPeriod int64 `json:"new_hunters_by_period"`
}

type MetricsBountyCsv struct {
Expand Down
18 changes: 18 additions & 0 deletions handlers/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ func PeopleMetrics(w http.ResponseWriter, r *http.Request) {

request := db.PaymentDateRange{}
body, err := io.ReadAll(r.Body)

if err != nil {
w.WriteHeader(http.StatusNotAcceptable)
json.NewEncoder(w).Encode("Request body not accepted")
return
}

r.Body.Close()

err = json.Unmarshal(body, &request)
Expand Down Expand Up @@ -127,6 +134,13 @@ func (mh *metricHandler) BountyMetrics(w http.ResponseWriter, r *http.Request) {

request := db.PaymentDateRange{}
body, err := io.ReadAll(r.Body)

if err != nil {
w.WriteHeader(http.StatusNotAcceptable)
json.NewEncoder(w).Encode("Request body not accepted")
return
}

r.Body.Close()

err = json.Unmarshal(body, &request)
Expand Down Expand Up @@ -163,6 +177,8 @@ func (mh *metricHandler) BountyMetrics(w http.ResponseWriter, r *http.Request) {
avgCompletedDays := mh.db.AverageCompletedTime(request, workspace)
uniqueHuntersPaid := mh.db.TotalHuntersPaid(request, workspace)
newHuntersPaid := mh.db.NewHuntersPaid(request, workspace)
newHunters := mh.db.GetNewHunters(request)
peopleByPeriod := mh.db.TotalPeopleByPeriod(request)

bountyMetrics := db.BountyMetrics{
BountiesPosted: totalBountiesPosted,
Expand All @@ -176,6 +192,8 @@ func (mh *metricHandler) BountyMetrics(w http.ResponseWriter, r *http.Request) {
AverageCompleted: avgCompletedDays,
UniqueHuntersPaid: uniqueHuntersPaid,
NewHuntersPaid: newHuntersPaid,
NewHunters: newHunters,
NewHuntersByPeriod: peopleByPeriod,
}

if db.RedisError == nil && db.RedisClient != nil {
Expand Down
9 changes: 7 additions & 2 deletions handlers/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import (
"bytes"
"context"
"encoding/json"
"github.com/google/uuid"
"github.com/lib/pq"
"net/http"
"net/http/httptest"
"strconv"
"testing"

"github.com/google/uuid"
"github.com/lib/pq"

"fmt"
"time"

Expand Down Expand Up @@ -154,6 +155,8 @@ func TestBountyMetrics(t *testing.T) {
avgCompletedDays := uint(0)
uniqueHuntersPaid := int64(2)
newHuntersPaid := int64(2)
newHunters := db.TestDB.GetNewHunters(dateRange)
peopleByPeriod := db.TestDB.TotalPeopleByPeriod(dateRange)

expectedMetricRes := db.BountyMetrics{
BountiesPosted: totalBountiesPosted,
Expand All @@ -167,6 +170,8 @@ func TestBountyMetrics(t *testing.T) {
AverageCompleted: avgCompletedDays,
UniqueHuntersPaid: uniqueHuntersPaid,
NewHuntersPaid: newHuntersPaid,
NewHunters: newHunters,
NewHuntersByPeriod: peopleByPeriod,
}

var res db.BountyMetrics
Expand Down
92 changes: 92 additions & 0 deletions mocks/Database.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 20 additions & 20 deletions routes/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,35 +142,35 @@ func getFromAuth(path string) (*extractResponse, error) {
}

// Middleware to handle InternalServerError
func internalServerErrorHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rr := &responseRecorder{ResponseWriter: w, statusCode: http.StatusOK}
next.ServeHTTP(rr, r)

if rr.statusCode == http.StatusInternalServerError {
fmt.Printf("Internal Server Error: %s %s\n", r.Method, r.URL.Path)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
}
})
}
// func internalServerErrorHandler(next http.Handler) http.Handler {
// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// rr := &responseRecorder{ResponseWriter: w, statusCode: http.StatusOK}
// next.ServeHTTP(rr, r)

// if rr.statusCode == http.StatusInternalServerError {
// fmt.Printf("Internal Server Error: %s %s\n", r.Method, r.URL.Path)
// http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
// }
// })
// }

// Custom ResponseWriter to capture status codes
type responseRecorder struct {
http.ResponseWriter
statusCode int
}
// type responseRecorder struct {
// http.ResponseWriter
// statusCode int
// }

func (rr *responseRecorder) WriteHeader(code int) {
rr.statusCode = code
rr.ResponseWriter.WriteHeader(code)
}
// func (rr *responseRecorder) WriteHeader(code int) {
// rr.statusCode = code
// rr.ResponseWriter.WriteHeader(code)
// }

func initChi() *chi.Mux {
r := chi.NewRouter()
r.Use(middleware.RequestID)
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(internalServerErrorHandler)
// r.Use(internalServerErrorHandler)
cors := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
Expand Down

0 comments on commit c4eb948

Please sign in to comment.