Explore all Discord open source software, libraries, packages, source code, cloud functions and APIs.

Popular New Releases in Discord

discord.js

@discordjs/voice@0.9.0

whatsapp-web.js

v1.16.6

gb-studio

GB Studio v3.0.3

BetterDiscord

BetterDiscord v1.5.2

bottender

1.5.5 / 2021-11-10

Popular Libraries in Discord

discord.js

by discordjs doticonjavascriptdoticon

star image 18961 doticonApache-2.0

A powerful JavaScript library for interacting with the Discord API

discord.py

by Rapptz doticonpythondoticon

star image 10275 doticonMIT

An API wrapper for Discord written in Python.

Google-Play-Music-Desktop-Player-UNOFFICIAL-

by MarshallOfSound doticonjavascriptdoticon

star image 8451 doticonMIT

A beautiful cross platform Desktop Player for Google Play Music

awesome-ctf

by apsdehal doticonjavascriptdoticon

star image 6128 doticonCC0-1.0

A curated list of CTF frameworks, libraries, resources and softwares

whatsapp-web.js

by pedroslopez doticonjavascriptdoticon

star image 6086 doticonApache-2.0

A WhatsApp client library for NodeJS that connects through the WhatsApp Web browser app

gb-studio

by chrismaltby doticoncdoticon

star image 5995 doticonMIT

A quick and easy to use drag and drop retro game creator for your favourite handheld video game system

xenia

by xenia-project doticonc++doticon

star image 5520 doticonNOASSERTION

Xbox 360 Emulator Research Project

BetterDiscord

by BetterDiscord doticonjavascriptdoticon

star image 4145 doticonNOASSERTION

Better Discord enhances Discord desktop app with new features.

discord-api-docs

by discord doticontypescriptdoticon

star image 4043 doticon

Official Discord API Documentation

Trending New libraries in Discord

fosscord

by fosscord doticonjavascriptdoticon

star image 3576 doticonAGPL-3.0

Fosscord is a free open source selfhostable discord compatible communication platform

Impostor

by Impostor doticoncsharpdoticon

star image 1963 doticonGPL-3.0

Impostor - An open source reimplementation of the Among Us Server

pycord

by Pycord-Development doticonpythondoticon

star image 1944 doticonMIT

Pycord, a maintained fork of discord.py, is a python wrapper for the Discord API

epicgames-freebies-claimer

by Revadike doticonjavascriptdoticon

star image 1686 doticonMIT

Claim available free game promotions from the Epic Games Store.

Discord-MusicBot

by SudhanPlayz doticonjavascriptdoticon

star image 1586 doticonNOASSERTION

An advanced discord music bot, supports Spotify, Soundcloud, YouTube with Shuffling, Volume Control and Web Dashboard with Slash Commands support!

git-notify

by jevakallio doticontypescriptdoticon

star image 1261 doticonMIT

🙉 📣 Communicate important updates to your team via git commit messages

disc-11

by zhycorp doticontypescriptdoticon

star image 1223 doticonBSD-3-Clause

A dedicated open-source Discord bot for Zhycorp based on our Discord bot template with more features. Easy to use, and with no coding required.

bird-bot

by natewong1313 doticonpythondoticon

star image 1187 doticonMIT

A Nintendo Switch checkout bot. Currently supports Walmart and Best buy

Aliucord

by Aliucord doticonjavadoticon

star image 980 doticonOSL-3.0

A modification for the Discord Android App

Top Authors in Discord

1

Androz2091

35 Libraries

star icon2619

2

Tomato6966

24 Libraries

star icon608

3

navaneethkm004

15 Libraries

star icon185

4

Koolwiza

15 Libraries

star icon140

5

Snowflake107

15 Libraries

star icon213

6

discordjs

13 Libraries

star icon21787

7

Yaekith

13 Libraries

star icon126

8

zekroTJA

13 Libraries

star icon191

9

Stanley-GF

12 Libraries

star icon144

10

jagrosh

12 Libraries

star icon4359

1

35 Libraries

star icon2619

2

24 Libraries

star icon608

3

15 Libraries

star icon185

4

15 Libraries

star icon140

5

15 Libraries

star icon213

6

13 Libraries

star icon21787

7

13 Libraries

star icon126

8

13 Libraries

star icon191

9

12 Libraries

star icon144

10

12 Libraries

star icon4359

Trending Kits in Discord

No Trending Kits are available at this moment for Discord

Trending Discussions on Discord

discord.js-commando enabling and working with mongodb

How can you create a pop-up window in Discord that accepts an input from the user?

Reply to a suggestion with a reaction

How do I fix CLIENT_MISSING_INTENTS error?

Is there a way to access the children of a CategoryChannel before it is deleted? [Discord.js]

How do I get mobile status for discord bot by directly modifying IDENTIFY packet?

Changing Category/Channels Permissions Returns Error "Missing Permissions" - Novus/Discord.py

Error [ERR_REQUIRE_ESM]: require() of ES Module not supported

How to setup .NET 6 with Dapper Identity and Discord Login

How to check if a bot can DM a user

QUESTION

discord.js-commando enabling and working with mongodb

Asked 2022-Apr-01 at 17:52

I'm trying to create a discord bot, specifically the wedding team.

I am using a MongoDB database. Now everything works and is saved, but there is one problem, the data is saved for the second and third rounds, etc.

That is, the checks that I added do not work. I am trying to find data through const exists = Marry.findOne({ message.author.id });, everything finds, I checked with console log.

But when I try to validate it just doesn't work. if (exists == message.author.id) { return message.channel.send("You are already married!"); }

What could be the problem? Help me please!

Maybe instead userID: message.author.id i just need to find for the value message.author.id. Is it possible?

1const { Command } = require("discord.js-commando");
2const mongoose = require("mongoose");
3
4mongoose.connect('mongodb+srv://admon:admin@cluster0.sobzp.mongodb.net/dbname?retryWrites=true&w=majority');
5
6//create Schema
7
8const marrySchema = new mongoose.Schema({
9    userID: {
10        type: mongoose.SchemaTypes.String,
11        required: true
12    },
13
14    userMarryID: {
15        type: mongoose.SchemaTypes.String,
16        required: true
17    },
18
19    userPartnerID: {
20        type: mongoose.SchemaTypes.String,
21        required: true
22    }
23});
24
25const Marry = mongoose.model('Marry', marrySchema);
26
27module.exports = class MarryCommand extends Command {
28    constructor(client) {
29        super(client, {
30            name: "marry",
31            memberName: "marry",
32            group: "test",
33            description: "Marry the mentioned user",
34            guildOnly: true,
35            args: [{
36                key: "userToMarry",
37                prompt: "Please select the member you wish to marry.",
38                type: "member",
39            }, ],
40        });
41    }
42
43    run(message, { userToMarry }) {
44        const exists = Marry.findOne({ userID: message.author.id });
45        const married = Marry.findOne({ userID: userToMarry.id });
46
47        if (!userToMarry) {
48            return message.channel.send("Please try again with a valid user.");
49        }
50        if (exists == message.author.id) {
51            return message.channel.send("You are already married!");
52        }
53        if (married == userToMarry.id) {
54            return message.channel.send("This user is already married!");
55        }
56        if (userToMarry.id == message.author.id) {
57            return message.channel.send("You cannot marry yourself!");
58        }
59        if (exists != message.author.id && married != userToMarry.id) {
60            message.channel.send(
61                    `**Important announcement!**
62    
63    ${message.author} makes a marriage proposal ${userToMarry}
64    
65    Are you ready to get married?`
66                )
67                .then((message) => {
68                    message.react("👍")
69                    .then(() => message.react("👎"))
70                    .catch(() => {
71                        //code
72                    });
73                    message.awaitReactions((reaction, user) =>
74                        user.id == userToMarry.id && (reaction.emoji.name == "👍" || reaction.emoji.name == "👎"), {
75                            max: 1,
76                            time: 10000,
77                            errors: ["time"]
78                        }
79                    ).then((collected) => {
80                        const reaction = collected.first();
81                        if (reaction.emoji.name === "👎") {
82                            return message.channel.send("I think **no**...");
83                        }
84                        if (reaction.emoji.name === "👍") {
85                                const createdExists = new Marry({
86                                    userID: message.author.id,
87                                    userMarryID: message.author.id,
88                                    userPartnerID: userToMarry.id
89                                });
90                                createdExists.save().catch(e => console.log(e));
91
92                                const createdMarried = new Marry({
93                                    userID: userToMarry.id,
94                                    userMarryID: userToMarry.id,
95                                    userPartnerID: message.author.id
96                                });
97                                createdMarried.save().catch(e => console.log(e));
98
99                            message.channel.send(`${message.author} and ${userToMarry} now married!!`)
100                                .catch(() => {
101                                    message.reply(
102                                        "No reaction after 10 seconds, operation canceled"
103                                    );
104                                });
105                        }
106                    }).catch(() => {});
107                }).catch(() => {});
108        }
109    }
110};
111

ANSWER

Answered 2022-Mar-31 at 16:07

So I think you're having an async issue in your code. The query itself should work just fined. However, I suggest you move exists and married outside of run. Maybe paste them under the MongoDB connection and find a way to pass the message.

1const { Command } = require("discord.js-commando");
2const mongoose = require("mongoose");
3
4mongoose.connect('mongodb+srv://admon:admin@cluster0.sobzp.mongodb.net/dbname?retryWrites=true&w=majority');
5
6//create Schema
7
8const marrySchema = new mongoose.Schema({
9    userID: {
10        type: mongoose.SchemaTypes.String,
11        required: true
12    },
13
14    userMarryID: {
15        type: mongoose.SchemaTypes.String,
16        required: true
17    },
18
19    userPartnerID: {
20        type: mongoose.SchemaTypes.String,
21        required: true
22    }
23});
24
25const Marry = mongoose.model('Marry', marrySchema);
26
27module.exports = class MarryCommand extends Command {
28    constructor(client) {
29        super(client, {
30            name: "marry",
31            memberName: "marry",
32            group: "test",
33            description: "Marry the mentioned user",
34            guildOnly: true,
35            args: [{
36                key: "userToMarry",
37                prompt: "Please select the member you wish to marry.",
38                type: "member",
39            }, ],
40        });
41    }
42
43    run(message, { userToMarry }) {
44        const exists = Marry.findOne({ userID: message.author.id });
45        const married = Marry.findOne({ userID: userToMarry.id });
46
47        if (!userToMarry) {
48            return message.channel.send("Please try again with a valid user.");
49        }
50        if (exists == message.author.id) {
51            return message.channel.send("You are already married!");
52        }
53        if (married == userToMarry.id) {
54            return message.channel.send("This user is already married!");
55        }
56        if (userToMarry.id == message.author.id) {
57            return message.channel.send("You cannot marry yourself!");
58        }
59        if (exists != message.author.id && married != userToMarry.id) {
60            message.channel.send(
61                    `**Important announcement!**
62    
63    ${message.author} makes a marriage proposal ${userToMarry}
64    
65    Are you ready to get married?`
66                )
67                .then((message) => {
68                    message.react("👍")
69                    .then(() => message.react("👎"))
70                    .catch(() => {
71                        //code
72                    });
73                    message.awaitReactions((reaction, user) =>
74                        user.id == userToMarry.id && (reaction.emoji.name == "👍" || reaction.emoji.name == "👎"), {
75                            max: 1,
76                            time: 10000,
77                            errors: ["time"]
78                        }
79                    ).then((collected) => {
80                        const reaction = collected.first();
81                        if (reaction.emoji.name === "👎") {
82                            return message.channel.send("I think **no**...");
83                        }
84                        if (reaction.emoji.name === "👍") {
85                                const createdExists = new Marry({
86                                    userID: message.author.id,
87                                    userMarryID: message.author.id,
88                                    userPartnerID: userToMarry.id
89                                });
90                                createdExists.save().catch(e => console.log(e));
91
92                                const createdMarried = new Marry({
93                                    userID: userToMarry.id,
94                                    userMarryID: userToMarry.id,
95                                    userPartnerID: message.author.id
96                                });
97                                createdMarried.save().catch(e => console.log(e));
98
99                            message.channel.send(`${message.author} and ${userToMarry} now married!!`)
100                                .catch(() => {
101                                    message.reply(
102                                        "No reaction after 10 seconds, operation canceled"
103                                    );
104                                });
105                        }
106                    }).catch(() => {});
107                }).catch(() => {});
108        }
109    }
110};
111const Marry = mongoose.model('Marry', marrySchema);
112const exists = Marry.findOne({ message.author.id });
113const married = Marry.findOne({ userToMarry.id });
114

