generated from nhcarrigan/template
feat: build out initial prototype #1
52
commandJson.js
Normal file
52
commandJson.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import { ApplicationIntegrationType, InteractionContextType, SlashCommandBuilder } from "discord.js";
|
||||
|
||||
const about = new SlashCommandBuilder()
|
||||
.setName("about")
|
||||
.setDescription("Get information about this application.")
|
||||
.setContexts([InteractionContextType.Guild, InteractionContextType.BotDM, InteractionContextType.PrivateChannel])
|
||||
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall]);
|
||||
|
||||
const add = new SlashCommandBuilder()
|
||||
.setName("add")
|
||||
.setDescription("Add a new short URL.")
|
||||
.setContexts([InteractionContextType.Guild, InteractionContextType.BotDM, InteractionContextType.PrivateChannel])
|
||||
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("slug")
|
||||
.setDescription("The slug for the new short URL.")
|
||||
.setRequired(true)
|
||||
.setMaxLength(100),
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("url")
|
||||
.setDescription("The URL to shorten.")
|
||||
.setRequired(true)
|
||||
.setMaxLength(2000),
|
||||
)
|
||||
|
||||
const remove = new SlashCommandBuilder()
|
||||
.setName("remove")
|
||||
.setDescription("Remove a short URL.")
|
||||
.setContexts([InteractionContextType.Guild, InteractionContextType.BotDM, InteractionContextType.PrivateChannel])
|
||||
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("slug")
|
||||
.setDescription("The slug for the short URL to remove.")
|
||||
.setRequired(true)
|
||||
.setMaxLength(100),
|
||||
)
|
||||
const list = new SlashCommandBuilder()
|
||||
.setName("list")
|
||||
.setDescription("List your short URLs.")
|
||||
.setContexts([InteractionContextType.Guild, InteractionContextType.BotDM, InteractionContextType.PrivateChannel])
|
||||
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
|
||||
|
||||
console.log(JSON.stringify([
|
||||
about.toJSON(),
|
||||
add.toJSON(),
|
||||
remove.toJSON(),
|
||||
list.toJSON(),
|
||||
]));
|
||||
@@ -3,6 +3,7 @@
|
||||
"version": "0.0.0",
|
||||
"description": "Link shortening service managed via a Discord bot",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
|
||||
89
src/commands/about.ts
Normal file
89
src/commands/about.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
import {
|
||||
TextDisplayBuilder,
|
||||
SeparatorBuilder,
|
||||
SeparatorSpacingSize,
|
||||
ContainerBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
ActionRowBuilder,
|
||||
MessageFlags,
|
||||
} from "discord.js";
|
||||
import { errorHandler } from "../utils/errorHandler.js";
|
||||
import type { Command } from "../interfaces/command.js";
|
||||
|
||||
/**
|
||||
* Handles the `/about` command interaction.
|
||||
* @param _lynira - Lynira's Discord instance (unused).
|
||||
* @param interaction - The command interaction payload from Discord.
|
||||
*/
|
||||
// eslint-disable-next-line max-lines-per-function -- It's mostly components.
|
||||
export const about: Command = async(_lynira, interaction) => {
|
||||
try {
|
||||
const components = [
|
||||
new ContainerBuilder().
|
||||
addTextDisplayComponents(
|
||||
new TextDisplayBuilder().setContent("# About Lynira"),
|
||||
).
|
||||
addTextDisplayComponents(
|
||||
new TextDisplayBuilder().setContent(
|
||||
// eslint-disable-next-line stylistic/max-len -- Big boi string.
|
||||
"Hi there~! I am Lynira, a bot that allows you to create and delete short URLs. Links will be available under the `lynira.link` domain.",
|
||||
),
|
||||
).
|
||||
addSeparatorComponents(
|
||||
new SeparatorBuilder().
|
||||
setSpacing(SeparatorSpacingSize.Small).
|
||||
setDivider(true),
|
||||
).
|
||||
addTextDisplayComponents(
|
||||
new TextDisplayBuilder().setContent("## What can I do?"),
|
||||
).
|
||||
addTextDisplayComponents(
|
||||
new TextDisplayBuilder().setContent(
|
||||
// eslint-disable-next-line stylistic/max-len -- Big boi string.
|
||||
"To get started, you will need to subscribe to our service. We offer four tiers, each with different limits on the number of short URLs you can create. Once you have subscribed, you can use `/add`, `/delete`, and `/list` to manage your short URLs.",
|
||||
),
|
||||
).
|
||||
addSeparatorComponents(
|
||||
new SeparatorBuilder().
|
||||
setSpacing(SeparatorSpacingSize.Small).
|
||||
setDivider(true),
|
||||
).
|
||||
addTextDisplayComponents(
|
||||
new TextDisplayBuilder().setContent("## What if I need help?"),
|
||||
).
|
||||
addTextDisplayComponents(
|
||||
new TextDisplayBuilder().setContent(
|
||||
// eslint-disable-next-line stylistic/max-len -- Big boi string.
|
||||
"My deepest apologies if I have made a mistake! Please reach out to us in our Discord server or on the forum, and we will do our best to assist you.",
|
||||
),
|
||||
),
|
||||
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder().
|
||||
setStyle(ButtonStyle.Link).
|
||||
setLabel("Discord Server").
|
||||
setURL("https://chat.nhcarrigan.com"),
|
||||
new ButtonBuilder().
|
||||
setStyle(ButtonStyle.Link).
|
||||
setLabel("Forum").
|
||||
setURL("https://forum.nhcarrigan.com"),
|
||||
),
|
||||
];
|
||||
await interaction.editReply({
|
||||
components: components,
|
||||
flags: MessageFlags.IsComponentsV2,
|
||||
});
|
||||
} catch (error) {
|
||||
await errorHandler(error, "about command");
|
||||
await interaction.editReply({
|
||||
content:
|
||||
// eslint-disable-next-line stylistic/max-len -- Big boi string.
|
||||
"An error occurred while processing your request. Please try again later.",
|
||||
});
|
||||
}
|
||||
};
|
||||
74
src/commands/add.ts
Normal file
74
src/commands/add.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
import { reservedSlugs } from "../config/reservedSlugs.js";
|
||||
import { getEntitlement } from "../modules/getEntitlement.js";
|
||||
import { getSkuLimit } from "../modules/getSkuLimit.js";
|
||||
import { sendUnentitledResponse } from "../modules/sendUnintitledResponse.js";
|
||||
import { errorHandler } from "../utils/errorHandler.js";
|
||||
import type { Command } from "../interfaces/command.js";
|
||||
|
||||
/**
|
||||
* Handles the `/add` command interaction.
|
||||
* @param lynira - Lynira's Discord instance.
|
||||
* @param interaction - The command interaction payload from Discord.
|
||||
*/
|
||||
// eslint-disable-next-line max-lines-per-function, max-statements -- This is a larger handler.
|
||||
export const add: Command = async(lynira, interaction) => {
|
||||
try {
|
||||
const subscription = await getEntitlement(lynira, interaction.user.id);
|
||||
if (!subscription) {
|
||||
await sendUnentitledResponse(interaction);
|
||||
return;
|
||||
}
|
||||
const slug = interaction.options.getString("slug", true);
|
||||
if (reservedSlugs.includes(slug)) {
|
||||
await interaction.editReply({
|
||||
content: "This slug is reserved and cannot be used.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const url = interaction.options.getString("url", true);
|
||||
const slugExists = await lynira.db.links.findFirst({ where: {
|
||||
slug,
|
||||
} });
|
||||
if (slugExists) {
|
||||
await interaction.editReply({
|
||||
content: "This slug is already in use. Please choose a different one.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const count = await lynira.db.links.count({
|
||||
where: {
|
||||
deleted: false,
|
||||
userId: interaction.user.id,
|
||||
},
|
||||
});
|
||||
const limit = getSkuLimit(subscription.skuId);
|
||||
if (count >= limit) {
|
||||
await interaction.editReply({
|
||||
content: `You have reached your limit of ${limit.toString()} short URLs.`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
await lynira.db.links.create({
|
||||
data: {
|
||||
slug: slug,
|
||||
url: url,
|
||||
userId: interaction.user.id,
|
||||
},
|
||||
});
|
||||
await interaction.editReply({
|
||||
content: `Short URL created. Visit <https://lynira.link/${slug}> to access it. Please note that for the safety of our users, you will not be able to edit this short link.`,
|
||||
});
|
||||
} catch (error) {
|
||||
await errorHandler(error, "add command");
|
||||
await interaction.editReply({
|
||||
content:
|
||||
// eslint-disable-next-line stylistic/max-len -- Big boi string.
|
||||
"An error occurred while processing your request. Please try again later.",
|
||||
});
|
||||
}
|
||||
};
|
||||
74
src/commands/list.ts
Normal file
74
src/commands/list.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
import {
|
||||
ContainerBuilder,
|
||||
TextDisplayBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
ActionRowBuilder,
|
||||
MessageFlags,
|
||||
} from "discord.js";
|
||||
import { getEntitlement } from "../modules/getEntitlement.js";
|
||||
import { getLinkComponents } from "../modules/getLinkComponents.js";
|
||||
import { getSkuLimit } from "../modules/getSkuLimit.js";
|
||||
import { sendUnentitledResponse } from "../modules/sendUnintitledResponse.js";
|
||||
import { errorHandler } from "../utils/errorHandler.js";
|
||||
import type { Command } from "../interfaces/command.js";
|
||||
|
||||
/**
|
||||
* Handles the `/list` command interaction.
|
||||
* @param lynira - Lynira's Discord instance.
|
||||
* @param interaction - The command interaction payload from Discord.
|
||||
*/
|
||||
export const list: Command = async(lynira, interaction) => {
|
||||
try {
|
||||
const subscription = await getEntitlement(lynira, interaction.user.id);
|
||||
if (!subscription) {
|
||||
await sendUnentitledResponse(interaction);
|
||||
return;
|
||||
}
|
||||
const urls = await lynira.db.links.findMany({
|
||||
where: {
|
||||
deleted: false,
|
||||
userId: interaction.user.id,
|
||||
},
|
||||
});
|
||||
const components: Array<ContainerBuilder | ActionRowBuilder<ButtonBuilder>>
|
||||
= getLinkComponents(urls);
|
||||
components.push(
|
||||
new ContainerBuilder().addTextDisplayComponents(
|
||||
new TextDisplayBuilder().setContent(
|
||||
`You are currently using ${urls.length.toString()} short URL${
|
||||
urls.length === 1
|
||||
? ""
|
||||
: "s"
|
||||
} out of ${getSkuLimit(subscription.skuId).toString()}.`,
|
||||
),
|
||||
),
|
||||
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder().
|
||||
setStyle(ButtonStyle.Link).
|
||||
setLabel("Discord Server").
|
||||
setURL("https://chat.nhcarrigan.com"),
|
||||
new ButtonBuilder().
|
||||
setStyle(ButtonStyle.Link).
|
||||
setLabel("Forum").
|
||||
setURL("https://forum.nhcarrigan.com"),
|
||||
),
|
||||
);
|
||||
await interaction.editReply({
|
||||
components: components,
|
||||
flags: MessageFlags.IsComponentsV2,
|
||||
});
|
||||
} catch (error) {
|
||||
await errorHandler(error, "list command");
|
||||
await interaction.editReply({
|
||||
content:
|
||||
// eslint-disable-next-line stylistic/max-len -- Big boi string.
|
||||
"An error occurred while processing your request. Please try again later.",
|
||||
});
|
||||
}
|
||||
};
|
||||
51
src/commands/remove.ts
Normal file
51
src/commands/remove.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
import { getEntitlement } from "../modules/getEntitlement.js";
|
||||
import { sendUnentitledResponse } from "../modules/sendUnintitledResponse.js";
|
||||
import { errorHandler } from "../utils/errorHandler.js";
|
||||
import type { Command } from "../interfaces/command.js";
|
||||
|
||||
/**
|
||||
* Handles the `/remove` command interaction.
|
||||
* @param lynira - Lynira's Discord instance.
|
||||
* @param interaction - The command interaction payload from Discord.
|
||||
*/
|
||||
export const remove: Command = async(lynira, interaction) => {
|
||||
try {
|
||||
const subscription = await getEntitlement(lynira, interaction.user.id);
|
||||
if (!subscription) {
|
||||
await sendUnentitledResponse(interaction);
|
||||
return;
|
||||
}
|
||||
const slug = interaction.options.getString("slug", true);
|
||||
const slugExists = await lynira.db.links.findFirst({ where: {
|
||||
deleted: false,
|
||||
slug: slug,
|
||||
userId: interaction.user.id,
|
||||
} });
|
||||
if (!slugExists) {
|
||||
await interaction.editReply({
|
||||
content: "This slug does not exist, or does not belong to you.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
await lynira.db.links.delete({
|
||||
where: {
|
||||
id: slugExists.id,
|
||||
},
|
||||
});
|
||||
await interaction.editReply({
|
||||
content: `Short URL <https://lynira.link/${slug}> has been removed. Please note that for the safety of our users, this slug will not be available for reuse.`,
|
||||
});
|
||||
} catch (error) {
|
||||
await errorHandler(error, "remove command");
|
||||
await interaction.editReply({
|
||||
content:
|
||||
// eslint-disable-next-line stylistic/max-len -- Big boi string.
|
||||
"An error occurred while processing your request. Please try again later.",
|
||||
});
|
||||
}
|
||||
};
|
||||
23
src/config/handlers.ts
Normal file
23
src/config/handlers.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { about } from "../commands/about.js";
|
||||
import { add } from "../commands/add.js";
|
||||
import { list } from "../commands/list.js";
|
||||
import type { Command } from "../interfaces/command.js";
|
||||
|
||||
const defaultHandler: Command = async(_lynira, interaction) => {
|
||||
await interaction.editReply({
|
||||
content: "This command is not implemented yet.",
|
||||
});
|
||||
};
|
||||
|
||||
export const handlers: { _default: Command } & Record<string, Command> = {
|
||||
_default: defaultHandler,
|
||||
about: about,
|
||||
add: add,
|
||||
list: list,
|
||||
};
|
||||
12
src/config/reservedSlugs.ts
Normal file
12
src/config/reservedSlugs.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
export const reservedSlugs = [
|
||||
"error",
|
||||
"unsub",
|
||||
"overlimit",
|
||||
"404",
|
||||
];
|
||||
23
src/index.ts
23
src/index.ts
@@ -5,8 +5,10 @@
|
||||
*/
|
||||
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { Client } from "discord.js";
|
||||
import { Client, Events, MessageFlags } from "discord.js";
|
||||
import { handlers } from "./config/handlers.js";
|
||||
import { instantiateServer } from "./server/serve.js";
|
||||
import { logger } from "./utils/logger.js";
|
||||
import type { Lynira } from "./interfaces/lynira.js";
|
||||
|
||||
const lynira: Lynira = {
|
||||
@@ -14,6 +16,25 @@ const lynira: Lynira = {
|
||||
discord: new Client({ intents: [] }),
|
||||
};
|
||||
|
||||
lynira.discord.once("ready", () => {
|
||||
void logger.log("debug", `Logged in as ${lynira.discord.user?.tag ?? "unknown"}`);
|
||||
});
|
||||
|
||||
lynira.discord.on("error", (error) => {
|
||||
void logger.error("Discord client error", error);
|
||||
});
|
||||
|
||||
lynira.discord.on(Events.InteractionCreate, (interaction) => {
|
||||
if (interaction.isChatInputCommand()) {
|
||||
void interaction.deferReply({
|
||||
flags: [ MessageFlags.Ephemeral ],
|
||||
});
|
||||
const { commandName } = interaction;
|
||||
// eslint-disable-next-line no-underscore-dangle -- Accessing private property for command handler.
|
||||
void (handlers[commandName] ?? handlers._default)(lynira, interaction);
|
||||
}
|
||||
});
|
||||
|
||||
await lynira.db.$connect();
|
||||
await lynira.discord.login(process.env.DISCORD_TOKEN);
|
||||
|
||||
|
||||
12
src/interfaces/command.ts
Normal file
12
src/interfaces/command.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
import type { Lynira } from "./lynira.js";
|
||||
import type { ChatInputCommandInteraction } from "discord.js";
|
||||
|
||||
export type Command = (
|
||||
lynira: Lynira,
|
||||
interaction: ChatInputCommandInteraction
|
||||
)=> Promise<void>;
|
||||
29
src/modules/getEntitlement.ts
Normal file
29
src/modules/getEntitlement.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Lynira } from "../interfaces/lynira.js";
|
||||
import type { Entitlement } from "discord.js";
|
||||
|
||||
/**
|
||||
* Fetches an entitlement for a user. Only looks at the first ACTIVE entitlement.
|
||||
* @param lynira - Lynira's Discord instance.
|
||||
* @param userId - The ID of the user to fetch the entitlement for.
|
||||
* @returns The entitlement if found, or null if not found.
|
||||
*/
|
||||
export const getEntitlement = async(
|
||||
lynira: Lynira,
|
||||
userId: string,
|
||||
): Promise<Entitlement | null> => {
|
||||
const entitlements = await lynira.discord.application?.entitlements.fetch({
|
||||
excludeDeleted: true,
|
||||
excludeEnded: true,
|
||||
user: userId,
|
||||
}).catch(() => {
|
||||
return null;
|
||||
});
|
||||
|
||||
return entitlements?.first() ?? null;
|
||||
};
|
||||
33
src/modules/getLinkComponents.ts
Normal file
33
src/modules/getLinkComponents.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { ContainerBuilder, TextDisplayBuilder } from "discord.js";
|
||||
import type { Links } from "@prisma/client";
|
||||
|
||||
/**
|
||||
* Generates an array of components for displaying users' short URLs.
|
||||
* @param links - The array of links to display.
|
||||
* @returns An array of ContainerBuilder components.
|
||||
*/
|
||||
export const getLinkComponents
|
||||
= (links: Array<Links>): Array<ContainerBuilder> => {
|
||||
const components: Array<ContainerBuilder> = [];
|
||||
while (links.length > 0) {
|
||||
const slice = links.splice(0, 50);
|
||||
components.push(
|
||||
new ContainerBuilder().
|
||||
addTextDisplayComponents(
|
||||
new TextDisplayBuilder().setContent(
|
||||
slice.map((link) => {
|
||||
return `- \`${link.slug}\`: ${link.url}`;
|
||||
}).
|
||||
join("\n"),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return components;
|
||||
};
|
||||
48
src/modules/sendUnintitledResponse.ts
Normal file
48
src/modules/sendUnintitledResponse.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
MessageFlags,
|
||||
TextDisplayBuilder,
|
||||
type ChatInputCommandInteraction,
|
||||
} from "discord.js";
|
||||
import { SKU } from "../interfaces/skus.js";
|
||||
|
||||
/**
|
||||
* Responds with a default image and a button to subscribe.
|
||||
* @param interaction - The interaction object from Discord.
|
||||
*/
|
||||
export const sendUnentitledResponse = async(
|
||||
interaction: ChatInputCommandInteraction,
|
||||
): Promise<void> => {
|
||||
const components = [
|
||||
new TextDisplayBuilder().setContent(
|
||||
// eslint-disable-next-line stylistic/max-len -- Big boi string.
|
||||
"Hmm, you do not seem to have an active subscription. If you wish to continue using my services, you will need to rectify that.",
|
||||
),
|
||||
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder().
|
||||
setStyle(ButtonStyle.Premium).
|
||||
setSKUId(SKU.PERSONAL),
|
||||
new ButtonBuilder().
|
||||
setStyle(ButtonStyle.Premium).
|
||||
setSKUId(SKU.PROFESSIONAL),
|
||||
new ButtonBuilder().
|
||||
setStyle(ButtonStyle.Premium).
|
||||
setSKUId(SKU.BUSINESS),
|
||||
new ButtonBuilder().
|
||||
setStyle(ButtonStyle.Premium).
|
||||
setSKUId(SKU.ENTERPRISE),
|
||||
),
|
||||
];
|
||||
await interaction.editReply({
|
||||
components: components,
|
||||
flags: [ MessageFlags.IsComponentsV2 ],
|
||||
});
|
||||
};
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import fastify from "fastify";
|
||||
import { getEntitlement } from "../modules/getEntitlement.js";
|
||||
import { getSkuLimit } from "../modules/getSkuLimit.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { error } from "./html/error.js";
|
||||
@@ -52,7 +53,7 @@ export const instantiateServer = (lynira: Lynira): void => {
|
||||
});
|
||||
|
||||
// WILDCARD: anything static must come before this route.
|
||||
// eslint-disable-next-line max-lines-per-function, max-statements -- Big function due to multiple routes.
|
||||
// eslint-disable-next-line max-statements -- Big function due to multiple routes.
|
||||
server.get("*", async(request, response) => {
|
||||
try {
|
||||
const slug = request.url.replace(/^\//, "");
|
||||
@@ -73,15 +74,7 @@ export const instantiateServer = (lynira: Lynira): void => {
|
||||
return await response.redirect("/404");
|
||||
}
|
||||
|
||||
const subscribed = await lynira.discord.application?.entitlements.fetch(
|
||||
{
|
||||
excludeDeleted: true,
|
||||
excludeEnded: true,
|
||||
user: exists.userId,
|
||||
},
|
||||
);
|
||||
|
||||
const subscription = subscribed?.first();
|
||||
const subscription = await getEntitlement(lynira, exists.userId);
|
||||
|
||||
if (!subscription) {
|
||||
void logger.log("info", `User ${exists.userId} is not subscribed to Lynira, slug ${slug} will not work.`);
|
||||
|
||||
Reference in New Issue
Block a user