So I'm trying to make a command where someone can do -kill #firstUser #secondUser. This will increase the first user's kills by 1 and add a role to the second user mentioned. I can access the the first user mentioned by doing const firstUser = message.mentions.users.first(); but I'm not sure how to do the same for the second user.
I've tried accessing the message.mentions.users collection and converting it to an array (and trying to access that) but I can't get it to work.
const firstUser = message.mentions.users.get(0);
const secondUser = message.mentions.users.get(1);
How do I get the user class from a message with multiple mentions?
And what I found was, it returns an object, not a mention, and as you can't send an object, it will return as an empty message error.
So to send a mention, you send:
// Getting the first and second users
const allMentioned = message.mentions.users.array()
// First User `[0]`
const firstUser = allMentioned[0];
// Second User `[1]`
const secondUser = allMentioned[1];
// And so on and so forth...
// Add `<#` to the begginning of the id and `>` to the end of it to make a mention.
const mentionSecondUser = "<#" + secondUser.id + ">";
// Sending a message using the fetched property
message.channel.send(`Hey ${mentionSecondUser}, or whatever.`);
Alternatively, you can try using the other fetched properties using the following format, received from getting the property, say secondUser:
User {
id: '<secondUser's id>',
username: '<secondUser's username>',
bot: <true if secondUser a bot>,
discriminator: '<secondUser's discriminator>',
avatar: '<secondUser's avatarId>',
lastMessageID: <secondUser's lastMessageId>,
lastMessageChannelID: <secondUser's lastMessageChannelId>,
flags: UserFlags { bitfield: 0 }
}
An example of this is in the picture showed above.
You can use:
message.mentions.users.array()[1]
To get the second user in a message. Appropriately, use [2] for the third, [3] for the fourth, and so on.
Related
I have added the logs case for my warn slash command, but I have a problem.. that problem is that if the embed description reaches the limit, i get an error and thats not what I want.
So basically, I want the a new embed to be created as like a "second page", and I can use my pagination function to help with navigating between pages and so on. I just don't exactly know how to do that or how to get started.
I am asking for some assistance here because my goal is to have a functional "warning logs" embed with buttons to navigate through the pages if there are more than one like most users will have.
case "logs": {
const buttonPages = require("../../functions/pagination");
const user = interaction.options.getUser("user");
const userWarnings = await warnSchema.find({ Guild: interaction.guild.id, User: user.id });
if (!userWarnings?.length) return interaction.reply({ content: `\`${user.tag}\` does not have any warnings.`, ephemeral: true });
const embedDescription = userWarnings.map((warn) => {
const moderator = interaction.guild.members.cache.get(warn.Moderator);
return [
`<:CL_Shield:937188831227183135> Warn ID: ${warn.id}`,
`<:CL_ReplyContinued:909444370221137930> Moderator: ${moderator || "unknown"}`,
`<:CL_ReplyContinued:909444370221137930> User: ${user}`,
`<:CL_ReplyContinued:909444370221137930> Reason: \`${warn.Reason}\``,
`<:CL_Reply:909436090413363252> Date: ${warn.Date}`,
].join("\n");
}).join("\n\n");
const embed = new EmbedBuilder()
.setTitle(`${user.tag}'s warnings`)
.setDescription(embedDescription)
.setColor("#2f3136");
//const pages = [embed];
//buttonPages(interaction, pages);
await interaction.reply({ embeds: [embed] });
}
What you're trying to do is called pagination. Code is below, but here is how it works:
First what you've got to do is determine how many different embeds it'll be. We can do that with description.length/4096, but we need to round up so we'd use Math.ceil. The Array().keys() allows us to get a list of all the numbers up to it to iterate over. For example Array(3).keys() would give us [0, 1, 2] so we can iterate over it.
We then need to select which part of the description we want to send. We want to start at (i*4096) since all previous embeds have 4096 characters, and then we want it to be 4096 characters long so we simply end it at (i*4096)+4096).
You also need to consider that we cannot always use interaction.reply as interactions can only be replied to once, so we must use interaction.channel.send to send them all to the channel. But, we will want some sort of response to the interaction, so we send the first one as a response to the interaction, and all following ones to the channel.
Here's the code:
for (const i of Array(Math.ceil(embedDescription.length/4096)).keys()) {
const embed = new EmbedBuilder().setDescription(embedDescription.substring((i*4096), (i*4096)+4096))
if(i === 0) await interaction.reply({embeds: [embed]})
else await interaction.channel.send({embeds: [embed]})
}
I have a list of values each having another KEY value corresponding to it, when i present this list to user, user has to select a value and agent has to call an external api with selected value's KEY. how can i achieve this in dialogflow?
I tried to send the entire key value pair in the context and access it in the next intent but for some reason when i set a list(array) to context parameters dialogflow simply ignoring the fulfillment response.
What is happening here and is there any good way to achieve this? I am trying to develop a food ordering chatbot where the category of items in menu is presented and list items in that menu will fetched when user selects a category, this menu is not static thats why i am using api calls to get the dynamic menu.
function newOrder(agent)
{
var categories = []
var cat_parameters = {}
var catarray = []
const conv = agent.conv();
//conv.ask('sure, select a category to order');
agent.add('select a category to order');
return getAllCategories().then((result)=>{
for(let i=0; i< result.restuarantMenuList.length; i++)
{
try{
var name = result.restuarantMenuList[i].Name;
var catid = result.restuarantMenuList[i].Id;
categories.push(name)
//categories.name = catid
cat_parameters['id'] = catid;
cat_parameters['name'] = name
catarray.push(cat_parameters)
}catch(ex)
{
agent.add('trouble getting the list please try again later')
}
}
agent.context.set({
name: 'categorynames',
lifespan: 5,
parameters: catarray, // if i omit this line, the reponse is the fultillment response with categories names, if i keep this line the reponse is fetching from default static console one.
})
return agent.add('\n'+categories.toString())
})
function selectedCategory(agent)
{
//agent.add('category items should be fetched and displayed here');
var cat = agent.parameters.category
const categories = agent.context.get('categorynames')
const cat_ob = categories.parameters.cat_parameters
// use the key in the catarray with the parameter cat to call the external API
agent.add('you have selected '+ cat );
}
}
The primary issue is that the context parameters must be an object, it cannot be an array.
So when you save it, you can do something like
parameters: {
"cat_parameters": catarray
}
and when you deal with it when you get the reply, you can get the array back with
let catarray = categories.parameters.cat_parameters;
(There are some other syntax and scoping issues with your code, but this seems like it is the data availability issue you're having.)
var intent = args.intent;
var number = builder.EntityRecognizer.findEntity(intent.entities, 'builtin.numer');
when i use findentity it move forward if the answer is correct or not how can i use entity resolve on that which are not builtin entites
var location1 = builder.EntityRecognizer.findEntity(intent.entities, 'Location');
var time = builder.EntityRecognizer.resolveTime(intent.entities);
when i use resolve time it ask againand again unless entity is resolve;
var alarm = session.dialogData.alarm = {
number: number ? number.entity : null,
timestamp: time ? time.getTime() : null,
location1: location1? location1.entity :null
};
/* if (!number & !location1 time)
{} */
// Prompt for number
if (!alarm.number) {
builder.Prompts.text(session, 'how many people you are');
} else {
next();
}
},
function (session, results, next) {
var alarm = session.dialogData.alarm;
if (results.response) {
alarm.number = results.response;
}
I believe I've already answered this question on StackOverflow: "Botframework Prompt dialogs until user finishes".
You'll need to create a mini-dialog, that will have at least two waterfall steps. Your first step will take any args and check/set them as the potential value your chatbot is waiting for. It'll prompt the user to verify that these are the correct values. If no args were passed in, or the data was not valid, the user will be prompted to supply the value the chatbot is waiting for.
The second step will take the user's response to the first step and either set the value into a session data object (like session.userData or session.conversationData) or restart the dialog using session.replaceDialog() or session.beginDialog().
In your main dialog you'll modify the step where you employ your EntityRecognizers to include an if-statement that begins your mini-dialog. To trigger the if-statement, you could use the same design as shown in this GitHub example or in your code. This code might look like below:
var location1 = builder.EntityRecognizer.findEntity(intent.entities, 'Location');
session.userData.location1 = location1 ? location1.entity : null;
if(!session.userData.location1) {
session.beginDialog('<get-location-dialog>');
}
I have a userevent script to change the Field in Contract record from PO record. The Script is running fine. But whenever I edit a contract record and try to submit it : It throws the error "Another user has updated this record since you began editing it. Please close the record and open it again to make your changes".
May I know the reason behind this ?
/*---------------------------------------------------------------------------------------------------------------
Description : Whenever the PO vendor is changed(due to Split vendor) that should replace the same in Contract page record automatically.
Script type : User Event Script
Script id : customscript452
Version : 1.0
Applied to : Contract
----------------------------------------------------------------------------------------------------------------*/
function srchfield()
{
var stRecordid = nlapiGetRecordId(); //returns the contract id
if(stRecordid== undefined || stRecordid== null || stRecordid==' ')
{
}
else
{
var stRecordtype = nlapiGetRecordType(); //returns the contract record type = jobs
var stRecord = nlapiLoadRecord(nlapiGetRecordType(), stRecordid);
nlapiLogExecution('debug','Load Object',stRecord);
var stContractID = stRecord.getFieldValue('entityid'); //returns the value of the field contractid whose fieldid is = entityid
nlapiLogExecution('debug','stContractID',stContractID);
var stCompanyName = stRecord.getFieldValue('companyname'); //returns the value of the field company name whose fieldid is = companyname
nlapiLogExecution('debug','stCompanyName',stCompanyName);
var stConcatenate = stContractID+" : "+stCompanyName; //Concatenate the two Fields to get the result which needs to be found in PO
var arrFilters = new Array(); // This is Array Filters all the Purchase Order Record Search
arrFilters.push(new nlobjSearchFilter('type', null, 'anyof',
[
'PurchOrd'
]));
arrFilters.push(new nlobjSearchFilter('mainline', null, 'is', 'T')); //This is to exclude line level results
arrFilters.push(new nlobjSearchFilter('custbodycontract', null, 'is', stRecordid)); //This is Filters in Contracts Search
var arrColumns = new Array();
arrColumns.push(new nlobjSearchColumn('entity')); //This is Search Column Field in Records
var arrSearchresults = nlapiSearchRecord('purchaseorder', null, arrFilters, arrColumns); //This is Filters in Search Result Purchase Order
if(arrSearchresults== undefined || arrSearchresults== null || arrSearchresults==' ')
{
}
else
{
var length = arrSearchresults.length;
}
if(length== undefined || length== null || length==' ')
{
}
else
{
for (var i = 0; arrSearchresults != null && i < arrSearchresults.length; i++)
{
var objResult = arrSearchresults[i];
var stRecId = objResult.getId();
var stRecType = objResult.getRecordType();
var stCntrctName = objResult.getValue('entity'); //This is Value are Get Purchase Order Records and Field for Vendor = entity
}
}
//var record = nlapiLoadRecord(nlapiGetRecordType(), stRecordid, stCntrctName);
if (stCntrctName =='custentityranking_vendor_name')
{
}
else
{
var stChangeName = stRecord.setFieldValue('custentityranking_vendor_name', stCntrctName); //This is Value are the Set in Main Vendor Field = custentityranking_vendor_name
nlapiSubmitRecord(stRecord, null, null); // Submit the Field Value in Record Type
}
}
}
The User Event script executes as the Contract record is being saved to the database. At the same time, you are loading a second copy of the record from the database and trying to submit the copy as well. This is causing the error you're seeing.
You fix this by just using nlapiSetFieldValue to set the appropriate field on the Contract.
I might also recommend getting more familiar with JavaScript by going through the JavaScript Guide over at MDN. In particular, take a look at the Boolean description so that you know how JavaScript evaluates Boolean expressions. This will help you greatly reduce the amount of code you've written here, as many of your conditionals are unnecessary.
What userevent do you have? It is happening depending on what type of user event and API you are using. Looking at your code, you are trying to load contract record that is already updated at the database. So you might consider below to address your issue. Hope, it helps.
If it is a before submit, you don't need to load the record where the script is deployed.
Just use nlapiGet* and nlapiSet* to get and set values. You also don't need to use nlapiSubmitRecord to reflect the change. With before submit, it executes before the record is being saved to the database. So your changes will still be reflected.
Then if it is after submit, it will be executed after the record has been saved to the database, Thus you might use the following API depending on your needs. Actually, this is the best practice to make sure the solution .
nlapiGetNewRecord - only use this if the script only needs to retrieve info from header and sublists. And nothing to set.
nlapiLookupField - use this if the script only needs to get value/s at the header and nothing from the line.
nlapiSubmitField - the script don't need to load and submit record if the changes only on header. Just use this API.
nlapiLoadRecord and nlapiSubmitRecord- use the former if the script will have changes at the line and then use the latter api to commit it on the database.
Being a user event script code, The code you showed is very not good considering performance.
Here is the sample you can merge
var stRecordid = nlapiGetRecordId(); //returns the contract id
// Every record has an internal id associated with it. No need to add condition explicitly to check if its null
var stRecordtype = nlapiGetRecordType();
var fields = ['entityid','companyname'];
var columns = nlapiLookupField(stRecordtype, stRecordid, fields);
var stContractID = columns.entityid;
var stCompanyName = columns.companyname;
nlapiLogExecution('debug','stContractID/stCompanyName',stContractID+'/'+stCompanyName);
var stConcatenate = stContractID+" : "+stCompanyName; //Concatenate the two Fields to get the result which needs to be found in PO
//
//your code of search
//you can improve that code also by using nlapilook up
nlapiSubmitField(stRecordtype, stRecordid, 'custentityranking_vendor_name', 'name to be updated');
I've got a complex data type "AzureTemplate" containing a list of children "AzureField". I've implemented my read and insert on the server side according to this article. Works great.
Needing an update as well, I copy/pasted the insert into the update so it does the same thing, but using update instead. So my update looks like this:
function update(item, user, request) {
// remove complex child object, make copy first
var fields = item.fields;
if (fields) {
delete item.fields;
}
request.execute({
success: function () {
var templateId = item.id; // "foreign key"
var fieldsTable = tables.getTable('AzureFields');
if (fields) {
// update the child fields
var updateNextField = function (index) {
if (index >= fields.length) {
// done updating fields, respond to client
request.respond();
} else {
var field = fields[index];
field.templateId = templateId;
// *** THE ID LOGGED HERE LOOKS FINE ***
console.log("updating field w/ id ", field.id);
fieldsTable.update(field, {
success: function () {
updateNextField(index + 1);
}
});
}
};
// kick off the loop saving each field
updateNextField(0);
} else {
// no fields. no need to do anything else
request.respond();
}
}
});
}
The log that prints the ID of the child "field" shows a valid field id (I save them on the client side when reading them). But I get an error that says:
Error in script '/table/AzureTemplate.update.js'. Error: Invalid id value specified. AzureTemplate/update Tue Jan 27 2015, 10:11:31 AM
I put a console.log() at the top of the AzureField.update, but that never shows up, so it's not getting in there. Also, when I update a single child "Field" directly from the client it works fine. So the AzureField.update is working. Any ideas?
var fieldsTable = tables.getTable('AzureFields');
... my table name is AzureField, not AzureFields. The above code works, hopefully it helps someone.
I have misnamed a table before and got a meaningful error about "table not existing". Not sure why the error in this case is totally unrelated.