Finish up with new ranks and stuff on the API
This commit is contained in:
		@@ -43,7 +43,7 @@ func FriendsGET(md common.MethodData) common.CodeMessager {
 | 
				
			|||||||
	// Yes.
 | 
						// Yes.
 | 
				
			||||||
	myFriendsQuery := `
 | 
						myFriendsQuery := `
 | 
				
			||||||
SELECT
 | 
					SELECT
 | 
				
			||||||
	users.id, users.username, users.register_datetime, users.rank, users.latest_activity,
 | 
						users.id, users.username, users.register_datetime, users.privileges, users.latest_activity,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	users_stats.username_aka,
 | 
						users_stats.username_aka,
 | 
				
			||||||
	users_stats.country, users_stats.show_country
 | 
						users_stats.country, users_stats.show_country
 | 
				
			||||||
@@ -90,7 +90,7 @@ func friendPuts(md common.MethodData, row *sql.Rows) (user friendData) {
 | 
				
			|||||||
	registeredOn := int64(0)
 | 
						registeredOn := int64(0)
 | 
				
			||||||
	latestActivity := int64(0)
 | 
						latestActivity := int64(0)
 | 
				
			||||||
	var showcountry bool
 | 
						var showcountry bool
 | 
				
			||||||
	err = row.Scan(&user.ID, &user.Username, ®isteredOn, &user.Rank, &latestActivity, &user.UsernameAKA, &user.Country, &showcountry)
 | 
						err = row.Scan(&user.ID, &user.Username, ®isteredOn, &user.Privileges, &latestActivity, &user.UsernameAKA, &user.Country, &showcountry)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		md.Err(err)
 | 
							md.Err(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ type leaderboardResponse struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const lbUserQuery = `
 | 
					const lbUserQuery = `
 | 
				
			||||||
SELECT
 | 
					SELECT
 | 
				
			||||||
	users.id, users.username, users.register_datetime, users.rank, users.latest_activity,
 | 
						users.id, users.username, users.register_datetime, users.privileges, users.latest_activity,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	users_stats.username_aka, users_stats.country, users_stats.show_country,
 | 
						users_stats.username_aka, users_stats.country, users_stats.show_country,
 | 
				
			||||||
	users_stats.play_style, users_stats.favourite_mode,
 | 
						users_stats.play_style, users_stats.favourite_mode,
 | 
				
			||||||
@@ -53,7 +53,7 @@ func LeaderboardGET(md common.MethodData) common.CodeMessager {
 | 
				
			|||||||
			showCountry    bool
 | 
								showCountry    bool
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		err := rows.Scan(
 | 
							err := rows.Scan(
 | 
				
			||||||
			&u.ID, &u.Username, ®ister, &u.Rank, &latestActivity,
 | 
								&u.ID, &u.Username, ®ister, &u.Privileges, &latestActivity,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			&u.UsernameAKA, &u.Country, &showCountry,
 | 
								&u.UsernameAKA, &u.Country, &showCountry,
 | 
				
			||||||
			&u.PlayStyle, &u.FavouriteMode,
 | 
								&u.PlayStyle, &u.FavouriteMode,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@ func UserManageSetAllowedPOST(md common.MethodData) common.CodeMessager {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if data.Allowed == 0 {
 | 
						if data.Allowed == 0 {
 | 
				
			||||||
		banDatetime = time.Now().Unix()
 | 
							banDatetime = time.Now().Unix()
 | 
				
			||||||
		newPrivileges = privileges &^(common.UserPrivilegeNormal | common.UserPrivilegePublic)
 | 
							newPrivileges = privileges &^ (common.UserPrivilegeNormal | common.UserPrivilegePublic)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		banDatetime = 0
 | 
							banDatetime = 0
 | 
				
			||||||
		newPrivileges = privileges | (common.UserPrivilegeNormal | common.UserPrivilegePublic)
 | 
							newPrivileges = privileges | (common.UserPrivilegeNormal | common.UserPrivilegePublic)
 | 
				
			||||||
@@ -42,7 +42,7 @@ func UserManageSetAllowedPOST(md common.MethodData) common.CodeMessager {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	go fixPrivileges(data.UserID, md.DB)
 | 
						go fixPrivileges(data.UserID, md.DB)
 | 
				
			||||||
	query := `
 | 
						query := `
 | 
				
			||||||
SELECT users.id, users.username, register_datetime, rank,
 | 
					SELECT users.id, users.username, register_datetime, privileges,
 | 
				
			||||||
	latest_activity, users_stats.username_aka,
 | 
						latest_activity, users_stats.username_aka,
 | 
				
			||||||
	users_stats.country, users_stats.show_country
 | 
						users_stats.country, users_stats.show_country
 | 
				
			||||||
FROM users
 | 
					FROM users
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,7 +50,7 @@ func TokenNewPOST(md common.MethodData) common.CodeMessager {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var q *sql.Row
 | 
						var q *sql.Row
 | 
				
			||||||
	const base = "SELECT id, username, rank, password_md5, password_version, privileges FROM users "
 | 
						const base = "SELECT id, username, privileges, password_md5, password_version, privileges FROM users "
 | 
				
			||||||
	if data.UserID != 0 {
 | 
						if data.UserID != 0 {
 | 
				
			||||||
		q = md.DB.QueryRow(base+"WHERE id = ? LIMIT 1", data.UserID)
 | 
							q = md.DB.QueryRow(base+"WHERE id = ? LIMIT 1", data.UserID)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -58,10 +58,10 @@ func TokenNewPOST(md common.MethodData) common.CodeMessager {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		rank      int
 | 
							rank       int
 | 
				
			||||||
		pw        string
 | 
							pw         string
 | 
				
			||||||
		pwVersion int
 | 
							pwVersion  int
 | 
				
			||||||
		privileges   int
 | 
							privileges int
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = q.Scan(&r.ID, &r.Username, &rank, &pw, &pwVersion, &privileges)
 | 
						err = q.Scan(&r.ID, &r.Username, &rank, &pw, &pwVersion, &privileges)
 | 
				
			||||||
@@ -88,13 +88,14 @@ func TokenNewPOST(md common.MethodData) common.CodeMessager {
 | 
				
			|||||||
		md.Err(err)
 | 
							md.Err(err)
 | 
				
			||||||
		return Err500
 | 
							return Err500
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (privileges & 0) == 0 {
 | 
						const want = (common.UserPrivilegePublic | common.UserPrivilegeNormal)
 | 
				
			||||||
 | 
						if (privileges & want) != want {
 | 
				
			||||||
		r.Code = 200
 | 
							r.Code = 200
 | 
				
			||||||
		r.Message = "That user is banned."
 | 
							r.Message = "That user is banned."
 | 
				
			||||||
		r.Banned = true
 | 
							r.Banned = true
 | 
				
			||||||
		return r
 | 
							return r
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	r.Privileges = int(common.Privileges(data.Privileges).CanOnly(rank))
 | 
						r.Privileges = int(common.Privileges(data.Privileges).CanOnly(privileges))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		tokenStr string
 | 
							tokenStr string
 | 
				
			||||||
@@ -104,7 +105,7 @@ func TokenNewPOST(md common.MethodData) common.CodeMessager {
 | 
				
			|||||||
		tokenStr = common.RandomString(32)
 | 
							tokenStr = common.RandomString(32)
 | 
				
			||||||
		tokenMD5 = fmt.Sprintf("%x", md5.Sum([]byte(tokenStr)))
 | 
							tokenMD5 = fmt.Sprintf("%x", md5.Sum([]byte(tokenStr)))
 | 
				
			||||||
		r.Token = tokenStr
 | 
							r.Token = tokenStr
 | 
				
			||||||
		id := 0
 | 
							var id int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err := md.DB.QueryRow("SELECT id FROM tokens WHERE token=? LIMIT 1", tokenMD5).Scan(&id)
 | 
							err := md.DB.QueryRow("SELECT id FROM tokens WHERE token=? LIMIT 1", tokenMD5).Scan(&id)
 | 
				
			||||||
		if err == sql.ErrNoRows {
 | 
							if err == sql.ErrNoRows {
 | 
				
			||||||
@@ -210,7 +211,7 @@ func fixPrivileges(user int, db *sql.DB) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	rows, err := db.Query(`
 | 
						rows, err := db.Query(`
 | 
				
			||||||
SELECT
 | 
					SELECT
 | 
				
			||||||
	tokens.id, tokens.privileges, users.rank
 | 
						tokens.id, tokens.privileges, users.privileges
 | 
				
			||||||
FROM tokens
 | 
					FROM tokens
 | 
				
			||||||
LEFT JOIN users ON users.id = tokens.user
 | 
					LEFT JOIN users ON users.id = tokens.user
 | 
				
			||||||
`+wc, params...)
 | 
					`+wc, params...)
 | 
				
			||||||
@@ -221,15 +222,15 @@ LEFT JOIN users ON users.id = tokens.user
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	for rows.Next() {
 | 
						for rows.Next() {
 | 
				
			||||||
		var (
 | 
							var (
 | 
				
			||||||
			id       int
 | 
								id         int
 | 
				
			||||||
			privsRaw uint64
 | 
								privsRaw   uint64
 | 
				
			||||||
			privs    common.Privileges
 | 
								privs      common.Privileges
 | 
				
			||||||
			newPrivs common.Privileges
 | 
								newPrivs   common.Privileges
 | 
				
			||||||
			rank     int
 | 
								privileges int
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		rows.Scan(&id, &privsRaw, &rank)
 | 
							rows.Scan(&id, &privsRaw, &privileges)
 | 
				
			||||||
		privs = common.Privileges(privsRaw)
 | 
							privs = common.Privileges(privsRaw)
 | 
				
			||||||
		newPrivs = privs.CanOnly(rank)
 | 
							newPrivs = privs.CanOnly(privileges)
 | 
				
			||||||
		if newPrivs != privs {
 | 
							if newPrivs != privs {
 | 
				
			||||||
			_, err := db.Exec("UPDATE tokens SET privileges = ? WHERE id = ? LIMIT 1", uint64(newPrivs), id)
 | 
								_, err := db.Exec("UPDATE tokens SET privileges = ? WHERE id = ? LIMIT 1", uint64(newPrivs), id)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@ type userData struct {
 | 
				
			|||||||
	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   time.Time `json:"registered_on"`
 | 
				
			||||||
	Rank           int       `json:"rank"`
 | 
						Privileges     uint64    `json:"rank"`
 | 
				
			||||||
	LatestActivity time.Time `json:"latest_activity"`
 | 
						LatestActivity time.Time `json:"latest_activity"`
 | 
				
			||||||
	Country        string    `json:"country"`
 | 
						Country        string    `json:"country"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -29,7 +29,7 @@ func UsersGET(md common.MethodData) common.CodeMessager {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	query := `
 | 
						query := `
 | 
				
			||||||
SELECT users.id, users.username, register_datetime, rank,
 | 
					SELECT users.id, users.username, register_datetime, privileges,
 | 
				
			||||||
	latest_activity, users_stats.username_aka,
 | 
						latest_activity, users_stats.username_aka,
 | 
				
			||||||
	users_stats.country, users_stats.show_country
 | 
						users_stats.country, users_stats.show_country
 | 
				
			||||||
FROM users
 | 
					FROM users
 | 
				
			||||||
@@ -54,7 +54,7 @@ func userPuts(md common.MethodData, row *sql.Row) common.CodeMessager {
 | 
				
			|||||||
		latestActivity int64
 | 
							latestActivity int64
 | 
				
			||||||
		showCountry    bool
 | 
							showCountry    bool
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	err = row.Scan(&user.ID, &user.Username, ®isteredOn, &user.Rank, &latestActivity, &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!")
 | 
				
			||||||
@@ -109,11 +109,11 @@ type whatIDResponse struct {
 | 
				
			|||||||
// UserWhatsTheIDGET is an API request that only returns an user's ID.
 | 
					// UserWhatsTheIDGET is an API request that only returns an user's ID.
 | 
				
			||||||
func UserWhatsTheIDGET(md common.MethodData) common.CodeMessager {
 | 
					func UserWhatsTheIDGET(md common.MethodData) common.CodeMessager {
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		r       whatIDResponse
 | 
							r          whatIDResponse
 | 
				
			||||||
		privileges int
 | 
							privileges int
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	err := md.DB.QueryRow("SELECT id, privileges FROM users WHERE username = ? LIMIT 1", md.C.Query("name")).Scan(&r.ID, &privileges)
 | 
						err := md.DB.QueryRow("SELECT id, privileges FROM users WHERE username = ? LIMIT 1", md.C.Query("name")).Scan(&r.ID, &privileges)
 | 
				
			||||||
	if err != nil || ( (privileges & common.UserPrivilegePublic) == 0 && !md.User.Privileges.HasPrivilegeViewUserAdvanced()) {
 | 
						if err != nil || ((privileges&common.UserPrivilegePublic) == 0 && !md.User.Privileges.HasPrivilegeViewUserAdvanced()) {
 | 
				
			||||||
		return common.SimpleResponse(404, "That user could not be found!")
 | 
							return common.SimpleResponse(404, "That user could not be found!")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	r.Code = 200
 | 
						r.Code = 200
 | 
				
			||||||
@@ -153,7 +153,7 @@ func UserFullGET(md common.MethodData) common.CodeMessager {
 | 
				
			|||||||
	// Hellest query I've ever done.
 | 
						// Hellest query I've ever done.
 | 
				
			||||||
	query := `
 | 
						query := `
 | 
				
			||||||
SELECT
 | 
					SELECT
 | 
				
			||||||
	users.id, users.username, users.register_datetime, users.rank, users.latest_activity,
 | 
						users.id, users.username, users.register_datetime, users.privileges, users.latest_activity,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	users_stats.username_aka, users_stats.badges_shown, users_stats.country, users_stats.show_country,
 | 
						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.play_style, users_stats.favourite_mode,
 | 
				
			||||||
@@ -198,7 +198,7 @@ LIMIT 1
 | 
				
			|||||||
		latestActivity int64
 | 
							latestActivity int64
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	err := md.DB.QueryRow(query, param).Scan(
 | 
						err := md.DB.QueryRow(query, param).Scan(
 | 
				
			||||||
		&r.ID, &r.Username, ®isteredOn, &r.Rank, &latestActivity,
 | 
							&r.ID, &r.Username, ®isteredOn, &r.Privileges, &latestActivity,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		&r.UsernameAKA, &badges, &country, &showCountry,
 | 
							&r.UsernameAKA, &badges, &country, &showCountry,
 | 
				
			||||||
		&r.PlayStyle, &r.FavouriteMode,
 | 
							&r.PlayStyle, &r.FavouriteMode,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -114,27 +114,27 @@ func (p Privileges) String() string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var privilegeMustBe = [...]int{
 | 
					var privilegeMustBe = [...]int{
 | 
				
			||||||
	1,
 | 
						UserPrivilegeNormal,
 | 
				
			||||||
	1,
 | 
						UserPrivilegeNormal,
 | 
				
			||||||
	1,
 | 
						UserPrivilegeNormal,
 | 
				
			||||||
	3,
 | 
						AdminPrivilegeAccessRAP | AdminPrivilegeManageBadges,
 | 
				
			||||||
	3,
 | 
						AdminPrivilegeAccessRAP | AdminPrivilegeManageBetaKey,
 | 
				
			||||||
	4,
 | 
						AdminPrivilegeAccessRAP | AdminPrivilegeManageSetting,
 | 
				
			||||||
	4,
 | 
						AdminPrivilegeAccessRAP,
 | 
				
			||||||
	4,
 | 
						AdminPrivilegeAccessRAP | AdminPrivilegeManageUsers | AdminPrivilegeBanUsers,
 | 
				
			||||||
	4,
 | 
						AdminPrivilegeAccessRAP | AdminPrivilegeManageUsers | AdminPrivilegeManagePrivilege,
 | 
				
			||||||
	4,
 | 
						AdminPrivilegeAccessRAP | AdminPrivilegeManageUsers | AdminPrivilegeManageServer,
 | 
				
			||||||
	3,
 | 
						AdminPrivilegeChatMod, // temporary?
 | 
				
			||||||
	4,
 | 
						AdminPrivilegeManageServer,
 | 
				
			||||||
	4,
 | 
						AdminPrivilegeAccessRAP | AdminPrivilegeManageBeatmap,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CanOnly removes any privilege that the user has requested to have, but cannot have due to their rank.
 | 
					// CanOnly removes any privilege that the user has requested to have, but cannot have due to their rank.
 | 
				
			||||||
func (p Privileges) CanOnly(rank int) Privileges {
 | 
					func (p Privileges) CanOnly(userPrivs int) Privileges {
 | 
				
			||||||
	newPrivilege := 0
 | 
						newPrivilege := 0
 | 
				
			||||||
	for i, v := range privilegeMustBe {
 | 
						for i, v := range privilegeMustBe {
 | 
				
			||||||
		wants := p&1 == 1
 | 
							wants := p&1 == 1
 | 
				
			||||||
		can := rank >= v
 | 
							can := userPrivs&v == v
 | 
				
			||||||
		if wants && can {
 | 
							if wants && can {
 | 
				
			||||||
			newPrivilege |= 1 << uint(i)
 | 
								newPrivilege |= 1 << uint(i)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
package common
 | 
					package common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// user/admin privileges
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	UserPrivilegePublic = 1 << iota
 | 
						UserPrivilegePublic = 1 << iota
 | 
				
			||||||
	UserPrivilegeNormal
 | 
						UserPrivilegeNormal
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user