How to send private messages in slack channel? - javascript

I am currently sending a message to the slack channel using below function. But I want to send a private message which should be visible to selected member of the slack channel.
How can I do that ?
async function sendSlackMessage() {
const url = 'https://slack.com/api/chat.postMessage';
const inputBody = {
channel: "Slack_Channel_ID",
text: `Hey Welcome to the slack`,
};
const slackHeaders = {
'Content-Type': 'application/json;charset=utf-8',
'Authorization': 'Slack_Token',
};
const slackRes = await axios.post(url, inputBody, { headers: slackHeaders });
console.log(slackRes)
}
sendSlackMessage()

Solution using Boltjs for Javascript:
To send a private message visible only to a specific user on a channel on Slack, we may use a different method chat.postEphemeral from Bolt for JavaScript. Using the above method you can send an ephemeral message to a users in a channel that is visible only to a specific user that you can choose to display.
Note: I have offered my solution as simple blocks, you need to encapsulate it within the function you need this feature to operate on.
Requirements:
For using the chat.postEphemeral you are required to send the following arguments to work.
token: Slack_Bot_Token {Authentication token bearing required scopes. Tokens should be passed as an HTTP Authorization header or alternatively, as a POST parameter.}
channel: {Channel, private group, or IM channel to send message to. Can be an encoded ID, or a name}
user: {id of the user who will receive the ephemeral message. The user should be in the channel specified by the channel argument.}
text: "Anything you need here"
blocks: "Pack and Send from Block Kit Message Builder, not necessary though"
Note:
extract the channel id from the function or pass it as args to the async function
extract the user id from the function or pass it as args to the async function
text field is not enforced when blocks are used.
Methods Access: app.client.
chat.postEphemeral
Required Scopes in Slack App:
Bot Tokens
User Tokens
Example Code:
// Building the args object from body (Can also use, action, context, and few other slack parameters from Bolt API for js)
const args = {
user: body.user.id,
channel: body.container.channel_id,
team: body.user.team_id,
token: body.user.id,
trigger: body.trigger_id,
url: body.response_url,
};
Slack App Code:
try {
// Call the chat.postEphemeral method using the WebClient
const result = await client.chat.postEphemeral({
channel: channelId,
user: userId,
token: userToken,
text: "Shhhh only you can see this :shushing_face:"
});
console.log(result);
}
catch (error) {
console.error(error);
}
Documentation:
View this documentation for more Information: Slack API for Methods
Check here to Create Message Block Kits for Slack: Slack Block Kit Builder

Related

How to create a function to send messages

