Twilio Chat getChannels order by most recent message - twilio

In twilio chat, is there a way to specify an order to the getChannels() method? Or is there a property on the Channel object that will tell me when the last message sent on that channel was? The dateUpdated property on Channel seems to be when properties on the channel were updated, not including messages sent/received.
I would like to order my channels list by the most recent messages. And I would like to do this without having to retrieve all the messages first.

You can add the attributes parameter upon updating a channel.
An optional string metadata field you can use to store any data you
wish.
You could track time/date info of messages here.
# Update the channel
service = client.services.get(sid="CHANNEL_SID")
channel = service.channels.create()
response = channel.update(friendly_name="NEW_FRIENDLY_NAME", attributes="ANY_DATA_YOU_WISH")
print(response)
You should then be able to subscribe to a channel event (JavaScript SDK example). As you did not specify what language you're using you will also find more details in the API Docs for iOS and Android SDKs as well.
// A channel's attributes or metadata have changed.
messagingClient.on('channelUpdated', function(channel) {
console.log('Channel updates: ' + channel.sid);
});

Related

Multiple Immutable Id's for same mail message?

I am writing an Office Outlook add-in that has a React frontend and a dotnet core backend. I have set up a subscription using the Graph API to receive notifications when a new email appears on the SentItems folder. I want to correlate the email from the notification with information I have stored in a database.
Unfortunately the item id changes when the email is sent and moves from the Drafts folder into SentItems so it isn't useful for matching.
There is a new ImmutableId that doesn't change when the email is moved between folders. I've been unable to get the Office.js lib to generate an ImmutableId but there is a translateExchangeIds method that when given an email item id will return an immutable id.
// convert to immutable
var translateRequest = new {
inputIds = new string [] { mailMessage.ItemId },
targetIdType = "restImmutableEntryId",
sourceIdType = "restId"
};
var immutableResponse = await graphClient.PostAsJsonAsync("me/translateExchangeIds", translateRequest);
var immutableId = await immutableResponse.Content.ReadAsStringAsync();
I can use that immutable id to retrieve the email message using the Graph request:
await graphClient.GetAsync($"Users/cccccccc-dddd-eeee-ffff-ba0c52e56d99/Messages/AAkALgAAAAAAHYQDEapmEc2byACqAC-EWg0AQ-irLc2NFESKcGAhz1k_GBBDB5JMOwAA/
But the immutable id that is returned with the subscription notification is a different immutable id for the same message. So it's not possible to match the notification mail message with the message info stored in my database. So I still have to attach a custom property to the message for the sole purpose of matching the database entry with the SentItems notification.
Is there a better way to deal with this issue?
Update: my theory is the difference occurs because the immutable id is derived when the item is in different folders? When translating the item id to an immutable id, the item is still in the Drafts folder. When the subscription notification occurs, the item is in the Sent Items folder. The following responses were from queries using the different immutable id's but identify the same message - the myId GUID is a custom property attached to the message and used to correlate the notification with the message info stored in a local database.
\"id\":\"AAkALgAAAAAAHYQDEapmEc2byACqAC-EWg0AQ-irLc2NFESKcGAhz1k_GAADB4INPAAA\",...,\"myId\":\"8baa904f-cf64-437c-878c-be4f71714aee\"
\"id\":\"AAkALgAAAAAAHYQDEapmEc2byACqAC-EWg0AQ-irLc2NFESKcGAhz1k_GAADB4INLwAA\",...,\"myId\":\"8baa904f-cf64-437c-878c-be4f71714aee\"
We fixed this and now you should see the same ImmutableId for draft and sent messages. Can you try and let us know if this is working as expected?

Twilio - channel descriptor paginator order

I want to retrieve the list of channels for a user containing unread messages. The best solution I have found so far (please correct me if I'm wrong) is using channel descriptors.
// Example for a single page
client.getUserChannelDescriptors().then(function(paginator) {
for (var i = 0; i < paginator.items.length; i++) {
var descriptor = paginator.items[i].descriptor;
if (descriptor.unread_messages_count > 0) {
console.log("Channel found, id: " + descriptor.uniqueName);
}
}
});
My question: is there a way to order in the paginator object so I could retrieve channels with unread messages first so I wouldn't have to go through the whole list of channels?
Twilio developer evangelist here.
You can sort channels, but not with getUserChannelDescriptors. Instead, you need to make sure you've loaded all the subscribed channels and then you can sort them with getLocalChannels.
From the docs:
getLocalChannels( [sortingOptions])
Get array of Channels locally known to Client in provided sorting order. Locally known channels are the ones created and/or joined during client runtime and currently logged in User subscribed Channels. To ensure full list of subscribed Channels fetched - call the Client#getSubscribedChannels method and fetch all pages with help of Paginator#nextPage method.
The sorting options then allow you to sort by lastmessage.

Twilio SWIFT API get consumed messages always returns 0

I want to display next to a chat channel the number of messages a channel has that have been unconsumed or unread (I assume this is what unconsumed means?)
Currently I send messages to a channel that two users are subscribed to , a private chat. Then before opening up the chat window I check the channel for unconsumed messages, but it always say 0 messages even if I call setNoMessagesConsumedWithCompletion.
I am using the Swift API...What do I need to do to find out how many messages in my channel have not been read yet? At what point do they become read? (when the user opens up a chat channel and requests to getLastWithCount?)
I read in the docs you have to set something called the consumption horizon to get unconsumed message, but I don't know how you do that in SWIFT API https://www.twilio.com/docs/chat/consumption-horizon also this was for Javascript API so perhaps it is easier with Swift Api?
I figured out the solution. As per the documentation you need to update the last consumed message index. So for example if the user has a chat window open you need to record for that user (or instance of the Chat Client) what was the last message they saw before they close their chat. I am storing all the messages in a message array and update the last consumed message index with the length of the array of messages:
generalChannel?.messages?.setLastConsumedMessageIndex(NSNumber.init(value: self.messages.count), completion: { (result, count) in
if !result.isSuccessful() {
print(result.error.debugDescription)
}
})
Then if you send messages to that channel when the user is not in the channel these will be recorded as unconsumed, you can get the number by calling:
channel.getUnconsumedMessagesCount(completion: { (results, numberUnconsumed) in
print(numberUnconsumed)
})

How can a Slack bot detect a direct message vs a message in a channel?

TL;DR: Via the Slack APIs, how can I differentiate between a message in a channel vs a direct message?
I have a working Slack bot using the RTM API, let's call it Edi. And it works great as long as all commands start with "#edi"; e.g. "#edi help". It currently responses to any channel it's a member of and direct messages. However, I'd like to update the bot so that when it's a direct message, there won't be a need to start a command with "#edi"; e.g. "#edi help" in a channel, but "help" in a direct message. I don't see anything specific to differentiate between the two, but I did try using the channel.info endpoint and counting the number of people in "members"; however, this method only works on public channel. For private channels and direct messages, the endpoint returns an "channel_not_found" error.
Thanks in advance.
I talked to James at Slack and he gave me a simply way to determine if a message is a DM or not; if a channel ID begins with a:
C, it's a public channel
D, it's a DM with the user
G, it's either a private channel or multi-person DM
However, these values aren't set in stone and could change at some point, or be added to.
So if that syntax goes away, another way to detect a DM to use both channels.info and groups.info. If they both return “false” for the “ok” field, then you know it’s a DM.
Note:
channels.info is for public channels only
groups.info is for private channels and multi-person DMs only
Bonus info:
Once you detect a that a message is a DM, use either the user ID or channel ID and search for it in the results of im.list; if you find it, then you’ll know it’s a DM to the bot.
“id” from im.list is the channel ID
“user” from im.list is the user ID from the person DM’ing with the bot
You don’t pass in the bot’s user ID, because it’s extracted from the token
FYI as of July 2017, for "message.im" events (via your app's Event Subscriptions), the event payload seems to now return additional fields to detect if the message is coming from your own bot (pasted in here from my logs):
INFO[0012] got Slack message: (bot.SlackMessage) {
SlackEvent: (bot.SlackEvent) {
Type: (string) (len=7) "message",
EventTs: (string) (len=17) "1501076832.063834",
User: (string) ""
},
SubType: (string) (len=11) "bot_message",
Channel: (string) (len=9) "D6CJWD132",
Text: (string) (len=20) "this is my bot reply",
Username: (string) (len=15) "Myapp Local",
BotID: (string) (len=9) "B6DAZKTGG",
Ts: (string) (len=17) "1501076832.063834"
}
Slack have added Conversations API some time ago. You should use it to differentiate between PM/channel instead of relying on prefix.
From Conversations API documentation:
Each channel has a unique-to-the-team ID that begins with a single letter prefix, either C, G, or D. When a channel is shared across teams (see Developing for Shared Channels), the prefix of the channel ID may be changed, e.g. a private channel with ID G0987654321 may become ID C0987654321.
This is one reason you should use the conversations methods instead of the previous API methods! You cannot rely on a private shared channel's unique ID remaining constant during its entire lifetime.
Get conversation info using conversations.info method and check is_im flag. is_im == true means that the conversation is a direct message between two distinguished individuals or a user and a bot.
The info function is also available for private channels with the Slack API method groups.info. This works also for direct message channels with multiple participants, since they are a special form of private channels.
You can use groups.list to get the IDs of all private channels incl. direct message channels with multiple participants.
Note that groups.list will only return private channels, that the user or bot that the access token belongs to has been invited to.

Get related subscribed channel(s) in didReceiveStatus in PubNub for iOS objective C

When didReceiveStatus is called after subscribing to a channel, We are not able to retrieve the channel(s) that was just subscribed.
PNSubscribeStatus.data.subscribedChannel or PNSubscribeStatus.data.actualChannel are always null and PNSubscribeStatus.subscribedChannels gives all currently subscribed channels and not the ones that triggered the didReceiveStatus callback.
What are we doing wrong here ?
In SDK 4.0, didReceiveStatus returns a PNStatus, which according to the class documentation doesn't contain that extra information unless there's an error condition. For our application, we use that handler to monitor connection status to the PubNub server.
PubNub Message Received Channel Name in iOS
You should be able to get the channel that you received the message on but getting it depends on whether you are subscribed to the channel or to a channel group that contains the channel. This is sample code from the PubNub Objective-C for iOS SDK subscribe API Reference:
- (void)client:(PubNub *)client didReceiveMessage:(PNMessageResult *)message {
// Handle new message stored in message.data.message
if (message.data.actualChannel) {
// Message has been received on channel group stored in
// message.data.subscribedChannel
}
else {
// Message has been received on channel stored in
// message.data.subscribedChannel
}
NSLog(#"Received message: %# on channel %# at %#", message.data.message,
message.data.subscribedChannel, message.data.timetoken);
}
If you need other channels that the client is subscribed to, you can call the where-now API.
If you need to be more dynamic about what the reply-to channel should be, then just include that channel name in the message when it is published, assuming the publisher has prior knowledge about which channel this is. Or you can do a just in time lookup on your server as to which channel to reply to.
Here is PubNub support answer on this :
Actually status.data.subscribedChannel and status.data.actualChannel
dedicated to presence events and messages receiving callbacks where
information about sources of event is important.
In -client:didReceiveStatus: client doesn’t give information about
particular channel on which client has been subscribed. If client will
start track this information, there is no guarantee what it will
return expected value (as developer expect some channels to be there).
In previous version (3.x) all this information has been tracked, but
because it can be modified at any moment – result sometimes was
unpredictable.
Subscribe can be done in sequence of methods (one after another) like:
subscribe A1, subscribe C1, subscribe B1 and B2, unsubscribe C1 and B1
– this as result will end up with single call of
-client:didReceiveStatus: with resulting set of channels.
It always best practice just to check whether your channels is in
s_tatus.subscribedChannels_.
My comments:
The point of having asynchronous process is exactly not to think this as sequence of methods... We can not have the guaranty that subscriptions are done in the exact same order as the subscription request unless we block other subscription request until the previous one is done.

Resources