How can i get a user id from a .addUserOption? - javascript

Hey i made a xp system with discord-xp i wanted to make a slashcommand that can give a user xp. But everytime i give this user xp in the database there is a # behind the user id and i want it without because otherwise the bot will not work.
Here is my Code:
const { SlashCommandBuilder } = require("#discordjs/builders");
const Levels = require('discord-xp');
const { MessageEmbed } = require('discord.js');
const client = require("../index")
module.exports = {
data: new SlashCommandBuilder()
.setName("addxp")
.setDescription("add xp")
.addUserOption((option) => option.setName('user').setDescription('add user xp').setRequired(true))
.addNumberOption(option => option.setName('num').setDescription('Enter a number').setRequired(true)),
async execute(client, interaction) {
const user = interaction.options.user.id('target')
const number = interaction.options.getNumber('num');
var userID = interaction.user.id;
const levels = await Levels.fetch(userID, interaction.guildId);
Levels.appendXp(user, interaction.guild.id, number);
interaction.reply(`**${user.tag}** got added ${number} XP.`);
}
}

You can use this:
const user = interaction.options.getUser('user')
const id = user?.id

Related

issues with placeholders, with discord.js v14, mangodb

this is my ../Events/Guild/guildMemberAdd.js https://sourceb.in/iEEfLj7uM7
im trying to set placeholders that will in turn give out an output like
Welcome to OnlyScoped.gg #azz#5271! We're glad to have you as the 500th member.
but output is
Welcome to OnlyScoped.gg <#undefined>! We're glad to have you join us as the undefinedth member.`
../Commands/Moderation/setup-welcome.js
const {Message, Client, SlashCommandBuilder, PermissionFlagsBits} = require("discord.js");
const welcomeSchema = require("../../Models/Welcome");
const {model, Schema} = require("mongoose");
module.exports = {
data: new SlashCommandBuilder()
.setName("setup-welcome")
.setDescription("Set up your welcome message for the discord bot.")
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
.addChannelOption(option =>
option.setName("channel")
.setDescription("Channel for welcome messages.")
.setRequired(true)
)
.addStringOption(option =>
option.setName("welcome-message")
.setDescription("Enter your welcome message.")
.setRequired(true)
)
.addRoleOption(option =>
option.setName("welcome-role")
.setDescription("Enter your welcome role.")
.setRequired(true)
),
async execute(interaction) {
const {channel, options} = interaction;
const welcomeChannel = options.getChannel("channel");
const welcomeMessage = options.getString("welcome-message");
const roleId = options.getRole("welcome-role");
if(!interaction.guild.members.me.permissions.has(PermissionFlagsBits.SendMessages)) {
interaction.reply({content: "I don't have permissions for this.", ephemeral: true});
}
welcomeSchema.findOne({Guild: interaction.guild.id}, async (err, data) => {
if(!data) {
const newWelcome = await welcomeSchema.create({
Guild: interaction.guild.id,
Channel: welcomeChannel.id,
Msg: welcomeMessage,
Role: roleId.id
});
}
interaction.reply({content: 'Succesfully created a welcome message', ephemeral: true});
})
}
}
../Models/Welcome.js
const { model, Schema } = require("mongoose");
let welcomeSchema = new Schema({
Guild: String,
Channel: String,
Msg: String,
Role: String,
});
module.exports = model("Welcome", welcomeSchema);
im attempting to use string.replace()but its not working as expected
i decided to put it in guildMemberAdd.js since when a member joins this gets runs so it would be unwise to place it in setup-welcome.js or Welcome.js since those are not listening for anything.
for reference here's my package.json:
https://sourceb.in/FMBgygjyoh
for the record i cant find any of the id's like member.id or member.count so those are wild guesses as to what they are. it could very well just be that as im still learning v14 this is my first project in it.
one other way i thought could work is if i just pass it off as an interpolated string in mongodb but it seems that the only string is with "" so i cant use default ones like ${member.count} so i decided to add placeholders
The basics of formatting a template are this:
const string = "Welcome to OnlyScoped.gg {tagUser}! We're glad to have you as the {memberCount} member.";
string = string.replace(/{tagUser}/g, member.toString());
string = string.replace(/{memberCount}/g, '500th');
return string; // "Welcome to OnlyScoped.gg <#123456789012345678>! We're glad to have you as the 500th member.";
To make something extensible, put template strings like this somewhere in your configuration:
{
"welcome_message": "Welcome to OnlyScoped.gg {tagUser}! We're glad to have you as the {ordinal:memberCount} member."
}
and make a function
function formatMessage(template, lookup) {
let output = template;
output = output.replace(/{ordinal:([^}]*)}/g, (_, target) => withOrdinalSuffix(lookup(target)));
output = output.replace(/{([^}]*)}/g, (_, target) => lookup(target));
return output;
}
// https://stackoverflow.com/a/31615643/3310334
// turn 1 into '1st', 500 into '500th', 502 into '502nd'
function withOrdinalSuffix(n) {
var s = ["th", "st", "nd", "rd"],
v = n % 100;
return n + (s[(v - 20) % 10] || s[v] || s[0]);
}
and then use the function with a template and the lookup function:
client.on('guildMemberAdd', member => {
const welcomeMessageTemplate = config.welcome_message;
const memberCount = member.guild.members.filter(member => !member.user.bot).size;
const lookup = (item) => {
const items = {
memberCount,
tagUser: member.toString()
};
return items[item];
};
const welcomeMessage = formatMessage(welcomeMessageTemplate, lookup);
const welcomeChannel = member.guild.channels.cache.find(channel => channel.name === 'welcome');
welcomeChannel.send(welcomeMessage);
});
The main issue I can see is incorrect property names as you mention in the question.
DiscordJS Docs: GuildMember
member.id => The Members ID
member.user.username => The Members username
member.guild.name => The Server's Name
member.guild.memberCount => Number of users within the Server
I'd advise the user to input data in a specific format like Hello {userName}!. Then you could run a program like
while (string.includes('{userName}')) {
string = string.replace('{userName}', member.user.username);
}

