Skip to content

Commit 872e98f

Browse files
committed
new commands and improvements
1 parent fca0d85 commit 872e98f

File tree

9 files changed

+389
-15
lines changed

9 files changed

+389
-15
lines changed

src/commands/is-a-dev/check.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ const command: Command = {
4444
}
4545

4646
const res = (await axios.get("https://raw.is-a.dev/v2.json")).data;
47-
const subdomainData = res.find((entry: any) => entry.subdomain === subdomain);
47+
const data = res.find((entry: any) => entry.subdomain === subdomain);
4848

49-
if (!subdomainData) {
49+
if (!data) {
5050
const available = new Discord.EmbedBuilder()
5151
.setColor(client.config.embeds.default as ColorResolvable)
5252
.setDescription(`${emoji.tick} \`${subdomain}.is-a.dev\` is available!`);
@@ -60,14 +60,14 @@ const command: Command = {
6060

6161
await interaction.editReply({ embeds: [available], components: [registerButton] });
6262
return;
63-
} else if (subdomainData.internal) {
63+
} else if (data.internal) {
6464
const internal = new Discord.EmbedBuilder()
6565
.setColor(client.config.embeds.error as ColorResolvable)
6666
.setDescription(`${emoji.cross} \`${subdomain}.is-a.dev\` is being used internally.`);
6767

6868
await interaction.editReply({ embeds: [internal] });
6969
return;
70-
} else if (subdomainData.reserved) {
70+
} else if (data.reserved) {
7171
const reserved = new Discord.EmbedBuilder()
7272
.setColor(client.config.embeds.error as ColorResolvable)
7373
.setDescription(`${emoji.cross} \`${subdomain}.is-a.dev\` is reserved.`);
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import Command from "../../classes/Command";
2+
import ExtendedClient from "../../classes/ExtendedClient";
3+
import { AutocompleteInteraction, ChatInputCommandInteraction, ColorResolvable } from "discord.js";
4+
5+
import axios from "axios";
6+
import { emojis as emoji } from "../../../config.json";
7+
8+
const command: Command = {
9+
name: "get-domain-json",
10+
description: "Get a subdomain's JSON file.",
11+
options: [
12+
{
13+
type: 3,
14+
name: "subdomain",
15+
description: "The subdomain you want to get the JSON file for.",
16+
max_length: 253 - ".is-a.dev".length,
17+
required: true,
18+
autocomplete: true
19+
}
20+
],
21+
botPermissions: [],
22+
requiredRoles: [],
23+
cooldown: 5,
24+
enabled: true,
25+
deferReply: true,
26+
ephemeral: false,
27+
async execute(
28+
interaction: ChatInputCommandInteraction,
29+
client: ExtendedClient,
30+
Discord: typeof import("discord.js")
31+
) {
32+
try {
33+
const subdomain = interaction.options.get("subdomain").value as string;
34+
35+
const hostnameRegex =
36+
/^(?=.{1,253}$)(?:(?:[_a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)\.)+[a-zA-Z]{2,63}$/;
37+
38+
if (!hostnameRegex.test(`${subdomain}.is-a.dev`)) {
39+
const invalidSubdomain = new Discord.EmbedBuilder()
40+
.setColor(client.config.embeds.error as ColorResolvable)
41+
.setDescription(`${emoji.cross} \`${subdomain}\` is not a valid subdomain.`);
42+
43+
await interaction.editReply({ embeds: [invalidSubdomain] });
44+
return;
45+
}
46+
47+
const data = (await axios.get(`https://raw.githubusercontent.com/is-a-dev/register/main/domains/${subdomain}.json`)).data;
48+
49+
if (data.internal || data.reserved) {
50+
const internalError = new Discord.EmbedBuilder()
51+
.setColor(client.config.embeds.error as ColorResolvable)
52+
.setDescription(
53+
`${emoji.cross} \`${subdomain}.is-a.dev\` is an internal or reserved subdomain and cannot be accessed.`
54+
);
55+
56+
await interaction.editReply({ embeds: [internalError] });
57+
return;
58+
}
59+
60+
if (!data) {
61+
const noResult = new Discord.EmbedBuilder()
62+
.setColor(client.config.embeds.error as ColorResolvable)
63+
.setDescription(`${emoji.cross} \`${subdomain}.is-a.dev\` does not exist.`);
64+
65+
await interaction.editReply({ embeds: [noResult] });
66+
return;
67+
}
68+
69+
const result = new Discord.EmbedBuilder()
70+
.setColor(client.config.embeds.default as ColorResolvable)
71+
.setTitle(`${subdomain}.is-a.dev`)
72+
.setDescription(`\`\`\`json\n${JSON.stringify(data, null, 2)}\n\`\`\``)
73+
.setTimestamp();
74+
75+
await interaction.editReply({ embeds: [result] });
76+
} catch (err) {
77+
client.logCommandError(err, interaction, Discord);
78+
}
79+
},
80+
autocomplete: async (interaction: AutocompleteInteraction, client: ExtendedClient) => {
81+
const option = interaction.options.getFocused(true);
82+
83+
if (option.name === "subdomain") {
84+
// Fetch all subdomains
85+
const res = (await axios.get("https://raw.is-a.dev/v2.json")).data;
86+
87+
// Filter subdomains
88+
const filteredSubdomains = res.filter((entry: any) => entry.subdomain.startsWith(option.value) && !entry.internal && !entry.reserved);
89+
90+
// Map subdomains to choices
91+
const choices = filteredSubdomains
92+
.map((entry: any) => {
93+
return {
94+
name: entry.subdomain,
95+
value: entry.subdomain
96+
};
97+
})
98+
.slice(0, 25);
99+
100+
await interaction.respond(choices);
101+
}
102+
}
103+
};
104+
105+
export = command;

src/commands/is-a-dev/redirect-config.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ const command: Command = {
3333
const subdomain = interaction.options.get("subdomain").value;
3434

3535
const res = (await axios.get("https://raw.is-a.dev/v2.json")).data;
36-
const subdomainData = res.find((entry: any) => entry.subdomain === subdomain);
36+
const data = res.find((entry: any) => entry.subdomain === subdomain);
3737

38-
if (!subdomainData) {
38+
if (!data) {
3939
const noResult = new Discord.EmbedBuilder()
4040
.setColor(client.config.embeds.error as ColorResolvable)
4141
.setDescription(`${emoji.cross} \`${subdomain}.is-a.dev\` does not exist.`);
@@ -44,7 +44,7 @@ const command: Command = {
4444
return;
4545
}
4646

47-
if (!subdomainData.records.URL && !subdomainData?.redirect_config?.custom_paths) {
47+
if (!data.records.URL && !data?.redirect_config?.custom_paths) {
4848
const noResult = new Discord.EmbedBuilder()
4949
.setColor(client.config.embeds.error as ColorResolvable)
5050
.setDescription(`${emoji.cross} \`${subdomain}.is-a.dev\` does not have any URL configurations.`);
@@ -57,18 +57,18 @@ const command: Command = {
5757
.setColor(client.config.embeds.default as ColorResolvable)
5858
.setTitle(`${subdomain}.is-a.dev`);
5959

60-
if (subdomainData.records.URL) {
61-
urlRecord.setDescription(`${subdomainData.records.URL}`);
60+
if (data.records.URL) {
61+
urlRecord.setDescription(`${data.records.URL}`);
6262
urlRecord.addFields({
6363
name: "Redirect Paths",
64-
value: subdomainData?.redirect_config?.redirect_paths ? emoji.tick : emoji.cross,
64+
value: data?.redirect_config?.redirect_paths ? emoji.tick : emoji.cross,
6565
});
6666
}
6767

68-
if (subdomainData?.redirect_config?.custom_paths) {
68+
if (data?.redirect_config?.custom_paths) {
6969
urlRecord.addFields({
7070
name: "Custom Paths",
71-
value: Object.entries(subdomainData.redirect_config.custom_paths)
71+
value: Object.entries(data.redirect_config.custom_paths)
7272
.map(([path, url]) => `\`${path}\`: ${url}`)
7373
.join("\n"),
7474
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import Command from "../../classes/Command";
2+
import ExtendedClient from "../../classes/ExtendedClient";
3+
import { ChatInputCommandInteraction, ColorResolvable } from "discord.js";
4+
5+
import axios from "axios";
6+
import { emojis as emoji } from "../../../config.json";
7+
8+
const command: Command = {
9+
name: "reserved-domains",
10+
description: "Get a list of all the reserved domains.",
11+
options: [],
12+
botPermissions: [],
13+
requiredRoles: ["maintainer"],
14+
cooldown: 5,
15+
enabled: true,
16+
deferReply: true,
17+
ephemeral: true,
18+
async execute(
19+
interaction: ChatInputCommandInteraction,
20+
client: ExtendedClient,
21+
Discord: typeof import("discord.js")
22+
) {
23+
try {
24+
const res = (await axios.get("https://raw.is-a.dev/v2.json")).data;
25+
const data = res
26+
.filter((entry: any) => entry.reserved)
27+
.sort((a: any, b: any) => a.subdomain.localeCompare(b.subdomain));
28+
29+
if (!data) {
30+
const noResult = new Discord.EmbedBuilder()
31+
.setColor(client.config.embeds.error as ColorResolvable)
32+
.setDescription(`${emoji.cross} There are no reserved domains.`);
33+
34+
await interaction.editReply({ embeds: [noResult] });
35+
return;
36+
}
37+
38+
const result = new Discord.EmbedBuilder()
39+
.setColor(client.config.embeds.default as ColorResolvable)
40+
.setTitle("Reserved Subdomains")
41+
.setDescription(
42+
data
43+
.map((d: any) => `\`${d.subdomain}\``)
44+
.join(", ")
45+
)
46+
.setTimestamp();
47+
48+
await interaction.editReply({ embeds: [result] });
49+
} catch (err) {
50+
client.logCommandError(err, interaction, Discord);
51+
}
52+
}
53+
};
54+
55+
export = command;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import Command from "../../classes/Command";
2+
import ExtendedClient from "../../classes/ExtendedClient";
3+
import { ChatInputCommandInteraction, ColorResolvable } from "discord.js";
4+
5+
import axios from "axios";
6+
import { emojis as emoji } from "../../../config.json";
7+
8+
const command: Command = {
9+
name: "staff-domains",
10+
description: "Get a list of all the staff domains.",
11+
options: [],
12+
botPermissions: [],
13+
requiredRoles: ["maintainer"],
14+
cooldown: 5,
15+
enabled: true,
16+
deferReply: true,
17+
ephemeral: true,
18+
async execute(
19+
interaction: ChatInputCommandInteraction,
20+
client: ExtendedClient,
21+
Discord: typeof import("discord.js")
22+
) {
23+
try {
24+
const res = (await axios.get("https://raw.is-a.dev/v2.json")).data;
25+
const data = res
26+
.filter((entry: any) => entry.owner.username === "is-a-dev" && !entry.reserved)
27+
.sort((a: any, b: any) => a.subdomain.localeCompare(b.subdomain));
28+
29+
if (!data) {
30+
const noResult = new Discord.EmbedBuilder()
31+
.setColor(client.config.embeds.error as ColorResolvable)
32+
.setDescription(`${emoji.cross} There are no staff domains.`);
33+
34+
await interaction.editReply({ embeds: [noResult] });
35+
return;
36+
}
37+
38+
const result = new Discord.EmbedBuilder()
39+
.setColor(client.config.embeds.default as ColorResolvable)
40+
.setTitle("Staff Domains")
41+
.setDescription(
42+
data
43+
.map((d: any) => (d.internal ? `- \`${d.domain}\` :gear:` : `- \`${d.domain}\``))
44+
.join("\n")
45+
)
46+
.setFooter({ text: "⚙️ Internal" })
47+
.setTimestamp();
48+
49+
await interaction.editReply({ embeds: [result] });
50+
} catch (err) {
51+
client.logCommandError(err, interaction, Discord);
52+
}
53+
}
54+
};
55+
56+
export = command;
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import Command from "../../classes/Command";
2+
import ExtendedClient from "../../classes/ExtendedClient";
3+
import { ChatInputCommandInteraction, ColorResolvable } from "discord.js";
4+
5+
import axios from "axios";
6+
7+
const command: Command = {
8+
name: "statistics",
9+
description: "Get a bunch of statistics about is-a.dev.",
10+
options: [],
11+
botPermissions: [],
12+
requiredRoles: [],
13+
cooldown: 5,
14+
enabled: true,
15+
deferReply: true,
16+
ephemeral: false,
17+
async execute(
18+
interaction: ChatInputCommandInteraction,
19+
client: ExtendedClient,
20+
Discord: typeof import("discord.js")
21+
) {
22+
try {
23+
const res = (await axios.get("https://raw.is-a.dev/v2.json")).data;
24+
const data = res.filter(
25+
(entry: any) => entry.owner.username !== "is-a-dev" && !entry.internal && !entry.reserved
26+
);
27+
28+
const statistics = new Discord.EmbedBuilder()
29+
.setColor(client.config.embeds.default as ColorResolvable)
30+
.setTitle("is-a.dev Statistics")
31+
.setTimestamp();
32+
33+
const mainStats = [];
34+
const recordStats: any = {};
35+
36+
const owners = new Set(data.map((entry: any) => entry.owner.username.toLowerCase()));
37+
38+
mainStats.push(`Subdomains: \`${data.length}\``);
39+
mainStats.push(`Users: \`${owners.size}\``);
40+
41+
let totalRecords = 0;
42+
43+
for (const domain of data) {
44+
for (const [recordType, recordValue] of Object.entries(domain.records)) {
45+
if (!recordStats[recordType]) recordStats[recordType] = 0;
46+
if (Array.isArray(recordValue)) {
47+
recordStats[recordType] += recordValue.length;
48+
totalRecords += recordValue.length;
49+
} else {
50+
recordStats[recordType]++;
51+
totalRecords++;
52+
}
53+
}
54+
}
55+
56+
mainStats.push(`DNS Records: \`${totalRecords}\``);
57+
58+
statistics.addFields(
59+
{ name: "General", value: mainStats.join("\n"), inline: true },
60+
{
61+
name: "DNS Records",
62+
value: Object.entries(recordStats)
63+
.sort(([a], [b]) => a.localeCompare(b))
64+
.map(([type, count]) => `${type.toUpperCase()}: \`${count}\``)
65+
.join("\n"),
66+
inline: true
67+
}
68+
);
69+
70+
const customPaths = data.filter((entry: any) => entry.redirect_config?.custom_paths).length;
71+
const redirectPaths = data.filter((entry: any) => entry.redirect_config?.redirect_paths).length;
72+
73+
statistics.addFields({
74+
name: "Redirect Config",
75+
value: `Custom Redirect Paths: \`${customPaths}\`\nRedirecting Paths: \`${redirectPaths}\``,
76+
inline: true
77+
});
78+
79+
await interaction.editReply({ embeds: [statistics] });
80+
} catch (err) {
81+
client.logCommandError(err, interaction, Discord);
82+
}
83+
}
84+
};
85+
86+
export = command;

src/commands/is-a-dev/whois.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ const command: Command = {
5151
iconURL: `https://github.com/${data.owner?.username}.png`,
5252
url: `https://github.com/${data.owner?.username}`
5353
})
54-
.setTitle(`${subdomain}.is-a.dev`);
54+
.setTitle(`${subdomain}.is-a.dev`)
55+
.setTimestamp();
5556

5657
if (!data.internal && !data.reserved) {
5758
if (!subdomain.includes("_")) {
@@ -143,7 +144,7 @@ const command: Command = {
143144
}
144145

145146
if (records.length > 0 && !data.reserved && !data.internal) {
146-
whoisResult.setDescription(`### DNS Records\n${records.join("\n")}`);
147+
whoisResult.setDescription(`**DNS Records**\n\n${records.join("\n")}`);
147148
}
148149

149150
if (data?.redirect_config?.custom_paths) {

0 commit comments

Comments
 (0)