Skip to content

Commit bfeb4fa

Browse files
committed
Feat/#18 사용자 랜덤 선택 기능 구현 (#19)
* feat: Added command * feat: Implemented user random choice * docs: Docs for `getRandomUserByChannel` * feat: Implemented random number generator in util * test: Tested `PickRandomNumber` * feat: Modified `PickRandomNumber` logic - upperBound가 0 이하일 경우 0을 반환하는 로직 추가 * feat: add exception handling to restrict command execution to voice channels - Check the channel type to ensure the command runs only in voice channels - Send an error message to the user if the command is executed in a text channel
1 parent f20350e commit bfeb4fa

File tree

4 files changed

+78
-0
lines changed

4 files changed

+78
-0
lines changed

internal/handler/commands.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const (
1111
commandGetTodayRetrospectives = "오늘-회고-보기"
1212
commandGetScrumByDate = "다짐-보기"
1313
commandGetRetrospectivesByDate = "회고-보기"
14+
commandRandomUserPick = "사용자-랜덤-선택"
1415
)
1516

1617
const (
@@ -76,4 +77,8 @@ var commands = []*discordgo.ApplicationCommand{
7677
},
7778
},
7879
},
80+
{
81+
Name: commandRandomUserPick,
82+
Description: "채널에 있는 사용자 중 랜덤으로 한 명을 선택합니다.",
83+
},
7984
}

internal/handler/handlers.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ var (
2828
commandGetTodayRetrospectives: getTodayRetrospectives,
2929
commandGetScrumByDate: getScrumsByDate,
3030
commandGetRetrospectivesByDate: getRetrospectivesByDate,
31+
commandRandomUserPick: getRandomUserByChannel,
3132
}
3233
)
3334

@@ -180,6 +181,56 @@ func getScrumsByDate(session *discordgo.Session, interaction *discordgo.Interact
180181
sendMessage(session, interaction, scrumsToString(date, scrums))
181182
}
182183

184+
// getRandomUserByChannel 채널에 있는 사용자 중 랜덤으로 한 명을 선택합니다.
185+
func getRandomUserByChannel(session *discordgo.Session, interaction *discordgo.InteractionCreate) {
186+
channel, err := session.Channel(interaction.ChannelID)
187+
// 채널 정보를 불러오는 중 오류가 발생하면 에러 메시지를 전송합니다.
188+
if err != nil {
189+
logErrorAndSendMessage(session, interaction, "채널을 불러오는 중 오류가 발생했습니다.", err)
190+
return
191+
}
192+
// 음성 채널이 아니면 에러 메시지를 전송합니다.
193+
if channel.Type != discordgo.ChannelTypeGuildVoice {
194+
sendMessage(session, interaction, "음성 채널에서만 사용할 수 있는 명령어입니다.")
195+
return
196+
}
197+
log.Printf("Channel type: %v", channel.Type)
198+
guild, err := session.State.Guild(channel.GuildID)
199+
// 서버 정보를 불러오는 중 오류가 발생하면 에러 메시지를 전송합니다.
200+
if err != nil {
201+
logErrorAndSendMessage(session, interaction, "서버 정보를 불러오는 중 오류가 발생했습니다.", err)
202+
return
203+
}
204+
var members []*discordgo.Member // 음성 채널에 있는 사용자 목록을 저장합니다.
205+
memberMap := make(map[string]*discordgo.Member) // 사용자 ID를 키로 사용자 정보를 저장합니다.
206+
for _, member := range guild.Members {
207+
memberMap[member.User.ID] = member
208+
}
209+
210+
// 음성 채널에 있는 사용자 목록을 불러옵니다.
211+
for _, vs := range guild.VoiceStates {
212+
if vs.ChannelID == channel.ID {
213+
if member, ok := memberMap[vs.UserID]; ok {
214+
members = append(members, member)
215+
}
216+
}
217+
}
218+
// 음성 채널에 사용자가 없으면 에러 메시지를 전송합니다.
219+
if len(members) == 0 {
220+
sendMessage(session, interaction, "음성 채널에 사용자가 없습니다.")
221+
return
222+
}
223+
224+
// 음성 채널에 있는 사용자 중 랜덤으로 한 명을 선택합니다.
225+
randomMember := members[util.PickRandomNumber(len(members))]
226+
// 사용자의 닉네임이 없으면 사용자 이름을 사용합니다.
227+
username := randomMember.Nick
228+
if username == "" {
229+
username = randomMember.User.GlobalName
230+
}
231+
sendMessage(session, interaction, fmt.Sprintf("랜덤으로 선택된 사람은 %s입니다!", username))
232+
}
233+
183234
// retrospectiveToString 회고 목록을 문자열로 변환합니다.
184235
func retrospectiveToString(date time.Time, retrospectives []*model.RetrospectiveDto) string {
185236
var builder strings.Builder

internal/util/util.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package util
33
import (
44
"fmt"
55
"io"
6+
"math/rand"
67
"os"
78
"strings"
89
"time"
@@ -55,3 +56,13 @@ func LoadFile(filePath string) ([]byte, error) {
5556
}
5657
return arr, nil
5758
}
59+
60+
// PickRandomNumber 0부터 upperBound-1 사이의 랜덤한 숫자를 반환 (upperBound는 포함하지 않음) upperBound가 0 이하일 경우 0을 반환
61+
func PickRandomNumber(upperBound int) int {
62+
if upperBound <= 0 {
63+
return 0
64+
}
65+
source := rand.NewSource(time.Now().UnixNano())
66+
r := rand.New(source)
67+
return r.Intn(upperBound - 1)
68+
}

internal/util/util_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,14 @@ func TestLoadFile_InvalidFile(t *testing.T) {
108108
t.Errorf("expected error, but nil")
109109
}
110110
}
111+
112+
func TestPickRandomNumber(t *testing.T) {
113+
// Arrange
114+
upperBound := 10
115+
// Act
116+
actual := PickRandomNumber(upperBound)
117+
// Assert
118+
if actual < 0 || actual >= upperBound {
119+
t.Errorf("expected 0 <= actual < %d, but got %d", upperBound, actual)
120+
}
121+
}

0 commit comments

Comments
 (0)