If that doesn't work, another thing you could try is making the findOne queries async inside the run method, like this:

1const { Command } = require("discord.js-commando");
2const mongoose = require("mongoose");
3
4mongoose.connect('mongodb+srv://admon:admin@cluster0.sobzp.mongodb.net/dbname?retryWrites=true&w=majority');
5
6//create Schema
7
8const marrySchema = new mongoose.Schema({
9    userID: {
10        type: mongoose.SchemaTypes.String,
11        required: true
12    },
13
14    userMarryID: {
15        type: mongoose.SchemaTypes.String,
16        required: true
17    },
18
19    userPartnerID: {
20        type: mongoose.SchemaTypes.String,
21        required: true
22    }
23});
24
25const Marry = mongoose.model('Marry', marrySchema);
26
27module.exports = class MarryCommand extends Command {
28    constructor(client) {
29        super(client, {
30            name: "marry",
31            memberName: "marry",
32            group: "test",
33            description: "Marry the mentioned user",
34            guildOnly: true,
35            args: [{
36                key: "userToMarry",
37                prompt: "Please select the member you wish to marry.",
38                type: "member",
39            }, ],
40        });
41    }
42
43    run(message, { userToMarry }) {
44        const exists = Marry.findOne({ userID: message.author.id });
45        const married = Marry.findOne({ userID: userToMarry.id });
46
47        if (!userToMarry) {
48            return message.channel.send("Please try again with a valid user.");
49        }
50        if (exists == message.author.id) {
51            return message.channel.send("You are already married!");
52        }
53        if (married == userToMarry.id) {
54            return message.channel.send("This user is already married!");
55        }
56        if (userToMarry.id == message.author.id) {
57            return message.channel.send("You cannot marry yourself!");
58        }
59        if (exists != message.author.id && married != userToMarry.id) {
60            message.channel.send(
61                    `**Important announcement!**
62    
63    ${message.author} makes a marriage proposal ${userToMarry}
64    
65    Are you ready to get married?`
66                )
67                .then((message) => {
68                    message.react("👍")
69                    .then(() => message.react("👎"))
70                    .catch(() => {
71                        //code
72                    });
73                    message.awaitReactions((reaction, user) =>
74                        user.id == userToMarry.id && (reaction.emoji.name == "👍" || reaction.emoji.name == "👎"), {
75                            max: 1,
76                            time: 10000,
77                            errors: ["time"]
78                        }
79                    ).then((collected) => {
80                        const reaction = collected.first();
81                        if (reaction.emoji.name === "👎") {
82                            return message.channel.send("I think **no**...");
83                        }
84                        if (reaction.emoji.name === "👍") {
85                                const createdExists = new Marry({
86                                    userID: message.author.id,
87                                    userMarryID: message.author.id,
88                                    userPartnerID: userToMarry.id
89                                });
90                                createdExists.save().catch(e => console.log(e));
91
92                                const createdMarried = new Marry({
93                                    userID: userToMarry.id,
94                                    userMarryID: userToMarry.id,
95                                    userPartnerID: message.author.id
96                                });
97                                createdMarried.save().catch(e => console.log(e));
98
99                            message.channel.send(`${message.author} and ${userToMarry} now married!!`)
100                                .catch(() => {
101                                    message.reply(
102                                        "No reaction after 10 seconds, operation canceled"
103                                    );
104                                });
105                        }
106                    }).catch(() => {});
107                }).catch(() => {});
108        }
109    }
110};
111const Marry = mongoose.model('Marry', marrySchema);
112const exists = Marry.findOne({ message.author.id });
113const married = Marry.findOne({ userToMarry.id });
114const married = await db.collection("yourcollectioname").findOne({ message.author.id });
115const exists = await db.collection("yourcollectioname").findOne({ userToMarry.id });
116

Source https://stackoverflow.com/questions/71619299

QUESTION

How can you create a pop-up window in Discord that accepts an input from the user?

Asked 2022-Mar-30 at 07:14

It's my first time seeing this feature from a Discord bot. I tried looking everywhere but it seems that I have failed. There's this feature from Captcha.bot Discord bot where you can accept input from a pop-up window inside Discord.

There's a button in an embedded message made by Captcha.bot where you will have to answer a Captcha test. After pressing the button, it creates a pop-up window like this.

enter image description here

After placing the right answer on the captcha bot, here's the aftermath of the experience.

enter image description here

All I want to learn is how to summon that pop-up window using Discord.js if it's even possible or at least learn how they did it.

ANSWER

Answered 2022-Mar-30 at 07:12

Those are called modals, and they will be available in the next discord.js version, v14. There is already a pull request for this.

In the meantime, you can use an npm package like discord-modals or discordjs-modal.

You can find a working example with the discord-modals package below. Don't forget to install it first using npm i discord-modals.

1const {
2  Client,
3  Intents,
4  MessageActionRow,
5  MessageButton,
6} = require('discord.js');
7const discordModals = require('discord-modals');
8const { Modal, TextInputComponent, showModal } = discordModals;
9
10const TOKEN = 'YOUR TOKEN HERE';
11const client = new Client({
12  intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES],
13});
14discordModals(client);
15
16client.on('messageCreate', (message) => {
17  if (message.author.bot) return;
18
19  let button = new MessageActionRow();
20  button.addComponents(
21    new MessageButton()
22      .setCustomId('verification-button')
23      .setStyle('PRIMARY')
24      .setLabel('Open modal dialog'),
25  );
26  message.reply({
27    components: [button],
28  });
29});
30
31client.on('interactionCreate', async (interaction) => {
32  if (interaction.isButton()) {
33    if (interaction.customId === 'verification-button') {
34      const modal = new Modal() // We create a Modal
35        .setCustomId('verification-modal')
36        .setTitle('Verify yourself')
37        .addComponents([
38          new TextInputComponent()
39            .setCustomId('verification-input')
40            .setLabel('Answer')
41            .setStyle('SHORT')
42            .setMinLength(4)
43            .setMaxLength(12)
44            .setPlaceholder('ABCDEF')
45            .setRequired(true),
46        ]);
47
48      showModal(modal, {
49        client,
50        interaction,
51      });
52    }
53  }
54});
55
56client.on('modalSubmit', async (modal) => {
57  if (modal.customId === 'verification-modal') {
58    const response = modal.getTextInputValue('verification-input');
59    modal.reply(`Yay, your answer is submitted: "${response}"`);
60  }
61});
62
63client.once('ready', () => {
64  console.log('Bot v13 is connected...');
65});
66
67client.login(TOKEN);
68

enter image description here

Source https://stackoverflow.com/questions/71672321

QUESTION

Reply to a suggestion with a reaction

Asked 2022-Mar-25 at 20:36

I'm trying to create a bot for a discord server. I added the "marry" command to it.

When a user makes an offer, an announcement message appears. I've added two reactions to this post.

Now you can answer the offer by writing yes or no.

But I want to make it possible to answer the offer by clicking on the reaction, the first reaction is yes, the second is no. Will it be hard to do?

I did everything as in the documentation https://discordjs.guide/popular-topics/reactions.html#awaiting-reactions

But my bot does not react in any way to clicking reactions, please help..

1(`Are you ready to get married?`).then(message => {
2      message.react("👍")
3      message.react("👎")
4    });
5
6const filter = (reaction) => {
7      return ['👍', '👎'].includes(reaction.emoji.name) && message.author.id === userToMarry.id;
8    };
9
10      message.awaitReactions({ filter, max: 1, time: 60000, errors: ['time'] })
11      .then(collected => {
12        const reaction = collected.first();
13        if (reaction.emoji.name === '👎') {
14      return message.channel.send('I think **no**...')}
15        if (reaction.emoji.name === '👍') {
16      db.set(message.author.id, { user: message.author.id, partner: userToMarry.id });
17      db.set(userToMarry.id, { user: userToMarry.id, partner: message.author.id });
18    message.channel.send(`${message.author} and ${userToMarry} now married!`)
19      .catch(err => {
20        message.channel.send(
21          `Something went wrong while trying to marry this user. ${err}`
22        );
23        return console.log(err)});
24      }
25  })
26  .catch(collected => {
27        message.reply('You reacted with neither a thumbs up, nor a thumbs down.');
28    });
29

Here is the complete file:

