Why is the following code not adding a role to the user? - discord

In the following code, i am trying to add a role to a user whenever a user reacts the "A" emoji to a specific message. However, when I react to the message, I only see the console log Role Added1, meaning the thread is stuck in the line trying assigning roles to the user. What have I done wrong in the following code causing the error?
bot.on("raw", event => {
const eventName = event.t;
if(eventName == "MESSAGE_REACTION_ADD"){
var roles = JSON.parse(fs.readFileSync("roles.json"));
var info = JSON.parse(fs.readFileSync("info.json"))
if(event.d.message_id == info["Class Message"]){//class selection
switch(event.d.emoji.name){
case "🇦":
console.log("Role Added1");
event.d.member.roles.add(bot.guilds.cache.get("721695624613068830")
.roles.cache.get(roles["myrole"]));
console.log("Role Added2");
break;
}
}
}
}

You are not receiving a GuildMember class instance from the raw event. It's a simple json object, it has nothing to do with discordjs. Here is something working:
bot.on("raw", async event => {
const eventName = event.t;
if(eventName == "MESSAGE_REACTION_ADD"){
var roles = JSON.parse(fs.readFileSync("roles.json"));
var info = JSON.parse(fs.readFileSync("info.json"))
if(event.d.message_id == info["Class Message"]){//class selection
switch(event.d.emoji.name){
case "🇦":
console.log("Role Added1");
const guild = bot.guilds.cache.get("721695624613068830");
const memberID = event.d.user_id;
const member = await guild.members.fetch(memberID);
member.roles.add(roles["myrole"]);
console.log("Role Added2");
break;
}
}
}
}
You could also use the following to make your event function synchronous:
bot.on("raw", event => {
const eventName = event.t;
if(eventName == "MESSAGE_REACTION_ADD"){
var roles = JSON.parse(fs.readFileSync("roles.json"));
var info = JSON.parse(fs.readFileSync("info.json"))
if(event.d.message_id == info["Class Message"]){//class selection
switch(event.d.emoji.name){
case "🇦":
console.log("Role Added1");
const guild = bot.guilds.cache.get("721695624613068830");
const memberID = event.d.user_id;
guild.members.fetch(memberID).then((member) => {
member.roles.add(roles["myrole"]);
console.log("Role Added2");
});
break;
}
}
}
}

Related

.NET MAUI Setting an item SelectedIndex on Page Load is Delayed

When the view appears on the screen there is a short delay setting the values to each control. Is it possible to set the values before the user sees the view?
public UserSettingsView()
{
InitializeComponent();
LoadAsync();
}
private async void LoadAsync()
{
try
{
// Loading data from API
Languages = await _languageService.GetAsync(AccessToken);
USStates = await _uSStateService.GetAsync(AccessToken);
// Assigning the list to the ItemSource of each Picker.
ddlLanguages.ItemsSource = Languages;
ddlUSStates.ItemsSource = USStates;
// Getting the user's preferred settings
var userSettings = await _accountService.GetSettingsAsync(UserID, AccessToken);
if (userSettings != null)
{
// Setting user values to each Picker control.
// This is where the delay happens.
ddlLanguages.SelectedIndex = Languages.FindIndex(x => x.ID == userSettings .LanguageID);
ddlUSStates.SelectedIndex = USStates.FindIndex(x => x.ID == userSettings .USStateID);
cbAge.IsChecked = currentSettings.AgeQualified;
}
}
catch
{
await DisplayAlert("Oh no!", "Error loading the page", "OK");
}
}
To resolve the delay, I am passing the two lists for the languages and the States from the previous page.
public UserSettingsView(List<Language> _languages, List<USState> _usStates)
{
InitializeComponent();
Languages = _languages;
USStates = _usStates;
LoadAsync();
}
private async void LoadAsync()
{
try
{
ddlLanguages.ItemsSource = Languages;
ddlUSStates.ItemsSource = USStates;
var currentSettings = await _accountService.GetSettingsAsync(UserID, AccessToken);
if (currentSettings != null)
{
ddlLanguages.SelectedIndex = Languages.FindIndex(x => x.ID == currentSettings.LanguageID);
ddlUSStates.SelectedIndex = USStates.FindIndex(x => x.ID == currentSettings.USStateID);
switchAgeQualification.IsToggled = currentSettings.AgeQualified;
}
}
catch
{
await DisplayAlert("Error", "Could not load page data", "OK");
}
}
If I understand correctly, you currently have a line like this:
await Navigation.PushModalAsync(new UserSettingsView());
I don't see the types of the properties involved, but the basic idea is to do all the slow awaits BEFORE doing new UserSettingsView....
Something like this:
public class UserSettingsData
{
SomeType1 Languages;
SomeType2 USStates;
SomeType3 UserSettings;
}
...
// Slow await calls.
var data = await UserSettingsView.PrepAsync(UserId, AccessToken);
// Now create and display the view.
await Navigation.PushModalAsync(new UserSettingsView(data));
...
public static async UserSettingsData PrepAsync(SomeType4 UserId, SomeType5 AccessToken)
{
var data = new UserSettingsData();
data.Languages = await _accountService.GetSettingsAsync(...);
data.USStates = await ...;
data.UserSettings = await ...;
}
public UserSettingsView(UserSettingsData data)
{
...
// NOT AN ASYNC METHOD, so happens immediately, before page is shown.
Load(data);
}
// NOT AN ASYNC METHOD, so happens immediately.
private void Load(UserSettingsData data)
{
Languages = data.Languages;
USStates = data.USStates;
var userSettings = data.UserSettings;
...
// if still need DisplayAlert
Dispatcher.InvokeOnMainThread(async () =>
await DisplayAlert...
);
}
Replace "SomeType" etc with your actual types.

Post a message from iframe in React

I have trouble about sending message from cross-domain iframe in React. I read many articles, most of them are about sending message to iframe.
The issue is that it didn't show any error message in the page that embed the iframe , and when I go to the see the page that I embed, it did show a error message.
Scene.js:230 Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://thewebsite.com') does not match the recipient window's origin ('https://mywebsite').
so I can't tell if I the message have been sent successfully or not.
Here is my code :
confirm = () => {
const { homeId, correctData } = this.state
const form = new FormData();
//process data
form.append('scene_id', homeId)
form.append('material_id', correctData[0].id)
form.append('material_img', correctData[0].component_img)
const obj = JSON.parse(JSON.stringify(form));
//
//way 1
parent.postMessage(obj, '*')
//way 2
parent.postMessage(obj, 'https://www.thewebsite.com/pro_wall.html')
//way 3
window.frames.postMessage(obj, '*')
//way 4
window.top.postMessage(obj, '*')
//way 5
const targetWindow = window.open('https://www.thewebsite.com/pro_wall.html')
setTimeout(() => {
targetWindow?.postMessage(obj, '*')
}, 3000)
}
Sorry for writing too many ways to post message, Just want to make sure I tried every possibility.
After few tries, I got positive feedback from the client. They got data. This is my code I wrote eventually.
confirm = () => {
const { homeId, correctData } = this.state
const formData = new FormData();
formData.append('scene_id', homeId)
formData.append('material_id', correctData[0]?.id)
formData.append('material_img', correctData[0]?.component_img)
var object = {};
formData.forEach((value, key) => {object[key] = value});
var json = JSON.stringify(object);
parent.postMessage(json, `https://www.thewebsite.com/pro_wall.html`)
}
and I saw the code at client's side from web devTool, it looks like this,
<script>
window.addEventListener("message", receivewall, false);
function receivewall(event){
var origin = event.origin;
if(origin == 'https://mywebsite'){
var params = JSON.parse(event.data);
$('#result').html($.param(params));
// console.log(params);
}
// $('#result').html(data);
}
function getQueryVariable(query) {
var vars = query.split('&');
var params = {};
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
}
return params;
}
</script>

how do i make sure that only one reaction can be added to a message?

I am creating a role reaction bot and I want that if a member has already clicked on a reaction and clicks another it removes the previous one and the role associated with it and gives him the role that corresponds to the last one clicked (there are 15 reactions available) , I was writing code similar to this:
let msg = reaction.message;
let msgGuild = msg.guild;
let userGuild = msgGuild.members.cache.get(user.id);
let userRole = userGuild.roles;
if(reaction.message.channel.id === "764148072498200589") {
if(reaction.emoji.name === "RedRoleID") {
if(userRole.cache.has("BaseRoleID")) {
userRole.remove("BaseRoleID");
userRole.add("RedRoleID");
} else if(userRole.cache.has("OrangeRoleID")) {
userRole.remove("OrangeRoleID");
userRole.add("RedRoleID");
}
};
};
is there an easier and shorter way to do what I want without creating an else if for each role?
I think you could probably make an array of all the emoji names, then use Array.prototype.forEach to check all of them.
let { emoji, message, message: { guild, channel }} = reaction;
let { roles } = guild.member(user.id);
const emojis = ['BaseRoleID', 'RedRoleID', 'OrangeRoleID', 'etc'];
if (channel.id === '764148072498200589') {
emojis.forEach((id) => (roles.cache.has(id) ? roles.remove(id) : id));
roles.add(emoji.name);
}
Edit: My mistake, I thought you had named the emojis as the corresponding role IDs. Here's an alternate method if you do not want to do that:
let { emoji, message, message: { guild, channel }} = reaction;
let { roles } = guild.member(user.id);
const emojis = [
{ emote: 'EmojiID', role: 'RoleID' },
'continue this pattern for all roles and emotes'
];
if (channel.id === '764148072498200589') {
emojis.forEach(({ emote, role }) => {
if (roles.cache.has(role))
return roles.remove(role)
if (emoji.id === emote) roles.add(role)
});
};

How to get the specific discord bot channel with channelid?

My bot returns undefined when using bot.channels.get(channelid).
Here's a sample of my code:
//this is executed in a guild with id 416809320513011713
const Discordjs = require("discord.js");
const bot = new Discordjs.Client();
const auth = require('./auth.json');
const FileSys = require("fs");
bot.on('messageDelete', async function (message) {
console.log('message deleted')
let currentguildsettings = JSON.parse(FileSys.readFileSync('./DatStore/GuildDat/' + message.guild.id + '.dat', 'UTF8'));
if (currentguildsettings[0] == 1) {
if (currentguildsettings[1] != 0) {
let channelid = currentguildsettings[1].toString()
let channel = bot.channels.get(channelid);
console.log('settings on true, channelid ' + channelid)
if (channel) {
console.log('channel found')
}
}
}
}
bot.login(auth.token)
file ./DatStore/GuildDat/416809320513011713.dat contains:
[1,424085503361417200,0]
Here's the output:
message deleted
settings on true, channelid 424085503361417200
If the channel was found it should've logged 'channel found' in the output.
What should I change to make it return the channel?
The channel id key is a string, you must enclose it as a string in your array.
let c1 = bot.channels.get(424085503361417200); // Will produce undefined
let c2 = bot.channels.get('424085503361417200'); // Will produce a channel object (if available)
The channel wasn't available since I used the wrong id:
I saved the id's at my server settings command in int format instead of string, parseInt() broke the exact number.
if (logchannelaction == 'set') {
if (currentguildsettings[1] == message.channel.id) return message.reply("logchannel was already set to this channel");
currentguildsettings[1] = parseInt(message.channel.id);
message.reply("logchannel has set to #" + message.channel.name);
if (currentguildsettings[0] == 0) {
currentguildsettings[0] = 1
message.reply("logchannel has automatically enabled");
}
FileSys.writeFileSync(guilddatpath, JSON.stringify(currentguildsettings));
return
}
Thank you for trying to help me.

Is there a way to toggle an event with command?

Is there any way to make an event toggleable with a command?
I'm trying to make a welcome/farewell event but I don't want it to be active on default.
This is how my event looks right now:
client.on("guildMemberAdd", (member) => {
const guild = member.guild;
let memberTag = member.user.tag;
guild.channels.sort(function(chan1, chan2) {
if (chan1.type !== `text`) return 1;
if (!chan1.permissionsFor(guild.me).has(`SEND_MESSAGES`)) return -1;
return chan1.position < chan2.position ? -1 : 1;
}).first().send(memberTag + " just joined <:floshed:533687801741443082>");
});
As requested here is an example of my comment:
One way to do it is to store a variable for a guild in some database which has a value of either true or false. Then you'd grab that variable and check if said guild has the option turned on or off
client.on("guildMemberAdd", (member) => {
const guild = member.guild;
let memberTag = member.user.tag;
// Code here to get the guild from database, this is just a non-working example
let dbGuild = database.get('Guild', guild.id);
// Check if the guild has the welcome command disabled
if (dbGuild.enableWelcomeCmd === false) {
// Breaks the function, no further message will be send
return;
}
guild.channels.sort(function(chan1,chan2){
if(chan1.type!==`text`) return 1;
if(!chan1.permissionsFor(guild.me).has(`SEND_MESSAGES`)) return -1;
return chan1.position < chan2.position ? -1 : 1;
}).first().send(memberTag + " just joined <:floshed:533687801741443082>");
});
client.on("message", async message => {
// Check if the msg has been send by a bot
if(message.author.bot) return;
// Check if message has correct prefix
if(message.content.indexOf(config.prefix) !== 0) return;
const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
// Code for actually changing the guild variable
if (command === 'toggleWelcome') {
// Code here to get the guild from database, this is just a non-working example
let dbGuild = database.get('Guild', message.guild.id);
dbGuild.enableWelcomeCmd = !dbGuild.enableWelcomeCmd;
// Save the new variable for the guild (also a non-working example)
database.save('Guild', message.guild.id, dbGuild);
}
});
You'll have to look into databases and such yourself, there is a wide variety of (free) options which all have a different syntax. That part is something for you to figure out but I hope this can give you a general idea.

Resources