getting weird mongodb object on client - node.js

well as i mentioned in the title when i'm sending message through socket to the server then save it in database mongodb with mongoose, then i returned the the message and send it back in the socket,
now when i tried to print it on console in the server right before i send it to the client with socket,
i got the object i wanted to send, but when i checked the object i got in the client, then i got diffrent object seems related to mongo probably(pretty sure) and i'm not sure what should i do to fix it.this is what i get in the server right before i send it back to the client
this what i get in the client when i recieve new message
const addMessage = async (newMessage) => {
try {
if (newMessage.type === 2) {
const audioBlob = new Buffer.from(newMessage.message).toString("base64");
newMessage.message = new Binary(audioBlob, Binary.SUBTYPE_BYTE_ARRAY);
}
const newMsg = new Message(newMessage);
await newMsg.save();
newMsg.message = Buffer.from(newMsg.message.buffer, "base64")
return newMsg;
} catch (error) {
console.log(error);
errorHandler(error);
}
};
i expected to get the same object i see in the server so in the client too

you should always, provide code snippets while asking a question.
Th probable reason for the above problem is, you are printing the console.log(result._docs) and sending to the databse the complete result object. Try sending result._docs to your database as well.
P.S: result is just a variable to which your assigning the data. This variable may be different in your code.
(If this does not work, edit your question and attach code)

well I found the problem, though i'm not sure how to describe it but the problem was here:
const newMsg = new Message(newMessage);
await newMsg.save();
newMsg.type === 2
? Buffer.from(newMsg.message.buffer, "base64")
: newMsg.message;
return newMsg;
so i took the newMessage and inserted newMsg.toJSON() to it;
if (newMessage.type === 2) {
const audioBlob = new Buffer.from(newMessage.message).toString("base64");
newMessage.message = new Binary(audioBlob, Binary.SUBTYPE_BYTE_ARRAY);
}
const newMsg = new Message(newMessage);
await newMsg.save();
newMessage = newMsg.toJSON();
if (newMessage.type === 2) {
newMessage.message = Buffer.from(newMessage.message.buffer, "base64");
}
return newMessage;
and now it's working!

Related

Gmail authentication is failing with MailKit

I'm writing an app that reads email folders and messages from gmail.
I started out with sample code I found for using MailKit, and it was working fine for a while.
Then it just started complaining about the scope I was passing to GoogleAuthorizationCodeFlow. I was using #"https:\mail.google.com" instead of "https://mail.google.com/". I don't understand why the scope was working earlier and then just started getting rejected.
But after fixing the scope, ImapClient.AuthenticateAsync() is now throwing an "Authentication failed" exception.
I can't find any detail in the exception as to why it's failing. I checked my settings on Google Cloud and everything seems to be in order.
Can anyone help point me to where I should look to debug the issue?
I don't know why it's failing after working for a while, so I haven't really tried anything yet.
Here's the function that's failing. The last line below calling _client.AuthenticateAsync is throwing an "Authentication failed." exception.
private async Task<bool> connectToGmailAsync()
{
var clientSecrets = new ClientSecrets
{
ClientId = Server.ClientId,
ClientSecret = Server.ClientSecret
};
var codeFlow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
DataStore = new FileDataStore("CredentialCacheFolder", false),
ClientSecrets = clientSecrets,
Scopes = new[] { "https://mail.google.com/" }
});
// Note: For a web app, you'll want to use AuthorizationCodeWebApp instead.
var codeReceiver = new LocalServerCodeReceiver();
var authCode = new AuthorizationCodeInstalledApp(codeFlow, codeReceiver);
var credential = await authCode.AuthorizeAsync(string.Format("{0}#{1}", UserId, Server.Name), CancellationToken.None);
if (credential.Token.IsExpired(SystemClock.Default))
await credential.RefreshTokenAsync(CancellationToken.None);
_oauth2 = new SaslMechanismOAuth2(credential.UserId, credential.Token.AccessToken);
_client = new ImapClient();
await _client.ConnectAsync("imap." + Server.Name, Server.PortNumber, SecureSocketOptions.SslOnConnect);
await _client.AuthenticateAsync(_oauth2);
return true;
}

Discord.js get user by nickname

