feat: support new username system (#1387)

* Add support for new username system in User.String and User.AvatarURL
* Move default avatar index logic from EndpointDefaultUserAvatar into User.DefaultAvatarIndex

---------

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>
This commit is contained in:
Muhammad Wildan Aldiansyah 2023-07-05 06:37:47 +07:00 committed by GitHub
parent 0b0ea10b47
commit e39e715086
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 17 deletions

View file

@ -49,9 +49,8 @@ var (
EndpointUser = func(uID string) string { return EndpointUsers + uID } EndpointUser = func(uID string) string { return EndpointUsers + uID }
EndpointUserAvatar = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" } EndpointUserAvatar = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" }
EndpointUserAvatarAnimated = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".gif" } EndpointUserAvatarAnimated = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".gif" }
EndpointDefaultUserAvatar = func(uDiscriminator string) string { EndpointDefaultUserAvatar = func(idx int) string {
uDiscriminatorInt, _ := strconv.Atoi(uDiscriminator) return EndpointCDN + "embed/avatars/" + strconv.Itoa(idx) + ".png"
return EndpointCDN + "embed/avatars/" + strconv.Itoa(uDiscriminatorInt%5) + ".png"
} }
EndpointUserBanner = func(uID, cID string) string { EndpointUserBanner = func(uID, cID string) string {
return EndpointCDNBanners + uID + "/" + cID + ".png" return EndpointCDNBanners + uID + "/" + cID + ".png"

37
user.go
View file

@ -1,5 +1,9 @@
package discordgo package discordgo
import (
"strconv"
)
// UserFlags is the flags of "user" (see UserFlags* consts) // UserFlags is the flags of "user" (see UserFlags* consts)
// https://discord.com/developers/docs/resources/user#user-object-user-flags // https://discord.com/developers/docs/resources/user#user-object-user-flags
type UserFlags int type UserFlags int
@ -44,6 +48,10 @@ type User struct {
// The discriminator of the user (4 numbers after name). // The discriminator of the user (4 numbers after name).
Discriminator string `json:"discriminator"` Discriminator string `json:"discriminator"`
// The user's display name, if it is set.
// For bots, this is the application name.
GlobalName string `json:"global_name"`
// The token of the user. This is only present for // The token of the user. This is only present for
// the user represented by the current session. // the user represented by the current session.
Token string `json:"token"` Token string `json:"token"`
@ -81,7 +89,14 @@ type User struct {
} }
// String returns a unique identifier of the form username#discriminator // String returns a unique identifier of the form username#discriminator
// or just username, if the discriminator is set to "0".
func (u *User) String() string { func (u *User) String() string {
// If the user has been migrated from the legacy username system, their discriminator is "0".
// See https://support-dev.discord.com/hc/en-us/articles/13667755828631
if u.Discriminator == "0" {
return u.Username
}
return u.Username + "#" + u.Discriminator return u.Username + "#" + u.Discriminator
} }
@ -91,17 +106,35 @@ func (u *User) Mention() string {
} }
// AvatarURL returns a URL to the user's avatar. // AvatarURL returns a URL to the user's avatar.
//
// size: The size of the user's avatar as a power of two // size: The size of the user's avatar as a power of two
// if size is an empty string, no size parameter will // if size is an empty string, no size parameter will
// be added to the URL. // be added to the URL.
func (u *User) AvatarURL(size string) string { func (u *User) AvatarURL(size string) string {
return avatarURL(u.Avatar, EndpointDefaultUserAvatar(u.Discriminator), return avatarURL(
EndpointUserAvatar(u.ID, u.Avatar), EndpointUserAvatarAnimated(u.ID, u.Avatar), size) u.Avatar,
EndpointDefaultUserAvatar(u.DefaultAvatarIndex()),
EndpointUserAvatar(u.ID, u.Avatar),
EndpointUserAvatarAnimated(u.ID, u.Avatar),
size,
)
} }
// BannerURL returns the URL of the users's banner image. // BannerURL returns the URL of the users's banner image.
//
// size: The size of the desired banner image as a power of two // size: The size of the desired banner image as a power of two
// Image size can be any power of two between 16 and 4096. // Image size can be any power of two between 16 and 4096.
func (u *User) BannerURL(size string) string { func (u *User) BannerURL(size string) string {
return bannerURL(u.Banner, EndpointUserBanner(u.ID, u.Banner), EndpointUserBannerAnimated(u.ID, u.Banner), size) return bannerURL(u.Banner, EndpointUserBanner(u.ID, u.Banner), EndpointUserBannerAnimated(u.ID, u.Banner), size)
} }
// DefaultAvatarIndex returns the index of the user's default avatar.
func (u *User) DefaultAvatarIndex() int {
if u.Discriminator == "0" {
id, _ := strconv.ParseUint(u.ID, 10, 64)
return int((id >> 22) % 6)
}
id, _ := strconv.Atoi(u.Discriminator)
return id % 5
}

View file

@ -2,15 +2,36 @@ package discordgo
import "testing" import "testing"
func TestUser(t *testing.T) { func TestUser_String(t *testing.T) {
t.Parallel() t.Parallel()
user := &User{ tests := []struct {
name string
u *User
want string
}{
{
name: "User with a discriminator",
u: &User{
Username: "bob", Username: "bob",
Discriminator: "8192", Discriminator: "8192",
},
want: "bob#8192",
},
{
name: "User with discriminator set to 0",
u: &User{
Username: "aldiwildan",
Discriminator: "0",
},
want: "aldiwildan",
},
} }
for _, tc := range tests {
if user.String() != "bob#8192" { t.Run(tc.name, func(t *testing.T) {
t.Errorf("user.String() == %v", user.String()) if got := tc.u.String(); got != tc.want {
t.Errorf("User.String() = %v, want %v", got, tc.want)
}
})
} }
} }