Discord.js v14: Embed-Fields empty after using EmbedBuilder - discord.js

i have a strange Problem after updating from v13 to v14 that i don't understand.
A part of my Bot works as a Ticketsystem, where Tickets (as MessageEmbeds) can be changed via Reactions.
But when i try to change the embed with the new EmbedBuilder, every data inside the embed seems fine except the "fields"-data that are suddenly "undefined".
here is some example-code:
const embedObject = reaction.message.embeds[0]
console.log(embedObject.fields)
const tmpEmbed = EmbedBuilder.from(reaction.message.embeds[0])
console.log(tmpEmbed.fields)
First output is something like:
[
{ name: 'Priorität:', value: 'Normal', inline: true },
{ name: 'Übernommen:', value: '-', inline: true },
{ name: 'User:', value: '<#369058976245219330>', inline: false },
{ name: 'Inhalt:', value: '```test```', inline: false }
]
Second output is "undefined"
Solution:
With some trial and error i found a solution and possible inconsistency in the code of the discord-api (or it's my limit understanding) when trying to alter specific embed data.
So, what my code looked like in v13:
const embedObject = reaction.message.embeds[0]
embedObject.setDescription("**Status:** in Bearbeitung")
embedObject.setColor("#2db300")
embedObject.fields[1].value = `<#${user.id}>`
embedObject.setFooter({text: `Bearbeitet von: ${user.username}`, iconURL: userIcon})
embedObject.setTimestamp(new Date())
await reaction.message.edit({embeds: [embedObject]}).catch(console.error)
Now in v14, all of the .set-Functions didn't worked anymore for an already existing embed, so i thought i needed to construct an embed with the EmbedBuilder.
But now it's gets odd, while the .setDescription (and some other .set-Functions) just changed syntax to directly change the data (like it was for "fields" already):
const embedObject = reaction.message.embeds[0]
embedObject.Description = "**Status:** in Bearbeitung"
embedObject.fields[1].value = `<#${user.id}>`
for .setColor, .setFooter and .setTimestamp this doesn't work!
Also the "field"-data is not accessable from the EmbedBuilder-Object.
So you need to first edit some of the data "directly" (like description or fields) and then actually need to construct an embed with the EmbedBuilder to change color,footer and/or timestamp:
tmpEmbed = EmbedBuilder.from(embedObject)
.setColor(0x2db300)
.setFooter({text: `Bearbeitet von: ${user.username}`, iconURL: userIcon})
.setTimestamp(new Date())
Keep in mind, for this EmbedBuilder-Object, you can't read/change "fields", so do that before using the EmbedBuilder.
The working new code in v14, equal to the old code, is:
const embedObject = reaction.message.embeds[0]
embedObject.Description = "**Status:** in Bearbeitung"
embedObject.fields[1].value = `<#${user.id}>`
tmpEmbed = EmbedBuilder.from(embedObject)
.setColor(0x2db300)
.setFooter({text: `Bearbeitet von: ${user.username}`, iconURL: userIcon})
.setTimestamp(new Date())
await reaction.message.edit({embeds: [tmpEmbed]}).catch(console.error)
I'm no expert on Javascript or the Discord-API, so everything is learning by doing for me.
Possibly i got something wrong, did the v13 code already "odd" or am just missing something, but i hope this could help others when struggling with embeds :)

Related

it is possible to change the default received language from iso-3166-1-alpha-2

I would like to explain my problem of the day.
currently I receive data in the following format
[{location: "CU"},{location: "FR"},{location: "ES"}]
then I map and re map to correctly recover value, label, flag
const country = Array.from(
new Set(data?.map((e) => e.location))
).map((countryCode) => ({
value: countryCode,
label: `${iso3311a2.getCountry(countryCode)} (${countryCode})`,
flag: countryCode,
}));
it works correctly
I get the new data in the following format
[{flag: "CU" label: "Cuba (CU)"value: "CU"},
{flag: "FR" label: "France (FR) "value: "FR"},
{flag: "ES" label: "Spain (ES) "value: "ES"},
]
so my problem and the next one
here I recover spain
while I would like to recover "Espagne" according to the language
basically, is it possible to recover it in another language?
iam open to any proposal thank you very much.

user.joinedAt displays current time

The code is here. In line 41, user.joinedAt displays the current date and time instead of the user's joined-in date. What is the issue there? I have done research online but those either display the current time or errors in my console. I heard that I would have to use member.joinedAt, but then I would have to define "member". "user" is already defined as you can conclude in the code.
A User does not have a joinedAt property. Therefore, the date being used is: moment.utc(undefined), which defaults to the latest date.
Instead, you need to use a GuildMember. In your code, you can do this by using message.mentions.members:
let member = message.mentions.members.first();
However, you are also using user.createdAt, which a GuildMember does not have. You can access the createdAt property through the GuildMember.user property, which contains the createdAt property:
let user = member.user;
Then you can use the correct values like so:
let embed = new Discord.MessageEmbed()
.setTitle(`Userinfo`)
.setColor(`BLUE`)
.setThumbnail(user.avatarURL({ size: 2048, dynamic: true }))
.addFields (
{name: `Username + tag`, value: `${user.tag}`, inline: true},
{name: `Server join date`, value: `${moment.utc(member.joinedAt).format("dddd, MMMM Do YYYY, h:mm:ss a")} UTC`, inline: true },
{name: `User creation date`, value: `${moment.utc(user.createdAt).format("dddd, MMMM Do YYYY, h:mm:ss a")} UTC`, inline: true}
);

Auto generated key in Ant Design Upload react component causes snapshot test to fail

