How to check multiconditions to concatenate an observable with rxjs - node.js

I would like to make check condition on message which is an observable and to costumize the output like this scenerio :
check if the messsage is to me or from me and concatenate 20 first caracters with the name of friend or if it is my message with you
chech the type of message if it is a photo or file to make a message you sent an attament for example
getLastMessage(onlineUserModel: OnlineUserModel): Observable<string> {
let message: Observable<string>;
const messageModel = this.allDirectMessages$
.pipe(
map((x) =>
x.filter(
(f) =>
f.messageModel.to.userName === onlineUserModel.userName ||
f.messageModel.from.userName === onlineUserModel.userName
)
)
)
.pipe(map((data) => data[data.length - 1].messageModel))
.pipe(
map((item) => {
if (item.to.userName == onlineUserModel.userName) {
message = concat("You", item.content, "...");
}
else (item.to.userName == onlineUserModel.userName) {
message = concat("You", item.content, "...");
}
})
);
return message;
}

If you want to return the message as an Observable<string> you can do something like this:
getLastMessage(onlineUserModel: OnlineUserModel): Observable<string> {
return this.allDirectMessages$
.pipe(
filter((f) =>
f.messageModel.to.userName === onlineUserModel.userName ||
f.messageModel.from.userName === onlineUserModel.userName
),
map((data) => {
const item = data[data.length - 1].messageModel;
if (item.to.userName == onlineUserModel.userName) {
return `You ${item.content}...`;
}
else (item.from.userName == onlineUserModel.userName) {
return `Them ${item.content}...`;
}
})
);
}

I try to share you my result, just I added the map operator before filter:
getLastMessage(onlineUserModel: OnlineUserModel): Observable<string> {
return this.allDirectMessages$
.pipe(
filter((f) =>
f.messageModel.to.userName === onlineUserModel.userName ||
f.messageModel.from.userName === onlineUserModel.userName
),
map((data) => {
const item = data[data.length - 1].messageModel;
if (item.to.userName == onlineUserModel.userName) {
return `You ${item.content}...`;
}
else (item.from.userName == onlineUserModel.userName) {
return `Them ${item.content}...`;
}
})
);
}

Related

Why "member.add.roles" doesnt work for me?

I have this code rn
async function role(color) {
let user = message.member
user.roles.cache.map(v => { return v }).filter(v => v.name.startsWith('MerasuMin-Clr-')).forEach(role => {
console.log(role)
user.roles.remove(role)
})
let roleColor = message.guild.roles.cache.find(v => v.name === ("MerasuMin-Clr-"+color))
user.roles.add(roleColor)
user.send('Your name in '+message.guild.name+' has colorized to '+color)
}
Well i console logged the roleColor variable, and it returns the role that i expected
But... the role is not added
I have tried passing the id of role but no luck
What do i need to fix or add?
Full code
const { Client, EmbedBuilder } = require('discord.js')
module.exports = {
name: "color",
type: "customization",
description: "Customize the color of your name",
aliases: ["clr", "cl"],
callback: async(client, message, args, cmd) => {
let emb = new EmbedBuilder()
.setTitle('Colorize Name!')
.setDescription('Colors Available\n\n1⃣ - Black\n2⃣ - Purple\n3⃣ - Pink\n4⃣ - Green\n5⃣ - Orange\n6⃣ - Red\n7⃣ - Blue\n8⃣ - Yellow\n9⃣ - LightBlue')
.setColor(0xADD8E6)
.setFooter({ text: message.author.tag, iconUrl: message.author.displayAvatarURL() })
message.reply({embeds:[emb]}).then((msg) => {
msg.react('1⃣')
msg.react('2⃣')
msg.react('3⃣')
msg.react('4⃣')
msg.react('5⃣')
msg.react('6⃣')
msg.react('7⃣')
msg.react('8⃣')
msg.react('9⃣')
let filter = (reaction, user) => {
return user.id === message.author.id
}
msg.awaitReactions({filter, max: 1, time: 172800000, errors: ['time']})
.then(goods)
.catch(gan)
async function goods(collected) {
let reaction = collected.first()
if(reaction.emoji.name === '1⃣') {
reaction.users.remove(message.author.id)
return role('Black')
} else if(reaction.emoji.name === '2⃣') {
reaction.users.remove(message.author.id)
return role('Purple')
} else if(reaction.emoji.name === '3⃣') {
reaction.users.remove(message.author.id)
return role('Pink')
} else if(reaction.emoji.name === '4⃣') {
reaction.users.remove(message.author.id)
return role('Green')
} else if(reaction.emoji.name === '5⃣') {
reaction.users.remove(message.author.id)
return role('Orange')
} else if(reaction.emoji.name === '6⃣') {
reaction.users.remove(message.author.id)
return role('Red')
} else if(reaction.emoji.name === '7⃣') {
reaction.users.remove(message.author.id)
return role('Blue')
} else if(reaction.emoji.name === '8⃣') {
reaction.users.remove(message.author.id)
return role('Yellow')
} else if(reaction.emoji.name === '9⃣') {
reaction.users.remove(message.author.id)
return role('LightBlue')
}
async function role(color) {
let user = message.member
user.roles.cache.map(v => { return v }).filter(v => v.name.startsWith('MerasuMin-Clr-')).forEach(role => {
console.log(role)
user.roles.remove(role)
})
let roleColor = message.guild.roles.cache.find(v => v.name === ("MerasuMin-Clr-"+color))
user.roles.add(roleColor)
user.send('Your name in '+message.guild.name+' has colorized to '+color)
}
}
async function gan() {
setTimeout(() => {
msg.edit('USED!')
}, 1000)
}
})
}
}

