diff --git a/app/start.go b/app/start.go index 3cc27e7..c41e4e4 100644 --- a/app/start.go +++ b/app/start.go @@ -30,6 +30,7 @@ func Start(conf common.Conf, db *sql.DB) { gv1.GET("/users/name/:name", Method(v1.UserByNameGET, db, common.PrivilegeRead)) gv1.GET("/users/self", Method(v1.UserSelfGET, db, common.PrivilegeRead)) gv1.GET("/users/whatid/:username", Method(v1.UserWhatsTheIDGET, db, common.PrivilegeRead)) + gv1.GET("/users/full/:id", Method(v1.UserFullGET, db, common.PrivilegeRead)) gv1.GET("/badges", Method(v1.BadgesGET, db, common.PrivilegeRead)) gv1.GET("/badges/:id", Method(v1.BadgeByIDGET, db, common.PrivilegeRead)) diff --git a/app/v1/user.go b/app/v1/user.go index 13c744c..2c8000e 100644 --- a/app/v1/user.go +++ b/app/v1/user.go @@ -73,11 +73,13 @@ func userPuts(md common.MethodData, row *sql.Row) (r common.Response) { var err error var user userData - registeredOn := int64(0) - latestActivity := int64(0) - var badges string - var showcountry bool - err = row.Scan(&user.ID, &user.Username, ®isteredOn, &user.Rank, &latestActivity, &user.UsernameAKA, &badges, &user.Country, &showcountry) + var ( + registeredOn int64 + latestActivity int64 + badges string + showCountry bool + ) + err = row.Scan(&user.ID, &user.Username, ®isteredOn, &user.Rank, &latestActivity, &user.UsernameAKA, &badges, &user.Country, &showCountry) switch { case err == sql.ErrNoRows: r.Code = 404 @@ -92,6 +94,17 @@ func userPuts(md common.MethodData, row *sql.Row) (r common.Response) { user.RegisteredOn = time.Unix(registeredOn, 0) user.LatestActivity = time.Unix(latestActivity, 0) + user.Badges = badgesToArray(badges) + + user.Country = genCountry(md, user.ID, showCountry, user.Country) + + r.Code = 200 + r.Data = user + return +} + +func badgesToArray(badges string) []int { + var end []int badgesSl := strings.Split(badges, ",") for _, badge := range badgesSl { if badge != "" && badge != "0" { @@ -99,20 +112,20 @@ func userPuts(md common.MethodData, row *sql.Row) (r common.Response) { // particular thing, we can just silently ignore this. nb, err := strconv.Atoi(badge) if err == nil && nb != 0 { - user.Badges = append(user.Badges, nb) + end = append(end, nb) } } } + return end +} +func genCountry(md common.MethodData, uid int, showCountry bool, country string) string { // 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. - if !(showcountry || (md.User.Privileges.HasPrivilegeReadConfidential() && user.ID == md.User.UserID)) { - user.Country = "XX" + if showCountry || (md.User.Privileges.HasPrivilegeReadConfidential() && uid == md.User.UserID) { + return country } - - r.Code = 200 - r.Data = user - return + return "XX" } // UserSelfGET is a shortcut for /users/id/self. (/users/self) @@ -142,3 +155,116 @@ func UserWhatsTheIDGET(md common.MethodData) common.Response { Data: id, } } + +type modeData struct { + RankedScore uint64 `json:"ranked_score"` + TotalScore uint64 `json:"total_score"` + PlayCount int `json:"playcount"` + ReplaysWatched int `json:"replays_watched"` + TotalHits int `json:"total_hits"` + Level float64 `json:"level"` + Accuracy float64 `json:"accuracy"` + GlobalLeaderboardRank int `json:"global_leaderboard_rank"` +} +type userFullData struct { + userData + STD modeData `json:"std"` + Taiko modeData `json:"taiko"` + CTB modeData `json:"ctb"` + Mania modeData `json:"mania"` + PlayStyle int `json:"play_style"` + FavouriteMode int `json:"favourite_mode"` +} + +// UserFullGET gets all of an user's information, with one exception: their userpage. +func UserFullGET(md common.MethodData) (r common.Response) { + // Hellest query I've ever done. + query := ` +SELECT + users.id, users.username, users.register_datetime, users.rank, users.latest_activity, + + users_stats.username_aka, users_stats.badges_shown, users_stats.country, users_stats.show_country, + users_stats.play_style, users_stats.favourite_mode, + + users_stats.ranked_score_std, users_stats.total_score_std, users_stats.playcount_std, + users_stats.replays_watched_std, users_stats.total_hits_std, users_stats.level_std, + users_stats.avg_accuracy_std, leaderboard_std.position as std_position, + + users_stats.ranked_score_taiko, users_stats.total_score_taiko, users_stats.playcount_taiko, + users_stats.replays_watched_taiko, users_stats.total_hits_taiko, users_stats.level_taiko, + users_stats.avg_accuracy_taiko, leaderboard_taiko.position as taiko_position, + + users_stats.ranked_score_ctb, users_stats.total_score_ctb, users_stats.playcount_ctb, + users_stats.replays_watched_ctb, users_stats.total_hits_ctb, users_stats.level_ctb, + users_stats.avg_accuracy_ctb, leaderboard_ctb.position as ctb_position, + + users_stats.ranked_score_mania, users_stats.total_score_mania, users_stats.playcount_mania, + users_stats.replays_watched_mania, users_stats.total_hits_mania, users_stats.level_mania, + users_stats.avg_accuracy_mania, leaderboard_mania.position as mania_position + +FROM users +LEFT JOIN users_stats +ON users.id=users_stats.id +LEFT JOIN leaderboard_std +ON users.id=leaderboard_std.user +LEFT JOIN leaderboard_taiko +ON users.id=leaderboard_taiko.user +LEFT JOIN leaderboard_ctb +ON users.id=leaderboard_ctb.user +LEFT JOIN leaderboard_mania +ON users.id=leaderboard_mania.user +WHERE users.id=? +LIMIT 1 +` + // Fuck. + fd := userFullData{} + var ( + badges string + country string + showCountry bool + registeredOn int64 + latestActivity int64 + ) + err := md.DB.QueryRow(query, md.C.Param("id")).Scan( + &fd.ID, &fd.Username, ®isteredOn, &fd.Rank, &latestActivity, + + &fd.UsernameAKA, &badges, &country, &showCountry, + &fd.PlayStyle, &fd.FavouriteMode, + + &fd.STD.RankedScore, &fd.STD.TotalScore, &fd.STD.PlayCount, + &fd.STD.ReplaysWatched, &fd.STD.TotalHits, &fd.STD.Level, + &fd.STD.Accuracy, &fd.STD.GlobalLeaderboardRank, + + &fd.Taiko.RankedScore, &fd.Taiko.TotalScore, &fd.Taiko.PlayCount, + &fd.Taiko.ReplaysWatched, &fd.Taiko.TotalHits, &fd.Taiko.Level, + &fd.Taiko.Accuracy, &fd.Taiko.GlobalLeaderboardRank, + + &fd.CTB.RankedScore, &fd.CTB.TotalScore, &fd.CTB.PlayCount, + &fd.CTB.ReplaysWatched, &fd.CTB.TotalHits, &fd.CTB.Level, + &fd.CTB.Accuracy, &fd.CTB.GlobalLeaderboardRank, + + &fd.Mania.RankedScore, &fd.Mania.TotalScore, &fd.Mania.PlayCount, + &fd.Mania.ReplaysWatched, &fd.Mania.TotalHits, &fd.Mania.Level, + &fd.Mania.Accuracy, &fd.Mania.GlobalLeaderboardRank, + ) + switch { + case err == sql.ErrNoRows: + r.Code = 404 + r.Message = "That user could not be found!" + return + case err != nil: + md.C.Error(err) + r = Err500 + return + } + + fd.Country = genCountry(md, fd.ID, showCountry, country) + fd.Badges = badgesToArray(badges) + + fd.RegisteredOn = time.Unix(registeredOn, 0) + fd.LatestActivity = time.Unix(latestActivity, 0) + + r.Code = 200 + r.Data = fd + return +}