Role connections (#1295)
* feat: role connection metadata * feat: add role connection endpoints Add User Application Role Connection endpoints: * Get User Application Role Connection * Update User Application Role Connection * feat: add example Add basic example to showcase linked roles flow. * refactor(endpoints): move role connection metadata Move Application Role Connection Metadata endpoint to other Application endpoints.
This commit is contained in:
parent
4074561d23
commit
4eef78e7e4
6 changed files with 298 additions and 7 deletions
16
endpoints.go
16
endpoints.go
|
@ -60,11 +60,12 @@ var (
|
|||
return EndpointCDNBanners + uID + "/" + cID + ".gif"
|
||||
}
|
||||
|
||||
EndpointUserGuilds = func(uID string) string { return EndpointUsers + uID + "/guilds" }
|
||||
EndpointUserGuild = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID }
|
||||
EndpointUserGuildMember = func(uID, gID string) string { return EndpointUserGuild(uID, gID) + "/member" }
|
||||
EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" }
|
||||
EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
|
||||
EndpointUserGuilds = func(uID string) string { return EndpointUsers + uID + "/guilds" }
|
||||
EndpointUserGuild = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID }
|
||||
EndpointUserGuildMember = func(uID, gID string) string { return EndpointUserGuild(uID, gID) + "/member" }
|
||||
EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" }
|
||||
EndpointUserApplicationRoleConnection = func(aID string) string { return EndpointUsers + "@me/applications/" + aID + "/role-connection" }
|
||||
EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
|
||||
|
||||
EndpointGuild = func(gID string) string { return EndpointGuilds + gID }
|
||||
EndpointGuildAutoModeration = func(gID string) string { return EndpointGuild(gID) + "/auto-moderation" }
|
||||
|
@ -197,8 +198,9 @@ var (
|
|||
EndpointEmoji = func(eID string) string { return EndpointCDN + "emojis/" + eID + ".png" }
|
||||
EndpointEmojiAnimated = func(eID string) string { return EndpointCDN + "emojis/" + eID + ".gif" }
|
||||
|
||||
EndpointApplications = EndpointAPI + "applications"
|
||||
EndpointApplication = func(aID string) string { return EndpointApplications + "/" + aID }
|
||||
EndpointApplications = EndpointAPI + "applications"
|
||||
EndpointApplication = func(aID string) string { return EndpointApplications + "/" + aID }
|
||||
EndpointApplicationRoleConnectionMetadata = func(aID string) string { return EndpointApplication(aID) + "/role-connections/metadata" }
|
||||
|
||||
EndpointOAuth2 = EndpointAPI + "oauth2/"
|
||||
EndpointOAuth2Applications = EndpointOAuth2 + "applications"
|
||||
|
|
11
examples/linked_roles/go.mod
Normal file
11
examples/linked_roles/go.mod
Normal file
|
@ -0,0 +1,11 @@
|
|||
module github.com/bwmarrin/discordgo/examples/linked_roles
|
||||
|
||||
go 1.13
|
||||
|
||||
replace github.com/bwmarrin/discordgo v0.26.1 => ../../
|
||||
|
||||
require (
|
||||
github.com/bwmarrin/discordgo v0.26.1
|
||||
github.com/joho/godotenv v1.4.0
|
||||
golang.org/x/oauth2 v0.3.0
|
||||
)
|
54
examples/linked_roles/go.sum
Normal file
54
examples/linked_roles/go.sum
Normal file
|
@ -0,0 +1,54 @@
|
|||
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8=
|
||||
golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
133
examples/linked_roles/main.go
Normal file
133
examples/linked_roles/main.go
Normal file
|
@ -0,0 +1,133 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/joho/godotenv"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
var oauthConfig = oauth2.Config{
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: "https://discord.com/oauth2/authorize",
|
||||
TokenURL: "https://discord.com/api/oauth2/token",
|
||||
},
|
||||
Scopes: []string{"identify", "role_connections.write"},
|
||||
}
|
||||
|
||||
var (
|
||||
appID = flag.String("app", "", "Application ID")
|
||||
token = flag.String("token", "", "Application token")
|
||||
clientSecret = flag.String("secret", "", "OAuth2 secret")
|
||||
redirectURL = flag.String("redirect", "", "OAuth2 Redirect URL")
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.Parse()
|
||||
godotenv.Load()
|
||||
oauthConfig.ClientID = *appID
|
||||
oauthConfig.ClientSecret = *clientSecret
|
||||
oauthConfig.RedirectURL, _ = url.JoinPath(*redirectURL, "/linked-roles-callback")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s, _ := discordgo.New("Bot " + *token)
|
||||
|
||||
_, err := s.ApplicationRoleConnectionMetadataUpdate(*appID, []*discordgo.ApplicationRoleConnectionMetadata{
|
||||
{
|
||||
Type: discordgo.ApplicationRoleConnectionMetadataIntegerGreaterThanOrEqual,
|
||||
Key: "loc",
|
||||
Name: "Lines of Code",
|
||||
NameLocalizations: map[discordgo.Locale]string{},
|
||||
Description: "Total lines of code written",
|
||||
DescriptionLocalizations: map[discordgo.Locale]string{},
|
||||
},
|
||||
{
|
||||
Type: discordgo.ApplicationRoleConnectionMetadataBooleanEqual,
|
||||
Key: "gopher",
|
||||
Name: "Gopher",
|
||||
NameLocalizations: map[discordgo.Locale]string{},
|
||||
Description: "Writes in Go",
|
||||
DescriptionLocalizations: map[discordgo.Locale]string{},
|
||||
},
|
||||
{
|
||||
Type: discordgo.ApplicationRoleConnectionMetadataDatetimeGreaterThanOrEqual,
|
||||
Key: "first_line",
|
||||
Name: "First line written",
|
||||
NameLocalizations: map[discordgo.Locale]string{},
|
||||
Description: "Days since the first line of code",
|
||||
DescriptionLocalizations: map[discordgo.Locale]string{},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println("Updated application metadata")
|
||||
http.HandleFunc("/linked-roles", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
// Redirect the user to Discord OAuth2 page.
|
||||
http.Redirect(w, r, oauthConfig.AuthCodeURL("random-state"), http.StatusMovedPermanently)
|
||||
})
|
||||
http.HandleFunc("/linked-roles-callback", func(w http.ResponseWriter, r *http.Request) {
|
||||
q := r.URL.Query()
|
||||
// A safeguard against CSRF attacks.
|
||||
// Usually tied to requesting user or random.
|
||||
// NOTE: Hardcoded for the sake of the example.
|
||||
if q["state"][0] != "random-state" {
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch the tokens with code we've received.
|
||||
tokens, err := oauthConfig.Exchange(r.Context(), q["code"][0])
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// Construct a temporary session with user's OAuth2 access_token.
|
||||
ts, _ := discordgo.New("Bearer " + tokens.AccessToken)
|
||||
|
||||
// Retrive the user data.
|
||||
u, err := ts.User("@me")
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch external metadata...
|
||||
// NOTE: Hardcoded for the sake of the example.
|
||||
metadata := map[string]string{
|
||||
"gopher": "1", // 1 for true, 0 for false
|
||||
"loc": "10000",
|
||||
"first_line": "1970-01-01", // YYYY-MM-DD
|
||||
}
|
||||
|
||||
// And submit it back to discord.
|
||||
_, err = ts.UserApplicationRoleConnectionUpdate(*appID, &discordgo.ApplicationRoleConnection{
|
||||
PlatformName: "Discord Gophers",
|
||||
PlatformUsername: u.Username,
|
||||
Metadata: metadata,
|
||||
})
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// Retrieve it to check if everything is ok.
|
||||
info, err := ts.UserApplicationRoleConnection(*appID)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
jsonMetadata, _ := json.Marshal(info.Metadata)
|
||||
// And show it to the user.
|
||||
w.Write([]byte(fmt.Sprintf("Your updated metadata is: %s", jsonMetadata)))
|
||||
})
|
||||
http.ListenAndServe(":8010", nil)
|
||||
}
|
59
restapi.go
59
restapi.go
|
@ -3245,3 +3245,62 @@ func (s *Session) AutoModerationRuleDelete(guildID, ruleID string) (err error) {
|
|||
_, err = s.RequestWithBucketID("DELETE", endpoint, nil, endpoint)
|
||||
return
|
||||
}
|
||||
|
||||
// ApplicationRoleConnectionMetadata returns application role connection metadata.
|
||||
// appID : ID of the application
|
||||
func (s *Session) ApplicationRoleConnectionMetadata(appID string) (st []*ApplicationRoleConnectionMetadata, err error) {
|
||||
endpoint := EndpointApplicationRoleConnectionMetadata(appID)
|
||||
var body []byte
|
||||
body, err = s.RequestWithBucketID("GET", endpoint, nil, endpoint)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = unmarshal(body, &st)
|
||||
return
|
||||
}
|
||||
|
||||
// ApplicationRoleConnectionMetadataUpdate updates and returns application role connection metadata.
|
||||
// appID : ID of the application
|
||||
// metadata : New metadata
|
||||
func (s *Session) ApplicationRoleConnectionMetadataUpdate(appID string, metadata []*ApplicationRoleConnectionMetadata) (st []*ApplicationRoleConnectionMetadata, err error) {
|
||||
endpoint := EndpointApplicationRoleConnectionMetadata(appID)
|
||||
var body []byte
|
||||
body, err = s.RequestWithBucketID("PUT", endpoint, metadata, endpoint)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = unmarshal(body, &st)
|
||||
return
|
||||
}
|
||||
|
||||
// UserApplicationRoleConnection returns user role connection to the specified application.
|
||||
// appID : ID of the application
|
||||
func (s *Session) UserApplicationRoleConnection(appID string) (st *ApplicationRoleConnection, err error) {
|
||||
endpoint := EndpointUserApplicationRoleConnection(appID)
|
||||
var body []byte
|
||||
body, err = s.RequestWithBucketID("GET", endpoint, nil, endpoint)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = unmarshal(body, &st)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// UserApplicationRoleConnectionUpdate updates and returns user role connection to the specified application.
|
||||
// appID : ID of the application
|
||||
// connection : New ApplicationRoleConnection data
|
||||
func (s *Session) UserApplicationRoleConnectionUpdate(appID string, rconn *ApplicationRoleConnection) (st *ApplicationRoleConnection, err error) {
|
||||
endpoint := EndpointUserApplicationRoleConnection(appID)
|
||||
var body []byte
|
||||
body, err = s.RequestWithBucketID("PUT", endpoint, rconn, endpoint)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = unmarshal(body, &st)
|
||||
return
|
||||
}
|
||||
|
|
32
structs.go
32
structs.go
|
@ -156,6 +156,38 @@ type Application struct {
|
|||
Flags int `json:"flags,omitempty"`
|
||||
}
|
||||
|
||||
// ApplicationRoleConnectionMetadataType represents the type of application role connection metadata.
|
||||
type ApplicationRoleConnectionMetadataType int
|
||||
|
||||
// Application role connection metadata types.
|
||||
const (
|
||||
ApplicationRoleConnectionMetadataIntegerLessThanOrEqual ApplicationRoleConnectionMetadataType = 1
|
||||
ApplicationRoleConnectionMetadataIntegerGreaterThanOrEqual ApplicationRoleConnectionMetadataType = 2
|
||||
ApplicationRoleConnectionMetadataIntegerEqual ApplicationRoleConnectionMetadataType = 3
|
||||
ApplicationRoleConnectionMetadataIntegerNotEqual ApplicationRoleConnectionMetadataType = 4
|
||||
ApplicationRoleConnectionMetadataDatetimeLessThanOrEqual ApplicationRoleConnectionMetadataType = 5
|
||||
ApplicationRoleConnectionMetadataDatetimeGreaterThanOrEqual ApplicationRoleConnectionMetadataType = 6
|
||||
ApplicationRoleConnectionMetadataBooleanEqual ApplicationRoleConnectionMetadataType = 7
|
||||
ApplicationRoleConnectionMetadataBooleanNotEqual ApplicationRoleConnectionMetadataType = 8
|
||||
)
|
||||
|
||||
// ApplicationRoleConnectionMetadata stores application role connection metadata.
|
||||
type ApplicationRoleConnectionMetadata struct {
|
||||
Type ApplicationRoleConnectionMetadataType `json:"type"`
|
||||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
NameLocalizations map[Locale]string `json:"name_localizations"`
|
||||
Description string `json:"description"`
|
||||
DescriptionLocalizations map[Locale]string `json:"description_localizations"`
|
||||
}
|
||||
|
||||
// ApplicationRoleConnection represents the role connection that an application has attached to a user.
|
||||
type ApplicationRoleConnection struct {
|
||||
PlatformName string `json:"platform_name"`
|
||||
PlatformUsername string `json:"platform_username"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
}
|
||||
|
||||
// UserConnection is a Connection returned from the UserConnections endpoint
|
||||
type UserConnection struct {
|
||||
ID string `json:"id"`
|
||||
|
|
Loading…
Reference in a new issue