member.presence is undefined in Discord.JS?

I'm setting up Slash Commands with my Discord.JS bot.
I have a /rank command in the XP/leveling portion of my bot, but when I check interaction.member.presence for displaying it in the rank card, it returns null.
I've tried to look up this problem and look through the documentation of Discord.JS, but nobody else seems to have had this problem yet and I don't see anything in the documentation or Discord.JS guide to help solve this problem.
Here is the /rank command:
const Discord = require("discord.js");
const SQLite = require("better-sqlite3");
const sql = new SQLite('./mainDB.sqlite')
const client = new Discord.Client({ intents: [Discord.Intents.FLAGS.GUILDS, Discord.Intents.FLAGS.GUILD_MESSAGES] });
const canvacord = require("canvacord");
module.exports = {
name: 'rank',
aliases: ['rank'],
description: "Get your rank or another member's rank",
cooldown: 3,
category: "Leveling",
async execute(interaction) {
if(!interaction.isCommand()) return console.log("yes");
await interaction.deferReply()
.then(console.log("a"))
.catch(console.error);
let user = interaction.user;
client.getScore = sql.prepare("SELECT * FROM levels WHERE user = ? AND guild = ?");
client.setScore = sql.prepare("INSERT OR REPLACE INTO levels (id, user, guild, xp, level, totalXP) VALUES (#id, #user, #guild, #xp, #level, #totalXP);");
const top10 = sql.prepare("SELECT * FROM levels WHERE guild = ? ORDER BY totalXP").all(interaction.guild.id);
let score = client.getScore.get(user.id, interaction.guild.id);
if (!score) {
return interaction.editReply(`This user does not have any XP yet!`)
}
const levelInfo = score.level
const nextXP = levelInfo * 2 * 250 + 250
const xpInfo = score.xp;
const totalXP = score.totalXP
let rank = top10.sort((a, b) => {
return b.totalXP - a.totalXP
});
let ranking = rank.map(x => x.totalXP).indexOf(totalXP) + 1
//if (!interaction.guild.me.hasPermission("ATTACH_FILES")) return interaction.editReply(`**Missing Permission**: ATTACH_FILES or MESSAGE ATTACHMENTS`);
try {
var cardBg = sql.prepare("SELECT bg FROM background WHERE user = ? AND guild = ?").get(user.id, message.guild.id).bg;
var bgType = "IMAGE";
} catch (e) {
var cardBg = "#000000";
var bgType = "COLOR";
}
console.log(interaction.member.presence);
const rankCard = new canvacord.Rank()
.setAvatar(user.displayAvatarURL({
format: "jpg"
}))
.setStatus(interaction.member.presence.status, true, 1)
.setCurrentXP(xpInfo)
.setRequiredXP(nextXP)
.setProgressBar("#5AC0DE", "COLOR")
.setUsername(user.username)
.setDiscriminator(user.discriminator)
.setRank(ranking)
.setLevel(levelInfo)
.setLevelColor("#5AC0DE")
.renderEmojis(true)
.setBackground(bgType, cardBg);
rankCard.build()
.then(data => {
const attachment = new Discord.MessageAttachment(data, "RankCard.png");
return interaction.editReply({attachments: [attachment]});
});
}
}
Notes:
I do have the Presence Intent enabled.
Sorry if this seems like too little information. It's just what I
know so far, and I can't think of anything that I can do about it.
I know this command is very messy. I'm not asking how to fix that. I will fix that later.
Even though you have the PRESENCE INTENT enabled, you need to specify that you will be using the aforementioned intent in ClientOptions.
const client = new Discord.Client({
intents: [Discord.Intents.FLAGS.GUILDS, Discord.Intents.FLAGS.GUILD_MESSAGES, Discord.Intents.FLAGS.GUILD_PRESENCES],
});
First You need to enable intent
const client = new Discord.Client({
intents: [
Discord.Intents.FLAGS.GUILD_PRESENCES
],
});
Now we need Create a var of member
let member = message.mentions.members.first()
For get the presence of members use #presence
console.log(member.presence)
Will get results as
Presence {
userId: 'USER_ID',
guild: [Guild],
status: 'online',
activities: [Array],
clientStatus: [Object]
}

