added slash web

This commit is contained in:
Penguin-71630
2025-12-12 23:25:05 +08:00
parent 067e279a8b
commit 344176063b
4 changed files with 119 additions and 3 deletions

View File

@@ -7,3 +7,13 @@ https://hackmd.io/@penguin71630/go-final-project
Note:
- View API document: `make viewapi`
<!-- My friend wrote this login test script. So our goal is to make bot generates a link and send this link in the form of Ephemeral message to user. User can open the webpage with provided link (this way we can skip the hassles over Discord OAuth in webpage), and use some magic mechanism (my friend said cookie but I'm not familiar with it).
Here's my understanding of the entire workflow:
1. User types /web in discord chat room.
2. Bot calls POST /auth/get-login-url with payload {
"userId": "string"
}, and receive a response: {
"loginUrl": "http://localhost:8080/login?token=T2KsDcj-kiULQLdotioxmsZG"
}
3. -->

View File

@@ -31,6 +31,14 @@ type AliasesResponse struct {
Aliases []string `json:"aliases"`
}
type GenLoginURLRequest struct {
UserID string `json:"userId"`
}
type GenLoginURLResponse struct {
LoginURL string `json:"loginUrl"`
}
func NewClient(baseURL string) *Client {
return &Client{
baseURL: baseURL,
@@ -216,3 +224,41 @@ func (c *Client) GetImageFile(id string) ([]byte, error) {
return io.ReadAll(resp.Body)
}
func (c *Client) GenerateLoginURL(userID string) (string, error) {
url := fmt.Sprintf("%s/auth/gen-login-url", c.baseURL)
reqBody := GenLoginURLRequest{UserID: userID}
jsonBody, err := json.Marshal(reqBody)
if err != nil {
return "", err
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
if err != nil {
return "", err
}
req.Header.Set("Content-Type", "application/json")
// TODO: Set preshared key authorization
req.Header.Set("Authorization", "Bearer poop")
resp, err := c.httpClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return "", fmt.Errorf("API returned status %d: %s", resp.StatusCode, string(body))
}
var result GenLoginURLResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return "", err
}
return result.LoginURL, nil
}

View File

@@ -48,7 +48,7 @@ func New(cfg *config.Config) (*Bot, error) {
return bot, nil
}
func (b *Bot) registerSlashCommands() error {
func (b *Bot) registerSlashCommands(guildID string) error {
commands := []*discordgo.ApplicationCommand{
{
Name: "ping",
@@ -70,10 +70,14 @@ func (b *Bot) registerSlashCommands() error {
},
},
},
{
Name: "web",
Description: "Get a login link to the web interface",
},
}
for _, cmd := range commands {
_, err := b.session.ApplicationCommandCreate(b.session.State.User.ID, "", cmd)
_, err := b.session.ApplicationCommandCreate(b.session.State.User.ID, guildID, cmd)
if err != nil {
return fmt.Errorf("cannot create command %s: %w", cmd.Name, err)
}
@@ -82,6 +86,21 @@ func (b *Bot) registerSlashCommands() error {
return nil
}
func (b *Bot) clearSlashCommands(guildID string) error {
commands, err := b.session.ApplicationCommands(b.session.State.User.ID, guildID)
if err != nil {
return err
}
for _, cmd := range commands {
err := b.session.ApplicationCommandDelete(b.session.State.User.ID, guildID, cmd.ID)
if err != nil {
log.Printf("Failed to delete command %s: %v", cmd.Name, err)
}
}
return nil
}
func (b *Bot) registerHandlers() {
b.session.AddHandler(b.onReady)
b.session.AddHandler(b.onMessageCreate)
@@ -91,8 +110,17 @@ func (b *Bot) registerHandlers() {
func (b *Bot) onReady(s *discordgo.Session, event *discordgo.Ready) {
log.Printf("Logged in as: %v#%v", s.State.User.Username, s.State.User.Discriminator)
// For development: set your guild ID here for instant updates
// For production: use "" for global commands
guildID := "1377176828833169468" // Replace with your Discord server ID for faster testing
// clear slash commands
if err := b.clearSlashCommands(guildID); err != nil {
log.Printf("Error clearing slash commands: %v", err)
}
// Register slash commands
if err := b.registerSlashCommands(); err != nil {
if err := b.registerSlashCommands(guildID); err != nil {
log.Printf("Error registering slash commands: %v", err)
}
@@ -115,6 +143,8 @@ func (b *Bot) onInteractionCreate(s *discordgo.Session, i *discordgo.Interaction
b.handleSlashGreet(s, i)
case "echo":
b.handleSlashEcho(s, i)
case "web":
b.handleSlashWeb(s, i)
}
}

View File

@@ -69,3 +69,33 @@ func (b *Bot) handleSlashEcho(s *discordgo.Session, i *discordgo.InteractionCrea
},
})
}
func (b *Bot) handleSlashWeb(s *discordgo.Session, i *discordgo.InteractionCreate) {
var userID string
if i.Member != nil {
userID = i.Member.User.ID
} else if i.User != nil {
userID = i.User.ID
}
// Call backend API
loginURL, err := b.apiClient.GenerateLoginURL(userID)
if err != nil {
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "❌ Failed to generate login URL: " + err.Error(),
Flags: discordgo.MessageFlagsEphemeral,
},
})
return
}
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: fmt.Sprintf("🔗 **Click here to access the web page:**\n%s\n\n", loginURL),
Flags: discordgo.MessageFlagsEphemeral,
},
})
}