1(`Are you ready to get married?`).then(message => {
2      message.react("👍")
3      message.react("👎")
4    });
5
6const filter = (reaction) => {
7      return ['👍', '👎'].includes(reaction.emoji.name) && message.author.id === userToMarry.id;
8    };
9
10      message.awaitReactions({ filter, max: 1, time: 60000, errors: ['time'] })
11      .then(collected => {
12        const reaction = collected.first();
13        if (reaction.emoji.name === '👎') {
14      return message.channel.send('I think **no**...')}
15        if (reaction.emoji.name === '👍') {
16      db.set(message.author.id, { user: message.author.id, partner: userToMarry.id });
17      db.set(userToMarry.id, { user: userToMarry.id, partner: message.author.id });
18    message.channel.send(`${message.author} and ${userToMarry} now married!`)
19      .catch(err => {
20        message.channel.send(
21          `Something went wrong while trying to marry this user. ${err}`
22        );
23        return console.log(err)});
24      }
25  })
26  .catch(collected => {
27        message.reply('You reacted with neither a thumbs up, nor a thumbs down.');
28    });
29const { Command } = require('discord.js-commando');
30const db = require("quick.db");
31
32
33module.exports = class MarryCommand extends Command {
34  constructor(client) {
35    super(client, {
36      name: 'marry',
37      memberName: 'marry',
38      group: 'test',
39      description: 'Marry the mentioned user',
40      guildOnly: true,
41      args: [
42        {
43          key: 'userToMarry',
44          prompt: 'Please select the member you wish to marry.',
45          type: 'member'
46        }
47      ]
48    });
49  }
50
51  run(message, { userToMarry }) {
52    const exists = db.get(`${message.author.id}.user`);
53    const married = db.get(`${userToMarry.id}.user`);
54    if (!userToMarry) {
55      return message.channel.send('Please try again with a valid user.')}
56    if (exists == message.author.id) {
57      return message.channel.send('You are already married!')}
58    if (married == userToMarry.id) {
59      return message.channel.send('This user is already married!')}
60    if (userToMarry.id == message.author.id) {
61      return message.channel.send('You cannot marry yourself!');
62    }
63    if (exists != message.author.id && married != userToMarry.id) {
64    message.channel.send(`**Important announcement!**
65    
66    ${message.author} makes a marriage proposal ${userToMarry}
67    
68    Are you ready to get married?`).then(message => {
69      message.react("👍")
70      message.react("👎")
71    });
72      message.channel.awaitMessages(message => message.author.id == userToMarry.id, {max: 1}).then(collected => {
73    if (collected.first().content.toLowerCase() == 'no') {
74      return message.channel.send('I think **no**...')}
75    if (collected.first().content.toLowerCase() == 'yes') {
76      db.set(message.author.id, { user: message.author.id, partner: userToMarry.id });
77      db.set(userToMarry.id, { user: userToMarry.id, partner: message.author.id });
78    message.channel.send(`${message.author} and ${userToMarry} now married!`)
79      .catch(err => {
80        message.channel.send(
81          `Something went wrong while trying to marry this user. ${err}`
82        );
83        return console.log(err)});
84      }
85  });
86}}};
87

ANSWER

Answered 2022-Mar-25 at 20:36

Try like this