I have a node.js app that I have created a discord bot to interact with. I would like it so that if a particular event happens with my node.js app that it will send a message to a particular channel in my discord server.
This is my first time using discord.js. However, my thought was to create a function that I can call to send my messages. However, it would seem that I need to wait for my client to be ready first.
Alternatively, would I just have to instantiate a new client every time I want to send a message and wait for it to come available before I send the message I want?
I feel like there has to be a better way... Is there a clean way that I can set up this basic discord bot that I can just call a function to send a message from anywhere within my app?
Here is the code that I have now:
import { Client, Events, GatewayIntentBits } from "discord.js";
import { botToken, CHANNEL_ID } from "../../config.js";
const client = new Client({ intents: [GatewayIntentBits.Guilds] }); // Create a new client instance
// When the client is ready, run this code (only once)
// We use 'c' for the event parameter to keep it separate from the already defined 'client'
client.once(Events.ClientReady, c => {
console.log(`Ready! Logged in as ${c.user.tag}`);
client.channels.cache.get(CHANNEL_ID).send("Hello!");
});
// Log in to Discord with your client's token
client.login(botToken);
"I would like it so that if a particular event happens with my node.js app that it will send a message to a particular channel in my discord server."
It sounds like you're looking for webhooks. Webhooks are a way for an external source, such as your Node.js app, to send messages to a Discord channel without having to log in as a bot. Instead of using a Discord bot, you can use a webhook to send messages to a channel as if they were posted by a bot.
Using a webhook is simple; you just need to make an HTTP POST request to a URL provided by Discord, with the message you want to send in the body of the request. Discord will then post that message to the specified channel.
This is useful in cases where you want to receive notifications from your app in a Discord channel, or simply want to send messages to a channel without having to log in as a bot. It's a clean and efficient way to integrate your app with Discord.
Here is an example of a sendMessage function. It takes two arguments, payload and webhookUrl. If the payload is not a string, it is assumed to be an object that conforms to the Discord webhook format and will be used as is.
function sendMessage(payload, webhookUrl) {
const data = typeof payload === 'string' ? { content: payload } : payload;
return new Promise((resolve, reject) => {
fetch(webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then((response) => {
if (!response.ok) {
reject(new Error(`Could not send message: ${response.status}`));
}
resolve();
})
.catch((error) => {
console.error(error);
reject(error);
});
});
}
If you're using node.js v18+, you can use the built-in fetch, if not, you'll need to install a library like node-fetch, axios, or something else.
Here is an example how you could use it:
// send a simple message
sendMessage('Hello from my app!', WEBHOOK_URL).catch((error) =>
console.error(error),
);
// send a message, but change the username and the avatar
sendMessage(
{
content: 'Hello from my app!',
avatar_url: 'https://i.imgur.com/KEungv8.png',
username: 'Test Hook',
},
WEBHOOK_URL,
).catch((error) => console.error(error));
// send an embed and change the user again
sendMessage(
{
avatar_url: 'https://i.imgur.com/ofPowdD.png',
username: 'Cattian Hook',
embeds: [
{
title: 'Cats, cats, cats',
color: 0xe7d747,
thumbnail: {
url: 'https://i.imgur.com/2bvab7y.jpeg',
},
},
],
},
WEBHOOK_URL,
).catch((error) => console.error(error));
And here is the result:
If you're already using discord.js, you can use the WebhookClient:
import { WebhookClient } from 'discord.js';
const webhookClient = new WebhookClient({
url: WEBHOOK_URL,
});
webhookClient.send({
content: 'Discord.js webhook test',
username: 'DJS Webhook',
avatarURL: 'https://i.imgur.com/KEungv8.png',
});
To create a webhook, you'll need to go to your discord server settings and click on APPS => Integrations. Then click on the Create Webhook button. There you can select the channel where you want the messages to be sent.
Once the webhook is created, you can click the Copy webhook URL button and use that URL.

How to use node.js to create a new chat message in an existing channel in Teams with application permissions

I am trying to create a new chat message in an existing channel in Teams using node.js. My application needs to send messages to this channel to notify members of the channel that something has happened with my app and allow replies, etc.
It looks like Microsoft has limited this functionality to the migration permission, based on this document note.
Note: Application permissions are only supported for migration. In the future, Microsoft may require you or your customers to pay additional fees based on the amount of data imported.
Since I am not trying to migrate data from another service, and instead trying to create a new chat in the channel, am I out of luck?
Is there any way to create a new chat message in a channel using application permissions vs. signed in user permissions?
I am getting this error:
{
error: {
code: 'Unauthorized',
message: 'Unauthorized',
innerError: {
date: '2021-05-15T01:07:08',
'request-id': '<my request-id>',
'client-request-id': '<my client-request-id>'
}
}
}
This is my code:
let res = await fetch(`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, {
method: 'post',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: `client_id=${clientId}&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=${clientSecret}&grant_type=client_credentials`
})
let token = await res.json()
let teamsId = '<teamsId>'
let teamsChannelId = '19%<teamsChannelId>#thread.tacv2'
const chatMessage = {
body: {
content: 'Hello World'
}
};
let sendChat = await fetch(`https://graph.microsoft.com/v1.0/teams/${teamsId}/channels/${teamsChannelId}/messages`, {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token.access_token
},
body: JSON.stringify(chatMessage)
})
let chatRes = await sendChat.json()
console.log(chatRes)
If you just create a new chat message in the channel, it's not supported to use application permissions. As the document says, "Application permissions are only supported for migration.". And you can see the supported permission is Teamwork.Migrate.All, which is used to manage migration to Microsoft Teams.
It's recommended for you to use authorization code flow with the delegated permission(ChannelMessage.Send). You could also get access token directly with username and password using ropc flow, but it carries risks, you could use it just for test.
// Request an authorization code
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=<client_id>
&response_type=code
&redirect_uri=<redirect_uri>
&response_mode=query
&scope=https://graph.microsoft.com/ChannelMessage.Send
&state=12345
// Request an access token with a client_secret
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
client_id=<client_id>
&scope=https://graph.microsoft.com/ChannelMessage.Send
&code=<authorization code from previous step>
&redirect_uri=<redirect_uri>
&grant_type=authorization_code
&code_verifier=ThisIsntRandomButItNeedsToBe43CharactersLong
&client_secret=<client_secret>
Note: you need to add ChannelMessage.Send permission in API permissions first.
Sample of node js using the auth code flow: https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-v2-nodejs-webapp-msal