Type 'Promise<UserDomain>[]' is not assignable to type 'UserrDomain[]'

I'm stuck in async hell:
function convertToDomainUsers(dbUsers: Array<UserDB>): Array<UserDomain> {
// iterate each DB user and convert them to domain user types
const domainUsers: Array<UserDomain> = dbUsers.map( async (dbUser: UserDB) => {
// first convert the DB user to a Domain User
const domainUser: UserDomain = newUserDomainModel(dbUser);
// Now we need to get their user links from the DB
const dbUserLinks: Array<UserLinkDB> = await findDBUserLinks(dbUser.user_id);
// convert their user links to Domain user links
const domainUserLinks: Array<UserLinkDomain> = convertToUserLinks(dbUserLinks);
// now merry up the domain user links to the domain user
domainUser.links = domainUserLinks;
return domainUser;
});
return domainUsers;
}
function newUserDomainModel(user: UserDB): UserDomain {
const domainUser: UserDomain = {
username: user.user_username,
firstName: user.user_name_first,
lastName: user.user_name_last
};
return domainUser;
}
async function findDBUserLinks(userId: bigint): Promise<Array<UserLinkDB>> {
const dbUserLinks: Array<UserLinkDB> = await getUserLinks(userId);
return dbUserLinks;
}
async function getUserLinks(id: bigint): Promise<Array<UserLinkDB>> {
setDB();
await client.connect();
const query = `
select
link_url,
social_type_id
from user_links
WHERE user_id = ${id}`;
const res = await client.query(query);
const links: Array<UserLinkDB> = res.rows;
return Promise.resolve(links);
}
Error (happening on const domainUsers: in the convertToDomainUsers function):
TS2322: Type 'Promise<UserDomain>[]' is not assignable to type 'UserDomain[]'.   Type 'Promise<UserDomain>' is missing the following properties from type 'UserDomain': username, firstName, lastName, fullName, and 6 more
comments were added for the sake of making this stack post easier to follow. I don't normally write comments, they're cruft.
Calling:
const domainUsers = await Promise.all(convertToDomainUsers(dbUsers));
Working implementation:
function convertToDomainUsers(dbUsers: Array<UserDB>): Array<Promise<UserDomain>> {
const domainUsers: Array<Promise<UserDomain>> = dbUsers.map( async (dbUser: UserDB) => {
const domainUser: UserDomain = newUserDomainModel(dbUser);
const dbUserLinks: Array<UserLinkDB> = await findDBUserLinks(dbUser.user_id);
const domainUserLinks: Array<UserLinkDomain> = convertToUserLinks(dbUserLinks);
domainUser.links = domainUserLinks;
return domainUser;
});
return domainUsers;
}