1(`Are you ready to get married?`).then(message => {
2      message.react("👍")
3      message.react("👎")
4    });
5
6const filter = (reaction) => {
7      return ['👍', '👎'].includes(reaction.emoji.name) && message.author.id === userToMarry.id;
8    };
9
10      message.awaitReactions({ filter, max: 1, time: 60000, errors: ['time'] })
11      .then(collected => {
12        const reaction = collected.first();
13        if (reaction.emoji.name === '👎') {
14      return message.channel.send('I think **no**...')}
15        if (reaction.emoji.name === '👍') {
16      db.set(message.author.id, { user: message.author.id, partner: userToMarry.id });
17      db.set(userToMarry.id, { user: userToMarry.id, partner: message.author.id });
18    message.channel.send(`${message.author} and ${userToMarry} now married!`)
19      .catch(err => {
20        message.channel.send(
21          `Something went wrong while trying to marry this user. ${err}`
22        );
23        return console.log(err)});
24      }
25  })
26  .catch(collected => {
27        message.reply('You reacted with neither a thumbs up, nor a thumbs down.');
28    });
29const { Command } = require('discord.js-commando');
30const db = require("quick.db");
31
32
33module.exports = class MarryCommand extends Command {
34  constructor(client) {
35    super(client, {
36      name: 'marry',
37      memberName: 'marry',
38      group: 'test',
39      description: 'Marry the mentioned user',
40      guildOnly: true,
41      args: [
42        {
43          key: 'userToMarry',
44          prompt: 'Please select the member you wish to marry.',
45          type: 'member'
46        }
47      ]
48    });
49  }
50
51  run(message, { userToMarry }) {
52    const exists = db.get(`${message.author.id}.user`);
53    const married = db.get(`${userToMarry.id}.user`);
54    if (!userToMarry) {
55      return message.channel.send('Please try again with a valid user.')}
56    if (exists == message.author.id) {
57      return message.channel.send('You are already married!')}
58    if (married == userToMarry.id) {
59      return message.channel.send('This user is already married!')}
60    if (userToMarry.id == message.author.id) {
61      return message.channel.send('You cannot marry yourself!');
62    }
63    if (exists != message.author.id && married != userToMarry.id) {
64    message.channel.send(`**Important announcement!**
65    
66    ${message.author} makes a marriage proposal ${userToMarry}
67    
68    Are you ready to get married?`).then(message => {
69      message.react("👍")
70      message.react("👎")
71    });
72      message.channel.awaitMessages(message => message.author.id == userToMarry.id, {max: 1}).then(collected => {
73    if (collected.first().content.toLowerCase() == 'no') {
74      return message.channel.send('I think **no**...')}
75    if (collected.first().content.toLowerCase() == 'yes') {
76      db.set(message.author.id, { user: message.author.id, partner: userToMarry.id });
77      db.set(userToMarry.id, { user: userToMarry.id, partner: message.author.id });
78    message.channel.send(`${message.author} and ${userToMarry} now married!`)
79      .catch(err => {
80        message.channel.send(
81          `Something went wrong while trying to marry this user. ${err}`
82        );
83        return console.log(err)});
84      }
85  });
86}}};
87.then(msg=> {
88      msg.react('👍').then(() => msg.react('👎'));
89    
90
91      msg.awaitReactions((reaction, user) => user.id == userToMarry.id && (reaction.emoji.name == '👍' || reaction.emoji.name == '👎'),
92        { max: 1, time: 60000, errors: ['time'] })
93      .then(collected => {
94        const reaction = collected.first();
95        if (reaction.emoji.name === '👎') {
96      return message.channel.send('I think **no**...')}
97    if (reaction.emoji.name === '👍') {
98      db.set(message.author.id, { user: message.author.id, partner: userToMarry.id });
99      db.set(userToMarry.id, { user: userToMarry.id, partner: message.author.id });
100    message.channel.send(`${message.author} and ${userToMarry} now married!!`)
101 
102    ...
103
104  });
105});
106

Source https://stackoverflow.com/questions/71576281

QUESTION

How do I fix CLIENT_MISSING_INTENTS error?

Asked 2022-Mar-11 at 10:51

I started learning about discord.js but now I am facing this issue. I tried some googling but couldn't manage to fix it.

1const Discord = require('discord.js');
2// const Discord = require('discord.js');
3
4// using Intents class
5const client = new Discord.Client();
6
7client.on('message', (msg) => {
8  // Send back a reply when the specific command has been written by a user.
9  if (msg.content === '!hello') {
10    msg.reply('Hello World!');
11  }
12});
13
14client.login('my_token');
15
16

This is the error I am getting:

enter image description here

ANSWER

Answered 2021-Aug-07 at 16:34

You need to specify the events which you want your bot to receive using gateway intents.

Instead of

const client = new Discord.Client();

Use

const client = new Discord.Client({ intents: [Enter intents here] })

For example

const client = new Discord.Client({ intents: ["GUILDS", "GUILD_MESSAGES"] })

Here's another useful link: https://discord.com/developers/docs/topics/gateway

Source https://stackoverflow.com/questions/68694195

QUESTION

Is there a way to access the children of a CategoryChannel before it is deleted? [Discord.js]

Asked 2022-Feb-19 at 14:09

I handle a channelDelete event in my discord bot. My original intent was to do the following:

  1. Listen for when a channel is deleted
  2. Check to see if its type equals 'GUILD_CATEGORY'
  3. Delete all the channels under that category

I can typically access channels under a CategoryChannel through its property called children anywhere else except during this event...

1module.exports = {
2    name: 'channelDelete',
3    once: false,
4    async execute(channel) {
5        if(channel.type == 'GUILD_CATEGORY')
6            for(let [child_id, child] of channel.children)
7                if (child.deletable) child.delete();
8    },
9}
10

I can confirm the code is being executed, but the problem is that the incoming channel object is in a state where it is already deleted, and I cannot get the children:

  • During debugging, I noticed the channel object has the property deleted: true
  • The children property is empty, even though I know there were channels in that channel category prior to deletion

Is there a way for my bot to collect and handle the children of a CategoryChannel prior to its deletion?

ANSWER

Answered 2022-Feb-19 at 14:09
Why?

Unfortunately, this is how CategoryChannels work in discord.js...
When the category is deleted, discord.js sends a request to the API to delete the channel. Only then, Discord sends you the event after the category is deleted.
What happens next is that the children are not located in the category anymore! So you will not be able to get the children inside the CategoryChannel object.


This is the code for the children property

1module.exports = {
2    name: 'channelDelete',
3    once: false,
4    async execute(channel) {
5        if(channel.type == 'GUILD_CATEGORY')
6            for(let [child_id, child] of channel.children)
7                if (child.deletable) child.delete();
8    },
9}
10get children() {
11    return this.guild.channels.cache.filter(c => c.parentId === this.id);
12}
13

It filters the channels which are in the guild, but those children channels are not located in the category anymore. Which is the reason the property is empty.

The (Only?) Solution

This will require caching the channels themselves. As there aren't really any other solutions.
You may cache the channels in different ways.
Just remember... there are instances and references in Javascript, and failure to acknowledge may lead to weird behaviors. The following code only works for small bots without sharding, just so you know.

1module.exports = {
2    name: 'channelDelete',
3    once: false,
4    async execute(channel) {
5        if(channel.type == 'GUILD_CATEGORY')
6            for(let [child_id, child] of channel.children)
7                if (child.deletable) child.delete();
8    },
9}
10get children() {
11    return this.guild.channels.cache.filter(c => c.parentId === this.id);
12}
13const cachedChannels = new Map()
14
15client.on('ready', () => {
16  // Looping thru guilds...
17  client.guilds.forEach((guild) => {
18    // Filtering the channels to category channels only and looping thru them...
19    guild.channels.filter((channel) => channel.type === "GUILD_CATEGORY").forEach((category) => {
20      // Note on references and instances: Numbers, Strings and Booleans do not have instances like Object, Arrays, etc. do
21      // We are using an array here to abuse the references
22      cachedChannels.set(category.id, [])
23
24      // Looping thru the children channels...
25      category.children.forEach((children) => {
26        // This is the array we've created earlier
27        const storedChannels = cachedChannels.get(category.id)
28
29        // Pushing the ID so we can fetch them later
30        storedChannels.push(children.id)
31      })
32    })
33  })
34})
35
36client.on('channelDelete', (channel) => {
37  if (channel.type === "GUILD_CATEGORY") {
38    // Looping thru our cached channel IDs defined earlier
39    cachedChannels.get(channel.id).forEach((id) => {
40      const child = channel.guild.channels.get(id)
41      child.delete()
42    })
43
44    // Delete the cached IDs to save memory
45    cachedChannels.delete(channel.id)
46  }
47})
48
49

Source https://stackoverflow.com/questions/70563152

QUESTION

How do I get mobile status for discord bot by directly modifying IDENTIFY packet?

Asked 2022-Feb-09 at 15:05

Apparently, discord bots can have mobile status as opposed to the desktop (online) status that one gets by default.

bot having mobile status

After a bit of digging I found out that such a status is achieved by modifying the IDENTIFY packet in discord.gateway.DiscordWebSocket.identify modifying the value of $browser to Discord Android or Discord iOS should theoretically get us the mobile status.

After modifying code snippets I found online which does this, I end up with this :

1def get_mobile():
2    """
3    The Gateway's IDENTIFY packet contains a properties field, containing $os, $browser and $device fields.
4    Discord uses that information to know when your phone client and only your phone client has connected to Discord,
5    from there they send the extended presence object.
6    The exact field that is checked is the $browser field. If it's set to Discord Android on desktop,
7    the mobile indicator is is triggered by the desktop client. If it's set to Discord Client on mobile,
8    the mobile indicator is not triggered by the mobile client.
9    The specific values for the $os, $browser, and $device fields are can change from time to time.
10    """
11    import ast
12    import inspect
13    import re
14    import discord
15
16    def source(o):
17        s = inspect.getsource(o).split("\n")
18        indent = len(s[0]) - len(s[0].lstrip())
19
20        return "\n".join(i[indent:] for i in s)
21
22    source_ = source(discord.gateway.DiscordWebSocket.identify)
23    patched = re.sub(
24        r'([\'"]\$browser[\'"]:\s?[\'"]).+([\'"])',
25        r"\1Discord Android\2",
26        source_,
27    )
28
29    loc = {}
30    exec(compile(ast.parse(patched), "<string>", "exec"), discord.gateway.__dict__, loc)
31    return loc["identify"]
32

Now all there is left to do is overwrite the discord.gateway.DiscordWebSocket.identify during runtime in the main file, something like this :

1def get_mobile():
2    """
3    The Gateway's IDENTIFY packet contains a properties field, containing $os, $browser and $device fields.
4    Discord uses that information to know when your phone client and only your phone client has connected to Discord,
5    from there they send the extended presence object.
6    The exact field that is checked is the $browser field. If it's set to Discord Android on desktop,
7    the mobile indicator is is triggered by the desktop client. If it's set to Discord Client on mobile,
8    the mobile indicator is not triggered by the mobile client.
9    The specific values for the $os, $browser, and $device fields are can change from time to time.
10    """
11    import ast
12    import inspect
13    import re
14    import discord
15
16    def source(o):
17        s = inspect.getsource(o).split("\n")
18        indent = len(s[0]) - len(s[0].lstrip())
19
20        return "\n".join(i[indent:] for i in s)
21
22    source_ = source(discord.gateway.DiscordWebSocket.identify)
23    patched = re.sub(
24        r'([\'"]\$browser[\'"]:\s?[\'"]).+([\'"])',
25        r"\1Discord Android\2",
26        source_,
27    )
28
29    loc = {}
30    exec(compile(ast.parse(patched), "<string>", "exec"), discord.gateway.__dict__, loc)
31    return loc["identify"]
32import discord
33import os
34from discord.ext import commands
35import mobile_status
36
37discord.gateway.DiscordWebSocket.identify = mobile_status.get_mobile()
38bot = commands.Bot(command_prefix="?")
39
40@bot.event
41async def on_ready():
42    print(f"Sucessfully logged in as {bot.user}")
43
44bot.run(os.getenv("DISCORD_TOKEN"))
45

And we do get the mobile status successfully
successful mobile status for bot

But here's the problem, I wanted to directly modify the file (which held the function) rather than monkey-patching it during runtime. So I cloned the dpy lib locally and edited the file on my machine, it ended up looking like this :

1def get_mobile():
2    """
3    The Gateway's IDENTIFY packet contains a properties field, containing $os, $browser and $device fields.
4    Discord uses that information to know when your phone client and only your phone client has connected to Discord,
5    from there they send the extended presence object.
6    The exact field that is checked is the $browser field. If it's set to Discord Android on desktop,
7    the mobile indicator is is triggered by the desktop client. If it's set to Discord Client on mobile,
8    the mobile indicator is not triggered by the mobile client.
9    The specific values for the $os, $browser, and $device fields are can change from time to time.
10    """
11    import ast
12    import inspect
13    import re
14    import discord
15
16    def source(o):
17        s = inspect.getsource(o).split("\n")
18        indent = len(s[0]) - len(s[0].lstrip())
19
20        return "\n".join(i[indent:] for i in s)
21
22    source_ = source(discord.gateway.DiscordWebSocket.identify)
23    patched = re.sub(
24        r'([\'"]\$browser[\'"]:\s?[\'"]).+([\'"])',
25        r"\1Discord Android\2",
26        source_,
27    )
28
29    loc = {}
30    exec(compile(ast.parse(patched), "<string>", "exec"), discord.gateway.__dict__, loc)
31    return loc["identify"]
32import discord
33import os
34from discord.ext import commands
35import mobile_status
36
37discord.gateway.DiscordWebSocket.identify = mobile_status.get_mobile()
38bot = commands.Bot(command_prefix="?")
39
40@bot.event
41async def on_ready():
42    print(f"Sucessfully logged in as {bot.user}")
43
44bot.run(os.getenv("DISCORD_TOKEN"))
45    async def identify(self):
46        """Sends the IDENTIFY packet."""
47        payload = {
48            'op': self.IDENTIFY,
49            'd': {
50                'token': self.token,
51                'properties': {
52                    '$os': sys.platform,
53                    '$browser': 'Discord Android',
54                    '$device': 'Discord Android',
55                    '$referrer': '',
56                    '$referring_domain': ''
57                },
58                'compress': True,
59                'large_threshold': 250,
60                'v': 3
61            }
62        }
63     # ...
64

(edited both $browser and $device to Discord Android just to be safe)

But this does not work and just gives me the regular desktop online icon.
So the next thing I did is to inspect the identify function after it has been monkey-patched, so I could just look at the source code and see what went wrong earlier, but due to hard luck I got this error :

1def get_mobile():
2    """
3    The Gateway's IDENTIFY packet contains a properties field, containing $os, $browser and $device fields.
4    Discord uses that information to know when your phone client and only your phone client has connected to Discord,
5    from there they send the extended presence object.
6    The exact field that is checked is the $browser field. If it's set to Discord Android on desktop,
7    the mobile indicator is is triggered by the desktop client. If it's set to Discord Client on mobile,
8    the mobile indicator is not triggered by the mobile client.
9    The specific values for the $os, $browser, and $device fields are can change from time to time.
10    """
11    import ast
12    import inspect
13    import re
14    import discord
15
16    def source(o):
17        s = inspect.getsource(o).split("\n")
18        indent = len(s[0]) - len(s[0].lstrip())
19
20        return "\n".join(i[indent:] for i in s)
21
22    source_ = source(discord.gateway.DiscordWebSocket.identify)
23    patched = re.sub(
24        r'([\'"]\$browser[\'"]:\s?[\'"]).+([\'"])',
25        r"\1Discord Android\2",
26        source_,
27    )
28
29    loc = {}
30    exec(compile(ast.parse(patched), "<string>", "exec"), discord.gateway.__dict__, loc)
31    return loc["identify"]
32import discord
33import os
34from discord.ext import commands
35import mobile_status
36
37discord.gateway.DiscordWebSocket.identify = mobile_status.get_mobile()
38bot = commands.Bot(command_prefix="?")
39
40@bot.event
41async def on_ready():
42    print(f"Sucessfully logged in as {bot.user}")
43
44bot.run(os.getenv("DISCORD_TOKEN"))
45    async def identify(self):
46        """Sends the IDENTIFY packet."""
47        payload = {
48            'op': self.IDENTIFY,
49            'd': {
50                'token': self.token,
51                'properties': {
52                    '$os': sys.platform,
53                    '$browser': 'Discord Android',
54                    '$device': 'Discord Android',
55                    '$referrer': '',
56                    '$referring_domain': ''
57                },
58                'compress': True,
59                'large_threshold': 250,
60                'v': 3
61            }
62        }
63     # ...
64Traceback (most recent call last):
65  File "c:\Users\Achxy\Desktop\fresh\file.py", line 8, in <module>
66    print(inspect.getsource(discord.gateway.DiscordWebSocket.identify))
67  File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 1024, in getsource
68    lines, lnum = getsourcelines(object)
69  File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 1006, in getsourcelines
70    lines, lnum = findsource(object)
71  File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 835, in findsource
72    raise OSError('could not get source code')
73OSError: could not get source code
74

Code :

1def get_mobile():
2    """
3    The Gateway's IDENTIFY packet contains a properties field, containing $os, $browser and $device fields.
4    Discord uses that information to know when your phone client and only your phone client has connected to Discord,
5    from there they send the extended presence object.
6    The exact field that is checked is the $browser field. If it's set to Discord Android on desktop,
7    the mobile indicator is is triggered by the desktop client. If it's set to Discord Client on mobile,
8    the mobile indicator is not triggered by the mobile client.
9    The specific values for the $os, $browser, and $device fields are can change from time to time.
10    """
11    import ast
12    import inspect
13    import re
14    import discord
15
16    def source(o):
17        s = inspect.getsource(o).split("\n")
18        indent = len(s[0]) - len(s[0].lstrip())
19
20        return "\n".join(i[indent:] for i in s)
21
22    source_ = source(discord.gateway.DiscordWebSocket.identify)
23    patched = re.sub(
24        r'([\'"]\$browser[\'"]:\s?[\'"]).+([\'"])',
25        r"\1Discord Android\2",
26        source_,
27    )
28
29    loc = {}
30    exec(compile(ast.parse(patched), "<string>", "exec"), discord.gateway.__dict__, loc)
31    return loc["identify"]
32import discord
33import os
34from discord.ext import commands
35import mobile_status
36
37discord.gateway.DiscordWebSocket.identify = mobile_status.get_mobile()
38bot = commands.Bot(command_prefix="?")
39
40@bot.event
41async def on_ready():
42    print(f"Sucessfully logged in as {bot.user}")
43
44bot.run(os.getenv("DISCORD_TOKEN"))
45    async def identify(self):
46        """Sends the IDENTIFY packet."""
47        payload = {
48            'op': self.IDENTIFY,
49            'd': {
50                'token': self.token,
51                'properties': {
52                    '$os': sys.platform,
53                    '$browser': 'Discord Android',
54                    '$device': 'Discord Android',
55                    '$referrer': '',
56                    '$referring_domain': ''
57                },
58                'compress': True,
59                'large_threshold': 250,
60                'v': 3
61            }
62        }
63     # ...
64Traceback (most recent call last):
65  File "c:\Users\Achxy\Desktop\fresh\file.py", line 8, in <module>
66    print(inspect.getsource(discord.gateway.DiscordWebSocket.identify))
67  File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 1024, in getsource
68    lines, lnum = getsourcelines(object)
69  File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 1006, in getsourcelines
70    lines, lnum = findsource(object)
71  File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 835, in findsource
72    raise OSError('could not get source code')
73OSError: could not get source code
74import discord
75import os
76from discord.ext import commands
77import mobile_status
78import inspect
79
80discord.gateway.DiscordWebSocket.identify = mobile_status.get_mobile()
81print(inspect.getsource(discord.gateway.DiscordWebSocket.identify))
82bot = commands.Bot(command_prefix="?")
83
84@bot.event
85async def on_ready():
86    print(f"Sucessfully logged in as {bot.user}")
87
88bot.run(os.getenv("DISCORD_TOKEN"))
89

Since this same behavior was exhibited for every patched function (aforementioned one and the loc["identify"]) I could no longer use inspect.getsource(...) and then relied upon dis.dis which lead to much more disappointing results

The disassembled data looks exactly identical to the monkey-patched working version, so the directly modified version simply does not work despite function content being the exact same. (In regards to disassembled data)

Notes: Doing Discord iOS directly does not work either, changing the $device to some other value but keeping $browser does not work, I have tried all combinations, none of them work.

TL;DR: How to get mobile status for discord bot without monkey-patching it during runtime?

ANSWER

Answered 2022-Feb-07 at 23:03

The following works by subclassing the relevant class, and duplicating code with the relevant changes. We also have to subclass the Client class, to overwrite the place where the gateway/websocket class is used. This results in a lot of duplicated code, however it does work, and requires neither dirty monkey-patching nor editing the library source code.

However, it does come with many of the same problems as editing the library source code - mainly that as the library is updated, this code will become out of date (if you're using the archived and obsolete version of the library, you have bigger problems instead).

1def get_mobile():
2    """
3    The Gateway's IDENTIFY packet contains a properties field, containing $os, $browser and $device fields.
4    Discord uses that information to know when your phone client and only your phone client has connected to Discord,
5    from there they send the extended presence object.
6    The exact field that is checked is the $browser field. If it's set to Discord Android on desktop,
7    the mobile indicator is is triggered by the desktop client. If it's set to Discord Client on mobile,
8    the mobile indicator is not triggered by the mobile client.
9    The specific values for the $os, $browser, and $device fields are can change from time to time.
10    """
11    import ast
12    import inspect
13    import re
14    import discord
15
16    def source(o):
17        s = inspect.getsource(o).split("\n")
18        indent = len(s[0]) - len(s[0].lstrip())
19
20        return "\n".join(i[indent:] for i in s)
21
22    source_ = source(discord.gateway.DiscordWebSocket.identify)
23    patched = re.sub(
24        r'([\'"]\$browser[\'"]:\s?[\'"]).+([\'"])',
25        r"\1Discord Android\2",
26        source_,
27    )
28
29    loc = {}
30    exec(compile(ast.parse(patched), "<string>", "exec"), discord.gateway.__dict__, loc)
31    return loc["identify"]
32import discord
33import os
34from discord.ext import commands
35import mobile_status
36
37discord.gateway.DiscordWebSocket.identify = mobile_status.get_mobile()
38bot = commands.Bot(command_prefix="?")
39
40@bot.event
41async def on_ready():
42    print(f"Sucessfully logged in as {bot.user}")
43
44bot.run(os.getenv("DISCORD_TOKEN"))
45    async def identify(self):
46        """Sends the IDENTIFY packet."""
47        payload = {
48            'op': self.IDENTIFY,
49            'd': {
50                'token': self.token,
51                'properties': {
52                    '$os': sys.platform,
53                    '$browser': 'Discord Android',
54                    '$device': 'Discord Android',
55                    '$referrer': '',
56                    '$referring_domain': ''
57                },
58                'compress': True,
59                'large_threshold': 250,
60                'v': 3
61            }
62        }
63     # ...
64Traceback (most recent call last):
65  File "c:\Users\Achxy\Desktop\fresh\file.py", line 8, in <module>
66    print(inspect.getsource(discord.gateway.DiscordWebSocket.identify))
67  File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 1024, in getsource
68    lines, lnum = getsourcelines(object)
69  File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 1006, in getsourcelines
70    lines, lnum = findsource(object)
71  File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 835, in findsource
72    raise OSError('could not get source code')
73OSError: could not get source code
74import discord
75import os
76from discord.ext import commands
77import mobile_status
78import inspect
79
80discord.gateway.DiscordWebSocket.identify = mobile_status.get_mobile()
81print(inspect.getsource(discord.gateway.DiscordWebSocket.identify))
82bot = commands.Bot(command_prefix="?")
83
84@bot.event
85async def on_ready():
86    print(f"Sucessfully logged in as {bot.user}")
87
88bot.run(os.getenv("DISCORD_TOKEN"))
89import asyncio
90import sys
91
92import aiohttp
93
94import discord
95from discord.gateway import DiscordWebSocket, _log
96from discord.ext.commands import Bot
97
98
99class MyGateway(DiscordWebSocket):
100
101    async def identify(self):
102        payload = {
103            'op': self.IDENTIFY,
104            'd': {
105                'token': self.token,
106                'properties': {
107                    '$os': sys.platform,
108                    '$browser': 'Discord Android',
109                    '$device': 'Discord Android',
110                    '$referrer': '',
111                    '$referring_domain': ''
112                },
113                'compress': True,
114                'large_threshold': 250,
115                'v': 3
116            }
117        }
118
119        if self.shard_id is not None and self.shard_count is not None:
120            payload['d']['shard'] = [self.shard_id, self.shard_count]
121
122        state = self._connection
123        if state._activity is not None or state._status is not None:
124            payload['d']['presence'] = {
125                'status': state._status,
126                'game': state._activity,
127                'since': 0,
128                'afk': False
129            }
130
131        if state._intents is not None:
132            payload['d']['intents'] = state._intents.value
133
134        await self.call_hooks('before_identify', self.shard_id, initial=self._initial_identify)
135        await self.send_as_json(payload)
136        _log.info('Shard ID %s has sent the IDENTIFY payload.', self.shard_id)
137
138
139class MyBot(Bot):
140
141    async def connect(self, *, reconnect: bool = True) -> None:
142        """|coro|
143
144        Creates a websocket connection and lets the websocket listen
145        to messages from Discord. This is a loop that runs the entire
146        event system and miscellaneous aspects of the library. Control
147        is not resumed until the WebSocket connection is terminated.
148
149        Parameters
150        -----------
151        reconnect: :class:`bool`
152            If we should attempt reconnecting, either due to internet
153            failure or a specific failure on Discord's part. Certain
154            disconnects that lead to bad state will not be handled (such as
155            invalid sharding payloads or bad tokens).
156
157        Raises
158        -------
159        :exc:`.GatewayNotFound`
160            If the gateway to connect to Discord is not found. Usually if this
161            is thrown then there is a Discord API outage.
162        :exc:`.ConnectionClosed`
163            The websocket connection has been terminated.
164        """
165
166        backoff = discord.client.ExponentialBackoff()
167        ws_params = {
168            'initial': True,
169            'shard_id': self.shard_id,
170        }
171        while not self.is_closed():
172            try:
173                coro = MyGateway.from_client(self, **ws_params)
174                self.ws = await asyncio.wait_for(coro, timeout=60.0)
175                ws_params['initial'] = False
176                while True:
177                    await self.ws.poll_event()
178            except discord.client.ReconnectWebSocket as e:
179                _log.info('Got a request to %s the websocket.', e.op)
180                self.dispatch('disconnect')
181                ws_params.update(sequence=self.ws.sequence, resume=e.resume, session=self.ws.session_id)
182                continue
183            except (OSError,
184                    discord.HTTPException,
185                    discord.GatewayNotFound,
186                    discord.ConnectionClosed,
187                    aiohttp.ClientError,
188                    asyncio.TimeoutError) as exc:
189
190                self.dispatch('disconnect')
191                if not reconnect:
192                    await self.close()
193                    if isinstance(exc, discord.ConnectionClosed) and exc.code == 1000:
194                        # clean close, don't re-raise this
195                        return
196                    raise
197
198                if self.is_closed():
199                    return
200
201                # If we get connection reset by peer then try to RESUME
202                if isinstance(exc, OSError) and exc.errno in (54, 10054):
203                    ws_params.update(sequence=self.ws.sequence, initial=False, resume=True, session=self.ws.session_id)
204                    continue
205
206                # We should only get this when an unhandled close code happens,
207                # such as a clean disconnect (1000) or a bad state (bad token, no sharding, etc)
208                # sometimes, discord sends us 1000 for unknown reasons so we should reconnect
209                # regardless and rely on is_closed instead
210                if isinstance(exc, discord.ConnectionClosed):
211                    if exc.code == 4014:
212                        raise discord.PrivilegedIntentsRequired(exc.shard_id) from None
213                    if exc.code != 1000:
214                        await self.close()
215                        raise
216
217                retry = backoff.delay()
218                _log.exception("Attempting a reconnect in %.2fs", retry)
219                await asyncio.sleep(retry)
220                # Always try to RESUME the connection
221                # If the connection is not RESUME-able then the gateway will invalidate the session.
222                # This is apparently what the official Discord client does.
223                ws_params.update(sequence=self.ws.sequence, resume=True, session=self.ws.session_id)
224
225
226bot = MyBot(command_prefix="?")
227
228
229@bot.event
230async def on_ready():
231    print(f"Sucessfully logged in as {bot.user}")
232
233bot.run("YOUR_BOT_TOKEN")
234

Personally, I think that the following approach, which does include some runtime monkey-patching (but no AST manipulation) is cleaner for this purpose:

1def get_mobile():
2    """
3    The Gateway's IDENTIFY packet contains a properties field, containing $os, $browser and $device fields.
4    Discord uses that information to know when your phone client and only your phone client has connected to Discord,
5    from there they send the extended presence object.
6    The exact field that is checked is the $browser field. If it's set to Discord Android on desktop,
7    the mobile indicator is is triggered by the desktop client. If it's set to Discord Client on mobile,
8    the mobile indicator is not triggered by the mobile client.
9    The specific values for the $os, $browser, and $device fields are can change from time to time.
10    """
11    import ast
12    import inspect
13    import re
14    import discord
15
16    def source(o):
17        s = inspect.getsource(o).split("\n")
18        indent = len(s[0]) - len(s[0].lstrip())
19
20        return "\n".join(i[indent:] for i in s)
21
22    source_ = source(discord.gateway.DiscordWebSocket.identify)
23    patched = re.sub(
24        r'([\'"]\$browser[\'"]:\s?[\'"]).+([\'"])',
25        r"\1Discord Android\2",
26        source_,
27    )
28
29    loc = {}
30    exec(compile(ast.parse(patched), "<string>", "exec"), discord.gateway.__dict__, loc)
31    return loc["identify"]
32import discord
33import os
34from discord.ext import commands
35import mobile_status
36
37discord.gateway.DiscordWebSocket.identify = mobile_status.get_mobile()
38bot = commands.Bot(command_prefix="?")
39
40@bot.event
41async def on_ready():
42    print(f"Sucessfully logged in as {bot.user}")
43
44bot.run(os.getenv("DISCORD_TOKEN"))
45    async def identify(self):
46        """Sends the IDENTIFY packet."""
47        payload = {
48            'op': self.IDENTIFY,
49            'd': {
50                'token': self.token,
51                'properties': {
52                    '$os': sys.platform,
53                    '$browser': 'Discord Android',
54                    '$device': 'Discord Android',
55                    '$referrer': '',
56                    '$referring_domain': ''
57                },
58                'compress': True,
59                'large_threshold': 250,
60                'v': 3
61            }
62        }
63     # ...
64Traceback (most recent call last):
65  File "c:\Users\Achxy\Desktop\fresh\file.py", line 8, in <module>
66    print(inspect.getsource(discord.gateway.DiscordWebSocket.identify))
67  File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 1024, in getsource
68    lines, lnum = getsourcelines(object)
69  File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 1006, in getsourcelines
70    lines, lnum = findsource(object)
71  File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 835, in findsource
72    raise OSError('could not get source code')
73OSError: could not get source code
74import discord
75import os
76from discord.ext import commands
77import mobile_status
78import inspect
79
80discord.gateway.DiscordWebSocket.identify = mobile_status.get_mobile()
81print(inspect.getsource(discord.gateway.DiscordWebSocket.identify))
82bot = commands.Bot(command_prefix="?")
83
84@bot.event
85async def on_ready():
86    print(f"Sucessfully logged in as {bot.user}")
87
88bot.run(os.getenv("DISCORD_TOKEN"))
89import asyncio
90import sys
91
92import aiohttp
93
94import discord
95from discord.gateway import DiscordWebSocket, _log
96from discord.ext.commands import Bot
97
98
99class MyGateway(DiscordWebSocket):
100
101    async def identify(self):
102        payload = {
103            'op': self.IDENTIFY,
104            'd': {
105                'token': self.token,
106                'properties': {
107                    '$os': sys.platform,
108                    '$browser': 'Discord Android',
109                    '$device': 'Discord Android',
110                    '$referrer': '',
111                    '$referring_domain': ''
112                },
113                'compress': True,
114                'large_threshold': 250,
115                'v': 3
116            }
117        }
118
119        if self.shard_id is not None and self.shard_count is not None:
120            payload['d']['shard'] = [self.shard_id, self.shard_count]
121
122        state = self._connection
123        if state._activity is not None or state._status is not None:
124            payload['d']['presence'] = {
125                'status': state._status,
126                'game': state._activity,
127                'since': 0,
128                'afk': False
129            }
130
131        if state._intents is not None:
132            payload['d']['intents'] = state._intents.value
133
134        await self.call_hooks('before_identify', self.shard_id, initial=self._initial_identify)
135        await self.send_as_json(payload)
136        _log.info('Shard ID %s has sent the IDENTIFY payload.', self.shard_id)
137
138
139class MyBot(Bot):
140
141    async def connect(self, *, reconnect: bool = True) -> None:
142        """|coro|
143
144        Creates a websocket connection and lets the websocket listen
145        to messages from Discord. This is a loop that runs the entire
146        event system and miscellaneous aspects of the library. Control
147        is not resumed until the WebSocket connection is terminated.
148
149        Parameters
150        -----------
151        reconnect: :class:`bool`
152            If we should attempt reconnecting, either due to internet
153            failure or a specific failure on Discord's part. Certain
154            disconnects that lead to bad state will not be handled (such as
155            invalid sharding payloads or bad tokens).
156
157        Raises
158        -------
159        :exc:`.GatewayNotFound`
160            If the gateway to connect to Discord is not found. Usually if this
161            is thrown then there is a Discord API outage.
162        :exc:`.ConnectionClosed`
163            The websocket connection has been terminated.
164        """
165
166        backoff = discord.client.ExponentialBackoff()
167        ws_params = {
168            'initial': True,
169            'shard_id': self.shard_id,
170        }
171        while not self.is_closed():
172            try:
173                coro = MyGateway.from_client(self, **ws_params)
174                self.ws = await asyncio.wait_for(coro, timeout=60.0)
175                ws_params['initial'] = False
176                while True:
177                    await self.ws.poll_event()
178            except discord.client.ReconnectWebSocket as e:
179                _log.info('Got a request to %s the websocket.', e.op)
180                self.dispatch('disconnect')
181                ws_params.update(sequence=self.ws.sequence, resume=e.resume, session=self.ws.session_id)
182                continue
183            except (OSError,
184                    discord.HTTPException,
185                    discord.GatewayNotFound,
186                    discord.ConnectionClosed,
187                    aiohttp.ClientError,
188                    asyncio.TimeoutError) as exc:
189
190                self.dispatch('disconnect')
191                if not reconnect:
192                    await self.close()
193                    if isinstance(exc, discord.ConnectionClosed) and exc.code == 1000:
194                        # clean close, don't re-raise this
195                        return
196                    raise
197
198                if self.is_closed():
199                    return
200
201                # If we get connection reset by peer then try to RESUME
202                if isinstance(exc, OSError) and exc.errno in (54, 10054):
203                    ws_params.update(sequence=self.ws.sequence, initial=False, resume=True, session=self.ws.session_id)
204                    continue
205
206                # We should only get this when an unhandled close code happens,
207                # such as a clean disconnect (1000) or a bad state (bad token, no sharding, etc)
208                # sometimes, discord sends us 1000 for unknown reasons so we should reconnect
209                # regardless and rely on is_closed instead
210                if isinstance(exc, discord.ConnectionClosed):
211                    if exc.code == 4014:
212                        raise discord.PrivilegedIntentsRequired(exc.shard_id) from None
213                    if exc.code != 1000:
214                        await self.close()
215                        raise
216
217                retry = backoff.delay()
218                _log.exception("Attempting a reconnect in %.2fs", retry)
219                await asyncio.sleep(retry)
220                # Always try to RESUME the connection
221                # If the connection is not RESUME-able then the gateway will invalidate the session.
222                # This is apparently what the official Discord client does.
223                ws_params.update(sequence=self.ws.sequence, resume=True, session=self.ws.session_id)
224
225
226bot = MyBot(command_prefix="?")
227
228
229@bot.event
230async def on_ready():
231    print(f"Sucessfully logged in as {bot.user}")
232
233bot.run("YOUR_BOT_TOKEN")
234import sys
235from discord.gateway import DiscordWebSocket, _log
236from discord.ext.commands import Bot
237
238
239async def identify(self):
240    payload = {
241        'op': self.IDENTIFY,
242        'd': {
243            'token': self.token,
244            'properties': {
245                '$os': sys.platform,
246                '$browser': 'Discord Android',
247                '$device': 'Discord Android',
248                '$referrer': '',
249                '$referring_domain': ''
250            },
251            'compress': True,
252            'large_threshold': 250,
253            'v': 3
254        }
255    }
256
257    if self.shard_id is not None and self.shard_count is not None:
258        payload['d']['shard'] = [self.shard_id, self.shard_count]
259
260    state = self._connection
261    if state._activity is not None or state._status is not None:
262        payload['d']['presence'] = {
263            'status': state._status,
264            'game': state._activity,
265            'since': 0,
266            'afk': False
267        }
268
269    if state._intents is not None:
270        payload['d']['intents'] = state._intents.value
271
272    await self.call_hooks('before_identify', self.shard_id, initial=self._initial_identify)
273    await self.send_as_json(payload)
274    _log.info('Shard ID %s has sent the IDENTIFY payload.', self.shard_id)
275
276
277DiscordWebSocket.identify = identify
278bot = Bot(command_prefix="?")
279
280
281@bot.event
282async def on_ready():
283    print(f"Sucessfully logged in as {bot.user}")
284
285bot.run("YOUR_DISCORD_TOKEN")
286

As to why editing the library source code did not work for you, I can only assume that you have edited the wrong copy of the file, as people have commented.

Source https://stackoverflow.com/questions/70903401

QUESTION

Changing Category/Channels Permissions Returns Error "Missing Permissions" - Novus/Discord.py

Asked 2022-Feb-08 at 01:39

SOLVED - The categories/channels were set to private which is why they couldn't be changed even with the correct permissions. My solution was to tell the user which ones and to add the role with the permissions manually. I added a message that said they can just give the bot administrator permissions and it will do it for them. Hopefully, this helps anyone who runs into this in the future.

I'm trying to change the permissions of multiple categories and channels using the following code:

1role = get(guild.roles, name="Fun")
2for channel in guild.channels:
3    overwrites = channel.overwrites_for(role)
4    overwrites.view_channel = False
5    await channel.set_permissions(role, overwrite=overwrites)
6

I get the following error:

1role = get(guild.roles, name="Fun")
2for channel in guild.channels:
3    overwrites = channel.overwrites_for(role)
4    overwrites.view_channel = False
5    await channel.set_permissions(role, overwrite=overwrites)
6await channel.set_permissions(role, overwrite=overwrites)
7discord.errors.Forbidden: 403 Forbidden (error code: 50013): Missing Permissions
8

It will work if I give the bot the administrator permission. However, it won't work if I give the bot every single other permission, the bot is at the top of the roles, and it has every category permission. What am I missing? I'm using Novus (fork of discord.py so it's pretty much the same thing).

Edit: I've asked people in the discord.py, Novus, and discord developers discord servers and they can't help me either. With the exception of the discord developers server they just didn't answer my question.

Edit 2: I was able to get it working when I manually added the bot's role to the category and enabled view_channel. This won't work, however, because that means the server owner has to manually do this for every category and channel which is really inconvenient.

ANSWER

Answered 2021-Oct-31 at 12:05

This is simply how Discord works, if a channel is private and the bot does not have administrator permissions or role that has permissions to view the channel, it is not able to view it.

You can create a new category that the bot can access like this:

1role = get(guild.roles, name="Fun")
2for channel in guild.channels:
3    overwrites = channel.overwrites_for(role)
4    overwrites.view_channel = False
5    await channel.set_permissions(role, overwrite=overwrites)
6await channel.set_permissions(role, overwrite=overwrites)
7discord.errors.Forbidden: 403 Forbidden (error code: 50013): Missing Permissions
8role = await guild.create_role(name="Fun")
9category = await guild.create_category("category_name")
10await category.set_permissions(role, read_messages=True, send_messages=True, connect=True, speak=True)
11await category.set_permissions(ctx.guild.me, read_messages=True, send_messages=True, speak=True)
12

Source https://stackoverflow.com/questions/69694159

QUESTION

Error [ERR_REQUIRE_ESM]: require() of ES Module not supported

Asked 2022-Feb-03 at 22:08

I'm trying to make a Discord bot that just says if someone is online on the game.

However I keep getting this message:

[ERR_REQUIRE_ESM]: require() of ES Module from not supported. Instead change the require of index.js in... to a dynamic import() which is available in all CommonJS modules.

This is my code:

1    module.exports = {
2        name: 'username',
3        description: "this is the username command",
4        async execute(message, args) {
5
6            const fetch = require('node-fetch');
7
8            if (args.length !== 1) {
9                return message.channel.send("invalid username wtf")
10            }
11
12            const ign = args[0]
13
14            if (ign.length > 16 || ign.length < 3) {
15                return message.channel.send("invalid username wtf")
16            }
17
18            const uuid = await fetch(`https://api.mojang.com/users/profiles/minecraft/${ign}`).then(data => data.json()).then(data => data.id).catch(err => message.channel.send("error wtf"));
19            const onlineInfo = await fetch(`https://api.hypixel.net/status?key=${john}&uuid=${uuid}`).then(data => data.json());
20
21            if (uuid.length !== 32) {
22                return;
23            }
24
25            if (onlineinfo.success) {
26                if (onlineinfo.session.online) {
27                    message.channel.send("they are online")
28                }
29                else {
30                    message.channel.send("they are offline")
31                }
32            }
33            else {
34                message.channel.send("hypixel api bad wtf")
35            }
36        }
37    }
38

This is my package.json file:

1    module.exports = {
2        name: 'username',
3        description: "this is the username command",
4        async execute(message, args) {
5
6            const fetch = require('node-fetch');
7
8            if (args.length !== 1) {
9                return message.channel.send("invalid username wtf")
10            }
11
12            const ign = args[0]
13
14            if (ign.length > 16 || ign.length < 3) {
15                return message.channel.send("invalid username wtf")
16            }
17
18            const uuid = await fetch(`https://api.mojang.com/users/profiles/minecraft/${ign}`).then(data => data.json()).then(data => data.id).catch(err => message.channel.send("error wtf"));
19            const onlineInfo = await fetch(`https://api.hypixel.net/status?key=${john}&uuid=${uuid}`).then(data => data.json());
20
21            if (uuid.length !== 32) {
22                return;
23            }
24
25            if (onlineinfo.success) {
26                if (onlineinfo.session.online) {
27                    message.channel.send("they are online")
28                }
29                else {
30                    message.channel.send("they are offline")
31                }
32            }
33            else {
34                message.channel.send("hypixel api bad wtf")
35            }
36        }
37    }
38{
39    "name": "discordbot",
40    "version": "1.0.0",
41    "main": "main.js",
42    "scripts": {
43        "test": "echo \"Error: no test specified\" && exit 1",
44        "start": "node main.js"
45    },
46    "author": "",
47    "license": "ISC",
48    "description": "",
49    "dependencies": {
50        "discord.js": "^13.0.1",
51        "node-fetch": "^3.0.0"
52    }
53}
54

ANSWER

Answered 2021-Sep-07 at 06:38

node-fetch v3 recently stopped support for the require way of importing it in favor of ES Modules. You'll need to use ESM imports now, like:

1    module.exports = {
2        name: 'username',
3        description: "this is the username command",
4        async execute(message, args) {
5
6            const fetch = require('node-fetch');
7
8            if (args.length !== 1) {
9                return message.channel.send("invalid username wtf")
10            }
11
12            const ign = args[0]
13
14            if (ign.length > 16 || ign.length < 3) {
15                return message.channel.send("invalid username wtf")
16            }
17
18            const uuid = await fetch(`https://api.mojang.com/users/profiles/minecraft/${ign}`).then(data => data.json()).then(data => data.id).catch(err => message.channel.send("error wtf"));
19            const onlineInfo = await fetch(`https://api.hypixel.net/status?key=${john}&uuid=${uuid}`).then(data => data.json());
20
21            if (uuid.length !== 32) {
22                return;
23            }
24
25            if (onlineinfo.success) {
26                if (onlineinfo.session.online) {
27                    message.channel.send("they are online")
28                }
29                else {
30                    message.channel.send("they are offline")
31                }
32            }
33            else {
34                message.channel.send("hypixel api bad wtf")
35            }
36        }
37    }
38{
39    "name": "discordbot",
40    "version": "1.0.0",
41    "main": "main.js",
42    "scripts": {
43        "test": "echo \"Error: no test specified\" && exit 1",
44        "start": "node main.js"
45    },
46    "author": "",
47    "license": "ISC",
48    "description": "",
49    "dependencies": {
50        "discord.js": "^13.0.1",
51        "node-fetch": "^3.0.0"
52    }
53}
54import fetch from "node-fetch";
55

at the top of your file.

Source https://stackoverflow.com/questions/69081410

QUESTION

How to setup .NET 6 with Dapper Identity and Discord Login

Asked 2022-Jan-29 at 17:34

I'm trying to figure out how to setup a login via Discord Oauth2 while using Dapper as my ORM.

Microsoft has a guide here that I have followed to setup all of my stores. I infact can call CreateAsync() method and a user gets created in my database, so I believe that side of things is completely setup.

My issues lie within external login. Below you will find what I have tried.

Program.cs:

1//omitted code that binds interfaces and classes - this code works and is fully tested. it is not related to problem at hand.
2builder.Services.AddIdentity<User, Role>()
3.AddDefaultTokenProviders();
4
5builder.Services.AddAuthentication()
6.AddCookie(options =>
7{
8    options.LoginPath = "/signin";
9    options.LogoutPath = "/signout";
10})
11.AddDiscord(options =>
12{
13    options.ClientId = "some id";
14    options.ClientSecret = "some secret";
15    options.ClaimActions.MapCustomJson("urn:discord:avatar:url", user =>
16        string.Format(
17            CultureInfo.InvariantCulture,
18            "https://cdn.discordapp.com/avatars/{0}/{1}.{2}",
19            user.GetString("id"),
20            user.GetString("avatar"),
21            user.GetString("avatar")!.StartsWith("a_") ? "gif" : "png"));
22});
23
24builder.Services.AddRazorPages();
25
26var app = builder.Build();
27app.UseDeveloperExceptionPage();
28
29app.UseHttpsRedirection();
30app.UseStaticFiles();
31
32app.UseRouting();
33app.UseAuthentication();
34
35app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
36
37app.Run();
38

Here is the Account Controller Code:

1//omitted code that binds interfaces and classes - this code works and is fully tested. it is not related to problem at hand.
2builder.Services.AddIdentity<User, Role>()
3.AddDefaultTokenProviders();
4
5builder.Services.AddAuthentication()
6.AddCookie(options =>
7{
8    options.LoginPath = "/signin";
9    options.LogoutPath = "/signout";
10})
11.AddDiscord(options =>
12{
13    options.ClientId = "some id";
14    options.ClientSecret = "some secret";
15    options.ClaimActions.MapCustomJson("urn:discord:avatar:url", user =>
16        string.Format(
17            CultureInfo.InvariantCulture,
18            "https://cdn.discordapp.com/avatars/{0}/{1}.{2}",
19            user.GetString("id"),
20            user.GetString("avatar"),
21            user.GetString("avatar")!.StartsWith("a_") ? "gif" : "png"));
22});
23
24builder.Services.AddRazorPages();
25
26var app = builder.Build();
27app.UseDeveloperExceptionPage();
28
29app.UseHttpsRedirection();
30app.UseStaticFiles();
31
32app.UseRouting();
33app.UseAuthentication();
34
35app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
36
37app.Run();
38public class AccountController : Controller
39{
40    private readonly ISignInService _signInService;
41    private readonly IUserService _userService;
42
43    public AccountController(ISignInService signInService, IUserService userService)
44    {
45        _signInService = signInService;
46        _userService = userService;
47    }
48
49    [HttpGet("~/signin")]
50    public async Task<IActionResult> SignIn() => View("SignIn", await HttpContext.GetExternalProvidersAsync());
51
52    [HttpPost("~/signin")]
53    public async Task<IActionResult> SignIn([FromForm] string provider, string returnUrl)
54    {
55        if (string.IsNullOrWhiteSpace(provider))
56        {
57            return BadRequest();
58        }
59
60        if (!await HttpContext.IsProviderSupportedAsync(provider))
61        {
62            return BadRequest();
63        }
64
65        var redirectUrl = Url.Action(nameof(LoginCallback), "Account", new { returnUrl });
66        var properties = _signInService.ConfigureExternalAuthenticationProperties(provider, redirectUrl, null);
67        properties.Items.Add("XsrfKey", "Test");
68        
69        return Challenge(properties, provider);
70    }
71
72    [HttpGet("~/signout")]
73    [HttpPost("~/signout")]
74    public IActionResult SignOutCurrentUser()
75    {
76        return SignOut(new AuthenticationProperties {RedirectUri = "/"},
77            CookieAuthenticationDefaults.AuthenticationScheme);
78    }
79
80    //[HttpGet("~/Account/LoginCallback")]
81    [HttpGet]
82    public async Task<IActionResult> LoginCallback(string returnUrl = null, string remoteError = null)
83    {
84        if (remoteError != null)
85        {
86            return RedirectToAction("Index", "Home");
87        }
88        var info = await _signInService.GetExternalLoginInfoAsync("Test");
89        if (info == null)
90        {
91            return RedirectToAction("Index", "Home");
92        }
93
94        var result = await _signInService.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
95        if (result.Succeeded)
96        {
97            return RedirectToLocal(returnUrl);
98        }
99        if (result.IsLockedOut)
100        {
101            return RedirectToAction("Index", "Home");
102        }
103        else
104        {
105            // If the user does not have an account, then ask the user to create an account.
106            ViewData["ReturnUrl"] = returnUrl;
107            ViewData["LoginProvider"] = info.LoginProvider;
108            var email = info.Principal.FindFirstValue(ClaimTypes.Email);
109            return RedirectToAction("Index", "Home");
110        }
111    }
112
113    private IActionResult RedirectToLocal(string returnUrl)
114    {
115        if (Url.IsLocalUrl(returnUrl))
116        {
117            return Redirect(returnUrl);
118        }
119        else
120        {
121            return RedirectToAction(nameof(HomeController.Index), "Home");
122        }
123    }
124}
125

Here is what happens:

  1. I click on the Login via discord button.
  2. I am taken to Discord Website
  3. I login via the discord website
  4. I am redirected back to my website
  5. info is never retrieved. var info = await _signInService.GetExternalLoginInfoAsync("Test"); that line is always null.

I've been struggling to figure out what I have overlooked in my setup as I don't have any errors about anything.

I am using this package.

ANSWER

Answered 2022-Jan-29 at 17:34

Firstly... We need to take a look at the implementation of the internal method GetExternalLoginInfoAsync inside SignInManager.cs and take note of all the conditions that could possibly lead to null being returned.

I will provide my answer as comments within the code below:

1//omitted code that binds interfaces and classes - this code works and is fully tested. it is not related to problem at hand.
2builder.Services.AddIdentity<User, Role>()
3.AddDefaultTokenProviders();
4
5builder.Services.AddAuthentication()
6.AddCookie(options =>
7{
8    options.LoginPath = "/signin";
9    options.LogoutPath = "/signout";
10})
11.AddDiscord(options =>
12{
13    options.ClientId = "some id";
14    options.ClientSecret = "some secret";
15    options.ClaimActions.MapCustomJson("urn:discord:avatar:url", user =>
16        string.Format(
17            CultureInfo.InvariantCulture,
18            "https://cdn.discordapp.com/avatars/{0}/{1}.{2}",
19            user.GetString("id"),
20            user.GetString("avatar"),
21            user.GetString("avatar")!.StartsWith("a_") ? "gif" : "png"));
22});
23
24builder.Services.AddRazorPages();
25
26var app = builder.Build();
27app.UseDeveloperExceptionPage();
28
29app.UseHttpsRedirection();
30app.UseStaticFiles();
31
32app.UseRouting();
33app.UseAuthentication();
34
35app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
36
37app.Run();
38public class AccountController : Controller
39{
40    private readonly ISignInService _signInService;
41    private readonly IUserService _userService;
42
43    public AccountController(ISignInService signInService, IUserService userService)
44    {
45        _signInService = signInService;
46        _userService = userService;
47    }
48
49    [HttpGet("~/signin")]
50    public async Task<IActionResult> SignIn() => View("SignIn", await HttpContext.GetExternalProvidersAsync());
51
52    [HttpPost("~/signin")]
53    public async Task<IActionResult> SignIn([FromForm] string provider, string returnUrl)
54    {
55        if (string.IsNullOrWhiteSpace(provider))
56        {
57            return BadRequest();
58        }
59
60        if (!await HttpContext.IsProviderSupportedAsync(provider))
61        {
62            return BadRequest();
63        }
64
65        var redirectUrl = Url.Action(nameof(LoginCallback), "Account", new { returnUrl });
66        var properties = _signInService.ConfigureExternalAuthenticationProperties(provider, redirectUrl, null);
67        properties.Items.Add("XsrfKey", "Test");
68        
69        return Challenge(properties, provider);
70    }
71
72    [HttpGet("~/signout")]
73    [HttpPost("~/signout")]
74    public IActionResult SignOutCurrentUser()
75    {
76        return SignOut(new AuthenticationProperties {RedirectUri = "/"},
77            CookieAuthenticationDefaults.AuthenticationScheme);
78    }
79
80    //[HttpGet("~/Account/LoginCallback")]
81    [HttpGet]
82    public async Task<IActionResult> LoginCallback(string returnUrl = null, string remoteError = null)
83    {
84        if (remoteError != null)
85        {
86            return RedirectToAction("Index", "Home");
87        }
88        var info = await _signInService.GetExternalLoginInfoAsync("Test");
89        if (info == null)
90        {
91            return RedirectToAction("Index", "Home");
92        }
93
94        var result = await _signInService.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
95        if (result.Succeeded)
96        {
97            return RedirectToLocal(returnUrl);
98        }
99        if (result.IsLockedOut)
100        {
101            return RedirectToAction("Index", "Home");
102        }
103        else
104        {
105            // If the user does not have an account, then ask the user to create an account.
106            ViewData["ReturnUrl"] = returnUrl;
107            ViewData["LoginProvider"] = info.LoginProvider;
108            var email = info.Principal.FindFirstValue(ClaimTypes.Email);
109            return RedirectToAction("Index", "Home");
110        }
111    }
112
113    private IActionResult RedirectToLocal(string returnUrl)
114    {
115        if (Url.IsLocalUrl(returnUrl))
116        {
117            return Redirect(returnUrl);
118        }
119        else
120        {
121            return RedirectToAction(nameof(HomeController.Index), "Home");
122        }
123    }
124}
125    /// <summary>
126    /// Gets the external login information for the current login, as an asynchronous operation.
127    /// </summary>
128    /// <param name="expectedXsrf">Flag indication whether a Cross Site Request Forgery token was expected in the current request.</param>
129    /// <returns>The task object representing the asynchronous operation containing the <see name="ExternalLoginInfo"/>
130    /// for the sign-in attempt.</returns>
131    public virtual async Task<ExternalLoginInfo> GetExternalLoginInfoAsync(string expectedXsrf = null)
132    {
133        var auth = await Context.AuthenticateAsync(IdentityConstants.ExternalScheme);
134        var items = auth?.Properties?.Items;
135        if (auth?.Principal == null || items == null || !items.ContainsKey(LoginProviderKey))
136        {
137            // What cases can lead us here?
138            // * The authentication was unsuccessful maybe due to
139            //   - Login cancellation
140            //   - Project not running on a secured environment (https)
141            //   - SignInScheme property of auth options not
142            //     equal to IdentityConstants.ExternalScheme
143            return null;
144        }
145
146        if (expectedXsrf != null)
147        {
148            // It is important to note that XsrfKey is a constant
149            // declared above in this class whose value is "XsrfId".
150            if (!items.ContainsKey(XsrfKey))
151            {
152              // What cases can lead us here?
153              // * You passed an argument for expectedXsrf but
154              //   the initialized key-value pairs does not contain
155              //   any key for XsrfKey ("XsrfId").
156              // In your case the below is wrong:
157              // properties.Items.Add("XsrfKey", "Test"); <= remove
158              // Pass the value as 3rd parameter in
159              // "ConfigureExternalAuthenticationProperties" method call instead
160              // _signInService.ConfigureExternalAuthenticationProperties(provider, redirectUrl, "Test")
161                return null;
162            }
163            var userId = items[XsrfKey] as string;
164            if (userId != expectedXsrf)
165            {
166              // What cases can lead us here?
167              // * The argument passed for expectedXsrf does not
168              //   match the value of initialized key-value pair
169              //   for XsrfKey ("XsrfId").
170              // Ensure "Test" should go with "XsrfId" as key
171              // by passing the value as 3rd parameter in
172              // "ConfigureExternalAuthenticationProperties" method call instead.
173                return null;
174            }
175        }
176
177        var providerKey = auth.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
178        var provider = items[LoginProviderKey] as string;
179        if (providerKey == null || provider == null)
180        {
181            return null;
182        }
183
184        var providerDisplayName = (await GetExternalAuthenticationSchemesAsync()).FirstOrDefault(p => p.Name == provider)?.DisplayName
185                                  ?? provider;
186        return new ExternalLoginInfo(auth.Principal, provider, providerKey, providerDisplayName)
187        {
188            AuthenticationTokens = auth.Properties.GetTokens()
189        };
190    }
191

So from the code review these are some possible causes for null:

  1. The authentication was unsuccessful maybe due to

    • Login cancellation

    • Project not running on a secured environment (https)

    • SignInScheme property of auth options under StartUp.cs or appsettings.json not equal to IdentityConstants.ExternalScheme

  2. You passed an argument for expectedXsrf but the initialized key-value pair does not contain any key for XsrfKey ("XsrfId").

    • In your case the below is wrong:

      properties.Items.Add("XsrfKey", "Test"); <= remove this line as "XsrfKey" is unknown.

      Instead you pass the value as 3rd parameter in "ConfigureExternalAuthenticationProperties" method call:

    _signInService.ConfigureExternalAuthenticationProperties(provider, redirectUrl, "Test");

Source https://stackoverflow.com/questions/70794402

QUESTION

How to check if a bot can DM a user

Asked 2022-Jan-22 at 22:03

If a user has the privacy setting "Allow direct messages from server members" turned off and a discord bot calls

1await user.dm_channel.send(&quot;Hello there&quot;)
2

You'll get this error:

1await user.dm_channel.send(&quot;Hello there&quot;)
2discord.errors.Forbidden: 403 Forbidden (error code: 50007): Cannot send messages to this user
3

I would like to check whether I can message a user without sending them a message. Trying to send a message and catching this error does not work for me, because I don't want a message to get sent in the event that the bot is allowed to message.

I have tried this:

1await user.dm_channel.send(&quot;Hello there&quot;)
2discord.errors.Forbidden: 403 Forbidden (error code: 50007): Cannot send messages to this user
3print(user.dm_channel.permissions_for(bot).send_messages)
4

but it always returns True, even if the message is not permitted.

I have also tried this:

1await user.dm_channel.send(&quot;Hello there&quot;)
2discord.errors.Forbidden: 403 Forbidden (error code: 50007): Cannot send messages to this user
3print(user.dm_channel.permissions_for(bot).send_messages)
4channel = await user.create_dm()
5if channel is None:
6    ...
7

but unfortunately, it seems that "has permission to message user" and "has permission to create a dm channel" are considered different.

EDIT

To clarify the exact usage since there seems to be a bit of confusion, take this example. There is a server, and 3 users in question: Me, My Bot, and Steve. Steve has "Allow direct messages from server members" checked off.

The bot has a command called !newgame which accepts a list of users and starts a game amongst them, which involves DMing some of the members of the game. Because of Steve's privacy settings, he cannot play the game (since the bot will need to message him). If I do

1await user.dm_channel.send(&quot;Hello there&quot;)
2discord.errors.Forbidden: 403 Forbidden (error code: 50007): Cannot send messages to this user
3print(user.dm_channel.permissions_for(bot).send_messages)
4channel = await user.create_dm()
5if channel is None:
6    ...
7!newgame @DJMcMayhem @Steve
8

I'd like to provide a response like:

1await user.dm_channel.send(&quot;Hello there&quot;)
2discord.errors.Forbidden: 403 Forbidden (error code: 50007): Cannot send messages to this user
3print(user.dm_channel.permissions_for(bot).send_messages)
4channel = await user.create_dm()
5if channel is None:
6    ...
7!newgame @DJMcMayhem @Steve
8&gt; I can't start a game with that list of users because @Steve has the wrong privacy settings.
9

But as far as I know right now, the only way to find out if Steve can play is by first attempting to message every user, which I'd like to avoid.

ANSWER

Answered 2022-Jan-22 at 22:03
Explanation

You can generate a Bad Request to the dm_channel. This can be accomplished by setting content to None, for example.

If it returns with 400 Bad Request, you can DM them. If it returns with 403 Forbidden, you can't.

Code
1await user.dm_channel.send(&quot;Hello there&quot;)
2discord.errors.Forbidden: 403 Forbidden (error code: 50007): Cannot send messages to this user
3print(user.dm_channel.permissions_for(bot).send_messages)
4channel = await user.create_dm()
5if channel is None:
6    ...
7!newgame @DJMcMayhem @Steve
8&gt; I can't start a game with that list of users because @Steve has the wrong privacy settings.
9async def can_dm_user(user: discord.User) -&gt; bool:
10    ch = user.dm_channel
11    if ch is None:
12        ch = await user.create_dm()
13
14    try:
15        await ch.send()
16    except discord.Forbidden:
17        return False
18    except discord.HTTPException:
19        return True
20
21

Source https://stackoverflow.com/questions/70660854

Community Discussions contain sources that include Stack Exchange Network

Tutorials and Learning Resources in Discord

Tutorials and Learning Resources are not available at this moment for Discord

Share this Page

share link

Get latest updates on Discord