Error using AWS Cognito for authentication with Hasura

i'm having some problems using lambda enviroment.
Looking to set a function that make a mutation to Hasura so I can relate Auth users of Cognito with my app information.
I set the following function Post Authentication in Lamba but it does not work.
function Add(event, context, callback) {
const userId = event.user_id;
const hasuraAdminSecret = "xxx";
const url = "xxx";
const upsertUserQuery = `
mutation($userId: String!){
insert_RegistroAnimal_users(objects: [{ id: $userId }], on_conflict: { constraint: users_pkey, update_columns: [] }) {
affected_rows
}
}`
const graphqlReq = { "query": upsertUserQuery, "variables": { "userId": userId } }
request.post({
headers: {'content-type' : 'application/json', 'x-hasura-admin-secret': hasuraAdminSecret},
url: url,
body: JSON.stringify(graphqlReq)
}, function(error, response, body){
console.log(body);
callback(null, user, context);
});
}
Followed this tutorial : https://hasura.io/docs/latest/graphql/core/guides/integrations/aws-cognito.html#introduction
What do you think is wrong with the code?
I don't think anything is wrong with the code, but to make it work with Cognito you'd need to provide your Hasura setup with a JWT claims function as shown in that same guide, https://hasura.io/docs/latest/graphql/core/guides/integrations/aws-cognito.html#create-a-lambda-function-to-add-claims-to-the-jwt. If you'd like to do it as the guide suggests, you need to create a lambda function like so;
exports.handler = (event, context, callback) => {
event.response = {
"claimsOverrideDetails": {
"claimsToAddOrOverride": {
"https://hasura.io/jwt/claims": JSON.stringify({
"x-hasura-user-id": event.request.userAttributes.sub,
"x-hasura-default-role": "user",
// do some custom logic to decide allowed roles
"x-hasura-allowed-roles": ["user"],
})
}
}
}
callback(null, event)
}
You then need to pick this function as the PreTokenGeneration trigger from your user pool settings. Then AWS Cognito will trigger this function before token generation, allowing you to add Hasura required claims to your token.
The next step is to tell Hasura where to lookup for the JWT claims by providing HASURA_GRAPHQL_JWT_SECRET during the setup, which is essentially an URL pointing to your Cognito setup, generated using the pool id.
Finally, you can obtain the idToken from your user session after a successful login, and pass that token as an Authentication header for your Hasura requests. Described here.
All of these steps were actually described in the guide you linked, but may not be as clear. I believe the reason your current setup does not work is that your Hasura setup is missing the HASURA_GRAPHQL_ADMIN_SECRET, which needs to be the same as the x-hasura-admin-secret you're using in your requests.
Mind you, if you use x-hasura-admin-secret in your app and expose it to your users which gives them admin access, that creates a potential security issue and anyone with that secret can wipe up your data. x-hasura-admin-secret should be reserved for your admin tasks and not used in an app where AWS Cognito authentication is planned to be used.

