TypeError: interaction.options.getSubcommand is not a function - discord.js

I have made a all-in-one moderation bot by compiling certain codes. Recently, I was adding Ticket-System to my bot and it showed me this error. Although, I tried all the fixes I could find on the internet but still couldn't solve it.
Here is my code -->
ticket-config.js
const { Util, MessageEmbed } = require('discord.js');
const configOptions = require('../../configOptions');
module.exports = {
name: "ticketconfig",
description: "Configuration ticket system.",
options: configOptions,
permission: "ADMINISTRATOR",
run: async(interaction, client) => {
const replyMessage = {
content: "Config has been set!"
}
if (interaction.options.getSubcommand() === 'message') {
const message = interaction.options.getString('message');
const content = interaction.options.getString('content') || null;
let data = await client.db.get('config', interaction.guild.id);
if (!data) data = {};
data.message = message;
data.content = content;
await client.db.set('config', interaction.guild.id, data);
return interaction.reply(replyMessage)
}
configOptions.js
module.exports = [
{
name: "message",
description: "Configuration your ticket message",
type: 1,
options: [
{
name: "message",
description: "The message to sent in ticket",
type: 3,
required: true
},
{
name: "content",
description: "content will be appeared above embed message, use /variables command to see all available variables.",
type: 3
}
]
},
./handler/index.js
module.exports = async (client) => {
const eventFiles = await globPromise(`${process.cwd()}/events/*.js`);
eventFiles.map((value) => require(value));
const slashCommands = await globPromise(
`${process.cwd()}/SlashCommands/*/*.js`
);
const arrayOfSlashCommands = [];
slashCommands.map((value) => {
const file = require(value);
if (!file?.name) return;
client.slashCommands.set(file.name, file);
if (["MESSAGE", "USER"].includes(file.type)) delete file.description;
arrayOfSlashCommands.push(file);
});
client.on("ready", async () => {
await client.application.commands.set(arrayOfSlashCommands);
});

Related

discrod.js REST is not a constructor

const config = require("./config.json");
const Discord = require('discord.js');
const { Intents } = Discord;
const client = new Discord.Client({
intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES]
})
const { REST, Routes } = require('discord.js');
const commands = [
{
name: 'test',
description: 'test',
},
];
const rest = new REST({ version: '10' }).setToken(config.BOT_TOKEN);
(async () => {
try {
console.log('Started refreshing application (/) commands.');
await rest.put(Routes.applicationCommands(config.CLIENT_ID), { body: commands });
console.log('Successfully reloaded application (/) commands.');
} catch (error) {
console.error(error);
}
})();
client.on('interactionCreate', async interaction => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === 'test') {
await interaction.reply('Hello boi!');
}
});
client.login(config.BOT_TOKEN)
const rest = new REST({ version: '10' }).setToken(config.BOT_TOKEN);
^
TypeError: REST is not a constructor
I followed the instructions to create a bot. I run it and then this error occurs. I 've been looking everywhere for a solution
You should probably change the following:
const { REST, Routes } = require('discord.js');
with the following lines:
const { REST } = require('#discordjs/rest');
const { Routes } = require('discord-api-types/v10');
This can been verified by checking this.

Mongoose deleting subdocuments from arrays using $pull

Hi I have a comment and post model that has a one-to-many relationship. It successfully creates a comments array and pushes the object id correctly, but when I try to delete a comment using $pull It doesn't delete or show errors just returns the object back unchanged and also I'm not sure how to update subdocuments either , it doesn't work
In comment.js
const mongoose = require("mongoose");
const AutoIncrement = require('mongoose-sequence')(mongoose);
const CommentSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
content:{
type: String,
required: true
},
createdAt:{
type: Date,
default: new Date()
},
})
CommentSchema.plugin(AutoIncrement, {inc_field: 'commentID'});
module.exports = mongoose.model("Comment", CommentSchema);
In post.js
const mongoose = require("mongoose");
const AutoIncrement = require('mongoose-sequence')(mongoose);
const PostsSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
createdAt:{
type: Date,
default: new Date()
},
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
});
PostsSchema.plugin(AutoIncrement, {inc_field: 'postID'});
module.exports = mongoose.model("Post", PostsSchema);
For the routes
router.post("/:id/comments", CommentController.createComment)
router.get("/:id/comments", CommentController.viewComments)
router.delete("/:id/comments/:commentID", CommentController.deleteComment)
router.patch("/:id/comments/:commentID", CommentController.updateComment)
And the controllers
const commentsModel = require("../models/comments")
const PostsModel = require("../models/posts");
const mongoose = require("mongoose")
const objID = mongoose.Types.ObjectId;
async function createComment(req, res){
try{
const comment = await commentsModel.create(req.body)
const data = await PostsModel.findOneAndUpdate(
{postID: req.params.id},
{$push: {comments: objID(comment._id)}},
{ new: true, useFindAndModify: false }
)
res.status(200).json({data})
}catch (e) {
res.status(404).json(e.message)
}
}
async function viewComments(req, res){
try{
const data = await PostsModel.findOne({postID: req.params.id}).populate("comments");
if(!data){
return res.status(404).json({msg: "No data found"});
}
res.status(200).json({comments: data.comments});
}catch (e) {
res.status(500).json(e.message);
}
}
async function deleteComment(req, res){
try{
const post = await PostsModel.update({ postID: req.params.id },
{
'$pull': {
comments: {
_id: objID(req.params.commentID)
}
}
}, {new: true});
if (!post){
return res.status(404).json({msg: "No post found"});
}
res.status(200).json({post});
}catch (e) {
res.status(500).json(e.message);
}
}
async function updateComment(req, res){
try{
const post = await PostsModel.findOneAndUpdate(
{"postID": req.params.id, "comments._id": objID(req.params.commentID)},
{
"$set":{
"comments.$.username": req.body.username,
"comments.$.content": req.body.content
}
}
)
if (!post){
return res.status(404).json({msg: "No post found"});
}
res.status(200).json({post});
}catch (e) {
res.status(500).json(e.message);
}
}