Changes of a json not taken into account NodeJS

I'm coming to you because I'm trying to do a foreach loop on Discord.JS to detect changes in a JSON file. My file does change content, but my foreach loop keeps the old content in memory. I have no idea how to solve the problem...
My index.js:
const Discord = require('discord.js');
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
const fetch = require('node-fetch');
const client = new Discord.Client();
const config = require('./config.json');
const database = require('./db.json');
const adapter = new FileSync('./db.json')
const db = low(adapter)
const prefix = config.prefix;
let api = config.api;
client.once('ready', () => {
db.defaults({numbers: []})
.write()
setInterval(function() {
database.numbers.forEach(async element => {
let state = await fetch(`some-api-url`).then(response => response.json());
if(state[0].response != element.response){
db.get('numbers')
.find({number: element.number})
.assign({response: state[0].response, sms: state[0].msg})
.write();
let user = element.clientId;
try {
await client.users.cache.get(user).send(`Your message for number ${element.number} is ${element.sms}`);
} catch(error){
console.log(error)
}
}
});
}, 3000);
console.log('Ready!');
});
It all works, it just keeps the old file in memory.
To solve this problem, I passed my const database = require('./db.json'); into let. Then I integrated fs so that I could clear the cache:
setInterval(function() {
delete require.cache[require.resolve('./db.json')]
database = require('./db.json');
Problem solved!

Post mentioned user's avatar embedded using Discord.js

I'm using Discord.js for a discord bot and I'm trying to make it so that when you do the command !avatar #user
It will reply back with an embedded image of the mentioned user's avatar. I keep getting:
(node:3168) UnhandledPromiseRejectionWarning: DiscordAPIError: Invalid Form Body embed.image.url: Not a well formed URL.
This is the code I have so far, however I'm unaware of how else to grab the user's avatar?
const Discord = require('discord.js');
const config = require('./config.json');
const client = new Discord.Client();
function getUserFromMention(mention) {
if (!mention) return;
if (mention.startsWith('<#') && mention.endsWith('>')) {
mention = mention.slice(2, -1);
if (mention.startsWith('!')) {
mention = mention.slice(1);
}
return client.users.get(mention);
}
}
function getUserFromMentionRegEx(mention) {
const matches = mention.match(/^<#!?(\d+)>$/);
const id = matches[1];
return client.users.get(id);
}
client.once('ready', () => {
console.log('Ready!');
});
const prefix = "!";
client.on('message', message => {
if (!message.content.startsWith(prefix)) return;
const withoutPrefix = message.content.slice(prefix.length);
const split = withoutPrefix.split(/ +/);
const command = split[0];
const args = split.slice(1);
if (command === 'avatar') {
if (args[0]) {
const user = getUserFromMention(args[0]);
const userAvatar = user.displayAvatarURL;
if (!user) {
return message.reply('Please use a proper mention if you want to see someone else\'s avatar.');
}
const avatarEmbed = new Discord.RichEmbed()
.setColor('#275BF0')
.setImage('userAvatar');
message.channel.send(avatarEmbed);
}
return message.channel.send(`${message.author.username}, your avatar: ${message.author.displayAvatarURL}`);
}
});
client.login(config.token);
you dont need parse mentions with another function, discord have method for this. You can use message.mentions.members.first()
And you try to set image a string, with text userAvatar so sure you got error.
You can get mention member avatar and send it with this code.
const Discord = require('discord.js');
const config = require('./config.json');
const client = new Discord.Client();
client.once('ready', () => {
console.log('Ready!');
});
const prefix = "!";
client.on('message', message => {
if (!message.content.startsWith(prefix)) return;
const withoutPrefix = message.content.slice(prefix.length);
const split = withoutPrefix.split(/ +/);
const command = split[0];
const args = split.slice(1);
if (command === 'avatar') {
let targetMember;
if(!message.mentions.members.first()) {
targetMember = message.guild.members.get(message.author.id);
} else {
targetMember = message.mentions.members.first()
}
let avatarEmbed = new Discord.RichEmbed()
.setImage(targetMember.user.displayAvatarURL)
.setColor(targetMember.displayHexColor);
message.channel.send(avatarEmbed);
}
});

Categories