I'm having a hard time figuring out
Is is possible to find a user by his or her nickname via the discord.js npm package.
How can I query a user by his or her nickname?
i've tried several things but nothing returns the nickname and I can't quite figure out how their documentation works.
So far I haven't been able to tell how to do it.
I've done as so in my code.
const { Client } = require('discord.js')
const discordClient = new Client()
discordClient.on('message', message => {
if (message.author.bot) return
if (message.content.startsWith('!gpwarn')) {
// The command is something like '!gpwarn thomas'.
// If his nick name is thomas but his username is john it doesn't work.
})
Yes, and it's pretty simple. Do this:
const user = client.users.cache.find(user => user.username == "The user's name");
Reference:
UserManager
To meet your exact requirements you would search the guild members cache for the provided nickname. However, I personally would suggest using either a direct tag or a UserID for this, as multiple people can have the same nickname in the server.
const U = message.guild.members.cache.find(E => E.nickname === 'NICKNAME')
Getting by Tag:
const U = message.mentions.members.first()
Getting by ID:
const U = message.guild.members.cache.find(U => U.id === 'IDHERE')
First you need to identify the nickname argument, you can do this by splitting, slicing, and joining message.content.
Next I recommend you fetch all of the GuildMembers from the guild using GuildMemberManager#fetch(), This way you don't run into the error of a member being uncached.
Handle the promise using async/await and use Collection#find() to return the member.
const { Client } = require('discord.js')
const discordClient = new Client()
discordClient.on('message', async message => {
if (message.author.bot) return
if (message.content.startsWith('!gpwarn')) {
// Returns all of the text after !gpwarn
const query = message.content.split(' ').slice(1).join(' ').toLowerCase()
const members = await message.guild.members.fetch()
const memberToWarn = members.find(m => m.nickname.toLowerCase() === query)
if (!memberToWarn) // No member found error
console.log(memberToWarn) // [GuildMember]
}
})

Set context on Google Actions through Dialogflow fulfillment

I'm using the Dialogflow editor fulfillment to build a conversation on Google Assistant, but I'm not sure how to use the agent.setContext function.
When I ask "Turn off my device" the first step returns successfully. The problem happens when the user responds with "TV", for example. The system returns with another context, ignoring the one I set.
When the user directly asks "Turn off my TV in the kitchen" the system also works perfectly. Because of it I think that the entities are correctly defined.
Conversation 1 (success):
Turn off my TV in the kitchen
Right. Turning off.
Conversation 2 (fail):
Turn off my device //Gives the same intent that Conversation 1
OK, which device?
TV
"My bot" isn't responding right now. Try again soon. //It throws "'final_response' must be set". I think it's because of generic intent actions.intent.TEXT.
My code:
The code below is nested in exports.dialogflowFirebaseFulfillment = functions.https.onRequest and the intent is called by intentMap.set('smarthome.device.switch.off', setDeviceOff);
const agent = new WebhookClient({ request: request, response: response });
function setDeviceOff(agent) {
const device = agent.parameters.device;
const room = agent.parameters.room;
const context= 'device-switch'; //I tried 'smarthome.device.switch.off' too
let resp = commandDevice(device, room, 'Off', agent, context);
return resp;
}
function commandDevice(device, room, cmd, agent, context) {
var conv = agent.conv();
if(device===''){
conv.ask("OK, which device?");
}else if (room===''){
conv.ask("Got it. of what room?");
}else{
conv.ask("Right. Turning off.");
}
agent.setContext({
name:context,
lifespan: 5, //Tried 0, 4 and 3 too
parameters:{
'device':device,
'room':room
}
});
agent.add(conv);
return true;
}
So I tried another version and the same problem persists:
const app = dialogflow();
app.intent('welcome', conv =>{
conv.ask("Welcome to auto obari. What can I do for you?");
});
app.intent('Default Fallback Intent',conv =>{
conv.ask("I didn't understand, can you try again?");
});
app.intent('smarthome.device.switch.off', (conv,{device, room})=> {
const context= 'device-switch';
if(device===''){
conv.ask("OK, which device?");
}else if (room===''){
conv.ask("Got it. of what room?");
}else{
conv.ask("Right. Turning off.");
}
const parameters = {'device':device, 'room': room};
conv.contexts.set(context, 5, parameters);
});
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app); //I tried exports.factsAboutGoogle, but it threw a error too.
The contexts are the same, but the intent is different.
If using conv, you may also try like this:
app.intent('<INTENT>', conv => {
conv.ask('<RESPONSE>');
const parameters = {'param1':param1, 'param2': param2}};
conv.contexts.set('welcome-context', 5, parameters);
});
and access it like here :
const conv.contexts.get(<context>).parameters[<param>];
you can try this method too it worked for me
const AppContexts = {CONTEXT_ONE: 'context-one'};
const app = dialogflow();
In current intent (for output context)
conv.contexts.set(AppContexts.CONTEXT_ONE, 1);
In next intent (for input context )
const context = conv.contexts.get(AppContexts.CONTEXT_ONE);

How to log deleted images with a discord bot

