Skip to content

Commit

Permalink
various reminder fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
GamingGeek committed Jan 31, 2025
1 parent 5af9b6e commit f0c30bf
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 60 deletions.
10 changes: 6 additions & 4 deletions languages/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -1143,15 +1143,17 @@
"REMINDER_NOT_AUTHORIZED_USER_APP": "To ensure that Fire can always deliver DMs to you, you must add Fire as a User App by using the button below",
"REMINDER_FAILURE_DM_CLOSED": "A past reminder failed due to your DMs being closed! Take the time to ensure you have DMs open in at least one server you share with Fire or add Fire as a User App by using the button below then try again",
"REMINDER_MISSING_ARG": "Reminder argument was not provided or invalid! Make sure to include the time for your reminder along with the reminder itself",
"REMINDER_CONTENT_TOO_LONG": "Your reminder is too long! It must be 4000 characters or less",
"REMINDER_MISSING_CONTEXT": "Something went wrong while creating a reminder. Make sure the message you choose has content",
"REMINDER_INVALID_REPEAT": "The repeat flag value is invalid, it must range from 1 to 5",
"REMINDER_SEPARATE_FLAGS": "The step and repeat flags must be used together, they cannot be used individually",
"REMINDER_INVALID_STEP": "The step flag value is invalid. Use this flag to set multiple reminders with a predefined \"step\" after each",
"REMINDER_MISSING_TIME": "You need to include a duration for your reminder, e.g. \"69 mins\" for 69 minutes",
"REMINDER_CONTEXT_PLACEHOLDER": "Select a time for your reminder",
"REMINDER_CONTEXT_CONTENT_NO_TZ": "Setting a reminder for \"{{content}}\"",
"REMINDER_CONTEXT_CONTENT_WITH_AUTHOR_TZ": "Setting a reminder for \"{{content}}\" (using {{author}}'s timezone unless one is specified)",
"REMINDER_CONTEXT_CONTENT": "Setting a reminder for \"{{content}}\" (using default timezone, UTC, unless specified in selected time)",
"REMINDER_CONTEXT_CONTENT_NO_TZ": "Setting a reminder with the following content:\n\n{{content}}",
"REMINDER_CONTEXT_CONTENT_WITH_AUTHOR_TZ": "Setting a reminder with the following content (using {{author}}'s timezone unless one is specified):\n\n{{content}}",
"REMINDER_CONTEXT_CONTENT": "Setting a reminder with the following content (using default timezone, UTC, unless specified in selected time):\n\n{{content}}",
"REMINDER_CONTEXT_TEMPORARY_WARNING": "-# WARNING: As I'm not a member of this server, I can only keep information about the message you selected for a short period of time.\n-# If you don't set a reminder soon, I may forget about it",
"REMINDER_CONTEXT_CANCELLED": "Alright, I won't remind you about that message.",
"REMINDER_MISSING_CONTENT": "I need something to remind you about...",
"REMINDER_TIME_LIMIT": "Reminders are currently limited to 2 years. This may increase in the future",
Expand All @@ -1165,7 +1167,7 @@
"REMINDER_COMPLETE_BUTTON": "Complete",
"REMINDER_LINK_BUTTON": "Source",
"REMINDER_SNOOZE_ERROR": "I was unable to snooze that reminder.",
"REMINDER_SNOOZE_UNKNOWN": "I was unable to read the data for the reminder so I was unable to snooze it.",
"REMINDER_SNOOZE_UNKNOWN": "I was unable to read the data for the reminder so I was unable to snooze/set it.",
"REMINDER_SNOOZE_PLACEHOLDER": "Select a time to snooze this reminder for",
"REMINDER_SNOOZE_TIME_INVALID": "That isn't a valid snooze time!",
"REMINDER_SNOOZE_FAILED": "Failed to snooze this reminder.",
Expand Down
3 changes: 1 addition & 2 deletions lib/extensions/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -660,8 +660,7 @@ export class FireMessage extends Message {
: (BigInt((destination as PartialQuoteDestination).permissions) &
EMBED_LINKS) ==
EMBED_LINKS;
if (!canEmbed && content)
content = content.replace(regexes.basicURL, (m) => `<${m}>`);
if (!canEmbed && content) content = this.client.util.supressLinks(content);
if (!content && this.attachments.size && canAttach)
content = this.attachments.map((a) => a.url).join("\n");
else if (canAttach && this.attachments.size) {
Expand Down
12 changes: 12 additions & 0 deletions lib/util/clientutil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,18 @@ export class Util extends ClientUtil {
return text.replace(regexes.maskedLink, "$<name>");
}

suppressMaskedLinks(text: string) {
return text.replace(regexes.maskedLink, "[$<name>](<$<link>>)");
}

supressLinks(text: string) {
// supress masked links first
// basicURL will exclude them
return this.suppressMaskedLinks(text).replace(regexes.basicURL, (url) =>
url.startsWith("<") && url.endsWith(">)") ? url : `<${url}>`
);
}

getUserStatuses(shard?: number) {
try {
return {
Expand Down
2 changes: 1 addition & 1 deletion lib/util/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export const constants = {
"gim"
),
URL: /https?:\/\/([^\/?#]*)([^?#]*)(\?([^#]*))?(#(.*))?/gim,
basicURL: /(https?:\/\/[^\s]+)/gim,
basicURL: /((?:<)?https?:\/\/[^\s\n]+(?:>)?)/gi,
protocol: /\w{1,10}:\/\//gim,
blockedUsername: /Username cannot contain "(\w*)"/gim,
joinleavemsgs: {
Expand Down
71 changes: 54 additions & 17 deletions src/commands/Utilities/createremind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import { Language, LanguageKeys } from "@fire/lib/util/language";
import { ParsedTime, parseWithUserTimezone } from "@fire/src/arguments/time";
import { ParsedResult, strict } from "chrono-node";
import * as dayjs from "dayjs";
import { Snowflake } from "discord-api-types/globals";
import {
Collection,
Formatters,
MessageActionRow,
MessageButton,
Expand Down Expand Up @@ -59,9 +61,13 @@ const getContextOptions = (
});
};

type ClickedMessage = { message: FireMessage; clickedAt: number };

export default class RemindersCreate extends Command {
repeatRegex = /--repeat (\d*)/gim;
stepRegex = /--step ([^-]*)/gim;
recentlyClicked: Collection<Snowflake, ClickedMessage>;

constructor() {
super("reminders-create", {
description: (language: Language) =>
Expand Down Expand Up @@ -99,6 +105,15 @@ export default class RemindersCreate extends Command {
ephemeral: true,
slashOnly: true,
});

this.recentlyClicked = new Collection();
setInterval(
() =>
(this.recentlyClicked = this.recentlyClicked.filter(
(m) => +new Date() - m.clickedAt >= 300_000
)),
30_000
);
}

async run(
Expand Down Expand Up @@ -158,6 +173,16 @@ export default class RemindersCreate extends Command {

const now = +new Date();

if (!this.client.guilds.cache.has(command.guildId))
// we need this to get the data for setting the reminder
// since we can't fetch the message in future interactions
// and will overwrite the previous one if it exists
// with new data & new timestamp
this.recentlyClicked.set(clickedMessage.id, {
message: clickedMessage,
clickedAt: now,
});

// Parse with chrono-node early so we can get the content without the time
let { parsed, preliminaryParsedDate: date } = parseWithUserTimezone(
clickedMessage.content,
Expand Down Expand Up @@ -339,24 +364,32 @@ export default class RemindersCreate extends Command {
.setCustomId("!reminders_context_cancel");

return await command.channel.send({
content: command.author.language.get(
parsed.length
? clickedMessage.author.settings.has("reminders.timezone.iana")
? clickedMessage.author.id == command.author.id
content:
command.author.language.get(
parsed.length
? clickedMessage.author.settings.has("reminders.timezone.iana")
? clickedMessage.author.id == command.author.id
? command.author.settings.has("reminders.timezone.iana")
? "REMINDER_CONTEXT_CONTENT_NO_TZ"
: "REMINDER_CONTEXT_CONTENT"
: "REMINDER_CONTEXT_CONTENT_WITH_AUTHOR_TZ"
: command.author.settings.has("reminders.timezone.iana")
? "REMINDER_CONTEXT_CONTENT_NO_TZ"
: "REMINDER_CONTEXT_CONTENT_WITH_AUTHOR_TZ"
: command.author.settings.has("reminders.timezone.iana")
? "REMINDER_CONTEXT_CONTENT_NO_TZ"
: "REMINDER_CONTEXT_CONTENT"
: "REMINDER_CONTEXT_CONTENT_NO_TZ",
{
content:
reminderText.length >= 503
? reminderText.slice(0, 500) + "..."
: reminderText,
author: clickedMessage.author.toString(),
}
),
: "REMINDER_CONTEXT_CONTENT"
: "REMINDER_CONTEXT_CONTENT_NO_TZ",
{
content:
reminderText.length >= 503
? reminderText.slice(0, 500) + "..."
: reminderText,
author: clickedMessage.author.toString(),
}
) +
(!this.client.guilds.cache.has(command.guildId)
? `\n${command.author.language.get(
"REMINDER_CONTEXT_TEMPORARY_WARNING"
)}`
: ""),
components: [
new MessageActionRow().addComponents(dropdown),
new MessageActionRow().addComponents(cancelButton),
Expand All @@ -372,6 +405,10 @@ export default class RemindersCreate extends Command {
return await command.error("REMINDER_MISSING_ARG", {
includeSlashUpsell: true,
});
else if (reminder.text.length > 4000)
return await command.error("REMINDER_CONTENT_TOO_LONG", {
includeSlashUpsell: true,
});
else if (reminder.date < command.createdAt)
return await command.error("REMINDER_PAST_TIME", {
includeSlashUpsell: true,
Expand Down
5 changes: 3 additions & 2 deletions src/commands/Utilities/deleteremind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ComponentMessage } from "@fire/lib/extensions/componentmessage";
import { Command } from "@fire/lib/util/command";
import { Language } from "@fire/lib/util/language";
import { Snowflake } from "discord-api-types/globals";
import { MessageFlags } from "discord-api-types/v9";
import {
ApplicationCommandOptionChoiceData,
CommandInteractionOption,
Expand Down Expand Up @@ -58,7 +59,7 @@ export default class RemindersDelete extends Command {
interaction.language
);
let text = this.client.util.shortenText(
reminder.get("reminder") as string,
this.client.util.stripMaskedLinks(reminder.get("reminder") as string),
100 - 3 - relativeTime.length
);
text += ` - ${relativeTime}`;
Expand Down Expand Up @@ -114,7 +115,7 @@ export default class RemindersDelete extends Command {
);
return await command.send("REMINDERS_DELETE_CONFIRM", {
text: this.client.util.shortenText(
reminder.text,
this.client.util.supressLinks(reminder.text),
2000 - emptyConfirmMessage.length
),
date: Formatters.time(reminder.date, "R"),
Expand Down
25 changes: 17 additions & 8 deletions src/listeners/button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1303,16 +1303,23 @@ Please choose accurately as it will allow us to help you as quick as possible!
components: [new MessageActionRow().addComponents(dropdown)],
});
} else if (button.customId == "complete_reminder") {
const hasReminderContentEmbed =
button.message.embeds.length &&
// this specific color is used for the embed with the reminder content
// whenever the content is too long for the main message content
button.message.embeds[0].color == 3066993;

let content = (
button.message.content || button.message.embeds[0].description
hasReminderContentEmbed
? button.message.embeds[0].description
: button.message.content
).split("\n");
content = content.map((line) => {
// suppress any embeds
line = line.replace(regexes.basicURL, (url) => `<${url}>`);
if (line.length) return Formatters.strikethrough(line);
if (line.length)
return Formatters.strikethrough(this.client.util.supressLinks(line));
});
return await button.channel.update(
button.message.embeds.length
hasReminderContentEmbed
? {
content: Formatters.strikethrough(button.message.content),
embeds: [
Expand Down Expand Up @@ -1480,9 +1487,11 @@ Please choose accurately as it will allow us to help you as quick as possible!
(option) => +option.value > +new Date()
);
dropdown.options.forEach((option) => (option.default = false));
await button.message.edit({
components: button.message.components,
});
await button.message
.edit({
components: button.message.components,
})
.catch(() => {});
return await button.error("REMINDERS_EDIT_PAST_DATE");
}

Expand Down
59 changes: 40 additions & 19 deletions src/listeners/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ import LoggingConfig from "../commands/Configuration/logging-configure";
import Google from "../commands/Fun/google";
import LogScan from "../commands/Utilities/log-scan";
import ReminderSendEvent from "../ws/events/ReminderSendEvent";
import RemindersCreate from "../commands/Utilities/createremind";

const { regexes } = constants;
const SET_AT_QUERY = "?setAt=";

export default class Select extends Listener {
constructor() {
Expand Down Expand Up @@ -244,9 +246,21 @@ export default class Select extends Listener {

if (select.customId.startsWith(`snooze:${select.author.id}:`)) {
const isContext = select.customId.endsWith(":context");
const originalMessage = (await select.message
.fetchReference()
.catch(() => {})) as FireMessage;
const createRemind = this.client.getCommand(
"reminders-create"
) as RemindersCreate;

let originalMessage: FireMessage;
const referencedId = select.message.reference?.messageId;
if (createRemind.recentlyClicked.has(referencedId)) {
originalMessage =
createRemind.recentlyClicked.get(referencedId).message;
createRemind.recentlyClicked.delete(referencedId);
} else
originalMessage = (await select.message
.fetchReference()
.catch(() => {})) as FireMessage;

if (
// these conditions should all be true for the reminder message
// so if any aren't, it's not usable
Expand All @@ -259,8 +273,7 @@ export default class Select extends Listener {
)
return await select.error("REMINDER_SNOOZE_UNKNOWN");

let hasYouTubeLink = false,
contextText: string;
let contextText: string;
if (isContext) {
// currently we only have a single case for useEmbedDescription
// in createremind.ts so we can just use that condition as the value
Expand All @@ -272,20 +285,19 @@ export default class Select extends Listener {
originalMessage.embeds[0].description;

const hasYouTubeLink = regexes.youtube.video.exec(
originalMessage.content
),
hasYouTubeEmbed = originalMessage.embeds.find((e) =>
e.url.includes(`/watch?v=${hasYouTubeLink?.groups?.video}`)
);
originalMessage.content
);
const hasYouTubeEmbed = originalMessage.embeds.find((e) =>
e.url.includes(`/watch?v=${hasYouTubeLink?.groups?.video}`)
);
regexes.youtube.video.lastIndex = 0;

contextText = useEmbedDescription
? originalMessage.embeds[0].description
: hasYouTubeLink
? hasYouTubeEmbed
contextText =
hasYouTubeLink && hasYouTubeEmbed
? `[${hasYouTubeEmbed.title}](${hasYouTubeEmbed.url})`
: originalMessage.content
: originalMessage.content;
: useEmbedDescription
? originalMessage.embeds[0].description
: originalMessage.content;
}

const currentRemind = {
Expand All @@ -297,12 +309,14 @@ export default class Select extends Listener {
link: originalMessage.components.length
? (originalMessage.components[0].components as MessageButton[]).find(
(button) => button.style == "LINK"
)?.url ?? originalMessage.url
: originalMessage.url,
)?.url ?? originalMessage.url + `?setAt=${+new Date()}`
: originalMessage.url + `?setAt=${+new Date()}`,
};
// if we don't have the text, we can't snooze it so we return an error
if (!currentRemind.text)
return await select.error("REMINDER_SNOOZE_UNKNOWN");
else if (currentRemind.text.length > 4000)
return await select.error("REMINDER_CONTENT_TOO_LONG");

const hasSelectedOther = select.values.find((v) => v == "other");
let specifyTimeModal: ModalMessage;
Expand Down Expand Up @@ -649,6 +663,13 @@ export default class Select extends Listener {
let deconstructed: DeconstructedSnowflake;
if (snowflake) deconstructed = SnowflakeUtil.deconstruct(snowflake);

let reminderSetAt: Date;
if (reminder.link.includes(SET_AT_QUERY)) {
const [link, setAt] = reminder.link.split(SET_AT_QUERY);
reminderSetAt = new Date(parseInt(setAt));
reminder.link = link;
} else if (deconstructed) reminderSetAt = deconstructed.date;

const embed = new MessageEmbed()
.setColor(select.member?.displayColor || "#FFFFFF")
.setAuthor({
Expand All @@ -674,7 +695,7 @@ export default class Select extends Listener {
name: select.language.get(
"REMINDERS_LIST_SELECTED_CREATED_AT_FIELD_NAME"
),
value: Formatters.time(deconstructed.date, "F"),
value: Formatters.time(reminderSetAt, "F"),
},
]);

Expand Down
Loading

0 comments on commit f0c30bf

Please sign in to comment.