feat: updated plugins to co-ordinate with automations (#36)

This commit is contained in:
Evo
2023-09-02 20:18:21 +05:30
committed by GitHub
parent ab5550d7de
commit 0bff31afd1
21 changed files with 99 additions and 120 deletions

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@
.env
.vscode/
.idea/
pluginlist.json
# Yarn files
.yarn/install-state.gz
.yarn/build-state.yml

View File

@@ -1,5 +1,5 @@
import { commandModule, CommandType } from "@sern/handler";
import type { TagMessage } from "../../types";
import type { TagMessage } from "typings";
export default commandModule({
type: CommandType.Button,

View File

@@ -1,7 +1,8 @@
import { commandModule, CommandType } from "@sern/handler";
import { existsSync, writeFileSync } from "fs";
import type { TagData } from "../../types";
import type { TagData } from "typings";
import { createRequire } from "module";
import { TagList } from "#constants";
const require = createRequire(import.meta.url);
export default commandModule({
@@ -32,7 +33,7 @@ export default commandModule({
const tags = [tag];
writeFileSync(filePath, JSON.stringify(tags, null, 2));
} else {
const file: TagData[] = require(`${process.cwd()}/tags.json`);
const file: TagData[] = require(TagList);
if (file.find((t) => t.name === tagName)) {
return ctx.reply(`Tag __${tagName}__ already exists`);

View File

@@ -1,7 +1,8 @@
import { TagList } from "#constants";
import { commandModule, CommandType } from "@sern/handler";
import { writeFileSync } from "fs";
import { createRequire } from "module";
import type { TagData } from "../../types";
import type { TagData } from "typings";
const require = createRequire(import.meta.url);
export default commandModule({
@@ -25,7 +26,7 @@ export default commandModule({
: [],
};
const filePath = `./tags.json`;
const file: TagData[] = require(`${process.cwd()}/tags.json`);
const file: TagData[] = require(TagList);
const oldTag = file.find((t) => t.name === (ctx.user.data as { tag: string }).tag)!;
const similarKeywords = file.filter(

View File

@@ -1,7 +1,8 @@
import { ApplicationCommandOptionType, EmbedBuilder } from "discord.js";
import { cooldown, publish } from "#plugins";
import { parse } from "jsdoc-parse-plus";
import { slashCommand } from "#utils";
import { slashCommand, require, cutText } from "#utils";
import type { Plugin } from "typings";
import { PluginList } from "#constants";
export default slashCommand({
description: "View sern plugins",
@@ -15,17 +16,20 @@ export default slashCommand({
command: {
onEvent: [],
async execute(ctx) {
const { cache } = ctx.client;
const focus = ctx.options.getFocused();
if (!cache) return ctx.respond([{ name: "No plugins found", value: "" }]);
const data = [...cache.values()] as Data[];
const plugins = require(PluginList) as Plugin[];
const focus = ctx.options.getFocused();
if (!plugins.length) return ctx.respond([{ name: "No plugins found", value: "" }]);
const filtered = plugins.filter((p) =>
p.name.toLowerCase().includes(focus.toLowerCase())
);
const plugins = data.map((d) => {
const name = d.name.replace(".ts", "");
return { name, value: d.download_url };
});
return ctx.respond(
plugins.filter((p) => p.name.toLowerCase().includes(focus?.toLowerCase()))
filtered.map((p) => ({
name: p.name,
value: p.link,
}))
);
},
},
@@ -41,38 +45,38 @@ export default slashCommand({
),
],
async execute(ctx, [, options]) {
if (!ctx.client.cache) return ctx.reply("Plugins are uncached, contact Evo!");
const plugins = require(PluginList) as Plugin[];
if (!plugins.length) return ctx.reply("Plugins are uncached, contact Evo!");
const url = options.getString("plugin", true);
const name = ctx.client.cache.findKey((d) => d.download_url === url) as string;
const plugin = plugins.find((p) => p.link === url);
if (!name || !ctx.client.cache.get(name)!.rawData)
if (!plugin) {
return ctx.reply(`No plugin found at this [link](<${url}>)`);
const JSdoc = parse(ctx.client.cache.get(name)!.rawData) as A;
const github = `https://github.com/sern-handler/awesome-plugins/blob/main/TypeScript/${name}.ts`;
}
const embed = new EmbedBuilder()
.setColor("Random")
.setTimestamp()
.setTitle(`${name}`)
.setURL(github)
.setTitle(plugin.name)
.setURL(plugin.link)
.setFields(
{
name: "Description",
value: JSdoc.description.value,
value: plugin.description,
},
{
name: "Version",
value: JSdoc.version.value,
value: plugin.version,
},
{
name: "Author",
value: parseAuthor(JSdoc.author.value),
value: plugin.author.map(parseAuthor).join("\n"),
},
{
name: "Example",
value: (JSdoc as unknown as B).example[0].value,
value: plugin.example,
}
);
@@ -94,20 +98,3 @@ export interface Data {
download_url: string;
rawData: string;
}
interface ParsedData {
author: DocData;
description: DocData;
version: DocData;
example: DocData[];
requires?: DocData[];
}
interface DocData {
tag: string;
value: string;
raw: string;
}
type A = Record<keyof ParsedData, DocData>;
type B = Record<keyof ParsedData, DocData[]>;

View File

@@ -1,13 +1,11 @@
import { Collection, Client } from "discord.js";
import { fetch } from "undici";
import type { Data } from "./plugin.js";
import { ownerOnly, publish, refreshCache } from "#plugins";
import { Evo } from "#constants";
import { writeFileSync } from "fs";
import { ownerOnly, publish } from "#plugins";
import { Evo, PluginList } from "#constants";
import { slashCommand } from "#utils";
import type { Plugin } from "typings";
export default slashCommand({
plugins: [
refreshCache(),
publish({
dmPermission: false,
defaultMemberPermissions: ["Administrator"],
@@ -16,31 +14,25 @@ export default slashCommand({
],
description: "refresh plugins cache",
async execute(ctx) {
const success = await cp(ctx.client);
if (!success)
return ctx.reply({
content: "Fetch failed!",
ephemeral: true,
});
return ctx.reply({
content: `Refreshed Plugins! [${success.size} plugins]`,
ephemeral: true,
await ctx.interaction.deferReply({ ephemeral: true });
const size = await cp();
if (!size) return ctx.interaction.editReply({ content: "Fetch failed!" });
return ctx.interaction.editReply({
content: `Refreshed ${size} Plugins!`,
});
},
});
export async function cp(client: Client) {
const cache: Collection<string, Data> = new Collection();
const link = `https://api.github.com/repos/sern-handler/awesome-plugins/contents/TypeScript`;
/**
* Downloads the plugin list from github and writes it to the cache
* @returns {Promise<number | null>} The number of plugins fetched
*/
export async function cp(): Promise<number | null> {
const link = `https://raw.githubusercontent.com/sern-handler/awesome-plugins/main/pluginlist.json`;
const resp = await fetch(link).catch(() => null);
if (!resp) return null;
const dataArray = (await resp.json()) as Data[];
// TODO: use octokit instead of fetch
for (const data of dataArray) {
const name = data.name.replace(".ts", "");
data.rawData = await (await fetch(data.download_url)).text().catch(() => "");
cache.set(name, data);
}
client.cache = cache;
return cache;
const dataArray = (await resp.json()) as Plugin[];
writeFileSync(PluginList, JSON.stringify(dataArray, null, 2), { flag: "w" });
return dataArray.length;
}

View File

@@ -1,11 +1,9 @@
import { ApplicationCommandOptionType, EmbedBuilder } from "discord.js";
import { existsSync } from "fs";
import { publish } from "#plugins";
import { Paginator, slashCommand } from "#utils";
import { createRequire } from "module";
import type { TagData } from "../types/index.js";
const require = createRequire(import.meta.url);
import { Paginator, slashCommand, require } from "#utils";
import { Tag, type TagData } from "typings";
import { TagList } from "#constants";
export default slashCommand({
description: "Send a tag",
@@ -30,12 +28,11 @@ export default slashCommand({
command: {
onEvent: [],
execute(ctx) {
const filePath = `./tags.json`;
const focus = ctx.options.getFocused();
if (!existsSync(filePath)) {
if (!existsSync(`./tags.json`)) {
return ctx.respond([{ name: "No tags found", value: "" }]);
} else {
const file: TagData[] = require(`${process.cwd()}/tags.json`);
const file: TagData[] = require(TagList);
const tags = file.map((t) => t.name);
return ctx.respond(
tags
@@ -62,7 +59,7 @@ export default slashCommand({
const subCmd = options.getSubcommand();
switch (subCmd) {
case "list": {
const file: TagData[] = require(`${process.cwd()}/tags.json`);
const file: TagData[] = require(TagList);
const embeds = file.map((tag) => {
const embed = new EmbedBuilder()
.setTitle(tag.name)
@@ -91,7 +88,7 @@ export default slashCommand({
const user = options.getUser("target");
const mention = user ? `**Tag suggestion for:** ${user}\n\n` : "";
const tag = options.getString("tag", true);
const file: TagData[] = require(`${process.cwd()}/tags.json`);
const file: TagData[] = require(TagList);
const tagData = file.find((t) => t.name === tag);
if (!tagData) {
return ctx.reply(`No tag found with name __${tag}__`);

View File

@@ -7,9 +7,9 @@ import {
} from "discord.js";
import { existsSync, writeFileSync } from "fs";
import { createRequire } from "module";
import { Evo, Seren } from "#constants";
import { Evo, Seren, TagList } from "#constants";
import { ownerOnly, publish } from "#plugins";
import type { TagData } from "../types";
import type { TagData } from "typings";
import { slashCommand } from "#utils";
const require = createRequire(import.meta.url);
@@ -41,7 +41,7 @@ export default slashCommand({
if (!existsSync(filePath)) {
return ctx.respond([{ name: "No tags found", value: "" }]);
} else {
const file: TagData[] = require(`${process.cwd()}/tags.json`);
const file: TagData[] = require(TagList);
const tags = file.map((t) => t.name);
return ctx.respond(
tags
@@ -75,7 +75,7 @@ export default slashCommand({
if (!existsSync(filePath)) {
return ctx.respond([{ name: "No tags found", value: "" }]);
} else {
const file: TagData[] = require(`${process.cwd()}/tags.json`);
const file: TagData[] = require(TagList);
const tags = file.map((t) => t.name);
return ctx.respond(
tags
@@ -95,7 +95,7 @@ export default slashCommand({
const [, options] = args;
const subcmd = options.getSubcommand();
const file: TagData[] = require(`${process.cwd()}/tags.json`);
const file: TagData[] = require(TagList);
if (subcmd === "create") {
const modal = new ModalBuilder().setTitle("Tag Creation").setCustomId("@sern/tag/create");
@@ -185,7 +185,7 @@ export default slashCommand({
return context.reply("Tag not found");
}
file.splice(file.indexOf(tagData), 1);
writeFileSync(`${process.cwd()}/tags.json`, JSON.stringify(file, null, 2));
writeFileSync(TagList, JSON.stringify(file, null, 2));
return context.reply(`Tag ${tag} deleted`);
}

View File

@@ -13,3 +13,6 @@ export const enum Emojis {
IssueClosed = "<:issue_closed:1101716515771920424>",
IssueNotPlanned = "<:issue_notplanned:1101719419434045540>",
}
export const PluginList = `${process.cwd()}/pluginlist.json`;
export const TagList = `${process.cwd()}/tags.json`;

View File

@@ -2,9 +2,10 @@ import { eventModule, EventType } from "@sern/handler";
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, Message } from "discord.js";
import { createRequire } from "module";
import { FuzzyMatcher } from "../utils/FuzzyMatcher.js";
import type { TagData, TagMessage } from "../types/index.js";
import type { TagData, TagMessage } from "typings";
import { TagList } from "#constants";
const require = createRequire(import.meta.url);
const file: TagData[] = require(`${process.cwd()}/tags.json`);
const file: TagData[] = require(TagList);
export default eventModule({
type: EventType.Discord,

View File

@@ -3,6 +3,7 @@ import { Dependencies, Sern, single, Singleton } from "@sern/handler";
import "dotenv/config";
import { randomStatus, SernLogger /*CommandSyncer*/ } from "#utils";
import { Octokit } from "@octokit/rest";
import { cp } from "./commands/refresh.js";
const client = new Client({
intents: [
@@ -48,10 +49,11 @@ Sern.init({
},
});
client.once("ready", (client) => {
client.once("ready", async (client) => {
randomStatus(client);
const [logger] = useContainer("@sern/logger");
logger.info({ message: `[✅]: Logged in as ${client.user.username}` });
await cp();
});
await client.login();

View File

@@ -2,4 +2,3 @@ export * from "./channelOnly.js";
export * from "./cooldown.js";
export * from "./ownerOnly.js";
export * from "./publish.js";
export * from "./refreshCache.js";

View File

@@ -1,26 +0,0 @@
import {
CommandInitPlugin,
CommandPlugin,
CommandType,
controller,
PluginType,
} from "@sern/handler";
import type { Collection } from "discord.js";
import { cp } from "../commands/refresh.js";
import type { Data } from "../commands/plugin.js";
import { useContainer } from "../../src/index.js";
export function refreshCache() {
return CommandInitPlugin<CommandType.Slash>(async (payload) => {
const [client] = useContainer("@sern/client");
const cache = await cp(client);
client.cache = cache;
return controller.next();
});
}
declare module "discord.js" {
interface Client {
cache: Collection<string, Data> | null;
data: unknown;
}
}

View File

@@ -1 +0,0 @@
export * from "./Tags.js";

View File

@@ -1,6 +1,6 @@
import type { Message, User } from "discord.js";
import { findBestMatch } from "string-similarity";
import type { TagData } from "../types/index.js";
import type { TagData } from "typings";
export class FuzzyMatcher {
public constructor(private readonly message: Message, private readonly tags: TagData[]) {}

6
src/utils/cutText.ts Normal file
View File

@@ -0,0 +1,6 @@
export function cutText(text: string) {
if (text.length > 100) {
return text.slice(0, 97) + "...";
}
return text;
}

View File

@@ -8,4 +8,6 @@ export * from "./randomStatus.js";
export * from "./codeUpload.js";
export * from "./Logger.js";
export * from "./composable/slashCommand.js";
export * from "./require.js";
export * from "./cutText.js";
//export * from './SyncCommands.js';

2
src/utils/require.ts Normal file
View File

@@ -0,0 +1,2 @@
import { createRequire } from "module";
export const require = createRequire(import.meta.url);

3
typings/index.ts Normal file
View File

@@ -0,0 +1,3 @@
export * from './docs.js'
export * from './plugin.js'
export * from './Tags.js'

9
typings/plugin.ts Normal file
View File

@@ -0,0 +1,9 @@
export interface Plugin {
description: string;
hash: string;
name: string;
author: string[];
link: string;
example: string;
version: string;
}