diff --git a/api/daily/rankings.go b/api/daily/rankings.go index b3ac2b6..4071cfe 100644 --- a/api/daily/rankings.go +++ b/api/daily/rankings.go @@ -25,8 +25,8 @@ import ( ) // /daily/rankings - fetch daily rankings -func Rankings(category, page int) ([]defs.DailyRanking, error) { - rankings, err := db.FetchRankings(category, page) +func Rankings(category, page int, uuid []byte) ([]defs.DailyRanking, error) { + rankings, err := db.FetchRankings(category, page, uuid) if err != nil { log.Print("failed to retrieve rankings") } diff --git a/api/daily/rankingspagecount.go b/api/daily/rankingspagecount.go index 458cbd6..43aa6c8 100644 --- a/api/daily/rankingspagecount.go +++ b/api/daily/rankingspagecount.go @@ -24,8 +24,8 @@ import ( ) // /daily/rankingpagecount - fetch daily ranking page count -func RankingPageCount(category int) (int, error) { - pageCount, err := db.FetchRankingPageCount(category) +func RankingPageCount(category int, uuid []byte) (int, error) { + pageCount, err := db.FetchRankingPageCount(category, uuid) if err != nil { log.Print("failed to retrieve ranking page count") } diff --git a/api/endpoints.go b/api/endpoints.go index de12aa0..627f702 100644 --- a/api/endpoints.go +++ b/api/endpoints.go @@ -860,7 +860,11 @@ func handleDailySeed(w http.ResponseWriter, r *http.Request) { } func handleDailyRankings(w http.ResponseWriter, r *http.Request) { - var err error + uuid, err := uuidFromRequest(r) + if err != nil { + httpError(w, r, err, http.StatusBadRequest) + return + } var category int if r.URL.Query().Has("category") { @@ -880,7 +884,7 @@ func handleDailyRankings(w http.ResponseWriter, r *http.Request) { } } - rankings, err := daily.Rankings(category, page) + rankings, err := daily.Rankings(category, page, uuid) if err != nil { httpError(w, r, err, http.StatusInternalServerError) return @@ -890,6 +894,12 @@ func handleDailyRankings(w http.ResponseWriter, r *http.Request) { } func handleDailyRankingPageCount(w http.ResponseWriter, r *http.Request) { + uuid, err := uuidFromRequest(r) + if err != nil { + httpError(w, r, err, http.StatusBadRequest) + return + } + var category int if r.URL.Query().Has("category") { var err error @@ -900,7 +910,7 @@ func handleDailyRankingPageCount(w http.ResponseWriter, r *http.Request) { } } - count, err := daily.RankingPageCount(category) + count, err := daily.RankingPageCount(category, uuid) if err != nil { httpError(w, r, err, http.StatusInternalServerError) } diff --git a/db/daily.go b/db/daily.go index e30574a..2543843 100644 --- a/db/daily.go +++ b/db/daily.go @@ -19,6 +19,7 @@ package db import ( "math" + "database/sql" "github.com/pagefaultgames/rogueserver/defs" ) @@ -53,9 +54,14 @@ func AddOrUpdateAccountDailyRun(uuid []byte, score int, wave int) error { return nil } -func FetchRankings(category int, page int) ([]defs.DailyRanking, error) { +func FetchRankings(category int, page int, uuid []byte) ([]defs.DailyRanking, error) { var rankings []defs.DailyRanking + username, err := FetchUsernameFromUUID(uuid); + if err != nil { + return rankings, err + } + offset := (page - 1) * 10 var query string @@ -64,9 +70,36 @@ func FetchRankings(category int, page int) ([]defs.DailyRanking, error) { query = "SELECT RANK() OVER (ORDER BY adr.score DESC, adr.timestamp), a.username, adr.score, adr.wave FROM accountDailyRuns adr JOIN dailyRuns dr ON dr.date = adr.date JOIN accounts a ON adr.uuid = a.uuid WHERE dr.date = UTC_DATE() AND a.banned = 0 LIMIT 10 OFFSET ?" case 1: query = "SELECT RANK() OVER (ORDER BY SUM(adr.score) DESC, adr.timestamp), a.username, SUM(adr.score), 0 FROM accountDailyRuns adr JOIN dailyRuns dr ON dr.date = adr.date JOIN accounts a ON adr.uuid = a.uuid WHERE dr.date >= DATE_SUB(DATE(UTC_TIMESTAMP()), INTERVAL DAYOFWEEK(UTC_TIMESTAMP()) - 1 DAY) AND a.banned = 0 GROUP BY a.username ORDER BY 1 LIMIT 10 OFFSET ?" + case 2: + // We retrieve the friends of the user and the user itself + query = `SELECT RANK() OVER (ORDER BY score DESC, timestamp) AS rank, username, score, wave + FROM ( + SELECT a.username, adr.score, adr.wave, adr.timestamp + FROM accountDailyRuns adr + JOIN dailyRuns dr ON dr.date = adr.date + JOIN accounts a ON adr.uuid = a.uuid + JOIN friends f ON a.username = f.friend + WHERE dr.date = UTC_DATE() + AND a.banned = 0 + AND f.user = ? + UNION + SELECT a.username, adr.score, adr.wave, adr.timestamp + FROM accountDailyRuns adr + JOIN dailyRuns dr ON dr.date = adr.date + JOIN accounts a ON adr.uuid = a.uuid + WHERE dr.date = UTC_DATE() + AND a.banned = 0 + AND a.username = ? + ) AS combined LIMIT 10 OFFSET ?;` + } + + var results *sql.Rows + if category == 2 { + results, err = handle.Query(query, username, username, offset) + } else { + results, err = handle.Query(query, offset) } - results, err := handle.Query(query, offset) if err != nil { return rankings, err } @@ -86,19 +119,37 @@ func FetchRankings(category int, page int) ([]defs.DailyRanking, error) { return rankings, nil } -func FetchRankingPageCount(category int) (int, error) { +func FetchRankingPageCount(category int, uuid []byte) (int, error) { + username, err := FetchUsernameFromUUID(uuid); + if err != nil { + return 0, err + } + var query string switch category { case 0: query = "SELECT COUNT(a.username) FROM accountDailyRuns adr JOIN dailyRuns dr ON dr.date = adr.date JOIN accounts a ON adr.uuid = a.uuid WHERE dr.date = UTC_DATE()" case 1: query = "SELECT COUNT(DISTINCT a.username) FROM accountDailyRuns adr JOIN dailyRuns dr ON dr.date = adr.date JOIN accounts a ON adr.uuid = a.uuid WHERE dr.date >= DATE_SUB(DATE(UTC_TIMESTAMP()), INTERVAL DAYOFWEEK(UTC_TIMESTAMP()) - 1 DAY)" + case 2: + query = `SELECT COUNT(a.username) + FROM accountDailyRuns adr + JOIN dailyRuns dr ON dr.date = adr.date + JOIN accounts a ON adr.uuid = a.uuid + JOIN friends f ON a.username = f.friend + WHERE dr.date = UTC_DATE() + AND f.user = ? + OR a.username = ?` } var recordCount int - err := handle.QueryRow(query).Scan(&recordCount) - if err != nil { - return 0, err + if category == 2 { + err = handle.QueryRow(query, username, username).Scan(&recordCount) + // We only fetch friends of the account, not the account itself so adding +1 here. + // this way, we don't have to do the big union query like in FetchRankings + recordCount += 1 + } else { + err = handle.QueryRow(query).Scan(&recordCount) } return int(math.Ceil(float64(recordCount) / 10)), nil