Add beatmap rank requests

This commit is contained in:
Howl 2016-11-19 19:53:55 +01:00
parent 9e57fedd80
commit 26435c1195
6 changed files with 64 additions and 14 deletions

View File

@ -48,6 +48,7 @@ func initialCaretaker(c *gin.Context, f func(md common.MethodData) common.CodeMe
RequestData: data, RequestData: data,
C: c, C: c,
Doggo: doggo, Doggo: doggo,
R: red,
} }
if token != "" { if token != "" {
tokenReal, exists := GetTokenFull(token, db) tokenReal, exists := GetTokenFull(token, db)

View File

@ -13,12 +13,14 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/serenize/snaker" "github.com/serenize/snaker"
"gopkg.in/redis.v5"
) )
var ( var (
db *sqlx.DB db *sqlx.DB
cf common.Conf cf common.Conf
doggo *statsd.Client doggo *statsd.Client
red *redis.Client
) )
var commonClusterfucks = map[string]string{ var commonClusterfucks = map[string]string{
@ -65,6 +67,13 @@ func Start(conf common.Conf, dbO *sqlx.DB) *gin.Engine {
doggo.Incr("requests", nil, 1) doggo.Incr("requests", nil, 1)
}) })
// redis
red = redis.NewClient(&redis.Options{
Addr: conf.RedisAddr,
Password: conf.RedisPassword,
DB: conf.RedisDB,
})
api := r.Group("/api") api := r.Group("/api")
{ {
p := api.Group("/") p := api.Group("/")
@ -119,7 +128,7 @@ func Start(conf common.Conf, dbO *sqlx.DB) *gin.Engine {
gv1.POST("/friends/del", Method(v1.FriendsDelPOST, common.PrivilegeWrite)) gv1.POST("/friends/del", Method(v1.FriendsDelPOST, common.PrivilegeWrite))
gv1.POST("/users/self/settings", Method(v1.UsersSelfSettingsPOST, common.PrivilegeWrite)) gv1.POST("/users/self/settings", Method(v1.UsersSelfSettingsPOST, common.PrivilegeWrite))
gv1.POST("/users/self/userpage", Method(v1.UserSelfUserpagePOST, common.PrivilegeWrite)) gv1.POST("/users/self/userpage", Method(v1.UserSelfUserpagePOST, common.PrivilegeWrite))
//gv1.POST("/beatmaps/rank_requests", Method(v1.BeatmapRankRequestsSubmitPOST, common.PrivilegeWrite)) gv1.POST("/beatmaps/rank_requests", Method(v1.BeatmapRankRequestsSubmitPOST, common.PrivilegeWrite))
// Admin: beatmap // Admin: beatmap
gv1.POST("/beatmaps/set_status", Method(v1.BeatmapSetStatusPOST, common.PrivilegeBeatmap)) gv1.POST("/beatmaps/set_status", Method(v1.BeatmapSetStatusPOST, common.PrivilegeBeatmap))

View File

@ -5,7 +5,6 @@ import (
"strconv" "strconv"
"time" "time"
"git.zxq.co/ripple/rippleapi/beatmapget"
"git.zxq.co/ripple/rippleapi/common" "git.zxq.co/ripple/rippleapi/common"
"git.zxq.co/ripple/rippleapi/limit" "git.zxq.co/ripple/rippleapi/limit"
) )
@ -106,26 +105,45 @@ func BeatmapRankRequestsSubmitPOST(md common.MethodData) common.CodeMessager {
return common.SimpleResponse(403, "It's not possible to do a rank request at this time.") return common.SimpleResponse(403, "It's not possible to do a rank request at this time.")
} }
if d.SetID == 0 { w := common.
d.SetID, err = beatmapget.Beatmap(d.ID) Where("beatmap_id = ?", strconv.Itoa(d.ID)).Or().
} else { Where("beatmapset_id = ?", strconv.Itoa(d.SetID))
err = beatmapget.Set(d.SetID)
var ranked int
err = md.DB.QueryRow("SELECT ranked FROM beatmaps "+w.Clause+" LIMIT 1", w.Params...).Scan(&ranked)
if ranked >= 2 {
return common.SimpleResponse(406, "That beatmap is already ranked.")
} }
if err == beatmapget.ErrBeatmapNotFound {
return common.SimpleResponse(404, "That beatmap could not be found anywhere!") switch err {
} case nil:
if err != nil { // move on
case sql.ErrNoRows:
if d.SetID != 0 {
md.R.Publish("ripple:beatmap_updates:sets", strconv.Itoa(d.SetID))
} else {
md.R.Publish("ripple:beatmap_updates:single", strconv.Itoa(d.ID))
}
default:
md.Err(err) md.Err(err)
return Err500 return Err500
} }
// type and value of beatmap rank request
t := "b"
v := d.ID
if d.SetID != 0 {
t = "s"
v = d.SetID
}
err = md.DB.QueryRow("SELECT 1 FROM rank_requests WHERE bid = ? AND type = ? AND time > ?", err = md.DB.QueryRow("SELECT 1 FROM rank_requests WHERE bid = ? AND type = ? AND time > ?",
d.SetID, "s", time.Now().Unix()).Scan(new(int)) v, t, time.Now().Add(-time.Hour*24).Unix()).Scan(new(int))
// error handling
switch err { switch err {
case sql.ErrNoRows: case sql.ErrNoRows:
break break
case nil: case nil:
// TODO: return beatmap
// we're returning a success because if the request was already sent in the past 24 // we're returning a success because if the request was already sent in the past 24
// hours, it's as if the user submitted it. // hours, it's as if the user submitted it.
return common.SimpleResponse(200, "Your request has been submitted.") return common.SimpleResponse(200, "Your request has been submitted.")
@ -136,12 +154,11 @@ func BeatmapRankRequestsSubmitPOST(md common.MethodData) common.CodeMessager {
_, err = md.DB.Exec( _, err = md.DB.Exec(
"INSERT INTO rank_requests (userid, bid, type, time, blacklisted) VALUES (?, ?, ?, ?, 0)", "INSERT INTO rank_requests (userid, bid, type, time, blacklisted) VALUES (?, ?, ?, ?, 0)",
md.ID(), d.SetID, "s", time.Now().Unix()) md.ID(), v, t, time.Now().Unix())
if err != nil { if err != nil {
md.Err(err) md.Err(err)
return Err500 return Err500
} }
// TODO: return beatmap
return common.SimpleResponse(200, "Your request has been submitted.") return common.SimpleResponse(200, "Your request has been submitted.")
} }

View File

@ -22,6 +22,9 @@ type Conf struct {
BeatmapRequestsPerUser int BeatmapRequestsPerUser int
RankQueueSize int RankQueueSize int
OsuAPIKey string OsuAPIKey string
RedisAddr string
RedisPassword string
RedisDB int
} }
var cachedConf *Conf var cachedConf *Conf
@ -43,6 +46,7 @@ func Load() (c Conf, halt bool) {
HanayoKey: "Potato", HanayoKey: "Potato",
BeatmapRequestsPerUser: 2, BeatmapRequestsPerUser: 2,
RankQueueSize: 25, RankQueueSize: 25,
RedisAddr: "localhost:6379",
}, "api.conf") }, "api.conf")
fmt.Println("Please compile the configuration file (api.conf).") fmt.Println("Please compile the configuration file (api.conf).")
} }

