Implement user/scores/best
This commit is contained in:
parent
45c67cf9b7
commit
da2a36537e
|
@ -37,6 +37,7 @@ func Start(conf common.Conf, dbO *sql.DB) *gin.Engine {
|
||||||
gv1.GET("/users/full", Method(v1.UserFullGET, common.PrivilegeRead))
|
gv1.GET("/users/full", Method(v1.UserFullGET, common.PrivilegeRead))
|
||||||
gv1.GET("/users/userpage", Method(v1.UserUserpageGET, common.PrivilegeRead))
|
gv1.GET("/users/userpage", Method(v1.UserUserpageGET, common.PrivilegeRead))
|
||||||
gv1.GET("/users/lookup", Method(v1.UserLookupGET, common.PrivilegeRead))
|
gv1.GET("/users/lookup", Method(v1.UserLookupGET, common.PrivilegeRead))
|
||||||
|
gv1.GET("/users/scores/best", Method(v1.UserScoresBestGET, common.PrivilegeRead))
|
||||||
gv1.GET("/badges", Method(v1.BadgesGET, common.PrivilegeRead))
|
gv1.GET("/badges", Method(v1.BadgesGET, common.PrivilegeRead))
|
||||||
|
|
||||||
// ReadConfidential privilege required
|
// ReadConfidential privilege required
|
||||||
|
|
|
@ -5,18 +5,53 @@ import "git.zxq.co/ripple/rippleapi/common"
|
||||||
type beatmap struct {
|
type beatmap struct {
|
||||||
BeatmapID int `json:"beatmap_id"`
|
BeatmapID int `json:"beatmap_id"`
|
||||||
BeatmapsetID int `json:"beatmapset_id"`
|
BeatmapsetID int `json:"beatmapset_id"`
|
||||||
BeatmapMD5 int `json:"beatmap_md5"`
|
BeatmapMD5 string `json:"beatmap_md5"`
|
||||||
SongName int `json:"song_name"`
|
SongName string `json:"song_name"`
|
||||||
AR float32 `json:"ar"`
|
AR float32 `json:"ar"`
|
||||||
OD float32 `json:"od"`
|
OD float32 `json:"od"`
|
||||||
Difficulty float64 `json:"difficulty"`
|
Difficulty float64 `json:"difficulty"`
|
||||||
MaxCombo int `json:"max_combo"`
|
MaxCombo int `json:"max_combo"`
|
||||||
HitLength int `json:"hit_length"`
|
HitLength int `json:"hit_length"`
|
||||||
BPM float64 `json:"bpm"`
|
|
||||||
Ranked int `json:"ranked"`
|
Ranked int `json:"ranked"`
|
||||||
RankedStatusFrozen int `json:"ranked_status_frozen"`
|
RankedStatusFrozen int `json:"ranked_status_frozen"`
|
||||||
LatestUpdate int `json:"latest_update"`
|
LatestUpdate int `json:"latest_update"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type beatmapMayOrMayNotExist struct {
|
||||||
|
BeatmapID *int
|
||||||
|
BeatmapsetID *int
|
||||||
|
BeatmapMD5 *string
|
||||||
|
SongName *string
|
||||||
|
AR *float32
|
||||||
|
OD *float32
|
||||||
|
Difficulty *float64
|
||||||
|
MaxCombo *int
|
||||||
|
HitLength *int
|
||||||
|
Ranked *int
|
||||||
|
RankedStatusFrozen *int
|
||||||
|
LatestUpdate *int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *beatmapMayOrMayNotExist) toBeatmap() *beatmap {
|
||||||
|
if b.BeatmapID == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &beatmap{
|
||||||
|
BeatmapID: *b.BeatmapID,
|
||||||
|
BeatmapsetID: *b.BeatmapsetID,
|
||||||
|
BeatmapMD5: *b.BeatmapMD5,
|
||||||
|
SongName: *b.SongName,
|
||||||
|
AR: *b.AR,
|
||||||
|
OD: *b.OD,
|
||||||
|
Difficulty: *b.Difficulty,
|
||||||
|
MaxCombo: *b.MaxCombo,
|
||||||
|
HitLength: *b.HitLength,
|
||||||
|
Ranked: *b.Ranked,
|
||||||
|
RankedStatusFrozen: *b.RankedStatusFrozen,
|
||||||
|
LatestUpdate: *b.LatestUpdate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type beatmapResponse struct {
|
type beatmapResponse struct {
|
||||||
common.ResponseBase
|
common.ResponseBase
|
||||||
beatmap
|
beatmap
|
||||||
|
|
|
@ -56,7 +56,7 @@ ON users_relationships.user2=users_stats.id
|
||||||
WHERE users_relationships.user1=?
|
WHERE users_relationships.user1=?
|
||||||
ORDER BY users_relationships.id`
|
ORDER BY users_relationships.id`
|
||||||
|
|
||||||
results, err := md.DB.Query(myFriendsQuery+common.Paginate(md.C.Query("p"), md.C.Query("l")), md.ID())
|
results, err := md.DB.Query(myFriendsQuery+common.Paginate(md.C.Query("p"), md.C.Query("l"), 50), md.ID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
md.Err(err)
|
md.Err(err)
|
||||||
return Err500
|
return Err500
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
package v1
|
package v1
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
type userScore struct {
|
"git.zxq.co/ripple/rippleapi/common"
|
||||||
ScoreID int `json:"score_id"`
|
)
|
||||||
|
|
||||||
|
type score struct {
|
||||||
|
ID int `json:"id"`
|
||||||
BeatmapMD5 string `json:"beatmap_md5"`
|
BeatmapMD5 string `json:"beatmap_md5"`
|
||||||
Score int64 `json:"score"`
|
Score int64 `json:"score"`
|
||||||
MaxCombo int `json:"max_combo"`
|
MaxCombo int `json:"max_combo"`
|
||||||
|
@ -18,4 +24,114 @@ type userScore struct {
|
||||||
Time time.Time `json:"time"`
|
Time time.Time `json:"time"`
|
||||||
PlayMode int `json:"play_mode"`
|
PlayMode int `json:"play_mode"`
|
||||||
Accuracy float64 `json:"accuracy"`
|
Accuracy float64 `json:"accuracy"`
|
||||||
|
PP float32 `json:"pp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type userScore struct {
|
||||||
|
score
|
||||||
|
Beatmap *beatmap `json:"beatmap"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type userScoresResponse struct {
|
||||||
|
common.ResponseBase
|
||||||
|
Scores []userScore `json:"scores"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const userScoreSelectBase = `
|
||||||
|
SELECT
|
||||||
|
scores.id, scores.beatmap_md5, scores.score,
|
||||||
|
scores.max_combo, scores.full_combo, scores.mods,
|
||||||
|
scores.300_count, scores.100_count, scores.50_count,
|
||||||
|
scores.gekis_count, scores.katus_count, scores.misses_count,
|
||||||
|
scores.time, scores.play_mode, scores.accuracy, scores.pp,
|
||||||
|
|
||||||
|
beatmaps.beatmap_id, beatmaps.beatmapset_id, beatmaps.beatmap_md5,
|
||||||
|
beatmaps.song_name, beatmaps.ar, beatmaps.od, beatmaps.difficulty,
|
||||||
|
beatmaps.max_combo, beatmaps.hit_length, beatmaps.ranked,
|
||||||
|
beatmaps.ranked_status_freezed, beatmaps.latest_update
|
||||||
|
FROM scores
|
||||||
|
LEFT JOIN beatmaps ON beatmaps.beatmap_md5 = scores.beatmap_md5
|
||||||
|
LEFT JOIN users ON users.username = scores.username
|
||||||
|
`
|
||||||
|
|
||||||
|
// UserScoresBestGET retrieves the best scores of an user, sorted by PP if
|
||||||
|
// mode is standard and sorted by ranked score otherwise.
|
||||||
|
func UserScoresBestGET(md common.MethodData) common.CodeMessager {
|
||||||
|
cm, wc, param := whereClauseUser(md, "users")
|
||||||
|
if cm != nil {
|
||||||
|
return *cm
|
||||||
|
}
|
||||||
|
var modeClause string
|
||||||
|
if md.C.Query("mode") != "" {
|
||||||
|
m, err := strconv.Atoi(md.C.Query("mode"))
|
||||||
|
if err == nil && m >= 0 && m <= 3 {
|
||||||
|
modeClause = fmt.Sprintf("AND scores.play_mode = '%d'", m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return scoresPuts(md, fmt.Sprintf(
|
||||||
|
`WHERE
|
||||||
|
scores.completed = '3'
|
||||||
|
AND %s
|
||||||
|
%s
|
||||||
|
AND users.allowed = '1'
|
||||||
|
ORDER BY scores.pp DESC, scores.score DESC %s`,
|
||||||
|
wc, modeClause, common.Paginate(md.C.Query("p"), md.C.Query("l"), 100),
|
||||||
|
), param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMode(m string) string {
|
||||||
|
switch m {
|
||||||
|
case "1":
|
||||||
|
return "taiko"
|
||||||
|
case "2":
|
||||||
|
return "ctb"
|
||||||
|
case "3":
|
||||||
|
return "mania"
|
||||||
|
default:
|
||||||
|
return "std"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func scoresPuts(md common.MethodData, whereClause string, params ...interface{}) common.CodeMessager {
|
||||||
|
rows, err := md.DB.Query(userScoreSelectBase+whereClause, params...)
|
||||||
|
if err != nil {
|
||||||
|
md.Err(err)
|
||||||
|
return Err500
|
||||||
|
}
|
||||||
|
var scores []userScore
|
||||||
|
for rows.Next() {
|
||||||
|
var (
|
||||||
|
us userScore
|
||||||
|
t string
|
||||||
|
b beatmapMayOrMayNotExist
|
||||||
|
)
|
||||||
|
err = rows.Scan(
|
||||||
|
&us.ID, &us.BeatmapMD5, &us.Score,
|
||||||
|
&us.MaxCombo, &us.FullCombo, &us.Mods,
|
||||||
|
&us.Count300, &us.Count100, &us.Count50,
|
||||||
|
&us.CountGeki, &us.CountKatu, &us.CountMiss,
|
||||||
|
&t, &us.PlayMode, &us.Accuracy, &us.PP,
|
||||||
|
|
||||||
|
&b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5,
|
||||||
|
&b.SongName, &b.AR, &b.OD, &b.Difficulty,
|
||||||
|
&b.MaxCombo, &b.HitLength, &b.Ranked,
|
||||||
|
&b.RankedStatusFrozen, &b.LatestUpdate,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
md.Err(err)
|
||||||
|
return Err500
|
||||||
|
}
|
||||||
|
// puck feppy
|
||||||
|
us.Time, err = time.Parse("060102150405", t)
|
||||||
|
if err != nil {
|
||||||
|
md.Err(err)
|
||||||
|
return Err500
|
||||||
|
}
|
||||||
|
us.Beatmap = b.toBeatmap()
|
||||||
|
scores = append(scores, us)
|
||||||
|
}
|
||||||
|
r := userScoresResponse{}
|
||||||
|
r.Code = 200
|
||||||
|
r.Scores = scores
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Paginate creates an additional SQL LIMIT clause for paginating.
|
// Paginate creates an additional SQL LIMIT clause for paginating.
|
||||||
func Paginate(page, limit string) string {
|
func Paginate(page, limit string, maxLimit int) string {
|
||||||
var (
|
var (
|
||||||
pInt int
|
pInt int
|
||||||
lInt int
|
lInt int
|
||||||
|
@ -34,6 +34,9 @@ func Paginate(page, limit string) string {
|
||||||
if lInt < 1 {
|
if lInt < 1 {
|
||||||
lInt = 50
|
lInt = 50
|
||||||
}
|
}
|
||||||
|
if lInt > maxLimit {
|
||||||
|
lInt = maxLimit
|
||||||
|
}
|
||||||
start := (pInt - 1) * lInt
|
start := (pInt - 1) * lInt
|
||||||
return fmt.Sprintf(" LIMIT %d,%d ", start, lInt)
|
return fmt.Sprintf(" LIMIT %d,%d ", start, lInt)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user