How to make discord bot send scraped message? - javascript

I want to make an a discord bot that sends a scraped message.
I expected it to send the message but it gave me an error:
throw new DiscordAPIError(request.path, data, request.method, res.status);
DiscordAPIError: Cannot send an empty message
I tried to use message.channel.send(); but it doesn't seem to work.
Code:
let data = await page.evaluate(() => {
let Name = document.querySelector('div[id="title"]').innerText;
let Description = document.querySelector('div[id="content"]').innerText;
return {
Name,
Description
}
});
console.log(data);
message.channel.send(data);
debugger;
await browser.close();

The problem is that you shouldn't send the dictionary directly. While message.channel.send only accepts StringResolvable or APIMessage, data as a dictionary is neither. For more information, see the documentation.
Instead, you can convert data to a string first. The following is one of the solutions.
// Convert using JSON.stringify
message.channel.send(JSON.stringify(data));
Full code example (I tried it on https://example.com and thus there are different queries):
let data = await page.evaluate(() => {
let Name = document.querySelector('h1').innerText;
let Description = document.querySelector('p').innerText;
return {
Name,
Description
}
});
console.log(data);
message.channel.send(JSON.stringify(data));
Message sent by the bot without errors being thrown:
{"Name":"Example Domain","Description":"This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission."}
If you expect a different message, just make sure that the argument you are passing to message.channel.send is acceptable or errors might be thrown.

Related

SendGrid + Nodejs - Handling errors when sending bulk emails

I'm building a command line app that will query a DynamoDB table, collect email addresses for each item on the table that has not already had an email sent to it, map over that array of items to create a customized message object for each one, pass that array into SendGrid's sgMail.send() method to send an email for each message inside, and then create a Communication object for each one on a second DynamoDB table. I followed the steps outlined in option three of this Twilio blog, and the code is working.
However, this method does not seem to allow error handling on a message by message basis when you pass in an array to .send(). Right now I first run sgMail.send(messages) in a try/catch block, and then create all of my Communication objects separately for each item only if the .send() call is completely successful. I'd prefer to be able to create an individual Communication object each time an email is successfully sent, rather than hoping that the try/catch block hits no errors and then wholesale creating the Communication objects after the fact.
My first thought was to iterate through the array returned from the DynamoDB query, and for each one first send an email, then once successful, create a Communication object. That method didn't work (the Communication was being created but the email was never sent, even though I was using await on all async calls). Once that didn't work, I found the blog linked above and used that method.
My worry is that if a random batch of the messages in the array fails and triggers the exception, but another chunk of emails was successfully sent before the error was caught, then I'll have a portion of emails sent out without corresponding Communication objects for them since the creation of those objects happens entirely independently from the email being sent.
I've combed through SendGrid's documentation as well as numerous Google searches, but haven't been able to find a helpful answer. Here's the current working code:
// First wait to send emails
console.log("Sending emails...")
try {
const messages = items.map((item) => {
return {
to: item.details.email,
from: SendGrid domain here,
subject: Email subject here,
html: Email content here
})
// Send email to each address passed in.
await sgMail.send(messages).then(() => {
console.log('emails sent successfully!');
}).catch(error => {
console.log(error);
});
} catch (error) {
throw error
}
// Then create communications
console.log("Creating communication objects...")
try {
for (let i = 0; i < items.length; i++) {
const params = {
TableName: process.env.COMMUNICATION_TABLE,
Item: {
communication_id: uuidv1(),
item_id: items[i].item_id,
date: new Date().toLocaleDateString()
}
};
try {
await docClient.put(params).promise();
} catch (error) {
throw error
}
}
} catch (error) {
throw error
}
// On success
console.log("Process complete!")
Twilio SendGrid developer evangelist here.
When you send an array of mail objects to sgMail.send, the #sendgrid/mail package actually loops through the array and makes an API call for each message. You are right though, that one may fail to send and you will be left in the state where some emails have sent and others failed or were cancelled.
So, you can loop through the array yourself and handle the successes/failures yourself too.
Try something like this:
console.log("Sending emails...");
items.forEach(async (item) => {
const mail = {
to: item.details.email,
from: "SendGrid domain here",
subject: "Email subject here",
html: "Email content here",
};
try {
await sgMail.send(mail);
console.log(`Sent mail for ${item.item_id} successfully, now saving Communication object`);
const params = {
TableName: process.env.COMMUNICATION_TABLE,
Item: {
communication_id: uuidv1(),
item_id: item.item_id,
date: new Date().toLocaleDateString(),
},
};
try {
await docClient.put(params).promise();
console.log(`Communications object saved successfully for ${item.item_id}.`);
} catch (error) {
console.log(
"There was a problem saving the Communications object: ",
error
);
}
} catch (error) {
console.error("Email could not be sent: ", error);
}
});
// On success
console.log("Process complete!");

Discord.js get motd

How do I get a MOTD of a Minecraftserver and put it into a embed?
If I type /status in. The Discord-Bot should reply the motd of the server replaysucht.de:255655 in a embed.
const serverInfo = require('minecraft-server-util');
let embed = new MessageEmbed()
.setTitle("Server Information")
.setTimestamp()
serverInfo.status('replaysucht.de') //default port: 25565
.then((response) => {
embed
.setDescription(response.description.descriptionText)
message.channel.send(embed)
})
.catch((error) => {
throw error;
});
For this example you need minecraft-server-util so make sure you've installed and defined it.
So in the code we create an embed embed. You can change the embed look to what you want, this was just an example. With serverInfo.status('replaysucht.de') we fetch all the information you need, for your problem. We get the MOTD from response by using .then after we fetched the information. The exact MOTD is stored in response.description.descriptionText. If the bot can fetch that without any problems, the embed gets sent in the channel, otherwise it will throw an error.
As the most Minecraft Servers have special and animated characters in their MOTD's it will be displayed like:
§f§f §7•§8● §eReplaySucht §8✕ §7we code for you §4:heart: §8✕ §e1§8.§e8 §8●§7•
§4Info §8» §cKurze Wartungsarbeiten!
inside the embed description.

Is possible to display collections(mongoDb) and each element from all collections on the same Ejs page?

I'm trying to create a little forum for my website with nodeJs/Express/MongoDb/Ejs(for Html render)
When i trying to display the content of the collections i have the fabulous : "can not set headers after they are sent to the client" i don't understand .. is about to create a forum on my website like all the collections are the questions send by users and in each collection there are the comments from users and response ..
this is my code , in bottom is the part with problem .. without that all work ..
Have a nice evening
app.get("/vosQuestions",(req,res)=>{
let test = db.collection(test1.toString())
const curseur = db.listCollections().toArray()
.then (result=>{
res.setHeader("Content-Type", "text/html")
res.render("vosQuestions",{collectionName :result })
res.end()
})
.catch(error=>console.error(error))
// Problem part //
test.find(function(err,results){
if (err) throw err
console.log("le find est :"+results)
res.render("vosQuestions",{TEST :results })
res.end()
})
})
You are getting the error: can not set headers after they are sent to the client because you are trying to send the response back to client again, after sending it once already.
You need to get all the required collection or documents first and then only send the response back to client. you can only send one response back.
Try this:
app.get("/vosQuestions",async (req,res)=>{
try{
let test = db.collection(test1.toString())
let collectionName = await db.listCollections().toArray()
let tests = await test.find();
res.setHeader("Content-Type", "text/html")
res.render("vosQuestions",{collectionName: collectionName, TEST :tests })
res.end()
}
catch(error){
console.error(error)
//send the error response back here.
}
})
Note: I have used async/await here for better readability.

Data part of Response is a long script instead of desired json object

I am building a web app using laravel and vuejs. I have made a axios get request to get a list of users .
I am getting a Promise object, and from what i have read. Reason for getting a promise object is because it's an async request.
I have tried .then() to get data part of the response. But i am getting a huge script instead of desired data.
axios......then(function(response){
console.log(response.data);
})
Initially what i did was
var res = axios.get('/allUsers');
console.log(res)
That time i came to know about promise object and read about.
When i checked network in dev tools, status code is 200 and i can see list of users. So i guess my request is successfully completed.
What should be done to get the list of the users. That list i will be using to update my UI.
Depending on what you're getting back for data there are a few ways to handle this. You may need to convert the data after the you get receive the response.
axios.get('some_url')
.then(res => res.json())
.then(data => {
// do something with the data
}).catch(err) {
conosole.error(err);
}
if you're seeing the data come through properly in the response and you're getting what you need without doing that then just do
axios.get('some url').then(res => {
// do something in here with the data here
})
also make sure you're getting back json if that's what you're looking for. check your response to see if its html or json because they can be handled a bit differently
as an "Edit" you could also handle this with async await so you dont end up in callback hell
async function fetchData() {
try {
const res = await axios.get('some url');
// next step might not be necessary
const data = await res.json();
// do something with the data
console.log(data); // if converting it was necessary
console.log(res); // if not converting
} catch (err) {
console.error(err);
}
}

Node-slack web api: chat.delete returns channel_not_found for all channels although channels.list returns all channels

I have been working on a simple chat bot using the slack-node web api and botkit, but am having some trouble using the chat.delete functionality. I am able to list out all of my channels properly, seeing their channel Id's and names, but when I try to send along the message channel with the chat.delete function, it returns "channel_not_found".
I have also tried to send along the channel name, testing with "general" and the actual channel name that I am targeting, both of which return the same error.
My bot is using a token of the admin user, which should allow deletion of any message. My bot has scope access for chat:write:bot and chat:write:user as well.
Below is a snippet of my code - I have also tried this in other places for deleting messages sent directly from the bot and get the same error, so I don't believe it has to do with permissions. I've looked into the docs and the usage seems to be correct for what I have below, but I may be missing a piece.
controller.on('ambient', function(bot, message) {
web.channels.list().then((res) => {
console.log(res); // this prints out all of the channels
// listed channels show a match for the channel ID given in message.channel
});
// this call returns an error "error: Response not OK: channel_not_found"
web.chat.delete(message.channel, message.ts).then((res) => {
console.log(res + " was deleted bc it was not tagged");
}).catch((err) => { console.log(err) });
});
The docs are a bit confusing on this, but the chat.delete method of the official #slack/client library take the parameters in a different order:
You'll want to change your code to be:
web.chat.delete(message.ts, message.chanel).then(...)
See here:
https://slackapi.github.io/node-slack-sdk/reference/ChatFacet#ChatFacet+delete

Categories

Resources