Skip to content

Feat/meta data v2 #990

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
744d816
alter help_thread table to add more meta data
ankitsmt211 Dec 17, 2023
bc3fab1
update write operation with extra fields
ankitsmt211 Dec 17, 2023
0f5e116
listener that updates meta data based on thread status
ankitsmt211 Dec 17, 2023
ff7ec2f
fix error in log messages
ankitsmt211 Dec 17, 2023
8508977
method to update tagName on change in db
ankitsmt211 Dec 17, 2023
198df3a
more suitable name for class and java doc
ankitsmt211 Dec 17, 2023
76b09e9
change name to avoid confusion & update java doc
ankitsmt211 Dec 17, 2023
c2842cf
minor bug that would change status back to active again and log messa…
ankitsmt211 Dec 18, 2023
c5768c2
more columns added for metadata
ankitsmt211 Dec 18, 2023
a1ecd95
update listener to record added metadata columns
ankitsmt211 Dec 18, 2023
0bd0c13
spotless fix
ankitsmt211 Dec 18, 2023
28c28b4
replacing get(0) with getFirst() for list
ankitsmt211 Dec 18, 2023
7708513
add routine to settle thread status if was left open
ankitsmt211 Jan 3, 2024
3323c48
resolve conflicts
ankitsmt211 Jan 9, 2024
ab0fe61
spotless fix
ankitsmt211 Jan 9, 2024
58b1292
refactor MarkHelpThreadCloseInDBRoutine and changes
ankitsmt211 Jan 24, 2024
dcf9a7a
document updated param in MarkHelpThreadCloseInDBRoutine constructor
ankitsmt211 Jan 24, 2024
41667e3
use time of creation/modfication from thread and tags as csv
ankitsmt211 May 16, 2024
ca6d4d4
rely on discord for getting thread status instead of DB
ankitsmt211 May 17, 2024
6d2848e
Merge branch 'develop' into feat/meta-data-v2
ankitsmt211 May 17, 2024
87461c3
changes
ankitsmt211 May 17, 2024
7d2256c
change list
ankitsmt211 May 18, 2024
3089083
spotless fix
ankitsmt211 May 18, 2024
a665aa7
tags from config sanitized
ankitsmt211 May 18, 2024
b061ae0
requested changes
ankitsmt211 May 25, 2024
e302e95
spotless
ankitsmt211 May 25, 2024
c745481
requested changes
ankitsmt211 Jun 1, 2024
495e4d2
remove unnecessary map
ankitsmt211 Jun 1, 2024
b10387c
increase routine schedule to 24 hrs
ankitsmt211 Jun 2, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
new CodeMessageHandler(blacklistConfig.special(), jshellEval);
ChatGptService chatGptService = new ChatGptService(config);
HelpSystemHelper helpSystemHelper = new HelpSystemHelper(config, database, chatGptService);
HelpThreadLifecycleListener helpThreadLifecycleListener =
new HelpThreadLifecycleListener(helpSystemHelper, database);

// NOTE The system can add special system relevant commands also by itself,
// hence this list may not necessarily represent the full list of all commands actually
Expand All @@ -106,6 +108,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
.add(new AutoPruneHelperRoutine(config, helpSystemHelper, modAuditLogWriter, database));
features.add(new HelpThreadAutoArchiver(helpSystemHelper));
features.add(new LeftoverBookmarksCleanupRoutine(bookmarksSystem));
features.add(new MarkHelpThreadCloseInDBRoutine(database, helpThreadLifecycleListener));

// Message receivers
features.add(new TopHelpersMessageListener(database, config));
Expand All @@ -125,6 +128,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
features.add(new GuildLeaveCloseThreadListener(config));
features.add(new LeftoverBookmarksListener(bookmarksSystem));
features.add(new HelpThreadCreatedListener(helpSystemHelper));
features.add(new HelpThreadLifecycleListener(helpSystemHelper, database));

