Why do I get channels link instead of attachment? - javascript

I'm trying to make a bot. When I type ".test" bot waits for a file. After receiving it, he must send me a Discord link from which I can download the same file. But he only refers to the message where I've sent the file.
Before that, I somehow did it and started experimenting something. After that I was unable to get the same result.
There is my code:
module.exports = {
commands: 'test',
callback: (message, arguments, text) => {
const msg_filter = (m) => m.author.id === message.author.id;
message.channel.awaitMessages({ filter: msg_filter, max: 1, time: 60000})
.then((collected) => {
console.log(collected.first())
console.log(collected.first().attachment)
console.log(collected.first().url)
console.log("finish")
}).catch('Error. No respond.')
}
}
Console output:
//First
attachments: Collection(1) [Map] {
'myId' => MessageAttachment {
attachment: 'https://cdn.discordapp.com/attachments/914907287603261510/myId/sample.pdf',
name: 'sample.pdf',
id: 'myId',
size: 3028,
url: 'https://cdn.discordapp.com/attachments/914907287603261510/myId/sample.pdf',
proxyURL: 'https://media.discordapp.net/attachments/914907287603261510/myId/sample.pdf',
height: null,
width: null,
contentType: 'application/pdf',
ephemeral: false
}
},
//Second
undefined
//Third
https://discord.com/channels/901476184532062209/914907287603261510/917789424857780224

collected is a collection that contains every message that got caught by channel.awaitMessages(), so collected.first() is a message.
To access this message's attachments, which is a collection, you would need to do collected.first().attachments (beware of the plural).
With this in mind, you can manage every attachment in a for-each loop, or just get the first attachment via collected.first().attachments.first()

Related

How to post the JSON data in a embed in discord.js

I wrote a code and i got the data in a json format. Now i want it to convert that data into a discord embed so that when i enter a command . EX:- .data the json data to be sent from the URL.
Here is the input
request({
url: "https://data.vatsim.net/v3/vatsim-data.json",
json: true
}, (err, response, body) => {
console.log(body)
})
The json data looks like this :
{
cid: 1435807,
name: ' ',
callsign: 'ZAP85LJ',
flight_plan: [Object],
last_updated: '2021-10-24T10:45:52.516736Z'
},
{
cid: 1439854,
name: ' ',
callsign: 'DLH1ML',
flight_plan: [Object],
last_updated: '2021-10-24T10:46:13.4226778Z'
}
You can use EmbedFields, you can use up to 25 fields on an embed. On this example I used .forEach so that for each element on the array I can create a field with its value:
request({
url: "https://data.vatsim.net/v3/vatsim-data.json",
json: true
}, (err, response, body) => {
const embed = new Discord.MessageEmbed()
const pilots = body.pilots.slice(0, 15)
body.pilots.forEach(pilot => {
embed.addField(p.name,
`CID : ${p.cid}
Server : ${p.server}
etc...`)
})
message.channel.send(embed)
}
If you really want to show every single one of your elements on the array you can use discord-buttons to make the embed edit its message and change pages but for now this is the simplest and easiest solution for you.

MongoDB Atlas with "Full Document" enabled returns only the changed item, not the full document

I am trying to use Triggers with MongoDB Atlas to notify on changes to a document in my collection. I want to receive the full document that had any data in it change, and use that full document upon receipt of the change notification. In the triggers configuration, there is a slider to enable/disable "Full Document" which has the following description:
By turning on Full Document, you will receive the document created or
modified in your change event. For Delete operations, the full
document will not exist.
However, with or without that slider enabled, I get the same results.
Here is my change listener code:
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true })
await client.connect().then(db => {
const collection = client.db("database_name").collection("collection_name")
const changeStream = collection.watch()
changeStream.on("change", async data => {
console.log("Detected database change on", Date())
console.log(data) // only returns changed data
})
})
Here is the example output, which as stated doesn't include the full document despite the trigger configuration:
{
_id: {
_data: '82606C926E000000012B022C0100296E5A10049008F3458DF14719A9225DF7AB403CEC46645F69640064606C76124670930F9A1F657C0004'
},
operationType: 'update',
clusterTime: Timestamp { _bsontype: 'Timestamp', low_: 1, high_: 1617728110 },
ns: { db: 'database_name', coll: 'collection_name' },
documentKey: { _id: 606c76124670930f9a1f657c },
updateDescription: {
updatedFields: {
my_data: 'my changed data',
created: 1617728109618
},
removedFields: []
}
}
The full document should look like this:
{
_id: 606c76124670930f9a1f657c,
myKey: 'something that never changed',
my_data: 'my changed data',
created: 1617728109618,
expires: 'some time in seconds that never changed',
other_info: 'something that never changed'
}
Any help would be appreciated... e.g. do I need to add a function in the trigger configuration to return the full document? If so, what would such a function look like?
I typically don't like answering my own questions, but I figured I'll post the answer here anyway in the event someone else needs it.
After a bit more digging, it looks like collection.watch() can accept options. With Full Document enabled in Atlas, my code needed this:
const changeStream = collection.watch([], { fullDocument: 'updateLookup' })
Now the full document is returned as expected. The documentation I found comes from here, and here.