View File

@ -6,6 +6,7 @@ import (
"github.com/DataDog/datadog-go/statsd" "github.com/DataDog/datadog-go/statsd"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"gopkg.in/redis.v5"
) )
// MethodData is a struct containing the data passed over to an API method. // MethodData is a struct containing the data passed over to an API method.
@ -15,6 +16,7 @@ type MethodData struct {
RequestData RequestData RequestData RequestData
C *gin.Context C *gin.Context
Doggo *statsd.Client Doggo *statsd.Client
R *redis.Client
} }
// Err logs an error into gin. // Err logs an error into gin.

View File

@ -5,6 +5,7 @@ package common
type WhereClause struct { type WhereClause struct {
Clause string Clause string
Params []interface{} Params []interface{}
useOr bool
} }
// Where adds a new WHERE clause to the WhereClause. // Where adds a new WHERE clause to the WhereClause.
@ -26,10 +27,26 @@ func (w *WhereClause) addWhere() {
if w.Clause == "" { if w.Clause == "" {
w.Clause += "WHERE " w.Clause += "WHERE "
} else { } else {
if w.useOr {
w.Clause += " OR "
return
}
w.Clause += " AND " w.Clause += " AND "
} }
} }
// Or enables using OR instead of AND
func (w *WhereClause) Or() *WhereClause {
w.useOr = true
return w
}
// And enables using AND instead of OR
func (w *WhereClause) And() *WhereClause {
w.useOr = false
return w
}
// In generates an IN clause. // In generates an IN clause.
// initial is the initial part, e.g. "users.id". // initial is the initial part, e.g. "users.id".
// Fields are the possible values. // Fields are the possible values.