Skip to content

Centralized all messages and console logs #230

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions localization.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# Console errors

roles_channel_doesnt_exists: Roles channel ($(rolesChannelId)) does not exist or is not text based.
roles_message_doesnt_exists: Role message does not exist for $(id)
to_be_forum_channel: Expected $(channel) to be a forum channel.
to_be_text_channel: Expected $(channel) to be a text channel.

# Console info

role_gave: Gave role $(role) to $(member)
role_removed: Removed role $(role) from $(member)
searching_algolia: Searching algolia for $(content)
algolia_response: 'Algolia response: $(data)'
new_request: |
Received new question from
$(owner)
in thread
$(thread)
creating_rep: Creating a Rep with recipient $(recipient)
received_rep: Received rep reaction on $(message)
querying_for_rep: Querying database for existing Rep
rep_exist_found: Found existing rep $(rep)
user_is_recipient: User is recipient; removing reaction
existing_amount_is: Existing amount is $(count)
incremented_amount: Incremented amount to $(amount)
recipient_is_bot: Recipient is bot; checking for message ownership
no_message_owner: No message owner recorded; removing reaction
message_owner_is: Message owner is $(owner)
decremented_rep: |
Decremented rep amount to
$(amount)
for message
$(id)

# Commands

command_ping:
description: See if the bot is alive
listener_message: 'pong. :ping_pong:'

handbook_command:
description: Search the TypeScript Handbook
listener:
no_results_found: ':x: No results found for that query'

help_command:
description: Sends what you're looking at right now
listener:
snippet_created: A custom snippet created by $(owner)
snippet_not_created: Run the first snippet that matches that pattern
command_not_found: ':x: Command not found'

helpers_command:
description: 'Help System: Ping the @Helper role from a help post'
listener:
not_help_channel: ':warning: You may only ping helpers from a help post'
only_asker: ':warning: Only the asker can ping helpers'
pls_wait: ':warning: Please wait a bit longer. You can ping helpers $(time)'

playground_command:
description: Shorten a TypeScript playground link
listener:
log: Playground $(content)
not_code: ":warning: couldn't find a codeblock!"

resolved_command:
description: 'Help System: Mark a post as resolved'

reopen_command:
description: 'Help System: Reopen a resolved post'

reputation_command:
description: 'Reputation: Give a different user some reputation points'

history_command:
description: "Reputation: View a user's reputation history"
listener:
cannot_find: Unable to find user to give rep

leaderboard_command:
description: 'Reputation: See who has the most reputation'
listener:
invalid_period: ':x: Invalid period (expected one of $(of))'

snippets_command:
description: 'Snippet: List snippets matching an optional filter'

snippet_command:
description: 'Snippet: Create or edit a snippet'
listener:
not_name: ':x: You have to supply a name for the command'
dont_have_permissions: ":x: You don't have permission to create a global snippet"
cannot_edit: ":x: Cannot edit another user's snippet"
second_arg: ':x: Second argument must be a valid discord message link or snippet id'
have_reply: ':x: You have to reply or link to a comment to make it a snippet'
cannot_generate: ':x: Cannot generate a snippet from that message'

delete_snippet_command:
description: 'Snippet: Delete a snippet you own'
listener:
not_found: ':x: No snippet found with that id'
cannot_delete: ":x: Cannot delete another user's snippet"
snippet_deleted_log: Deleted snippet $(id) for $(author)
snippet_deleted_msg: ':white_check_mark: Deleted snippet'

twoslash_command:
description: 'Twoslash: Run twoslash on the latest codeblock, optionally returning the quick infos of specified symbols. You can use [email protected] or ts@next to run a specific version.'
listener:
cannot_find: ':x: Could not find that version of TypeScript'
not_codeblocks: ':warning: could not find any TypeScript codeblocks in the past 10 messages'
invalid_symbol: You need to give me a valid symbol name to look for!

# Events

polling_finished: 'Polling finished; result: $(pollingResultStr)'

# Embeds

handbook_embed:
title: The TypeScript Handbook
url: https://www.typescriptlang.org/docs/handbook/intro.html
footer:
text: You can search with `!handbook <query>`

help_command_embed:
title: Bot Usage
description: Hello $(username)! Here is a list of all commands in me! To get detailed description on any specific command, do `help <command>`

playground_command_embed:
title: View in Playground

playground_link_embed:
title: Playground Link

# Messages