I am using the Upload ant design component, and its working well except it generates a file input with an auto generated key. Every time I run the tests, a new key is generated, so the snapshot don't match and my test fails.
Setting the key on the Upload doesn't affect the input key, so I have no evident way to mock this. I also tried using the new property matchers, but all the examples I found were very simple, using one simple object, couldn't figure out how to use with a wrapper containing many nested react components.
I couldn't find any documentation on how to deal with ant design auto generated keys... Any help or pointing in the right direction would be very much appreciated!!
This works for me using Enzyme and Jest with snapshot testing:
describe('<Uploader />', () => {
test('it renders', () => {
const uploaderProps = {
accept: 'application/pdf,image/*',
action: 'https://file-service.example.com/v1/upload',
defaultFileList: [
{
uid: '1',
name: 'under-construction.gif',
status: 'done',
url: 'https://media.giphy.com/media/EIiJp9cQ3GeEU/giphy.gif',
thumbUrl: 'https://media.giphy.com/media/EIiJp9cQ3GeEU/giphy.gif',
},
],
multiple: true,
name: 'file-input',
onChange: jest.fn(),
};
const uploader = mount(<Uploader {...uploaderProps} />);
expect(uploader.render()).toMatchSnapshot();
});
});
Note the use of .render() to generate the snapshot without the key.

Pushing onto Mongo SubDoc of SubDoc array

I'm going around in circles with this one so hoping someone can help. I'm building a nodejs application that receives sensor values from nodes. There can be multiple sensors on a node.
Using NodeJS, Mongod DB and Mongoose, all running on a raspberry pi, 3 I've built the following Schemas & Model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var valueSchema = new Schema ({
timestamp: {type: Date},
value: {}
});
var sensorSchema = new Schema ({
id: {type: Number},
type: {type: String},
description: {type: String},
ack: {type: Boolean},
values: [valueSchema]
});
var SensorNode = mongoose.model('SensorNode', {
id: {type: Number, required: true},
protocol: {},
sensors: [sensorSchema]
});
I can add in the node, and push sensors onto the sensors array, but I seem unable to push values onto the values array.
I've looked over a few other examples and questions on similar issues, and looked at using populate, but cant seem to get them to work.
Here is my code:
function saveValue(rsender, rsensor, payload) {
var value = {
values: {
timestamp: new Date().getTime(),
value: payload
}
}
SensorNode.findOneAndUpdate({
"id": rsender,
"sensors.id": rsensor
}, {
"$push": {
"sensors.$": value
}
}, function(err, result) {
if (err) {
console.log(err);
}
console.log(result);
});
}
This is returning undefined for the result and this error:
MongoError: exception: Cannot apply $push/$pushAll modifier to non-array
Values is definitely an array in the sensor schema.
I'm using readable ids rather than the auto assigned Mongo DB IDs for the sake of the UI, but I could use the MongoDB _id if that makes any difference, I don't see why it would?
Where am I going wrong ?
You're using positional operator $ so let's check the docs
The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array. To project, or return, an array element from a read operation, see the $ projection operator.
So sensors.$ will return one particular document from your sensors array. That's why you're getting an error. On this level of your document you can only replace this item by using $set. I bet you wanted to do something like this:
SensorNode.findOneAndUpdate({
"id": rsender,
"sensors.id": rsensor
}, {
"$push": {
"sensors.$.values": payload
}
});
This operation will just append payload to values array in one particular sensor with id equal to rsensor.

mongoose query: find an object by id in an array

How could I find an image by id in this Schema. I have the id of the User and the id of the image I am looking for. What would be the best way to do this and do all images in this case have different ids or could they have the same id because they don't belong to the same User?
My Schema looks like this:
var userSchema = new Schema({
local: {
email: String,
password: String
},
facebook: {
id: String,
token: String,
email: String,
name: String
},
name: String,
about: String,
images: [{
id: Schema.ObjectId,
link: String,
main: Boolean
}]
});
When you are interested in the full object it is a simple find:
.find({"facebook.id":"<id>", "images.id":<image-id>})
I don't think that there is a way to reduce the image array in the result.
To update a single element in the image array you can use this:
.update({"facebook.id":"<id>", "images.id":<image-id>}, {$set : {"images.$.main" :false} } );
userSchema .find({facebook.id: "some ID",{ "images.id": { $in: [ id1, id2, ...idn] }}
since images are inside the document you can have same ID's however every time you query you should keep in mind that you send some other parameters such as facebook.id or facebook.email along with image id's to retrieve them. Otherwise you end up getting all that might be irrelevant only because you decide to keep same ID's for images.
tl;dr
I struggled with this and came up with a solution. Like you, I was trying to query for a deeply nested object by the _id, but I kept coming up empty with the results. It wasn't until I did some type checking that I realized the id value I was getting from my frontend, while directly supplied by mongoose, was in fact a String and not an Object.
I realize this question was already partially answered before, but that person's solution didn't work for me, and the comment on the answer tells me you wanted to update the specific image you queried for, which is exactly what I was trying to do.
The solution
In order to select an object from the nested array by the _id value, first you'll have to install the npm package bson-objectid and use the provided method to convert your string into an objectId in your query.
In your terminal:
npm i bson-objectid
In your code:
const ObjectId = require('bson-objectid')
userSchema.findOneAndUpdate(
{ "facebook.id": <user-id>, "images._id": ObjectId(<image-id>) },
{ "$set": { "images.$.main": false } },
{ new: true }, // an extra options parameter that returns the mutated document
(err, user) => {
if (err) {
handleErr(err)
} else {
console.log(user)
// do something with new user info
}
)

Resources