Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .env

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
HELP.md
.env
dump.rdb
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ dependencies {
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-database-postgresql'
implementation 'org.springframework.session:spring-session-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
// implementation 'org.springframework.boot:spring-boot-starter-data-redis'
// implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
implementation 'org.apache.commons:commons-pool2'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
Expand Down
535 changes: 535 additions & 0 deletions codebase-analysis.md

Large diffs are not rendered by default.

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,41 +1,36 @@
package com.workingdead.chatbot.command;
package com.workingdead.chatbot.discord.command;

import com.workingdead.chatbot.scheduler.WendyScheduler;
import com.workingdead.chatbot.service.WendyService;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import com.workingdead.chatbot.discord.scheduler.DiscordWendyScheduler;
import com.workingdead.chatbot.discord.service.DiscordWendyService;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.interaction.component.EntitySelectInteractionEvent;
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.components.selections.EntitySelectMenu;
import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class WendyCommand extends ListenerAdapter {
private final WendyService wendyService;
private final WendyScheduler wendyScheduler;
public class DiscordWendyCommand extends ListenerAdapter {

private final DiscordWendyService discordWendyService;
private final DiscordWendyScheduler discordWendyScheduler;

private final Map<String, String> participantCheckMessages = new ConcurrentHashMap<>();
private final Map<String, Boolean> waitingForDateInput = new ConcurrentHashMap<>();

private static final String ATTENDEE_SELECT_MENU_ID = "wendy-attendees";
private static final String WEEK_SELECT_MENU_ID = "wendy-weeks";
private static final String WEEK_SELECT_MENU_REVOTE_ID = "wendy-weeks-revote";
public WendyCommand(WendyService wendyService, WendyScheduler wendyScheduler) {
this.wendyService = wendyService;
this.wendyScheduler = wendyScheduler;

public DiscordWendyCommand(DiscordWendyService discordWendyService, DiscordWendyScheduler discordWendyScheduler) {
this.discordWendyService = discordWendyService;
this.discordWendyScheduler = discordWendyScheduler;
}

@Override
Expand All @@ -52,45 +47,36 @@ public void onGuildJoin(net.dv8tion.jda.api.events.guild.GuildJoinEvent event) {
@Override
public void onMessageReceived(MessageReceivedEvent event) {
if (event.getAuthor().isBot()) return;

String content = event.getMessage().getContentRaw().trim();
TextChannel channel = event.getChannel().asTextChannel();
String channelId = channel.getId();
Member member = event.getMember();
// 1.1 웬디 시작

// 웬디 시작
if (content.equals("웬디 시작")) {
handleStart(channel);
return;
}
// 4.1 도움말

// 도움말
if (content.equals("/help") || content.equals("웬디 도움말")) {
handleHelp(channel);
return;
}

// 세션 체크
if (!wendyService.isSessionActive(channelId)) {
if (!discordWendyService.isSessionActive(channelId)) {
return;
}

// // 2.1~2.2 날짜 범위 입력
// if (waitingForDateInput.getOrDefault(channelId, false)) {
// Integer weeks = extractWeeks(content);
// if (weeks != null) {
// handleDateInput(channel, member, weeks, false);
// return;
// }
// }

// 4.2 재투표

// 재투표
if (content.equals("웬디 재투표")) {
handleRevote(channel);
return;
}
// 3.1 웬디 종료

// 웬디 종료
if (content.equals("웬디 종료")) {
handleEnd(channel);
return;
Expand All @@ -104,17 +90,16 @@ public void onEntitySelectInteraction(EntitySelectInteractionEvent event) {
}

String channelId = event.getChannel().getId();
if (!wendyService.isSessionActive(channelId)) {
if (!discordWendyService.isSessionActive(channelId)) {
return;
}

event.getMentions().getMembers().forEach(member -> {
wendyService.addParticipant(channelId, member.getId(), member.getEffectiveName());
System.out.println("[Command] Participant added via select menu: " + member.getEffectiveName());
discordWendyService.addParticipant(channelId, member.getId(), member.getEffectiveName());
System.out.println("[Discord Command] Participant added via select menu: " + member.getEffectiveName());
});

event.reply("참석자 명단이 업데이트됐어요!").setEphemeral(true).queue();

}

@Override
Expand All @@ -125,11 +110,10 @@ public void onStringSelectInteraction(StringSelectInteractionEvent event) {
}

String channelId = event.getChannel().getId();
if (!wendyService.isSessionActive(channelId)) {
if (!discordWendyService.isSessionActive(channelId)) {
return;
}

// 하나만 선택하게 설정할 예정이므로 첫 번째 값만 사용
String value = event.getValues().get(0);
int weeks;
try {
Expand All @@ -151,43 +135,17 @@ public void onStringSelectInteraction(StringSelectInteractionEvent event) {
event.reply("투표 날짜 범위를 선택하셨어요!").setEphemeral(true).queue();
}

// @Override
// public void onMessageReactionAdd(MessageReactionAddEvent event) {
// if (event.getUser() != null && event.getUser().isBot()) return;
//
// String channelId = event.getChannel().getId();
// String messageId = event.getMessageId();
//
// String checkMessageId = participantCheckMessages.get(channelId);
// if (checkMessageId == null || !checkMessageId.equals(messageId)) {
// return;
// }
//
// if (!event.getReaction().getEmoji().equals(Emoji.fromUnicode("✅"))) {
// return;
// }
//
// event.retrieveMember().queue(member -> {
// if (member != null) {
// wendyService.addParticipant(channelId, member.getId(), member.getEffectiveName());
// System.out.println("[Command] Participant added: " + member.getEffectiveName());
// }
// });
// }

private void handleStart(TextChannel channel) {
String channelId = channel.getId();
List<Member> members = channel.getMembers();
wendyService.startSession(channelId, members);

discordWendyService.startSession(channelId, members);

channel.sendMessage("""
안녕하세요! 일정 조율 도우미 웬디에요 :D
지금부터 여러분의 일정 조율을 도와드릴게요
""").queue();


// 참석자 입력용 엔티티 셀렉트 메뉴 (유저 선택 드롭다운)
EntitySelectMenu attendeeMenu = EntitySelectMenu.create(ATTENDEE_SELECT_MENU_ID, EntitySelectMenu.SelectTarget.USER)
.setPlaceholder("참석자를 선택 / 검색해 주세요.")
.setRequiredRange(1, 25)
Expand All @@ -197,7 +155,6 @@ private void handleStart(TextChannel channel) {
.setActionRow(attendeeMenu)
.queue();

// 2.1 날짜 범위 파악 질문 (드롭다운 방식)
StringSelectMenu weekMenu = StringSelectMenu.create(WEEK_SELECT_MENU_ID)
.setPlaceholder("몇 주 뒤의 일정을 계획하시나요?")
.addOption("이번 주", "0")
Expand All @@ -213,54 +170,36 @@ private void handleStart(TextChannel channel) {
.setActionRow(weekMenu)
.queue();
}

private void handleDateInput(TextChannel channel, Member member, int weeks, boolean isRevote) {
String channelId = channel.getId();
String userMention = member.getAsMention();
String channelName = channel.getName();

waitingForDateInput.put(channelId, false);

channel.sendMessage(userMention + " 님이 " + weeks + "주 뒤를 선택하셨어요!").queue();
channel.sendMessage("해당 일정의 투표를 만들어드릴게요 :D").queue();
channel.sendMessage("(투표 늦게 하는 사람 대머리🧑‍🦲)").queue();
channel.sendMessage("투표를 생성 중입니다🛜").queue();
String voteUrl = isRevote
? wendyService.recreateVote(channelId, channelName, weeks)
: wendyService.createVote(channelId, channelName, weeks);

String voteUrl = isRevote
? discordWendyService.recreateVote(channelId, channelName, weeks)
: discordWendyService.createVote(channelId, channelName, weeks);

channel.sendMessage(voteUrl).queue();
wendyScheduler.startSchedule(channel);


// // 투표 제한시간(24시간) + 30분 후 자동 종료 스케줄
// CompletableFuture
// .delayedExecutor(3 * 60 + 30, TimeUnit.SECONDS)
// .execute(() -> {
// String chId = channel.getId();
// // 스케줄러 정리 + 세션 종료
// wendyScheduler.stopSchedule(chId);
// wendyService.endSession(chId);
//
// // 안내 메시지 전송
// channel.sendMessage("""
// 투표 제한 시간이 지나 웬디가 자동으로 종료되었어요 :D
// 다시 일정 조율이 필요하시면 '웬디 시작'을 입력해 주세요!
// """).queue();
// });
discordWendyScheduler.startSchedule(channel);
}

private void handleRevote(TextChannel channel) {
String channelId = channel.getId();
if (!wendyService.hasPreviousVote(channelId)) {

if (!discordWendyService.hasPreviousVote(channelId)) {
channel.sendMessage("아직 진행된 투표가 없어요🗑️").queue();
return;
}

wendyScheduler.stopSchedule(channelId);

discordWendyScheduler.stopSchedule(channelId);

StringSelectMenu weekMenu = StringSelectMenu.create(WEEK_SELECT_MENU_REVOTE_ID)
.setPlaceholder("몇 주 뒤의 일정을 다시 계획하시나요?")
Expand All @@ -277,33 +216,33 @@ private void handleRevote(TextChannel channel) {
.setActionRow(weekMenu)
.queue();
}

private void handleEnd(TextChannel channel) {
String channelId = channel.getId();
wendyScheduler.stopSchedule(channelId);
wendyService.endSession(channelId);

discordWendyScheduler.stopSchedule(channelId);
discordWendyService.endSession(channelId);

participantCheckMessages.remove(channelId);
waitingForDateInput.remove(channelId);

channel.sendMessage("""
웬디는 여기서 눈치껏 빠질게요 :D
모두 알찬 시간 보내세요!
""").queue();
System.out.println("[Command] Session ended: " + channelId);
System.out.println("[Discord Command] Session ended: " + channelId);
}

private void handleHelp(TextChannel channel) {
channel.sendMessage("""
웬디는 다음과 같은 기능이 있어요!

**'웬디 시작'**: 일정 조율을 시작해요
**'웬디 종료'**: 작동을 종료해요
**'웬디 재투표'**: 동일한 참석자로 투표를 다시 올려요
""").queue();
}

private Integer extractWeeks(String content) {
String numbers = content.replaceAll("[^0-9]", "");
if (numbers.isEmpty()) return null;
Expand Down
Loading