How do I give my Firebase Cloud Messaging notification a tag property?

I am trying to give my Firebase Cloud Messaging notification a tag property on Android as described here and here so I can replace notifications that have been received if necessary.
I am using React Native, React Native Firebase and the ConnectyCube API. ConnectyCube works with Firebase to handle user management and push notifications - I have all of this working.
What I can't figure out is how to format my payload object to include optional properties such as tag as the documentation is fairly cryptic. I am successfully sending a message which is included in the message property, and in the ConnectyCube docs you will see that the iOS optional property of badge is just another property in the payload object, but in the case of tag for android, the below code is not working:
export const sendNotification = async (calleeId, callLength, tagUUID) => {
const callersUserName = await getUserNameFromStorage();
const payload = JSON.stringify({
message: callersUserName + '-' + callLength,
tag: tagUUID,
});
const pushParameters = {
notification_type: 'push',
user: { ids: [calleeId] }, // recipients.
environment: 'production', // environment, can be 'production'.
message: ConnectyCube.pushnotifications.base64Encode(payload)
};
ConnectyCube.pushnotifications.events.create(pushParameters, function (error, result) {
});
setTimeout(() => {
const payload2 = JSON.stringify({
message: 'replacement-notification',
tag: tagUUID,
});
const pushParameters2 = {
notification_type: 'push',
user: { ids: [calleeId] }, // recipients.
environment: 'production', // environment, can be 'production'.
message: ConnectyCube.pushnotifications.base64Encode(payload2)
};
ConnectyCube.pushnotifications.events.create(pushParameters2, function (error, result) {
});
}, 3000)
}
When push notifications have the same tag, each notification will be replaced with the newer one which I am trying to mimic with setTimeout.
I am receiving both messages but the first is not being replaced with the second!
Any help is much appreciated! :)
tag is a payload key for Notification type pushes, but ConnectyCube sends all pushes as Data.
With Data pushes there is full control over what to do with notification (to show or not to show), so there is a way to add a code in app to hide an existing notification and then show a new one once a Data push received

Can you use the getstream.io js client with react native instead of react-native-activity-feed?

Hi getstream community,
I am building a feed application with react native and node.js. I am struggling to add activities using the getstream.io js client, but I can do it with react-native-activity-feed's <StatusUpdateForm/> component. I get the following error with the js client:
An error occured when submitting activity: Error: {"detail":"You don't have the permission to do this","status_code":403,"code":17,"exception":"NotAllowedException","duration":"0.16ms"} with HTTP status code 403
I've set up the backend to send me a user token and initialize a user feed:
const streamClient = stream.connect(STREAM_KEY, STREAM_SECRET, STREAM_ID);
gsToken = streamClient.createUserToken(decodedToken.user_id);
streamClient.feed('user', decodedToken.user_id);
In the frontend I render a feed using <StreaApp/> & <FlatFeed/>
I've set up the post screen to send a sample activity on press to the feed:
var client = stream.connect(config.stream.app.key, config.stream.app.token, config.stream.app.id);
var user_feed = client.feed('user', config.stream.app.userId);
user_feed.addActivity({
actor: config.stream.app.userId,
tweet: 'Hello World I am finally here',
verb: 'Tweet',
object: 1
})
.then(function(data) { console.log('Activity Added! ' + data)})
.catch(function(err) { console.log('An error occured when submitting activity: ' + err)});
SideNote: I would like to use the js client instead of the react-native package so I can have more flexibility with UI.
When using user tokens please make sure to call setUser
let feed = client.feed("user", "jack");
await client.setUser({name: 'Jack'});
await userFeed.addActivity({
actor: client.currentUser,
verb: "post",
object: "my object",
})
this will populate client.currentUser which you can use as actor as well as store the user data in the actor field.

Categories

Resources