Add join button, rework a lot of the alternate and leave button to actually work and be efficient

This commit is contained in:
Ean Milligan (Bastion) 2023-04-08 03:42:22 -04:00
parent 34172e7266
commit 2b31e7949e
3 changed files with 112 additions and 50 deletions

View File

@ -1,17 +1,24 @@
import { Bot, Interaction } from '../../../deps.ts'; import { Bot, Interaction } from '../../../deps.ts';
import { dbClient, queries } from '../../db.ts'; import { dbClient, queries } from '../../db.ts';
import { somethingWentWrong } from '../../commandUtils.ts'; import { somethingWentWrong } from '../../commandUtils.ts';
import { idSeparator } from '../event-creation/utils.ts'; import { idSeparator } from '../eventUtils.ts';
import utils from '../../utils.ts'; import utils from '../../utils.ts';
import { joinMemberToEvent } from './utils.ts';
export const customId = 'joinEvent'; export const customId = 'joinEvent';
export const execute = async (bot: Bot, interaction: Interaction) => { export const execute = async (bot: Bot, interaction: Interaction) => {
if (interaction.data?.customId && interaction.member && interaction.message && interaction.message.embeds[0] && interaction.message.embeds[0].fields) { if (interaction.data?.customId && interaction.member && interaction.member.user && interaction.channelId && interaction.message && interaction.message.embeds[0]) {
// Light Telemetry // Light Telemetry
dbClient.execute(queries.callIncCnt(interaction.data.customId.includes(idSeparator) ? 'btn-joinWLEvent' : 'btn-joinEvent')).catch((e) => dbClient.execute(queries.callIncCnt(interaction.data.customId.includes(idSeparator) ? 'btn-joinWLEvent' : 'btn-joinEvent')).catch((e) =>
utils.commonLoggers.dbError('joinEvent.ts', 'call sproc INC_CNT on', e) utils.commonLoggers.dbError('joinEvent.ts', 'call sproc INC_CNT on', e)
); );
// Remove user from event
joinMemberToEvent(bot, interaction, interaction.message.embeds[0], interaction.message.id, interaction.channelId, {
id: interaction.member.id,
name: interaction.member.user.username,
});
} else { } else {
somethingWentWrong(bot, interaction, 'noDataFromJoinEventButton'); somethingWentWrong(bot, interaction, 'noDataFromJoinEventButton');
} }

View File

@ -5,7 +5,7 @@ import { generateAlternateList, generateMemberList, generateMemberTitle, LfgEmbe
import utils from '../../utils.ts'; import utils from '../../utils.ts';
// Get Member Counts from the title // Get Member Counts from the title
export const getEventMemberCount = (rawMemberTitle: string): [number, number] => { const getEventMemberCount = (rawMemberTitle: string): [number, number] => {
const [rawCurrentCount, rawMaxCount] = rawMemberTitle.split('/'); const [rawCurrentCount, rawMaxCount] = rawMemberTitle.split('/');
const currentMemberCount = parseInt(rawCurrentCount.split(':')[1] || '0'); const currentMemberCount = parseInt(rawCurrentCount.split(':')[1] || '0');
const maxMemberCount = parseInt(rawMaxCount || '0'); const maxMemberCount = parseInt(rawMaxCount || '0');
@ -13,7 +13,7 @@ export const getEventMemberCount = (rawMemberTitle: string): [number, number] =>
}; };
// Get LFGMember objects from string list // Get LFGMember objects from string list
export const getLfgMembers = (rawMemberList: string): Array<LFGMember> => const getLfgMembers = (rawMemberList: string): Array<LFGMember> =>
rawMemberList.trim() === noMembersStr ? [] : rawMemberList.split('\n').map((rawMember) => { rawMemberList.trim() === noMembersStr ? [] : rawMemberList.split('\n').map((rawMember) => {
const [memberName, memberMention] = rawMember.split('-'); const [memberName, memberMention] = rawMember.split('-');
const lfgMember: LFGMember = { const lfgMember: LFGMember = {
@ -25,80 +25,135 @@ export const getLfgMembers = (rawMemberList: string): Array<LFGMember> =>
}); });
// Remove LFGMember from array filter // Remove LFGMember from array filter
export const removeLfgMember = (memberList: Array<LFGMember>, memberId: bigint): Array<LFGMember> => memberList.filter((member) => member.id !== memberId); const removeLfgMember = (memberList: Array<LFGMember>, memberId: bigint): Array<LFGMember> => memberList.filter((member) => member.id !== memberId);
// Remove member from the event const editEvent = async (
export const removeMemberFromEvent = (bot: Bot, interaction: Interaction, evtMessageEmbed: Embed, evtMessageId: bigint, evtChannelId: bigint, userId: bigint) => { bot: Bot,
interaction: Interaction,
evtMessageEmbed: Embed,
evtMessageId: bigint,
evtChannelId: bigint,
memberList: Array<LFGMember>,
maxMemberCount: number,
alternateList: Array<LFGMember>,
) => {
if (evtMessageEmbed.fields) { if (evtMessageEmbed.fields) {
// Remove user from event // Update the fields
const [oldMemberCount, maxMemberCount] = getEventMemberCount(evtMessageEmbed.fields[LfgEmbedIndexes.JoinedMembers].name);
const memberList = removeLfgMember(getLfgMembers(evtMessageEmbed.fields[LfgEmbedIndexes.JoinedMembers].value), userId);
let alternateList = removeLfgMember(getLfgMembers(evtMessageEmbed.fields[LfgEmbedIndexes.AlternateMembers].value), userId);
// Check if we need to auto-promote a member
const memberToPromote = alternateList.find((member) => member.joined);
if (oldMemberCount !== memberList.length && oldMemberCount === maxMemberCount && memberToPromote) {
// Promote member
alternateList = removeLfgMember(alternateList, memberToPromote.id);
memberList.push(memberToPromote);
// Notify member of promotion
// TODO: send notification
}
// Update the event
evtMessageEmbed.fields[LfgEmbedIndexes.JoinedMembers].name = generateMemberTitle(memberList, maxMemberCount); evtMessageEmbed.fields[LfgEmbedIndexes.JoinedMembers].name = generateMemberTitle(memberList, maxMemberCount);
evtMessageEmbed.fields[LfgEmbedIndexes.JoinedMembers].value = generateMemberList(memberList); evtMessageEmbed.fields[LfgEmbedIndexes.JoinedMembers].value = generateMemberList(memberList);
evtMessageEmbed.fields[LfgEmbedIndexes.AlternateMembers].value = generateAlternateList(alternateList); evtMessageEmbed.fields[LfgEmbedIndexes.AlternateMembers].value = generateAlternateList(alternateList);
bot.helpers.editMessage(evtChannelId, evtMessageId, {
// Edit the event
await bot.helpers.editMessage(evtChannelId, evtMessageId, {
embeds: [evtMessageEmbed], embeds: [evtMessageEmbed],
}).then(() => { }).then(() => {
// Let discord know we didn't ignore the user // Let discord know we didn't ignore the user
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, { bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
type: InteractionResponseTypes.DeferredUpdateMessage, type: InteractionResponseTypes.DeferredUpdateMessage,
}).catch((e: Error) => utils.commonLoggers.interactionSendError('utils.ts@removeEvent', interaction, e)); }).catch((e: Error) => utils.commonLoggers.interactionSendError('utils.ts', interaction, e));
}).catch((e: Error) => { }).catch((e: Error) => {
// Edit failed, try to notify user // Edit failed, try to notify user
utils.commonLoggers.messageEditError('utils.ts@removeEvent', 'remove edit fail', e); utils.commonLoggers.messageEditError('utils.ts', 'event edit fail', e);
somethingWentWrong(bot, interaction, 'editFailedInRemoveMember'); somethingWentWrong(bot, interaction, 'editFailedInUpdateEvent');
}); });
}
};
const noEdit = async (bot: Bot, interaction: Interaction) =>
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
type: InteractionResponseTypes.DeferredUpdateMessage,
}).catch((e: Error) => utils.commonLoggers.interactionSendError('utils.ts', interaction, e));
// Remove member from the event
export const removeMemberFromEvent = async (bot: Bot, interaction: Interaction, evtMessageEmbed: Embed, evtMessageId: bigint, evtChannelId: bigint, userId: bigint) => {
if (evtMessageEmbed.fields) {
// Get old counts
const [oldMemberCount, maxMemberCount] = getEventMemberCount(evtMessageEmbed.fields[LfgEmbedIndexes.JoinedMembers].name);
// Remove user from event
const oldMemberList = getLfgMembers(evtMessageEmbed.fields[LfgEmbedIndexes.JoinedMembers].value);
const memberList = removeLfgMember(oldMemberList, userId);
const oldAlternateList = getLfgMembers(evtMessageEmbed.fields[LfgEmbedIndexes.AlternateMembers].value);
let alternateList = removeLfgMember(oldAlternateList, userId);
// Check if user actually left event
if (oldMemberList.length !== memberList.length || oldAlternateList.length !== alternateList.length) {
// Check if we need to auto-promote a member
const memberToPromote = alternateList.find((member) => member.joined);
if (oldMemberCount !== memberList.length && oldMemberCount === maxMemberCount && memberToPromote) {
// Promote member
alternateList = removeLfgMember(alternateList, memberToPromote.id);
memberList.push(memberToPromote);
// Notify member of promotion
// TODO: send notification
}
// Update the event
await editEvent(bot, interaction, evtMessageEmbed, evtMessageId, evtChannelId, memberList, maxMemberCount, alternateList);
} else {
// Send noEdit response because user did not actually leave
await noEdit(bot, interaction);
}
} else { } else {
somethingWentWrong(bot, interaction, 'noFieldsInRemoveMember'); await somethingWentWrong(bot, interaction, 'noFieldsInRemoveMember');
} }
}; };
// Alternate member to the event // Alternate member to the event
export const alternateMemberToEvent = async (bot: Bot, interaction: Interaction, evtMessageEmbed: Embed, evtMessageId: bigint, evtChannelId: bigint, member: LFGMember, userJoinOnFull = false) => { export const alternateMemberToEvent = async (bot: Bot, interaction: Interaction, evtMessageEmbed: Embed, evtMessageId: bigint, evtChannelId: bigint, member: LFGMember, userJoinOnFull = false) => {
if (evtMessageEmbed.fields) { if (evtMessageEmbed.fields) {
// Add user to the event
member.joined = userJoinOnFull; member.joined = userJoinOnFull;
const alternateList = getLfgMembers(evtMessageEmbed.fields[LfgEmbedIndexes.AlternateMembers].value); // Get current alternates
alternateList.push(member); let alternateList = getLfgMembers(evtMessageEmbed.fields[LfgEmbedIndexes.AlternateMembers].value);
// Update the event // Verify user is not already on the alternate list
evtMessageEmbed.fields[LfgEmbedIndexes.AlternateMembers].value = generateAlternateList(alternateList); if (!alternateList.find((alternateMember) => alternateMember.id === member.id && alternateMember.joined === member.joined)) {
bot.helpers.editMessage(evtChannelId, evtMessageId, { // Add user to event, remove first to update joined status if necessary
embeds: [evtMessageEmbed], alternateList = removeLfgMember(alternateList, member.id);
}).then(() => { alternateList.push(member);
// Let discord know we didn't ignore the user
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, { // Get member count and remove user from joined list (if they are there)
type: InteractionResponseTypes.DeferredUpdateMessage, const [_oldMemberCount, maxMemberCount] = getEventMemberCount(evtMessageEmbed.fields[LfgEmbedIndexes.JoinedMembers].name);
}).catch((e: Error) => utils.commonLoggers.interactionSendError('utils.ts@alternateEvent', interaction, e)); const memberList = removeLfgMember(getLfgMembers(evtMessageEmbed.fields[LfgEmbedIndexes.JoinedMembers].value), member.id);
}).catch((e: Error) => {
// Edit failed, try to notify user // Update the event
utils.commonLoggers.messageEditError('utils.ts@alternateEvent', 'alternate edit fail', e); evtMessageEmbed.fields[LfgEmbedIndexes.AlternateMembers].value = generateAlternateList(alternateList);
somethingWentWrong(bot, interaction, 'editFailedInAlternateMember'); await editEvent(bot, interaction, evtMessageEmbed, evtMessageId, evtChannelId, memberList, maxMemberCount, alternateList);
}); } else {
// Send noEdit response because user was already an alternate and joined status did not change
await noEdit(bot, interaction);
}
} else { } else {
// No fields, can't alternate // No fields, can't alternate
somethingWentWrong(bot, interaction, 'noFieldsInAlternateMember'); await somethingWentWrong(bot, interaction, 'noFieldsInAlternateMember');
} }
}; };
// Join member to the event // Join member to the event
export const joinMemberToEvent = (bot: Bot, interaction: Interaction, evtMessageEmbed: Embed, evtMessageId: bigint, evtChannelId: bigint, member: LFGMember) => { export const joinMemberToEvent = async (bot: Bot, interaction: Interaction, evtMessageEmbed: Embed, evtMessageId: bigint, evtChannelId: bigint, member: LFGMember) => {
if (evtMessageEmbed.fields) { if (evtMessageEmbed.fields) {
// Get current member list and count
const [oldMemberCount, maxMemberCount] = getEventMemberCount(evtMessageEmbed.fields[LfgEmbedIndexes.JoinedMembers].name);
const memberList = getLfgMembers(evtMessageEmbed.fields[LfgEmbedIndexes.JoinedMembers].value);
// Verify user is not already on the joined list
if (memberList.find((joinedMember) => joinedMember.id === member.id)) {
// Send noEdit response because user was already joined
await noEdit(bot, interaction);
} else if (oldMemberCount === maxMemberCount) {
// Event full, add member to alternate list
await alternateMemberToEvent(bot, interaction, evtMessageEmbed, evtMessageId, evtChannelId, member, true);
} else {
// Join member to event
memberList.push(member);
// Remove user from alternate list (if they are there)
const alternateList = removeLfgMember(getLfgMembers(evtMessageEmbed.fields[LfgEmbedIndexes.AlternateMembers].value), member.id);
// Update the event
await editEvent(bot, interaction, evtMessageEmbed, evtMessageId, evtChannelId, memberList, maxMemberCount, alternateList);
}
} else { } else {
somethingWentWrong(bot, interaction, 'noFieldsInJoinMember'); // No fields, can't join
await somethingWentWrong(bot, interaction, 'noFieldsInJoinMember');
} }
}; };

View File

@ -24,7 +24,7 @@ export const isLFGChannel = (guildId: bigint, channelId: bigint) => {
return (lfgChannelSettings.has(`${guildId}-${channelId}`) || channelId === 0n || guildId === 0n) ? ApplicationCommandFlags.Ephemeral : undefined; return (lfgChannelSettings.has(`${guildId}-${channelId}`) || channelId === 0n || guildId === 0n) ? ApplicationCommandFlags.Ephemeral : undefined;
}; };
export const somethingWentWrong = (bot: Bot, interaction: Interaction, errorCode: string) => export const somethingWentWrong = async (bot: Bot, interaction: Interaction, errorCode: string) =>
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, { bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
type: InteractionResponseTypes.ChannelMessageWithSource, type: InteractionResponseTypes.ChannelMessageWithSource,
data: { data: {