Use custom type UnixTimestamp instead of repeating boilerplate code over and over.
This commit is contained in:
parent
ff1d2fa1c3
commit
09523369b7
|
@ -2,24 +2,23 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.zxq.co/ripple/rippleapi/common"
|
"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 string `json:"beatmap_md5"`
|
BeatmapMD5 string `json:"beatmap_md5"`
|
||||||
SongName string `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"`
|
||||||
Ranked int `json:"ranked"`
|
Ranked int `json:"ranked"`
|
||||||
RankedStatusFrozen int `json:"ranked_status_frozen"`
|
RankedStatusFrozen int `json:"ranked_status_frozen"`
|
||||||
LatestUpdate time.Time `json:"latest_update"`
|
LatestUpdate common.UnixTimestamp `json:"latest_update"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type beatmapMayOrMayNotExist struct {
|
type beatmapMayOrMayNotExist struct {
|
||||||
|
@ -34,7 +33,7 @@ type beatmapMayOrMayNotExist struct {
|
||||||
HitLength *int
|
HitLength *int
|
||||||
Ranked *int
|
Ranked *int
|
||||||
RankedStatusFrozen *int
|
RankedStatusFrozen *int
|
||||||
LatestUpdate *time.Time
|
LatestUpdate *common.UnixTimestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *beatmapMayOrMayNotExist) toBeatmap() *beatmap {
|
func (b *beatmapMayOrMayNotExist) toBeatmap() *beatmap {
|
||||||
|
@ -146,21 +145,17 @@ func getSet(md common.MethodData, setID int) common.CodeMessager {
|
||||||
}
|
}
|
||||||
var r beatmapSetResponse
|
var r beatmapSetResponse
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var (
|
var b beatmap
|
||||||
b beatmap
|
|
||||||
rawLatestUpdate int64
|
|
||||||
)
|
|
||||||
err = rows.Scan(
|
err = rows.Scan(
|
||||||
&b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5,
|
&b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5,
|
||||||
&b.SongName, &b.AR, &b.OD, &b.Difficulty, &b.MaxCombo,
|
&b.SongName, &b.AR, &b.OD, &b.Difficulty, &b.MaxCombo,
|
||||||
&b.HitLength, &b.Ranked, &b.RankedStatusFrozen,
|
&b.HitLength, &b.Ranked, &b.RankedStatusFrozen,
|
||||||
&rawLatestUpdate,
|
&b.LatestUpdate,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
md.Err(err)
|
md.Err(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
b.LatestUpdate = time.Unix(rawLatestUpdate, 0)
|
|
||||||
r.Beatmaps = append(r.Beatmaps, b)
|
r.Beatmaps = append(r.Beatmaps, b)
|
||||||
}
|
}
|
||||||
r.Code = 200
|
r.Code = 200
|
||||||
|
@ -168,15 +163,12 @@ func getSet(md common.MethodData, setID int) common.CodeMessager {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBeatmap(md common.MethodData, beatmapID int) common.CodeMessager {
|
func getBeatmap(md common.MethodData, beatmapID int) common.CodeMessager {
|
||||||
var (
|
var b beatmap
|
||||||
b beatmap
|
|
||||||
rawLatestUpdate int64
|
|
||||||
)
|
|
||||||
err := md.DB.QueryRow(baseBeatmapSelect+"WHERE beatmap_id = ? LIMIT 1", beatmapID).Scan(
|
err := md.DB.QueryRow(baseBeatmapSelect+"WHERE beatmap_id = ? LIMIT 1", beatmapID).Scan(
|
||||||
&b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5,
|
&b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5,
|
||||||
&b.SongName, &b.AR, &b.OD, &b.Difficulty, &b.MaxCombo,
|
&b.SongName, &b.AR, &b.OD, &b.Difficulty, &b.MaxCombo,
|
||||||
&b.HitLength, &b.Ranked, &b.RankedStatusFrozen,
|
&b.HitLength, &b.Ranked, &b.RankedStatusFrozen,
|
||||||
&rawLatestUpdate,
|
&b.LatestUpdate,
|
||||||
)
|
)
|
||||||
switch {
|
switch {
|
||||||
case err == sql.ErrNoRows:
|
case err == sql.ErrNoRows:
|
||||||
|
@ -185,7 +177,6 @@ func getBeatmap(md common.MethodData, beatmapID int) common.CodeMessager {
|
||||||
md.Err(err)
|
md.Err(err)
|
||||||
return Err500
|
return Err500
|
||||||
}
|
}
|
||||||
b.LatestUpdate = time.Unix(rawLatestUpdate, 0)
|
|
||||||
var r beatmapResponse
|
var r beatmapResponse
|
||||||
r.Code = 200
|
r.Code = 200
|
||||||
r.beatmap = b
|
r.beatmap = b
|
||||||
|
|
|
@ -2,7 +2,6 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.zxq.co/ripple/rippleapi/common"
|
"git.zxq.co/ripple/rippleapi/common"
|
||||||
)
|
)
|
||||||
|
@ -87,18 +86,13 @@ ORDER BY users_relationships.id`
|
||||||
func friendPuts(md common.MethodData, row *sql.Rows) (user friendData) {
|
func friendPuts(md common.MethodData, row *sql.Rows) (user friendData) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
registeredOn := int64(0)
|
|
||||||
latestActivity := int64(0)
|
|
||||||
var showcountry bool
|
var showcountry bool
|
||||||
err = row.Scan(&user.ID, &user.Username, ®isteredOn, &user.Privileges, &latestActivity, &user.UsernameAKA, &user.Country, &showcountry)
|
err = row.Scan(&user.ID, &user.Username, &user.RegisteredOn, &user.Privileges, &user.LatestActivity, &user.UsernameAKA, &user.Country, &showcountry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
md.Err(err)
|
md.Err(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user.RegisteredOn = time.Unix(registeredOn, 0)
|
|
||||||
user.LatestActivity = time.Unix(latestActivity, 0)
|
|
||||||
|
|
||||||
// If the user wants to stay anonymous, don't show their country.
|
// If the user wants to stay anonymous, don't show their country.
|
||||||
// This can be overriden if we have the ReadConfidential privilege and the user we are accessing is the token owner.
|
// This can be overriden if we have the ReadConfidential privilege and the user we are accessing is the token owner.
|
||||||
if !(showcountry || (md.User.Privileges.HasPrivilegeReadConfidential() && user.ID == md.ID())) {
|
if !(showcountry || (md.User.Privileges.HasPrivilegeReadConfidential() && user.ID == md.ID())) {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.zxq.co/ripple/rippleapi/common"
|
"git.zxq.co/ripple/rippleapi/common"
|
||||||
)
|
)
|
||||||
|
@ -47,13 +46,11 @@ func LeaderboardGET(md common.MethodData) common.CodeMessager {
|
||||||
var resp leaderboardResponse
|
var resp leaderboardResponse
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var (
|
var (
|
||||||
u leaderboardUser
|
u leaderboardUser
|
||||||
register int64
|
showCountry bool
|
||||||
latestActivity int64
|
|
||||||
showCountry bool
|
|
||||||
)
|
)
|
||||||
err := rows.Scan(
|
err := rows.Scan(
|
||||||
&u.ID, &u.Username, ®ister, &u.Privileges, &latestActivity,
|
&u.ID, &u.Username, &u.RegisteredOn, &u.Privileges, &u.LatestActivity,
|
||||||
|
|
||||||
&u.UsernameAKA, &u.Country, &showCountry,
|
&u.UsernameAKA, &u.Country, &showCountry,
|
||||||
&u.PlayStyle, &u.FavouriteMode,
|
&u.PlayStyle, &u.FavouriteMode,
|
||||||
|
@ -69,8 +66,6 @@ func LeaderboardGET(md common.MethodData) common.CodeMessager {
|
||||||
if !showCountry {
|
if !showCountry {
|
||||||
u.Country = "XX"
|
u.Country = "XX"
|
||||||
}
|
}
|
||||||
u.RegisteredOn = time.Unix(register, 0)
|
|
||||||
u.LatestActivity = time.Unix(latestActivity, 0)
|
|
||||||
resp.Users = append(resp.Users, u)
|
resp.Users = append(resp.Users, u)
|
||||||
}
|
}
|
||||||
resp.Code = 200
|
resp.Code = 200
|
||||||
|
|
|
@ -5,20 +5,19 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.zxq.co/ripple/ocl"
|
"git.zxq.co/ripple/ocl"
|
||||||
"git.zxq.co/ripple/rippleapi/common"
|
"git.zxq.co/ripple/rippleapi/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type userData struct {
|
type userData struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
UsernameAKA string `json:"username_aka"`
|
UsernameAKA string `json:"username_aka"`
|
||||||
RegisteredOn time.Time `json:"registered_on"`
|
RegisteredOn common.UnixTimestamp `json:"registered_on"`
|
||||||
Privileges uint64 `json:"privileges"`
|
Privileges uint64 `json:"privileges"`
|
||||||
LatestActivity time.Time `json:"latest_activity"`
|
LatestActivity common.UnixTimestamp `json:"latest_activity"`
|
||||||
Country string `json:"country"`
|
Country string `json:"country"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UsersGET is the API handler for GET /users
|
// UsersGET is the API handler for GET /users
|
||||||
|
@ -49,12 +48,11 @@ func userPuts(md common.MethodData, row *sql.Row) common.CodeMessager {
|
||||||
var err error
|
var err error
|
||||||
var user userPutsUserData
|
var user userPutsUserData
|
||||||
|
|
||||||
var (
|
var showCountry bool
|
||||||
registeredOn int64
|
err = row.Scan(
|
||||||
latestActivity int64
|
&user.ID, &user.Username, &user.RegisteredOn, &user.Privileges, &user.LatestActivity,
|
||||||
showCountry bool
|
&user.UsernameAKA, &user.Country, &showCountry,
|
||||||
)
|
)
|
||||||
err = row.Scan(&user.ID, &user.Username, ®isteredOn, &user.Privileges, &latestActivity, &user.UsernameAKA, &user.Country, &showCountry)
|
|
||||||
switch {
|
switch {
|
||||||
case err == sql.ErrNoRows:
|
case err == sql.ErrNoRows:
|
||||||
return common.SimpleResponse(404, "No such user was found!")
|
return common.SimpleResponse(404, "No such user was found!")
|
||||||
|
@ -63,9 +61,6 @@ func userPuts(md common.MethodData, row *sql.Row) common.CodeMessager {
|
||||||
return Err500
|
return Err500
|
||||||
}
|
}
|
||||||
|
|
||||||
user.RegisteredOn = time.Unix(registeredOn, 0)
|
|
||||||
user.LatestActivity = time.Unix(latestActivity, 0)
|
|
||||||
|
|
||||||
user.Country = genCountry(md, user.ID, showCountry, user.Country)
|
user.Country = genCountry(md, user.ID, showCountry, user.Country)
|
||||||
|
|
||||||
user.Code = 200
|
user.Code = 200
|
||||||
|
@ -191,14 +186,12 @@ LIMIT 1
|
||||||
// Fuck.
|
// Fuck.
|
||||||
r := userFullResponse{}
|
r := userFullResponse{}
|
||||||
var (
|
var (
|
||||||
badges string
|
badges string
|
||||||
country string
|
country string
|
||||||
showCountry bool
|
showCountry bool
|
||||||
registeredOn int64
|
|
||||||
latestActivity int64
|
|
||||||
)
|
)
|
||||||
err := md.DB.QueryRow(query, param).Scan(
|
err := md.DB.QueryRow(query, param).Scan(
|
||||||
&r.ID, &r.Username, ®isteredOn, &r.Privileges, &latestActivity,
|
&r.ID, &r.Username, &r.RegisteredOn, &r.Privileges, &r.LatestActivity,
|
||||||
|
|
||||||
&r.UsernameAKA, &badges, &country, &showCountry,
|
&r.UsernameAKA, &badges, &country, &showCountry,
|
||||||
&r.PlayStyle, &r.FavouriteMode,
|
&r.PlayStyle, &r.FavouriteMode,
|
||||||
|
@ -230,9 +223,6 @@ LIMIT 1
|
||||||
r.Country = genCountry(md, r.ID, showCountry, country)
|
r.Country = genCountry(md, r.ID, showCountry, country)
|
||||||
r.Badges = badgesToArray(badges)
|
r.Badges = badgesToArray(badges)
|
||||||
|
|
||||||
r.RegisteredOn = time.Unix(registeredOn, 0)
|
|
||||||
r.LatestActivity = time.Unix(latestActivity, 0)
|
|
||||||
|
|
||||||
for _, m := range []*modeData{&r.STD, &r.Taiko, &r.CTB, &r.Mania} {
|
for _, m := range []*modeData{&r.STD, &r.Taiko, &r.CTB, &r.Mania} {
|
||||||
m.Level = ocl.GetLevelPrecise(int64(m.TotalScore))
|
m.Level = ocl.GetLevelPrecise(int64(m.TotalScore))
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,10 +128,9 @@ func scoresPuts(md common.MethodData, whereClause string, params ...interface{})
|
||||||
var scores []userScore
|
var scores []userScore
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var (
|
var (
|
||||||
us userScore
|
us userScore
|
||||||
t string
|
t string
|
||||||
b beatmapMayOrMayNotExist
|
b beatmapMayOrMayNotExist
|
||||||
rawLatestUpdate *int64
|
|
||||||
)
|
)
|
||||||
err = rows.Scan(
|
err = rows.Scan(
|
||||||
&us.ID, &us.BeatmapMD5, &us.Score,
|
&us.ID, &us.BeatmapMD5, &us.Score,
|
||||||
|
@ -144,7 +143,7 @@ func scoresPuts(md common.MethodData, whereClause string, params ...interface{})
|
||||||
&b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5,
|
&b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5,
|
||||||
&b.SongName, &b.AR, &b.OD, &b.Difficulty,
|
&b.SongName, &b.AR, &b.OD, &b.Difficulty,
|
||||||
&b.MaxCombo, &b.HitLength, &b.Ranked,
|
&b.MaxCombo, &b.HitLength, &b.Ranked,
|
||||||
&b.RankedStatusFrozen, &rawLatestUpdate,
|
&b.RankedStatusFrozen, &b.LatestUpdate,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
md.Err(err)
|
md.Err(err)
|
||||||
|
@ -156,11 +155,6 @@ func scoresPuts(md common.MethodData, whereClause string, params ...interface{})
|
||||||
md.Err(err)
|
md.Err(err)
|
||||||
return Err500
|
return Err500
|
||||||
}
|
}
|
||||||
if rawLatestUpdate != nil {
|
|
||||||
// fml i should have used an inner join
|
|
||||||
xd := time.Unix(*rawLatestUpdate, 0)
|
|
||||||
b.LatestUpdate = &xd
|
|
||||||
}
|
|
||||||
us.Beatmap = b.toBeatmap()
|
us.Beatmap = b.toBeatmap()
|
||||||
scores = append(scores, us)
|
scores = append(scores, us)
|
||||||
}
|
}
|
||||||
|
|
55
common/unix_timestamp.go
Normal file
55
common/unix_timestamp.go
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnixTimestamp is simply a time.Time, but can be used to convert an
|
||||||
|
// unix timestamp in the database into a native time.Time.
|
||||||
|
type UnixTimestamp time.Time
|
||||||
|
|
||||||
|
// Scan decodes src into an unix timestamp.
|
||||||
|
func (u *UnixTimestamp) Scan(src interface{}) error {
|
||||||
|
if u == nil {
|
||||||
|
return errors.New("rippleapi/common: UnixTimestamp is nil")
|
||||||
|
}
|
||||||
|
switch src := src.(type) {
|
||||||
|
case int64:
|
||||||
|
*u = UnixTimestamp(time.Unix(src, 0))
|
||||||
|
case float64:
|
||||||
|
*u = UnixTimestamp(time.Unix(int64(src), 0))
|
||||||
|
case string:
|
||||||
|
return u._string(src)
|
||||||
|
case []byte:
|
||||||
|
return u._string(string(src))
|
||||||
|
case nil:
|
||||||
|
// Nothing, leave zero value on timestamp
|
||||||
|
default:
|
||||||
|
return errors.New("rippleapi/common: unhandleable type")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnixTimestamp) _string(s string) error {
|
||||||
|
ts, err := strconv.Atoi(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*u = UnixTimestamp(time.Unix(int64(ts), 0))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON -> time.Time.MarshalJSON
|
||||||
|
func (u UnixTimestamp) MarshalJSON() ([]byte, error) {
|
||||||
|
return time.Time(u).MarshalJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON -> time.Time.UnmarshalJSON
|
||||||
|
func (u *UnixTimestamp) UnmarshalJSON(x []byte) error {
|
||||||
|
t := new(time.Time)
|
||||||
|
err := t.UnmarshalJSON(x)
|
||||||
|
*u = UnixTimestamp(*t)
|
||||||
|
return err
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user