Discord.js Ticket system doesn't send an ephemeral message

I'm trying to make a ticket system with discord.js v13, but the ephemeral method doesn't work and, when my bot turn on, i need to click one time in the button to activate the system.
print
My code:
const { MessageActionRow, MessageButton, MessageEmbed, Permissions } = require('discord.js');
const db = require("quick.db");
exports.run = async (client, interaction) => {
if (!interaction.isButton()) return;
interaction.deferUpdate();
let getContador = await db.get('counter')
if(getContador === null) {
let contador = await db.set("counter", 1)
}
await db.add("counter", 1)
let tcID = "895323735702253569"
let tmID = "895358127950659604"
const filter = i => i.customId === 'OPENTICKET'
const collector = interaction.channel.createMessageComponentCollector({ filter, max: 1 });
collector.on("collect", async i => {
let cTicket = await i.guild.channels.create(`🎫┆Ticket ${getContador}`, {
type: 'GUILD_TEXT',
permissionOverwrites: [
{
id: i.guild.id,
deny: [Permissions.FLAGS.VIEW_CHANNEL],
},
{
id: i.user.id,
allow: [Permissions.FLAGS.VIEW_CHANNEL, Permissions.FLAGS.SEND_MESSAGES],
},
]
})
await interaction.channel.messages.cache.get(tmID).reply({ content: `... ${cTicket.toString()}...`, ephemeral: true })
})
}
You are replying to a normal message. If you would like an ephemeral message, you have to directly reply to the interaction.
interaction.reply({
content: `... ${cTicket.toString()}...`,
ephemeral: true
})

discord.js image search with pages

is there a way to add pages for this command.
e.g | https://gyazo.com/e6782fc9386f9d15c7cc52dabeb8844e (it can be with reactions or buttons)
const { MessageEmbed } = require("discord.js");
module.exports = {
name: "img",
description: "Search for an image!",
category: "utility",
cooldown: {type: "map", time: 10},
aliases: ["is", "imgsearch"],
run: async (client, message, args) => {
if (!args) client.err(message);
gis(args.join(" "), logResults);
async function logResults(error, results){
if (error)return client.err(message);
let random = Math.floor(Math.random() * results.length);
let image = results[random].url
const embed = new MessageEmbed()
.setImage(image)
.setColor("#2f3136");
return message.reply(embed);
}
}
}
The easiest solution would be to add two reactions '⬅️, ➡️', and await till user reacts with one of them. (working with reactions is nicely described here)
Your code would look like this:
const { MessageEmbed } = require("discord.js");
module.exports = {
name: "img",
description: "Search for an image!",
category: "utility",
cooldown: {type: "map", time: 10},
aliases: ["is", "imgsearch"],
run: async (client, message, args) => {
if (!args) client.err(message);
gis(args.join(" "), logResults);
async function logResults(error, results){
if (error)return client.err(message);
let random = Math.floor(Math.random() * results.length);
let image = results[random].url
const embed = new MessageEmbed()
.setImage(image)
.setColor("#2f3136");
// Awaiting till the message gets sent so we can add reactions & await users to react
const msg = await message.reply(embed);
// Adding reactions
await msg.react('⬅️');
await msg.react('➡️');
// Create a filter so only when original author reacts with ⬅️ or ➡️ the message is edited.
const filter = (reaction, user) => {
return ['⬅️', '➡️'].includes(reaction.emoji.name) && user.id === message.author.id;
};
// Await until user reacts
message.awaitReactions(filter, { max: 1, time: 60000, errors: ['time'] })
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '⬅️') {
await msg.reactions.removeAll();
let image = results[random-1].url
const embed = new MessageEmbed()
.setImage(image)
.setColor("#2f3136");
msg.edit(embed);
} else {
await msg.reactions.removeAll();
let image = results[random+1].url
const embed = new MessageEmbed()
.setImage(image)
.setColor("#2f3136");
msg.edit(embed);
}
})
.catch(collected => {
message.reply('Your time to open next or previous image expired!');
});
}
}
}