Disord js bot user-info issue

I'm trying to create a bot, and one of its commands is user-info
for eg. !user-info #<username>
and i want it to display username, id and the avatar
like:
username:<username>
Id:<User Id>
Avatar:<the avatar >
Below is the code i used:
else if (message.content.startsWith(`${prefix}user-info`)) {
var member = message.mentions.users.first();
message.channel.send(`Username: ${member.username}\n ID:${member.id}\n Avatar:${member.displayAvatarURL()}` );
}
However it doesn't work, when i remove the avatar part the output comes out as :
Username:undefined
Id:<the id>
When I add the avatar part I just get a huge error on the command module when I use the bot command. What's the right way and what did I get wrong?
I'd suggest you use an Embed for this, as those can display images in a better way, the code for your request would be:
var user = message.mentions.users.first();
message.channel.send({
embed: {
title: `Profile of ${user.tag}`,
thumbnail: {
url: user.displayAvatarURL(),
},
fields: [
{
title: "ID:",
value: user.id
}
]
}
});
You can find more on this here

Stripe Payments Add Payment Source / Card / Method using NodeJS / Vue

I am building a simple SaaS application with recurring payments using NodeJS with Express for the API and Vue for the UI. I have code written to add a customer and link a subscription and plan as well as a few other routines. We allow users to sign up without entering a payment method so now, I need to add a way for a user to add a payment method. I have been through so much documentation that my head is spinning and Stripe support (or lack thereof) has been no help.
I have tried everything from createSource, createToken, and createPaymentMethod in the UI and then submitted that to the API where I have tried using everything from stripeapi.customers.createSource to stripe.paymentMethods.create and nothing works. Everything returns an error about either something missing in the object or the object being incorrect. I have attempted to look at the payment intents API however, this seems like overkill to just simply add a card to a customer.
Here is my latest code.
UI : Create Element
this.stripe = await loadStripe('pk_test_');
let stripeElem = this.stripe.elements();
this.card = stripeElem.create('card', { hideIcon: true, hidePostalCode: false, style: { base: { color: '#363636', fontSize: '22px', fontSmoothing: 'antialiased' }}});
this.card.mount(this.$refs.card);
UI: Submit to API
await this.stripe.createSource(this.card, { type: 'card' } ).then((source) => {
this.$http.post(`/api/route`, source).then((response) => {
if (response.status === 200) {
} else {
}
}).catch(() => {
});
API
await stripeapi.customers.createSource(customer_id, { source: card });
This code produces this object:
{ source:
{ id: 'src_1HLFsEDfvqoM1TxYXmFvlcK9',
object: 'source',
amount: null,
card:
{ exp_month: 1,
exp_year: 2022,
last4: '4242',
country: 'US',
brand: 'Visa',
address_zip_check: 'unchecked',
cvc_check: 'unchecked',
funding: 'credit',
three_d_secure: 'optional',
name: null,
address_line1_check: null,
tokenization_method: null,
dynamic_last4: null },
client_secret: 'src_client_secret_VILuqM6ZikLzp9nMq4gizfN8',
created: 1598653002,
currency: null,
flow: 'none',
livemode: false,
metadata: {},
owner:
{ address: [Object],
email: null,
name: null,
phone: null,
verified_address: null,
verified_email: null,
verified_name: null,
verified_phone: null },
statement_descriptor: null,
status: 'chargeable',
type: 'card',
usage: 'reusable' } }
This code and object produce this error:
(node:352976) UnhandledPromiseRejectionWarning: Error: The source hash must include an 'object' key indicating what type of source to create.
at Function.generate (/data/api/node_modules/stripe/lib/Error.js:39:16)
at IncomingMessage.res.once (/data/api/docroot/node_modules/stripe/lib/StripeResource.js:190:33)
at Object.onceWrapper (events.js:286:20)
at IncomingMessage.emit (events.js:203:15)
at IncomingMessage.EventEmitter.emit (domain.js:448:20)
at endReadableNT (_stream_readable.js:1145:12)
at process._tickCallback (internal/process/next_tick.js:63:19)
All I want to do is take an element, create a payment source/method (whatever it's called) and then associate that with a customer. Any help is appreciated. I have look at so many examples but nothing has worked for me. Everything seems to produce an error about the object or what not.
After more hours of development I finally figured it out! The API reference is severely lacking but this article here explains what to do: https://stripe.com/docs/payments/save-card-without-authentication
Essentially, you create and mount the element. Then, you use the createPaymentMethod in the UI and pass the card element to it. From there, you submit the paymentMethod.id string to your API and then use strip.paymentMethods.attach to attach it to a customer by passing the paymentMethod.id and the Stripe customer ID.
Front End HTML
<div ref="card" class="credit-card"></div>
Front End Create and Mount
this.stripe = await loadStripe('pk_test_YOURKEY');
let stripeElem = this.stripe.elements();
this.card = stripeElem.create('card', { hideIcon: true, hidePostalCode: false, style: { base: { color: '#363636', fontSize: '22px', fontSmoothing: 'antialiased' }}});
this.card.mount(this.$refs.card);
Front End Create Payment Method and Submit to Back End
await this.stripe.createPaymentMethod({ type: 'card', card: this.card }).then((method) => {
this.$http.post(`/users/billing/cards`, { id: method.paymentMethod.id }).then((response) => {
}).catch(() => {
});
}).catch(() => {
});
Please note: this code is NOT complete, it's just meant to give you an example for those that have struggled like I have.
The NodeJS error message reads:
The source hash must include an 'object' key indicating what type of source to create.
It can also be found here, but I'm not certain, if not this is a bogus error message. If this should indeed apply, it would be object: 'card' instead of object: 'source'; but I don't think so.
With Stripe there sometimes is more than one way to get something done:
The source should definitely be a client-side generated card token,
but your client-side doesn't have any code that would token-ize the card.
For reference, these would have to be combined:
https://stripe.com/docs/js/tokens_sources/create_token?type=cardElement
https://stripe.com/docs/api/cards/create

Attempt to search for a specific string

I'm trying to find a specific row in the database based on the user's message, namely: catalystname.
Within the schema I have successfully indexed the given string as text:
const { Schema } = mongoose;
const scheduleMessageSchema = new Schema({
_id: { type: Schema.Types.Oid, auto: true },
catalystname: String,
catalystdesc: String,
catalystquest: String,
date: String,
});
scheduleMessageSchema.index({catalystname: 'text'});
module.exports = mongoose.model('dbcatalyst', scheduleMessageSchema);
My search code:
const Catal = require("../src/models/dbcatalyst.js")
module.exports.run = async (client, message, args) => {
message.content = args.slice(0).join(" ")
Catal.find({$text: {$search: message.content}})
.exec(function(docs){
let embedlogs3 = new Discord.RichEmbed()
.setAuthor(`1`, message.author.displayAvatarURL)
.setDescription(`${docs}`)
.setColor("#33ffff")
message.channel.send(embedlogs3)
/*/ ${collected.first().content}/*/
});
}
And started searching for the required line in the message. The bot successfully copes with its task, but displays the entire document in full instead of 1 line.
_id: 5e243704961eb23c106bfb02,
catalystname: 'Чёрный Коготь',
catalystdesc: '0',
catalystquest: '0',
date: '1579430157018',
__v: 0
}
Can I somehow output exactly the string? catalystname
Looking at the Mongoose documentation, it seems the callback takes two parameters:
err An error or null
docs The returned document(s)
Change your callback to
Catal.find({$text: {$search: message.content}})
.exec(function(err, docs){
...
});
and you should receive an array of matching documents.

Categories