Add a threshold to starboard for discord bot

So far I got the bot to add the message to a specific channel when the ⭐ reaction is triggered. I am stuck now... I'm trying to add a threshold where it takes a certain amount of ⭐ reactions to trigger the push the specific channel. Any help will be greatly apperciated.
const handleStarboard = async () => {
const starboard = bot.channels.cache.find(channel => channel.name.toLowerCase() === 'starboard');
const msgs = await starboard.messages.fetch({ limit: 100 });
const existingMsg = msgs.find(msg =>
msg.embeds.length === 1 ?
(msg.embeds[0].footer.text.startsWith(reaction.message.id) ? true : false) : false);
if(existingMsg) existingMsg.edit(`${reaction.count} - ⭐`);
else {
const embed = new MessageEmbed()
.setAuthor(reaction.message.author.tag, reaction.message.author.displayAvatarURL())
.addField('Url', reaction.message.url)
.setDescription(reaction.message.content)
.setFooter(reaction.message.id + ' - ' + new Date(reaction.message.createdTimestamp));
if(starboard)
starboard.send('1 - ⭐', embed);
}
}
if(reaction.emoji.name === '⭐') {
if(reaction.message.channel.name.toLowerCase() === 'starboard') return;
if(reaction.message.partial) {
await reaction.fetch();
await reaction.message.fetch();
handleStarboard();
}
else
handleStarboard();
}
});
bot.on('messageReactionRemove', async (reaction, user) => {
const handleStarboard = async () => {
const starboard = bot.channels.cache.find(channel => channel.name.toLowerCase() === 'starboard');
const msgs = await starboard.messages.fetch({ limit: 100 });
const existingMsg = msgs.find(msg =>
msg.embeds.length === 1 ?
(msg.embeds[0].footer.text.startsWith(reaction.message.id) ? true : false) : false);
if(existingMsg) {
if(reaction.count === 0)
existingMsg.delete({ timeout: 2500 });
else
existingMsg.edit(`${reaction.count} - ⭐`)
};
}
if(reaction.emoji.name === '⭐') {
if(reaction.message.channel.name.toLowerCase() === 'starboard') return;
if(reaction.message.partial) {
await reaction.fetch();
await reaction.message.fetch();
handleStarboard();
}
else
handleStarboard();
}
});

Spreadsheet not saving when using process.exit()

I'm using google spreadsheet and when I use process.exit() to stop my script It doesn't save the changes that I made to the spreadsheet. The problem is in the "row.save()" part, row.id row.status and row.tr_link do update. If I take out the process.exit() everything works fine.
async function accessSpreadsheet() {
const document = new GoogleSpreadsheet(thespreadsheetkey)
await promisify(document.useServiceAccountAuth)(credentials)
const info = await promisify(document.getInfo)()
const sheet = info.worksheets[0]
const rows = await promisify(sheet.getRows)()
var counter = 0
rows.forEach(async (row) => {
if (row.status == "") {
let data = await getCompanyID(row.email)
if (!data) {
await createCompany(row)
console.log(
`...`
)
//sendEmail(company)
} else
console.error(
`...`
)
row.status = "sent"
row.save()
} else if (row.status == "sent" && row.id == "") {
let data = await getCompanyID(row.email)
if (!data) {
console.error(
`...`
)
}
try {
row.id = data.id
row.tr_link = `...`
row.save()
console.log(
`...`
)
} catch (err) {
console.error(err, err.stack)
}
}
counter++
if (counter == rows.length) {
console.log("...")
return process.exit(0)
}
})
}