forum_how_to_get_help: |
**How To Get Help**
- Create a new post $(post) with your question.
- It's always ok to just ask your question; you don't need permission.
- Someone will (hopefully!) come along and help you.
- When your question is resolved, type `!resolved`.
\u200b
**How To Get Better Help**
- Explain what you want to happen and why…
- …and what actually happens, and your best guess at why.
- Include a short code sample and any error messages you got.
- Text is better than screenshots. Start code blocks with ```ts.
- If possible, create a minimal reproduction in the TypeScript Playground: <https://www.typescriptlang.org/play>.
- Send the full link in its own message; do not use a link shortener.
- For more tips, check out StackOverflow's guide on asking good questions: <https://stackoverflow.com/help/how-to-ask>
\u200b
**If You Haven't Gotten Help**
Usually someone will try to answer and help solve the issue within a few hours. If not, and if you have followed the bullets above, you can ping helpers by running !helper.

forum_how_to_give_help: |
**How To Give Help**
- The channel sidebar on the left will list posts you have joined.
- You can scroll through the channel to see all recent questions.

**How To Give *Better* Help**
- Get yourself the $(trusted) role at $(channel)
- (If you don't like the pings, you can disable role mentions for the server.)
- As a $(trusted), you can:
- React to a help post to add tags.
- If a post appears to be resolved, run `!resolved` to mark it as such.
- *Only do this if the asker has indicated that their question has been resolved.*
- Conversely, you can run `!reopen` if the asker has follow-up questions.

**Useful Snippets**
- `!screenshot` — for if an asker posts a screenshot of code
- `!ask` — for if an asker only posts "can I get help?"

helper_resolve: |
$(owner)
Because your issue seemed to be resolved, this post was marked as resolved by $(helper).
If your issue is not resolved, **you can reopen this post by running `!reopen`**.
*If you have a different question, make a new post in $(channel).*

change_status:
not_help_thread: ':warning: Can only be run in a help post'
only_asker: ':warning: Only the asker can change the status of a help post'

shortened_url_playground: "$(author) Here's a shortened URL of your playground link! You can remove the full link from your message."
you_can_spec_lines: You can choose specific lines to embed by selecting them before copying the link.

# Modules

mod_module:
job_discord_message: "$(author) We don't do job posts here; see $(rules)"
job_console_message: Deleted job post message from $(author)
spam_message: |
Kicked
$(author)
for spam and deleted
$(messages)
identical messaged

get_ts_module:
downloading: 'Downloading typescript@$(version)'
doesnt_exists: typescript@$(version) does not exist
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
"description": "Typescript Community Bot",
"main": "dist/index.js",
"dependencies": {
"@types/js-yaml": "^4.0.9",
"@typescript/twoslash": "^3.2.1",
"algoliasearch": "^4.14.2",
"discord.js": "^14.6.0",
"dotenv-safe": "^8.2.0",
"html-entities": "^2.3.3",
"js-yaml": "^4.1.0",
"lz-string": "^1.4.4",
"npm-registry-fetch": "^14.0.2",
"parse-duration": "^1.0.2",
Expand Down
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { repModule } from './modules/rep';
import { twoslashModule } from './modules/twoslash';
import { snippetModule } from './modules/snippet';
import { helpForumModule } from './modules/helpForum';
import { Localization } from './modules/localization';
import path from 'path';

const client = new Client({
partials: [
Expand All @@ -37,6 +39,10 @@ const client = new Client({

getDB().then(() => client.login(token));

export const LOCALIZATION = new Localization(
path.resolve(process.cwd(), 'localization.yml'),
);

client.on('ready', async () => {
const bot = new Bot(client);
console.log(`Logged in as ${client.user?.tag}`);
Expand Down
25 changes: 21 additions & 4 deletions src/modules/autorole.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import { Bot } from '../bot';
import { autorole, rolesChannelId } from '../env';
import { LOCALIZATION } from '../index';

export async function autoroleModule({ client }: Bot) {
const channel = await client.channels.fetch(rolesChannelId);
if (!channel?.isTextBased()) {
console.error(
`Roles channel (${rolesChannelId}) does not exist or is not text based.`,
LOCALIZATION.getLocalizedText('roles_channel_doesnt_exists', {
rolesChannelId,
}),
);
return;
}

for (const ar of autorole) {
const msg = await channel.messages.fetch(ar.msgID);
if (!msg) {
console.error(`Role message does not exist for ${ar.msgID}`);
console.error(
LOCALIZATION.getLocalizedText('roles_message_doesnt_exists', {
id: ar.msgID,
}),
);
}
await msg?.react(ar.emoji);
}
Expand All @@ -32,7 +39,12 @@ export async function autoroleModule({ client }: Bot) {
if (ar.autoRemove) await reaction.users.remove(user.id);
const member = await msg.guild.members.fetch(user.id);
await member.roles.add(ar.roleID);
console.log('Gave role', ar.roleID, 'to', member);
console.log(
LOCALIZATION.getLocalizedText('gave_role', {
role: ar.roleID,
member,
}),
);
if (!reaction.users.cache.has(client.user.id)) {
await msg.react(reaction.emoji);
}
Expand All @@ -53,7 +65,12 @@ export async function autoroleModule({ client }: Bot) {
continue;
const member = await msg.guild.members.fetch(user.id);
await member.roles.remove(ar.roleID);
console.log('Removed role', ar.roleID, 'from', member);
console.log(
LOCALIZATION.getLocalizedText('role_removed', {
role: ar.roleID,
member,
}),
);
}
});
}
11 changes: 8 additions & 3 deletions src/modules/etc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
DELETE_EMOJI,
ownsBotMessage,
} from '../util/send';
import { LOCALIZATION } from '../index';

const emojiRegex = /<:\w+?:(\d+?)>|(\p{Emoji_Presentation})/gu;

Expand All @@ -20,9 +21,11 @@ const defaultPollEmojis = ['✅', '❌', '🤷'];
export function etcModule(bot: Bot) {
bot.registerCommand({
aliases: ['ping'],
description: 'See if the bot is alive',
description: LOCALIZATION.getLocalizedText('command_ping.description'),
async listener(msg) {
await msg.channel.send('pong. :ping_pong:');
await msg.channel.send(
LOCALIZATION.getLocalizedText('command_ping.listener_message'),
);
},
});

Expand Down Expand Up @@ -81,7 +84,9 @@ export function etcModule(bot: Bot) {
.map(([emoji, count]) => `${count} ${emoji}`)
.join(' ');
await suggestion.reply({
content: `Polling finished; result: ${pollingResultStr}`,
content: LOCALIZATION.getLocalizedText('polling_finished', {
pollingResultStr,
}),
});
});

Expand Down
25 changes: 18 additions & 7 deletions src/modules/handbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { sendWithMessageOwnership } from '../util/send';
import { TS_BLUE } from '../env';
import { decode } from 'html-entities';
import { Bot } from '../bot';
import { LOCALIZATION } from '../index';

const ALGOLIA_APP_ID = 'BGCDYOIYZ5';
const ALGOLIA_API_KEY = '37ee06fa68db6aef451a490df6df7c60';
Expand All @@ -18,22 +19,28 @@ type AlgoliaResult = {

const HANDBOOK_EMBED = new EmbedBuilder()
.setColor(TS_BLUE)
.setTitle('The TypeScript Handbook')
.setURL('https://www.typescriptlang.org/docs/handbook/intro.html')
.setFooter({ text: 'You can search with `!handbook <query>`' });
.setTitle(LOCALIZATION.getLocalizedText('handbook_embed.title'))
.setURL(LOCALIZATION.getLocalizedText('handbook_embed.url'))
.setFooter({
text: LOCALIZATION.getLocalizedText('handbook_embed.footer.text'),
});

export async function handbookModule(bot: Bot) {
bot.registerCommand({
aliases: ['handbook', 'hb'],
description: 'Search the TypeScript Handbook',
description: LOCALIZATION.getLocalizedText(
'handbook_command.description',
),
async listener(msg, content) {
if (!content) {
return await sendWithMessageOwnership(msg, {
embeds: [HANDBOOK_EMBED],
});
}

console.log('Searching algolia for', [content]);
console.log(
LOCALIZATION.getLocalizedText('searching_algolia', { content }),
);
const data = await algolia.search<AlgoliaResult>([
{
indexName: ALGOLIA_INDEX_NAME,
Expand All @@ -44,12 +51,16 @@ export async function handbookModule(bot: Bot) {
},
},
]);
console.log('Algolia response:', data);
console.log(
LOCALIZATION.getLocalizedText('algolia_response', { data }),
);
const hit = data.results[0].hits[0];
if (!hit)
return await sendWithMessageOwnership(
msg,
':x: No results found for that query',
LOCALIZATION.getLocalizedText(
'handbook_command.listener.no_results_found',
),
);
const hierarchyParts = [0, 1, 2, 3, 4, 5, 6]
.map(i => hit.hierarchy[`lvl${i}`])
Expand Down
Loading