Facebook and Google requires two login click to login with Firebase Auth

I have React web application with firebase auth (mail, Facebook, Google).
Google and Facebook work only after 2 login clicks.
The code is equal, just the provider is different.
import React from 'react';
import firebase from "firebase/app";
import { app } from "../../../../config/firebase";
const signupWithGoogle = (user, userInfo)=>{
app.firestore().collection('users').doc(user.uid).set({
firstName: userInfo.profile.given_name,
lastName: userInfo.profile.family_name});
const batch = app.firestore().batch();
const initData = [
{ Applied: { positionIds: [], title: 'Applied' } },
{ Contract: { positionIds: [], title: 'Contract' } },
{ Denied: { positionIds: [], title: 'Denied' } },
{ InProgress: { positionIds: [], title: 'In Progress' } },
{ ReceivedTask: { positionIds: [], title: 'Received Task' } },
];
initData.forEach((doc) => {
const docRef = app
.firestore()
.collection('users')
.doc( user.uid)
.collection('columns')
.doc(Object.keys(doc)[0]);
batch.set(docRef, Object.values(doc)[0]);
});
const batchCommit= batch.commit();
return batchCommit;
}
export const googleLogin = async (
history
) => {
var provider = new firebase.auth.GoogleAuthProvider();
await firebase.auth()
.signInWithPopup(provider)
.then( resp => {
let {user, credential,additionalUserInfo: userInfo} = resp;
if (userInfo.isNewUser) signupWithGoogle(user, userInfo);
}).then(()=>
history.push('/')
)
.catch((error) => {
console.error(error.message);
});
};
I saw this question, but didn't help.(Firebase Authentication Requires Two 'Login' Calls)
I had the same problem with Firebase Authentication with Facebook, I had to register two times to make it works.
The problem was in my HTLM, I used a form.
I changed for a simpler code, and it worked.
While waiting for where you call your function from, as your issue would relate to improper state management, here are some edits you can make to the code you have shared so far to squash some problems that it has.
In your signupWithGoogle function, you create a floating promise that should be included in the write batch that you use to create the /users/{userId}/columns collection. Because you use Object.keys(doc)[0] and Object.values(doc)[0], you should consider using an array of [docId, docData] pairs or a JSON-like object structure like so:
// prepare data to add to the user's columns collection
const initColumnsData = {
Applied: { positionIds: [], title: 'Applied' },
Contract: { positionIds: [], title: 'Contract' },
Denied: { positionIds: [], title: 'Denied' },
InProgress: { positionIds: [], title: 'In Progress' },
ReceivedTask: { positionIds: [], title: 'Received Task' }
};
// queue columns data upload
Object.entries(initColumnsData)
.forEach(([docId, docData]) => {
const docRef = userDocRef
.collection('columns')
.doc(docId);
batch.set(docRef, docData);
});
As you mentioned that a lot of your code is shared aside from the provider implementation, you should consider extracting the common code from those functions:
const initUserData = (user, userDocData) => {
// init write batch
const batch = app.firestore().batch();
// init ref to user data
const userDocRef = app.firestore().collection('users').doc(user.uid);
// queue user data upload
batch.set(userDocRef, userDocData);
// prepare data to add to the user's columns collection
const initColumnsData = {
Applied: { positionIds: [], title: 'Applied' },
Contract: { positionIds: [], title: 'Contract' },
Denied: { positionIds: [], title: 'Denied' },
InProgress: { positionIds: [], title: 'In Progress' },
ReceivedTask: { positionIds: [], title: 'Received Task' }
};
// queue columns data upload
Object.entries(initColumnsData)
.forEach(([docId, docData]) => {
const docRef = userDocRef
.collection('columns')
.doc(docId);
batch.set(docRef, docData);
});
// make the changes
return batch.commit();
}
const initUserDataForGoogle(user, userInfo) {
return initUserData(user, {
firstName: userInfo.profile.given_name,
lastName: userInfo.profile.family_name
});
}
const initUserDataForFacebook(user, userInfo) {
return initUserData(user, {
firstName: /* ... */,
lastName: /* ... */
});
}
When exporting a function to be called elsewhere, avoid causing "side effects" (like navigating using the History API) and don't trap errors (using .catch() without rethrowing the error). The calling code should handle the result and any errors itself.
export const loginWithGoogle = async () => {
const provider = new firebase.auth.GoogleAuthProvider();
return firebase.auth()
.signInWithPopup(provider)
.then(async resp => {
const {user, credential, additionalUserInfo: userInfo} = resp;
if (userInfo.isNewUser)
await initUserDataForGoogle(user, userInfo);
return user;
});
};
Then in your components, you'd use:
setLoading(true);
/* await/return */ loginWithGoogle()
.then(() => {
history.push('/');
// or
// setLoading(false)
// then do something
})
.catch((err) => {
console.error("loginWithGoogle failed: ", err);
setLoading(false);
setError("Failed to log in with Google!"); // <- displayed in UI to user
});

Resources