// Message context commands
features.add(new TransferQuestionCommand(config));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.togetherjava.tjbot.features.componentids.ComponentIdInteractor;

import java.awt.*;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -202,11 +203,17 @@ private RestAction<Message> useChatGptFallbackMessage(ThreadChannel threadChanne
}

void writeHelpThreadToDatabase(long authorId, ThreadChannel threadChannel) {

Instant createdAt = Instant.now();
String tag = threadChannel.getAppliedTags().getFirst().getName();

database.write(content -> {
HelpThreadsRecord helpThreadsRecord = content.newRecord(HelpThreads.HELP_THREADS)
.setAuthorId(authorId)
.setChannelId(threadChannel.getIdLong())
.setCreatedAt(threadChannel.getTimeCreated().toInstant());
.setCreatedAt(createdAt)
.setTag(tag)
.setTicketStatus(TicketStatus.ACTIVE.val);
if (helpThreadsRecord.update() == 0) {
helpThreadsRecord.insert();
}
Expand Down Expand Up @@ -356,6 +363,17 @@ public String getTagName() {
}
}

enum TicketStatus {
ARCHIVED(0),
ACTIVE(1);

final int val;

TicketStatus(int val) {
this.val = val;
}
}

Optional<Long> getAuthorByHelpThreadId(final long channelId) {

logger.debug("Looking for thread-record using channel ID: {}", channelId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package org.togetherjava.tjbot.features.help;

import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.events.channel.update.ChannelUpdateAppliedTagsEvent;
import net.dv8tion.jda.api.events.channel.update.ChannelUpdateArchivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.togetherjava.tjbot.db.Database;
import org.togetherjava.tjbot.features.EventReceiver;

import java.time.Instant;

import static org.togetherjava.tjbot.db.generated.tables.HelpThreads.HELP_THREADS;

/**
* Listens for help thread events after creation of thread. Updates metadata based on those events
* in database.
*/
public final class HelpThreadLifecycleListener extends ListenerAdapter implements EventReceiver {

private final HelpSystemHelper helper;
private final Logger logger = LoggerFactory.getLogger(HelpThreadLifecycleListener.class);
private final Database database;

/**
* Creates a new instance.
*
* @param helper to work with the help threads
* @param database the database to store help thread metadata in
*/
public HelpThreadLifecycleListener(HelpSystemHelper helper, Database database) {
this.helper = helper;
this.database = database;
}

@Override
public void onChannelUpdateArchived(@NotNull ChannelUpdateArchivedEvent event) {
if (!event.getChannelType().isThread()) {
return;
}
ThreadChannel threadChannel = event.getChannel().asThreadChannel();

if (!helper.isHelpForumName(threadChannel.getParentChannel().getName())) {
return;
}
handleThreadStatus(threadChannel);
}

@Override
public void onChannelUpdateAppliedTags(@NotNull ChannelUpdateAppliedTagsEvent event) {
ThreadChannel threadChannel = event.getChannel().asThreadChannel();

if (!helper.isHelpForumName(threadChannel.getParentChannel().getName())) {
return;
}

String updatedTag = event.getAddedTags().getFirst().getName();
long threadId = threadChannel.getIdLong();

handleTagsUpdate(threadId, updatedTag);
}

private void handleThreadStatus(ThreadChannel threadChannel) {
Instant closedAt = Instant.now();
long threadId = threadChannel.getIdLong();

int status = database.read(context -> context.selectFrom(HELP_THREADS)
.where(HELP_THREADS.CHANNEL_ID.eq(threadId))
.fetchOne(HELP_THREADS.TICKET_STATUS));

if (status == HelpSystemHelper.TicketStatus.ACTIVE.val) {
handleArchiveStatus(closedAt, threadChannel);
return;
}

changeStatusToActive(threadId);
}

void handleArchiveStatus(Instant closedAt, ThreadChannel threadChannel) {
long threadId = threadChannel.getIdLong();
int messageCount = threadChannel.getMessageCount();
int participantsExceptAuthor = threadChannel.getMemberCount() - 1;

database.write(context -> context.update(HELP_THREADS)
.set(HELP_THREADS.CLOSED_AT, closedAt)
.set(HELP_THREADS.TICKET_STATUS, HelpSystemHelper.TicketStatus.ARCHIVED.val)
.set(HELP_THREADS.MESSAGE_COUNT, messageCount)
.set(HELP_THREADS.PARTICIPANTS, participantsExceptAuthor)
.where(HELP_THREADS.CHANNEL_ID.eq(threadId))
.execute());

logger.info("Thread with id: {}, updated to archived status in database", threadId);
}

private void changeStatusToActive(long threadId) {
database.write(context -> context.update(HELP_THREADS)
.set(HELP_THREADS.TICKET_STATUS, HelpSystemHelper.TicketStatus.ACTIVE.val)
.where(HELP_THREADS.CHANNEL_ID.eq(threadId))
.execute());

logger.info("Thread with id: {}, updated to active status in database", threadId);
}

private void handleTagsUpdate(long threadId, String updatedTag) {
database.write(context -> context.update(HELP_THREADS)
.set(HELP_THREADS.TAG, updatedTag)
.where(HELP_THREADS.CHANNEL_ID.eq(threadId))
.execute());

logger.info("Updated tag for thread with id: {} in database", threadId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.togetherjava.tjbot.features.help;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.togetherjava.tjbot.db.Database;
import org.togetherjava.tjbot.db.generated.tables.records.HelpThreadsRecord;
import org.togetherjava.tjbot.features.Routine;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static org.togetherjava.tjbot.db.generated.tables.HelpThreads.HELP_THREADS;

/**
* Updates the status of help threads in database that were created a few days ago and couldn't be
* closed.
*/
public final class MarkHelpThreadCloseInDBRoutine implements Routine {
private final Logger logger = LoggerFactory.getLogger(MarkHelpThreadCloseInDBRoutine.class);
private final Database database;
private final HelpThreadLifecycleListener helpThreadLifecycleListener;

/**
* Creates a new instance.
*
* @param database the database to store help thread metadata in
* @param helpThreadLifecycleListener class which offers method to update thread status in
* database
*/
public MarkHelpThreadCloseInDBRoutine(Database database,
HelpThreadLifecycleListener helpThreadLifecycleListener) {
this.database = database;
this.helpThreadLifecycleListener = helpThreadLifecycleListener;
}

@Override
public Schedule createSchedule() {
return new Schedule(ScheduleMode.FIXED_RATE, 0, 1, TimeUnit.HOURS);
}

@Override
public void runRoutine(JDA jda) {
updateTicketStatus(jda);
}

private void updateTicketStatus(JDA jda) {
Instant now = Instant.now();
Instant threeDaysAgo = now.minus(3, ChronoUnit.DAYS);
List<Long> threadIdsToClose = database.read(context -> context.selectFrom(HELP_THREADS)
.where(HELP_THREADS.TICKET_STATUS.eq(HelpSystemHelper.TicketStatus.ACTIVE.val))
.and(HELP_THREADS.CREATED_AT.lessThan(threeDaysAgo))
.stream()
.map(HelpThreadsRecord::getChannelId)
.toList());


threadIdsToClose.forEach(id -> {
try {
ThreadChannel threadChannel = jda.getThreadChannelById(id);
helpThreadLifecycleListener.handleArchiveStatus(now, threadChannel);
} catch (Exception exception) {
logger.warn("unable to mark thread as close with id :{}", id, exception);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER TABLE help_threads ADD ticket_status INTEGER DEFAULT 0;
ALTER TABLE help_threads ADD tag TEXT DEFAULT 'none';
ALTER TABLE help_threads ADD closed_at TIMESTAMP NULL;
ALTER TABLE help_threads ADD participants INTEGER DEFAULT 1;
ALTER TABLE help_threads ADD message_count INTEGER DEFAULT 0;