discordmuffin/examples/linked_roles/main.go
Fedor Lapshin 4eef78e7e4
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.
2022-12-26 02:31:49 +03:00

133 lines
4 KiB
Go

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)
}