mirror of
https://github.com/aydenjahola/discord-multipurpose-bot.git
synced 2024-11-22 00:35:56 +00:00
initial commit
This commit is contained in:
commit
c6a5dd2701
6 changed files with 313 additions and 0 deletions
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Node
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
# .env
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
# yarn stuff
|
||||||
|
yarn-error.log
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
|
# db
|
||||||
|
db-data
|
1
Procfile
Normal file
1
Procfile
Normal file
|
@ -0,0 +1 @@
|
||||||
|
worker: node bot.js
|
60
README.md
Normal file
60
README.md
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
# Esports Verification Bot
|
||||||
|
|
||||||
|
Welcome to the **Esports Verification Bot**! This bot is designed to handle user verification for Discord servers, specifically for esports communities. It verifies users through their student email addresses and manages roles based on their verification status.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Email Verification**: Users receive a verification code via email and must enter it in Discord to verify their account.
|
||||||
|
- **Role Management**: Automatically assigns a specific role to users once they have been verified.
|
||||||
|
- **Customizable**: Easy to configure email domains, roles, and channels for different needs.
|
||||||
|
- **Expiration Handling**: Verification codes expire after 10 minutes for added security.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
Before you begin, ensure you have:
|
||||||
|
|
||||||
|
- A Discord bot token (create a bot on the [Discord Developer Portal](https://discord.com/developers/applications)).
|
||||||
|
- Access to a MongoDB database (you can use [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) for a free tier).
|
||||||
|
- A Gmail account for sending emails (you can use any email service, but make sure to adjust the Nodemailer configuration).
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
1. **Clone the Repository**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone git@github.com:aydenjahola/esports-verification-bot.git
|
||||||
|
cd esports-verification-bot
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Install Dependencies**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Set Up Environment Variables**
|
||||||
|
|
||||||
|
Create a `.env` file in the root directory and add the following:
|
||||||
|
|
||||||
|
```env
|
||||||
|
BOT_TOKEN=your_discord_bot_token
|
||||||
|
MONGODB_URI=your_mongodb_connection_string
|
||||||
|
EMAIL_USER=your_email@gmail.com
|
||||||
|
EMAIL_PASS=your_email_password
|
||||||
|
VERIFIED_ROLE_NAME=YourVerifiedRoleName
|
||||||
|
EMAIL_DOMAIN=mail.dcu.ie
|
||||||
|
GUILD_ID=your_discord_guild_id
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Run the Bot**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
node bot.js
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
- **!verify your_email@mail.dcu.ie**: Sends a verification code to the provided email.
|
||||||
|
- **!code your_code**: Validates the provided verification code.
|
206
bot.js
Normal file
206
bot.js
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
require("dotenv").config();
|
||||||
|
const { Client, GatewayIntentBits } = require("discord.js");
|
||||||
|
const nodemailer = require("nodemailer");
|
||||||
|
const mongoose = require("mongoose");
|
||||||
|
const VerificationCode = require("./models/VerificationCode");
|
||||||
|
|
||||||
|
const client = new Client({
|
||||||
|
intents: [
|
||||||
|
GatewayIntentBits.Guilds,
|
||||||
|
GatewayIntentBits.GuildMessages,
|
||||||
|
GatewayIntentBits.MessageContent,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const VERIFIED_ROLE_NAME = process.env.VERIFIED_ROLE_NAME; // Role name to assign after verification
|
||||||
|
const EMAIL_DOMAIN = process.env.EMAIL_DOMAIN; // Domain to verify against
|
||||||
|
const GUILD_ID = process.env.GUILD_ID; // Guild ID to restrict the bot
|
||||||
|
const VERIFICATION_CHANNEL_NAME = "verification"; // Channel name to restrict the bot
|
||||||
|
|
||||||
|
// Connect to MongoDB
|
||||||
|
mongoose
|
||||||
|
.connect(process.env.MONGODB_URI)
|
||||||
|
.then(() => console.log("Connected to MongoDB"))
|
||||||
|
.catch((err) => console.error("Failed to connect to MongoDB", err));
|
||||||
|
|
||||||
|
// Setup Nodemailer
|
||||||
|
const transporter = nodemailer.createTransport({
|
||||||
|
service: "Gmail",
|
||||||
|
auth: {
|
||||||
|
user: process.env.EMAIL_USER,
|
||||||
|
pass: process.env.EMAIL_PASS,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
client.once("ready", () => {
|
||||||
|
console.log(`Logged in as ${client.user.tag}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("messageCreate", async (message) => {
|
||||||
|
try {
|
||||||
|
// Ensure bot only operates in the designated channel
|
||||||
|
const verificationChannel = message.guild.channels.cache.find(
|
||||||
|
(channel) => channel.name === VERIFICATION_CHANNEL_NAME
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!message.guild || !verificationChannel) {
|
||||||
|
console.error("Guild or verification channel not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.author.bot || message.channel.id !== verificationChannel.id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (message.content.startsWith("!verify")) {
|
||||||
|
const email = message.content.split(" ")[1];
|
||||||
|
|
||||||
|
if (!email) {
|
||||||
|
return verificationChannel.send(
|
||||||
|
"Please provide your email address. Usage: `!verify your_email@mail.dcu.ie`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const emailDomain = email.split("@")[1];
|
||||||
|
if (emailDomain !== EMAIL_DOMAIN) {
|
||||||
|
return verificationChannel.send(
|
||||||
|
"You must use a valid DCU student email address."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const guild = client.guilds.cache.get(GUILD_ID);
|
||||||
|
if (!guild) {
|
||||||
|
console.error("Guild not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const member = guild.members.cache.get(message.author.id);
|
||||||
|
if (!member) {
|
||||||
|
console.error("Member not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const role = guild.roles.cache.find((r) => r.name === VERIFIED_ROLE_NAME);
|
||||||
|
if (!role) {
|
||||||
|
console.error("Role not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (member.roles.cache.has(role.id)) {
|
||||||
|
return verificationChannel.send("You are already verified!");
|
||||||
|
}
|
||||||
|
|
||||||
|
const verificationCode = Math.floor(
|
||||||
|
100000 + Math.random() * 900000
|
||||||
|
).toString();
|
||||||
|
|
||||||
|
const emailHtml = `
|
||||||
|
<html>
|
||||||
|
<body style="font-family: Arial, sans-serif; color: #333;">
|
||||||
|
<h2 style="color: #1e90ff;">Your Verification Code</h2>
|
||||||
|
<p>Hi there,</p>
|
||||||
|
<p>Thank you for requesting verification. Your verification code is:</p>
|
||||||
|
<h3 style="background-color: #f4f4f4; padding: 10px; border: 1px solid #ddd; border-radius: 5px; text-align: center; color: #1e90ff;">
|
||||||
|
${verificationCode}
|
||||||
|
</h3>
|
||||||
|
<p>This code is valid for 10 minutes. Please enter it in the Discord channel using the command <code>!code your_code</code>.</p>
|
||||||
|
<p>If you did not request this code, please ignore this email.</p>
|
||||||
|
<p>Best regards,<br>Esports Committee</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await transporter.sendMail({
|
||||||
|
from: process.env.EMAIL_USER,
|
||||||
|
to: email,
|
||||||
|
subject: "Esports Verification Code",
|
||||||
|
html: emailHtml, // Use HTML content
|
||||||
|
});
|
||||||
|
|
||||||
|
await VerificationCode.create({
|
||||||
|
userId: message.author.id,
|
||||||
|
email: email,
|
||||||
|
code: verificationCode,
|
||||||
|
});
|
||||||
|
|
||||||
|
verificationChannel.send(
|
||||||
|
`**A verification code has been sent to your email.**\n` +
|
||||||
|
`Please reply with \`!code your_code\` to verify your account.\n` +
|
||||||
|
`**Note:** The code is only valid for **10 minutes**.`
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error sending email or saving verification code:", err);
|
||||||
|
verificationChannel.send(
|
||||||
|
"There was an error sending the verification email."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.content.startsWith("!code")) {
|
||||||
|
const code = message.content.split(" ")[1];
|
||||||
|
|
||||||
|
if (!code) {
|
||||||
|
return verificationChannel.send(
|
||||||
|
"Please provide the verification code. Usage: `!code your_code`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const verificationEntry = await VerificationCode.findOne({
|
||||||
|
userId: message.author.id,
|
||||||
|
code,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!verificationEntry) {
|
||||||
|
return verificationChannel.send(
|
||||||
|
"Invalid or expired verification code. Please try again."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const guild = client.guilds.cache.get(GUILD_ID);
|
||||||
|
if (!guild) {
|
||||||
|
console.error("Guild not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const member = guild.members.cache.get(message.author.id);
|
||||||
|
if (!member) {
|
||||||
|
console.error("Member not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const role = guild.roles.cache.find(
|
||||||
|
(r) => r.name === VERIFIED_ROLE_NAME
|
||||||
|
);
|
||||||
|
if (!role) {
|
||||||
|
console.error("Role not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (member.roles.cache.has(role.id)) {
|
||||||
|
return verificationChannel.send("You are already verified!");
|
||||||
|
}
|
||||||
|
|
||||||
|
await member.roles.add(role);
|
||||||
|
verificationChannel.send(
|
||||||
|
`Congratulations ${message.author}, you have been verified!`
|
||||||
|
);
|
||||||
|
|
||||||
|
// No need to manually delete the verification entry, as it will expire automatically in 10 minutes
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error processing verification code:", err);
|
||||||
|
verificationChannel.send(
|
||||||
|
"There was an error processing your verification. Please try again later."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Unhandled error in messageCreate event:", err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("error", (err) => {
|
||||||
|
console.error("Client error:", err);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.login(process.env.BOT_TOKEN);
|
10
models/VerificationCode.js
Normal file
10
models/VerificationCode.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
const mongoose = require("mongoose");
|
||||||
|
|
||||||
|
const VerificationCodeSchema = new mongoose.Schema({
|
||||||
|
userId: { type: String, required: true },
|
||||||
|
email: { type: String, required: true },
|
||||||
|
code: { type: String, required: true },
|
||||||
|
createdAt: { type: Date, expires: "10m", default: Date.now }, // Code expires in 10 minutes
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model("VerificationCode", VerificationCodeSchema);
|
19
package.json
Normal file
19
package.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "esports-bot",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"discord.js": "^14.15.3",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"express": "^4.19.2",
|
||||||
|
"mongoose": "^8.6.0",
|
||||||
|
"nodemailer": "^6.9.14"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue