Skip to content

Commit 0ea05d4

Browse files
authored
Merge pull request #18 from Lumos-Programming/feat/tryhackme-achievement
✨ TryHackMe達成コマンドの追加
2 parents 3b3c3bc + 5ac4f6b commit 0ea05d4

File tree

7 files changed

+200
-8
lines changed

7 files changed

+200
-8
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
.env
1+
.env*
2+
!.env.template

cmd/cmd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type cmd struct {
1313
type SubCmd interface {
1414
Handle(s *discordgo.Session, i *discordgo.InteractionCreate)
1515
Info() *discordgo.ApplicationCommand
16+
ModalCustomIDs() []string
1617
}
1718

1819
func (c exec) Activate(s *discordgo.Session) cmd {

cmd/delete/main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,7 @@ func (n DeleteCmd) Handle(
113113
return
114114
}
115115
}
116+
117+
func (n DeleteCmd) ModalCustomIDs() []string {
118+
return []string{}
119+
}

cmd/exec.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,37 @@ import (
66
)
77

88
type exec struct {
9-
cmds map[string]SubCmd
9+
cmds map[string]SubCmd
10+
modals map[string]SubCmd
1011
}
1112

1213
func NewExec() *exec {
13-
return &exec{}
14+
return &exec{
15+
cmds: make(map[string]SubCmd),
16+
modals: make(map[string]SubCmd),
17+
}
1418
}
1519

1620
func (c *exec) Add(i SubCmd) {
17-
if c.cmds == nil {
18-
c.cmds = make(map[string]SubCmd)
19-
}
2021
c.cmds[i.Info().Name] = i
22+
for _, cid := range i.ModalCustomIDs() {
23+
c.modals[cid] = i
24+
}
25+
log.Println("added command: ", i.Info().Name)
2126
}
2227

2328
func (c *exec) Handle(s *discordgo.Session, i *discordgo.InteractionCreate) {
24-
if h, ok := c.cmds[i.ApplicationCommandData().Name]; ok {
29+
var name string
30+
switch i.Type {
31+
case discordgo.InteractionApplicationCommand:
32+
name = i.ApplicationCommandData().Name
33+
case discordgo.InteractionModalSubmit:
34+
name = i.ModalSubmitData().CustomID
35+
}
36+
37+
if h, ok := c.cmds[name]; ok {
2538
h.Handle(s, i)
2639
} else {
27-
log.Printf("unknown command: %s", i.ApplicationCommandData().Name)
40+
log.Printf("unknown command: %s", name)
2841
}
2942
}

cmd/nox/main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,7 @@ func (n NoxCmd) Handle(
6565
log.Printf("failed to send followup message, err: %v", err)
6666
}
6767
}
68+
69+
func (n NoxCmd) ModalCustomIDs() []string {
70+
return []string{}
71+
}

cmd/tryhackme-achievement/main.go

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package tryhackme_achievement
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"time"
7+
8+
"github.com/bwmarrin/discordgo"
9+
)
10+
11+
const (
12+
cmdName = "tryhackme-share"
13+
modalID = "tryhackme-share"
14+
titleID = "challenge_title"
15+
urlID = "challenge_url"
16+
commentsID = "comments"
17+
)
18+
19+
// TryHackMeCmd encapsulates all logic for the `/share` command.
20+
type TryHackMeCmd struct {
21+
GuildID string
22+
}
23+
24+
// NewTryHackMeCmd returns a new command handler.
25+
func NewTryHackMeCmd(guildID string) *TryHackMeCmd {
26+
return &TryHackMeCmd{GuildID: guildID}
27+
}
28+
29+
// RegisterCommand registers/updates the slash-command every time the bot becomes READY.
30+
func (c *TryHackMeCmd) RegisterCommand(s *discordgo.Session) error {
31+
_, err := s.ApplicationCommandCreate(
32+
s.State.User.ID,
33+
c.GuildID,
34+
&discordgo.ApplicationCommand{
35+
Name: cmdName,
36+
Description: "Share your TryHackMe achievement!",
37+
},
38+
)
39+
return err
40+
}
41+
42+
// Handle must be added with dg.AddHandler.
43+
// It processes both the slash-command invocation and the modal submit event.
44+
func (c *TryHackMeCmd) Handle(s *discordgo.Session, i *discordgo.InteractionCreate) {
45+
switch i.Type {
46+
47+
case discordgo.InteractionApplicationCommand:
48+
if i.ApplicationCommandData().Name != cmdName {
49+
return
50+
}
51+
52+
// Send modal
53+
modal := &discordgo.InteractionResponse{
54+
Type: discordgo.InteractionResponseModal,
55+
Data: &discordgo.InteractionResponseData{
56+
CustomID: modalID,
57+
Title: "TryHackMe達成共有しよう!",
58+
Components: []discordgo.MessageComponent{
59+
discordgo.ActionsRow{
60+
Components: []discordgo.MessageComponent{
61+
discordgo.TextInput{
62+
CustomID: titleID,
63+
Label: "Room名",
64+
Style: discordgo.TextInputShort,
65+
Placeholder: "e.g. 'Blue Team Basics'",
66+
Required: true,
67+
},
68+
},
69+
},
70+
discordgo.ActionsRow{
71+
Components: []discordgo.MessageComponent{
72+
discordgo.TextInput{
73+
CustomID: urlID,
74+
Label: "RoomのURL",
75+
Style: discordgo.TextInputShort,
76+
Placeholder: "https://tryhackme.com/room/…",
77+
Required: true,
78+
},
79+
},
80+
},
81+
discordgo.ActionsRow{
82+
Components: []discordgo.MessageComponent{
83+
discordgo.TextInput{
84+
CustomID: commentsID,
85+
Label: "Comments (任意)",
86+
Style: discordgo.TextInputParagraph,
87+
Required: false,
88+
},
89+
},
90+
},
91+
},
92+
},
93+
}
94+
95+
if err := s.InteractionRespond(i.Interaction, modal); err != nil {
96+
log.Printf("tryhackme: modal respond error: %v", err)
97+
}
98+
99+
case discordgo.InteractionModalSubmit:
100+
if i.ModalSubmitData().CustomID != modalID {
101+
return
102+
}
103+
104+
// Extract inputs
105+
var title, url, comment string
106+
for _, cmp := range i.ModalSubmitData().Components {
107+
row := cmp.(*discordgo.ActionsRow)
108+
for _, inner := range row.Components {
109+
input := inner.(*discordgo.TextInput)
110+
switch input.CustomID {
111+
case titleID:
112+
title = input.Value
113+
case urlID:
114+
url = input.Value
115+
case commentsID:
116+
comment = input.Value
117+
}
118+
}
119+
}
120+
121+
name := i.Member.Nick
122+
if name == "" {
123+
name = i.Member.User.GlobalName
124+
}
125+
embed := &discordgo.MessageEmbed{
126+
Title: "🎖TryHackMe達成共有⭐️",
127+
// orange
128+
Color: 0xFFA500,
129+
Timestamp: time.Now().Format(time.RFC3339),
130+
Fields: []*discordgo.MessageEmbedField{
131+
{Name: "Room名", Value: title, Inline: true},
132+
{Name: "リンク", Value: url, Inline: true},
133+
},
134+
Footer: &discordgo.MessageEmbedFooter{
135+
Text: fmt.Sprintf("%s(%s)", i.Member.Nick, i.Member.User.Username),
136+
IconURL: i.Member.User.AvatarURL(""),
137+
},
138+
}
139+
if comment != "" {
140+
embed.Fields = append(embed.Fields, &discordgo.MessageEmbedField{
141+
Name: "Comments",
142+
Value: comment,
143+
})
144+
}
145+
146+
if err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
147+
Type: discordgo.InteractionResponseChannelMessageWithSource,
148+
Data: &discordgo.InteractionResponseData{
149+
Embeds: []*discordgo.MessageEmbed{embed},
150+
},
151+
}); err != nil {
152+
log.Printf("tryhackme: embed respond error: %v", err)
153+
}
154+
}
155+
}
156+
157+
func (c *TryHackMeCmd) Info() *discordgo.ApplicationCommand {
158+
return &discordgo.ApplicationCommand{
159+
Name: cmdName,
160+
Description: "Share your achievement on TryHackMe!",
161+
}
162+
}
163+
164+
func (c *TryHackMeCmd) ModalCustomIDs() []string {
165+
return []string{modalID}
166+
}

main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"lumos-discord-bot/cmd"
99
del "lumos-discord-bot/cmd/delete"
1010
"lumos-discord-bot/cmd/nox"
11+
tryhackme_achievement "lumos-discord-bot/cmd/tryhackme-achievement"
1112
"lumos-discord-bot/handler"
1213
"os"
1314
"os/signal"
@@ -53,6 +54,8 @@ func main() {
5354
cmds.Add(noxCmd)
5455
deleteCmd := del.NewDeleteCmd()
5556
cmds.Add(deleteCmd)
57+
tryhackmeAchievementCmd := tryhackme_achievement.NewTryHackMeCmd(targetServer)
58+
cmds.Add(tryhackmeAchievementCmd)
5659

5760
cmdHandler := cmds.Activate(bot)
5861
defer cmdHandler.Deactivate()

0 commit comments

Comments
 (0)