Skip to content

Commit 3084d5f

Browse files
init:2
1 parent 9a4a122 commit 3084d5f

File tree

4 files changed

+348
-322
lines changed

4 files changed

+348
-322
lines changed

cmd/main.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,30 @@ import (
77
"github.com/sethvargo/go-envconfig"
88

99
"github.com/rog-golang-buddies/dev-buddy/internal/pkg/config"
10+
"github.com/rog-golang-buddies/dev-buddy/internal/pkg/constants"
11+
"github.com/rog-golang-buddies/dev-buddy/internal/pkg/discordCommandInterface"
1012
)
1113

1214
func main() {
1315
// create context
1416
ctx := context.Background()
1517

1618
// get all the environment variables
17-
var c config.EnvironmentConfig
18-
if err := envconfig.Process(ctx, &c); err != nil {
19+
var configValues config.EnvironmentConfig
20+
if err := envconfig.Process(ctx, &configValues); err != nil {
1921
log.Fatal(err)
2022
}
2123

24+
// setting the token value to a context
25+
ctx = context.WithValue(ctx, constants.BotTokenHeader, configValues.DiscordToken)
26+
27+
// calling the initialize server for discord
28+
s, err := discordCommandInterface.InitializeDiscordServer(ctx)
29+
if err != nil {
30+
log.Fatal(err)
31+
}
32+
33+
if err := discordCommandInterface.ReadWriteMethod(ctx, s); err != nil {
34+
log.Fatal(err)
35+
}
2236
}
Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
package commandHandlers
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"strings"
7+
"time"
8+
9+
"github.com/bwmarrin/discordgo"
10+
)
11+
12+
var (
13+
CommandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){
14+
"basic-command": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
15+
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
16+
Type: discordgo.InteractionResponseChannelMessageWithSource,
17+
Data: &discordgo.InteractionResponseData{
18+
Content: "Hey there! Congratulations, you just executed your first slash command",
19+
},
20+
})
21+
},
22+
"basic-command-with-files": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
23+
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
24+
Type: discordgo.InteractionResponseChannelMessageWithSource,
25+
Data: &discordgo.InteractionResponseData{
26+
Content: "Hey there! Congratulations, you just executed your first slash command with a file in the response",
27+
Files: []*discordgo.File{
28+
{
29+
ContentType: "text/plain",
30+
Name: "test.txt",
31+
Reader: strings.NewReader("Hello Discord!!"),
32+
},
33+
},
34+
},
35+
})
36+
},
37+
"localized-command": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
38+
responses := map[discordgo.Locale]string{
39+
discordgo.ChineseCN: "你好! 这是一个本地化的命令",
40+
}
41+
response := "Hi! This is a localized message"
42+
if r, ok := responses[i.Locale]; ok {
43+
response = r
44+
}
45+
err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
46+
Type: discordgo.InteractionResponseChannelMessageWithSource,
47+
Data: &discordgo.InteractionResponseData{
48+
Content: response,
49+
},
50+
})
51+
if err != nil {
52+
panic(err)
53+
}
54+
},
55+
"options": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
56+
// Access options in the order provided by the user.
57+
options := i.ApplicationCommandData().Options
58+
59+
// Or convert the slice into a map
60+
optionMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(options))
61+
for _, opt := range options {
62+
optionMap[opt.Name] = opt
63+
}
64+
65+
// This example stores the provided arguments in an []interface{}
66+
// which will be used to format the bot's response
67+
margs := make([]interface{}, 0, len(options))
68+
msgformat := "You learned how to use command options! " +
69+
"Take a look at the value(s) you entered:\n"
70+
71+
// Get the value from the option map.
72+
// When the option exists, ok = true
73+
if option, ok := optionMap["string-option"]; ok {
74+
// Option values must be type asserted from interface{}.
75+
// Discordgo provides utility functions to make this simple.
76+
margs = append(margs, option.StringValue())
77+
msgformat += "> string-option: %s\n"
78+
}
79+
80+
if opt, ok := optionMap["integer-option"]; ok {
81+
margs = append(margs, opt.IntValue())
82+
msgformat += "> integer-option: %d\n"
83+
}
84+
85+
if opt, ok := optionMap["number-option"]; ok {
86+
margs = append(margs, opt.FloatValue())
87+
msgformat += "> number-option: %f\n"
88+
}
89+
90+
if opt, ok := optionMap["bool-option"]; ok {
91+
margs = append(margs, opt.BoolValue())
92+
msgformat += "> bool-option: %v\n"
93+
}
94+
95+
if opt, ok := optionMap["channel-option"]; ok {
96+
margs = append(margs, opt.ChannelValue(nil).ID)
97+
msgformat += "> channel-option: <#%s>\n"
98+
}
99+
100+
if opt, ok := optionMap["user-option"]; ok {
101+
margs = append(margs, opt.UserValue(nil).ID)
102+
msgformat += "> user-option: <@%s>\n"
103+
}
104+
105+
if opt, ok := optionMap["role-option"]; ok {
106+
margs = append(margs, opt.RoleValue(nil, "").ID)
107+
msgformat += "> role-option: <@&%s>\n"
108+
}
109+
110+
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
111+
// Ignore type for now, they will be discussed in "responses"
112+
Type: discordgo.InteractionResponseChannelMessageWithSource,
113+
Data: &discordgo.InteractionResponseData{
114+
Content: fmt.Sprintf(
115+
msgformat,
116+
),
117+
},
118+
})
119+
},
120+
"permission-overview": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
121+
perms, err := s.ApplicationCommandPermissions(s.State.User.ID, i.GuildID, i.ApplicationCommandData().ID)
122+
123+
var restError *discordgo.RESTError
124+
if errors.As(err, &restError) && restError.Message != nil && restError.Message.Code == discordgo.ErrCodeUnknownApplicationCommandPermissions {
125+
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
126+
Type: discordgo.InteractionResponseChannelMessageWithSource,
127+
Data: &discordgo.InteractionResponseData{
128+
Content: ":x: No permission overwrites",
129+
},
130+
})
131+
return
132+
} else if err != nil {
133+
panic(err)
134+
}
135+
136+
if err != nil {
137+
panic(err)
138+
}
139+
format := "- %s %s\n"
140+
141+
channels := ""
142+
users := ""
143+
roles := ""
144+
145+
for _, o := range perms.Permissions {
146+
emoji := "❌"
147+
if o.Permission {
148+
emoji = "☑"
149+
}
150+
151+
switch o.Type {
152+
case discordgo.ApplicationCommandPermissionTypeUser:
153+
users += fmt.Sprintf(format, emoji, "<@!"+o.ID+">")
154+
case discordgo.ApplicationCommandPermissionTypeRole:
155+
if o.ID == i.GuildID {
156+
roles += fmt.Sprintf(format, emoji, "@everyone")
157+
} else {
158+
roles += fmt.Sprintf(format, emoji, "<@&"+o.ID+">")
159+
}
160+
}
161+
}
162+
163+
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
164+
Type: discordgo.InteractionResponseChannelMessageWithSource,
165+
Data: &discordgo.InteractionResponseData{
166+
Embeds: []*discordgo.MessageEmbed{
167+
{
168+
Title: "Permissions overview",
169+
Description: "Overview of permissions for this command",
170+
Fields: []*discordgo.MessageEmbedField{
171+
{
172+
Name: "Users",
173+
Value: users,
174+
},
175+
{
176+
Name: "Channels",
177+
Value: channels,
178+
},
179+
{
180+
Name: "Roles",
181+
Value: roles,
182+
},
183+
},
184+
},
185+
},
186+
AllowedMentions: &discordgo.MessageAllowedMentions{},
187+
},
188+
})
189+
},
190+
"subcommands": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
191+
options := i.ApplicationCommandData().Options
192+
content := ""
193+
194+
// As you can see, names of subcommands (nested, top-level)
195+
// and subcommand groups are provided through the arguments.
196+
switch options[0].Name {
197+
case "subcommand":
198+
content = "The top-level subcommand is executed. Now try to execute the nested one."
199+
case "subcommand-group":
200+
options = options[0].Options
201+
switch options[0].Name {
202+
case "nested-subcommand":
203+
content = "Nice, now you know how to execute nested commands too"
204+
default:
205+
content = "Oops, something went wrong.\n" +
206+
"Hol' up, you aren't supposed to see this message."
207+
}
208+
}
209+
210+
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
211+
Type: discordgo.InteractionResponseChannelMessageWithSource,
212+
Data: &discordgo.InteractionResponseData{
213+
Content: content,
214+
},
215+
})
216+
},
217+
"responses": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
218+
// Responses to a command are very important.
219+
// First of all, because you need to react to the interaction
220+
// by sending the response in 3 seconds after receiving, otherwise
221+
// interaction will be considered invalid and you can no longer
222+
// use the interaction token and ID for responding to the user's request
223+
224+
content := ""
225+
// As you can see, the response type names used here are pretty self-explanatory,
226+
// but for those who want more information see the official documentation
227+
switch i.ApplicationCommandData().Options[0].IntValue() {
228+
case int64(discordgo.InteractionResponseChannelMessageWithSource):
229+
content =
230+
"You just responded to an interaction, sent a message and showed the original one. " +
231+
"Congratulations!"
232+
content +=
233+
"\nAlso... you can edit your response, wait 5 seconds and this message will be changed"
234+
default:
235+
err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
236+
Type: discordgo.InteractionResponseType(i.ApplicationCommandData().Options[0].IntValue()),
237+
})
238+
if err != nil {
239+
s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
240+
Content: "Something went wrong",
241+
})
242+
}
243+
return
244+
}
245+
246+
err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
247+
Type: discordgo.InteractionResponseType(i.ApplicationCommandData().Options[0].IntValue()),
248+
Data: &discordgo.InteractionResponseData{
249+
Content: content,
250+
},
251+
})
252+
if err != nil {
253+
s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
254+
Content: "Something went wrong",
255+
})
256+
return
257+
}
258+
time.AfterFunc(time.Second*5, func() {
259+
content := content + "\n\nWell, now you know how to create and edit responses. " +
260+
"But you still don't know how to delete them... so... wait 10 seconds and this " +
261+
"message will be deleted."
262+
_, err = s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{
263+
Content: content,
264+
})
265+
if err != nil {
266+
s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
267+
Content: "Something went wrong",
268+
})
269+
return
270+
}
271+
time.Sleep(time.Second * 10)
272+
s.InteractionResponseDelete(i.Interaction)
273+
})
274+
},
275+
"followups": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
276+
// Followup messages are basically regular messages (you can create as many of them as you wish)
277+
// but work as they are created by webhooks and their functionality
278+
// is for handling additional messages after sending a response.
279+
280+
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
281+
Type: discordgo.InteractionResponseChannelMessageWithSource,
282+
Data: &discordgo.InteractionResponseData{
283+
// Note: this isn't documented, but you can use that if you want to.
284+
// This flag just allows you to create messages visible only for the caller of the command
285+
// (user who triggered the command)
286+
Content: "Surprise!",
287+
},
288+
})
289+
msg, err := s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
290+
Content: "Followup message has been created, after 5 seconds it will be edited",
291+
})
292+
if err != nil {
293+
s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
294+
Content: "Something went wrong",
295+
})
296+
return
297+
}
298+
time.Sleep(time.Second * 5)
299+
300+
content := "Now the original message is gone and after 10 seconds this message will ~~self-destruct~~ be deleted."
301+
s.FollowupMessageEdit(i.Interaction, msg.ID, &discordgo.WebhookEdit{
302+
Content: content,
303+
})
304+
305+
time.Sleep(time.Second * 10)
306+
307+
s.FollowupMessageDelete(i.Interaction, msg.ID)
308+
309+
s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
310+
Content: "For those, who didn't skip anything and followed tutorial along fairly, " +
311+
"take a unicorn :unicorn: as reward!\n" +
312+
"Also, as bonus... look at the original interaction response :D",
313+
})
314+
},
315+
}
316+
)

internal/pkg/constants/constants.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package constants
2+
3+
const (
4+
BotTokenHeader = "Token"
5+
)

0 commit comments

Comments
 (0)