I need to remove user reaction after reacting

I have a command which allows me to go and query an API to retrieve images and then display them in discord.
Currently I come to search from my API 10 images, I want to set up a navigation system thanks to the discord reactions. Everything works but the problem is that once the user has clicked the reaction remains active. I need to delete the reaction to improve the user experience. Currently it is therefore necessary to double click which is not very practical. Here's the method that doesn't work for deletion :
const removeReaction = (m, msg, emoji) => {
try {
m.reactions.find(r => r.emoji.name == emoji).users.remove(msg.author.id);
} catch(err) {
console.log('err: ', err)
}
}
here is all my code
bot.on('message', async msg => {
if (msg.content.startsWith('!test')) {
const args = msg.content.slice('!test').split(' ')
console.log('args :', args[1])
axios(`https://json-api.example.com/posts?tags=${args[1]}&limit=10`, {
method: 'GET',
})
.then((response) => {
if (response.status === 500) {
msg.channel.send('error')
} else {
if (response.data.posts.length === 0) {
msg.channel.send(`No result for ${args[1]}`)
}
if (response.data.posts.length > 0) {
const resultsLength = response.data.posts.length
const options = {
limit: 60000,
min: 1,
max: resultsLength - 1,
page: 1
}
const pages = []
response.data.posts.map((i, index) => {
pages.push({
"title": `Result page number ${index} for ${args[1]}`,
"url": `${response.data.posts[index].sample_url}`,
"color": 43333,
"footer": {
"icon_url": "https://cdn.discordapp.com/app-icons/708760465999790244/228b2993e942a361518b557ee4511b26.png?size=32",
"text": "Cool footer"
},
"image": {
"url": `${response.data.posts[index].url}`
},
"fields": [
{
"name": "tags",
"value": `${response.data.posts[index].tags[0] || '/'}, ${response.data.posts[index].tags[1] || '/'}, ${response.data.posts[index].tags[2] || '/'}, ${response.data.posts[index].tags[3] || '/'}`
}
]
})
})
const m = msg.channel.send({ embed: pages[options.page] }).then((el) => {
el.react('⬅️')
el.react('➡️')
el.react('🗑️')
})
const filter = (reaction, user) => {
return ['⬅️', '➡️', '🗑️'].includes(reaction.emoji.name) && user.id == msg.author.id
}
const awaitReactions = (msg, m, options, filter) => {
const { min, max, page, limit } = options
m.awaitReactions(filter, { max: 1, time: limit, errors: ['time'] })
.then((collected) => {
const reaction = collected.first()
const removeReaction = (m, msg, emoji) => {
try { m.reactions.find(r => r.emoji.name == emoji).users.remove(msg.author.id); } catch(err) { console.log('err: ', err) }
}
if (reaction.emoji.name === '⬅️') {
removeReaction(m, msg, '⬅️')
if (page != min) {
page = page - 1
m.edit({ embed: pages[page] })
}
awaitReactions(msg, m, options, filter)
}
else if (reaction.emoji.name === '➡️') {
removeReaction(m, msg, '➡️');
if (page != max) {
page = page + 1
m.edit({ embed: pages[page] })
}
awaitReactions(msg, m, options, filter);
}
else if (reaction.emoji.name === '➡️') {
removeReaction(m, msg, '➡️');
if (page != max) {
page = page + 1
m.edit({ embed: pages[page] })
}
awaitReactions(msg, m, options, filter);
}
else if (reaction.emoji.name === '🗑️') {
return m.delete()
}
else {
awaitReactions(msg, m, options, filter)
}
}).catch((err) => { console.log('err: ', err) })
}
awaitReactions(msg, m, options, filter)
Thanks in advance for your help
so, after much research I finally found. I share the answer here.
With the 12+ version of discord.js package a lot has evolved including my problem:
m.reactions.find(r => r.emoji.name == emoji).users.remove(msg.author.id);
must become :
m.reactions.cache.find(r => r.emoji.name == emoji).users.remove(msg.author);
I have made this code a while ago.
It is for an older version of Discord.js but according to docs it should still work.
Basically what you want to do is to use Discord.js createReactionCollector function after you send the picture, then inside this.reactionCollector.on('collect', (reaction, reactionCollector) => {//do your work here}) you can change the picture then call reaction.remove(user); which immediately removes the reaction for that user.
Here's my code:
Note: I have made a class for this command so it might look a bit different for you.
Also in my version, only the user who initially called the command can change the picture. So you will need to modify that part if you want to let anyone change the picture. (It might be a pretty bad idea if your bot is in a large server.)
this.channel.send({embed}).then(msg => {
this.message = msg;
this.message.react('⬅️').then(x => {
this.message.react('➡️');
})
const filter = (reaction, user) => {
return (reaction.emoji.name === '➡️' || reaction.emoji.name === '⬅️') && user.id === this.user.id;
};
this.reactionCollector = this.message.createReactionCollector(filter, { time: 600000 });
this.reactionCollector.on('collect', (reaction, reactionCollector) => {
if(reaction.emoji.name === '➡️') {
if(this.index + 1 < result.length) {
this.index++;
var embed = this.makeEmbed(result[this.index].img);
this.message.edit({embed});
}
}
else if(reaction.emoji.name === '⬅️') {
if(this.index - 1 > -1) {
this.index--;
var embed = this.makeEmbed(result[this.index].img);
this.message.edit({embed});
}
}
reaction.remove(this.user);
});
});

"async.forEach" itetarion stop until request get an output

This code works perfectly besides this line: "inventory[asset.assetid].floatvalue = getFloat". As you can see it is situated in async mode, and this line initializes a request to get some value, but it cant get it couse value is undefined. I tested it, and the main problem in request, which is asynchronous too. So the answer is how to stop the async mode and wait the return of the request.
'use strict'
const config = require('../config');
const request = require('request');
const async = require('async');
const Trade = require('./index');
const MAX_RETRIES = 3;
const API_URL = 'https://api.steamapis.com/steam/inventory';
const floaturl = 'https://api.csgofloat.com:1738/';
Trade.prototype.getInventory = function getInventory(steamID64, appID, contextID, callback, retries) {
request(`${API_URL}/${steamID64}/${appID}/${contextID}?api_key=${config.SteamApisKey}`, (error, response, body) => {
if (!error && response.statusCode === 200) {
const items = JSON.parse(body)
const assets = items.assets
const descriptions = items.descriptions
const inventory = {}
if ( descriptions && assets ) {
async.forEach(descriptions, (description, cbDesc) => async.forEach(assets, (asset, cbAsset) => {
if (description.classid === asset.classid && description.tradable && description.marketable && description.market_hash_name.indexOf('Souvenir') === -1 ) {
if (typeof inventory[asset.assetid] !== 'undefined') {
return true
}
const type = Trade.prototype.getItemType(description.market_hash_name, description.type)
const wear = Trade.prototype.getItemWear(description.market_hash_name)
const inspect = Trade.prototype.getInspect(steamID64, asset.assetid, description.actions)
const getFloat = Trade.prototype.getFloat(inspect, asset.assetid, function(_float){
var data = String(_float);
inventory[asset.assetid].floatvalue = data; // inside the callback, at this moment judging by the consol the data is defined,but outside the callback the data is not appreciated to inventory[asset.assetid].floatvalue
});
inventory[asset.assetid] = asset
inventory[asset.assetid].item_type = type
inventory[asset.assetid].item_wear = wear
inventory[asset.assetid].inspect = inspect
inventory[asset.assetid].floatvalue = getFloat // this line does not work properly
inventory[asset.assetid].data = {
background: description.background_color,
image: description.icon_url,
tradable: description.tradable,
marketable: description.marketable,
market_hash_name: description.market_hash_name,
type: description.type,
color: description.name_color,
}
}
return cbAsset()
}, cbDesc))
}
return callback(null, inventory)
}
let retry = retries
if (typeof retries === 'undefined') {
retry = 0
}
retry += 1
if (retry <= MAX_RETRIES) {
return Trade.prototype.getInventory(steamID64, appID, contextID, callback, retries)
}
let statusCode = null
if (typeof response !== 'undefined' && typeof response.statusCode !== 'undefined') {
statusCode = response.statusCode
}
return callback({ error, statusCode })
})
}
Trade.prototype.getInventories = function getInventories(params, callback) {
const inventories = {}
async.each(params, (user, cb) => {
Trade.prototype.getInventory(user.steamID64, user.appID, user.contextID, (err, data) => {
inventories[user.id] = {}
inventories[user.id] = {
error: err,
items: (!err) ? Object.keys(data).map(key => data[key]) : null,
}
cb()
})
}, () => {
callback(inventories)
})
}
Trade.prototype.getItemType = function getItemType(marketHashName, type) {
if (marketHashName.indexOf('Key') !== -1) {
return { value: 0, name: 'key' }
}
if (marketHashName.indexOf('★') !== -1) {
return { value: 1, name: 'knife' }
}
if (
type.indexOf('Classified') !== -1 ||
type.indexOf('Contraband') !== -1 ||
type.indexOf('Covert') !== -1
) {
return { value: 2, name: 'rare_skin' }
}
if (
type.indexOf('Consumer Grade') !== -1 ||
type.indexOf('Base Grade') !== -1 ||
type.indexOf('Graffiti') !== -1 ||
type.indexOf('Sticker') !== -1 ||
type.indexOf('Industrial Grade') !== -1
) {
return { value: 4, name: 'misc' }
}
return { value: 3, name: 'weapon' }
}
Trade.prototype.getItemWear = function getItemWear(marketHashName) {
if (marketHashName.indexOf('Factory New') !== -1) {
return 'FN'
}
if (marketHashName.indexOf('Minimal Wear') !== -1) {
return 'MW'
}
if (marketHashName.indexOf('Field-Tested') !== -1) {
return 'FT'
}
if (marketHashName.indexOf('Well-Worn') !== -1) {
return 'WW'
}
if (marketHashName.indexOf('Battle-Scarred') !== -1) {
return 'BS'
}
return false
}
Trade.prototype.getInspect = function getInspect (steamID64, assetid, actions) {
let inspectLink = null;
if (actions) {
for (const a in actions) {
if (actions[a].name.indexOf('Inspect') !== -1) {
inspectLink = actions[a].link
inspectLink = inspectLink.replace('%owner_steamid%', steamID64)
inspectLink = inspectLink.replace('%assetid%', assetid)
}
}
}
return inspectLink
}
Trade.prototype.getFloat = function getFloat (adding, callback) {
request ("https://api.csgofloat.com:1738/?url=" + adding, (error, response, body) => {
if (!error && response.statusCode == 200) {
var floatBody = JSON.parse(body);
var float = floatBody["iteminfo"]["floatvalue"];
var id = id;
if (float != "") {
callback(float);
} else {
return "wrong";
}
} else {
console.log('something goes wrong');
return "wrong";
}
});
}
Just move the block of inventory[asset.assetid] lines inside the callback where data is defined.
if (
description.classid !== asset.classid ||
!description.tradable ||
!description.marketable ||
description.market_hash_name.indexOf('Souvenir') > -1
) {
return cbAsset()
}
if (typeof inventory[asset.assetid] !== 'undefined') {
return cbAsset()
}
const type = Trade.prototype.getItemType(description.market_hash_name, description.type)
const wear = Trade.prototype.getItemWear(description.market_hash_name)
const inspect = Trade.prototype.getInspect(steamID64, asset.assetid, description.actions)
const getFloat = Trade.prototype.getFloat(inspect, asset.assetid, function(_float){
var data = String(_float);
inventory[asset.assetid].floatvalue = data;
inventory[asset.assetid] = asset
inventory[asset.assetid].item_type = type
inventory[asset.assetid].item_wear = wear
inventory[asset.assetid].inspect = inspect
inventory[asset.assetid].data = {
background: description.background_color,
image: description.icon_url,
tradable: description.tradable,
marketable: description.marketable,
market_hash_name: description.market_hash_name,
type: description.type,
color: description.name_color,
};
return cbAsset();
});
Side-remark:
(1) I always find its better to return early to avoid messy code.
(2) Ensure that you always trigger the callbacks i.e. cbDesc and cbAsset at least and at most once in each operation. Your code will hang or trigger errors if you don't do this properly.
(3) If Trade.getItemType(), Trade.getItemWear(), Trade.getInspect(), and Trade.getInspect() are all asynchronous, then you'll probably need to use another async function (such as async.series() or async.parallel()) and wait for its final callback to do inventory[asset.assetid] lines.

Resources