I have been spending hours trying to get this code to log deleted images but everything I have tried its been nothing but fails, it logs deleted messages but images it just ignores completely.
Can someone please point me in the right direction on how to fix this issue, please. Any help is very much appreciated
const Discord = require('discord.js')
module.exports = async (client, message) => {
if (!message.guild) return;
if (!message.content) return;
const logs = message.guild.channels.find(c => c.name === '420-logs');
if (!logs) {
return console.log(`[WARN]: The Delete Logs channel does not exist in the server named '${message.guild.name}'`)
}
if (message.attachments.size > 0) { // If I change this to: message.attachments.size>0 && message it works with deleted image & text but as it is without this said line it doesn't function
var Attachment = (message.attachments).array();
Attachment.forEach(function(attachment) {
const logembed = new Discord.RichEmbed()
.setAuthor(message.author.tag, message.author.displayAvatarURL)
.setDescription(`**Image sent by ${message.author.tag} deleted in <#${message.channel.id}>**`)
.setImage(attachment.proxyURL)
.setColor(message.guild.member(client.user).displayHexColor)
.setFooter(`Deleted Image`)
.setTimestamp()
logs.send(logembed);
console.log(attachment.proxyURL);
})
} else {
const logembed = new Discord.RichEmbed()
//.setTitle('Message Deleted')
.setAuthor(message.author.tag, message.author.displayAvatarURL)
.setDescription(`**Message sent by ${message.author.tag} deleted in <#${message.channel.id}>**`)
.addField("Message Content", `${message.content}`)
.setColor(message.guild.member(client.user).displayHexColor)
.setFooter(`Deleted Message`)
.setTimestamp()
logs.send(logembed);
}
}
So far you can't. When a member deletes a message, sure it does return all the stuff for a message with attachment links and all, but when that image is deleted the URL returned is useless because it references an image that doesn't exist on the Discord servers. If you open the link in a web browser it will say this:

agent.set.context() not working Dialogflow fulfillment

We are facing issues while managing multiple user interaction at the same time in Dialogflow.
How we can manage user unique session as we are using custom event which will process our 3rd party API and then return a response to the specific user.
To manage User unique session We try Dailogflow Set/Get Context method, to set Context with Unique Id (using this id will store API response to the Redis server) from the first intent when a user makes a first request then will traverse that Unique Id through the custom event.
Will get that Unique Id from Context and grab data from Redis server which we stored in first intent.
We used agent.set.context() to set unique id but this method is not working with "dialogflow-fulfillment"  version ^0.5.0, To get this work we have updated the version with "^0.6.1". But this will provide other error like "UnhandledPromiseRejectionWarning: Error: No responses defined for platform: null".
Required Output: Context set with a unique id and will get a proper response.
Current Output: UnhandledPromiseRejectionWarning: Error: No responses defined for platform: null
async function searchFromAPI(agent){
axios.post('https://testApi.com', searchString.data, {headers: headers})
.then((resp) => {
response.data = resp;
redisClient.set(sessionId, JSON.stringify(response));
}
}).catch(error => {
response.error = true;
response.message = error.response.statusText;
redisClient.set(sessionId, JSON.stringify(response));
});
await customsleep(2000);
const sessionId = uuid.v4();
const contextData = {'name':'userSession','lifespan': 5,'parameters':{'sessionId':sessionId}};
agent.context.set(contextData);
console.log(contextData);
agent.add('We are processing your request, Could you please wait?');
agent.add(new Suggestion("Yes"));
agent.add(new Suggestion("No"));
}
// wait for 4.5sec and call custom event
async function followOne(agent){
await customsleep(4500);
agent.setFollowupEvent('followUpTwo');
}
// wait for 4.7sec then red API response from redis server and return
async function followUpTwo(agent){
await customsleep(4000);
sess = session;
//get context
const response = agent.context.get('userSession');
// get the sessionId, Get the data from redis server
agent.add(response);
}
async function PleaseWait(agent){
await customsleep(3500);
agent.setFollowupEvent('followUpOne');
}
I found the only workaround to reassign a new context object via context.set(ctx). Then it worked.
//update context to show full menu
let context = agent.context.get('user_data');
if (!context) throw "User_data context ius nod defined in PreferrenceAdd"
let context2 = new Object();
context2 = {'name': 'user_data', 'lifespan': 40,
'parameters': context.parameters};
console.log("ctx: = " + JSON.stringify(context2));
context2.parameters.new = false;
context2.parameters.refresh = true;
agent.context.set(context2);
Check this resource on how to set a new Dialogflow outgoing context
dialogflow webhook-client.
I hope this helps you?

Resources