Dsharp GetAllMembersAsync() psermison needed - dsharp+

I am trying to get all the members of a guild. When i use GetAllMembersAsync() i get an exception of unauthorized 403. I tried to give the bot all permissions but I am still getting the exception.
Minimum reproducible example of code that may return this issue
private static async Task<IReadOnlyCollection<DiscordMember>>
GetEveryone(DiscordClient client, DiscordGuild guild)
{
DiscordGuild myGuild = await client.GetGuildAsync(guild);
var members = myGuild.GetAllMembersAsync();
return members;
}
Thx for your help

It's been a while since the question was asked but I wanted to answer for anyone who comes here in the future.
When creating your client you must declare your intentions with DiscordConfiguration() and not just by giving the bot permission in Discord's developer portal. To be clear, both your bot and Discord's developer portal must have matching configurations to avoid an HTTP 403 or 401 error. In the main method for creating your discord client you likely have something like this set up:
var discord = new DiscordClient(new DiscordConfiguration()
{
Token = tokenHere,
TokenType = TokenType.Bot
});
To declare this intention you must set the Intents configuration as well:
var discord = new DiscordClient(new DiscordConfiguration()
{
Token = tokenHere,
TokenType = TokenType.Bot,
Intents = DiscordIntents.All
});
The minimum Intent for your purpose is DiscordIntents.GuildMembers, however, there are many Intents and you can declare them individually. Be sure to check out the examples from DSharp+.
Important: Server Member intents are a part of the Privileged Gateway Intents set. You must set the SERVER MEMBERS INTENT configuration in the Discord Developer Portal Bot tab to true to act upon any Discord members in any way. Not all bots will have this access immediately but generally, most developers will be able to declare this intent after a short time.

Related

Skill host generating new conversation IDs every turn, breaking waterfall dialogs

I'm working on converting some existing bots to skills so that we can create a Skill Host bot that can call multiple "child bots". I used the skills-simple-bot-to-bot sample, and it kind of works. I can call the skill bot from the host and it works...for a single turn. But the host is creating a new conversation ID every turn, clearing the conversation state which makes my multi-turn waterfall dialogs not work. It is also causing any other values stored in conversation state to be cleared (e.g. I capture email address in conversation state so I don't have to reprompt it). The skill bot works fine when invoked directly (i.e. not through the skill host), so it's definitely something with the way the skill host works. I found this issue on GitHub which seems to be the same thing (that's for .NET but there are links to the other SDKs including js), though it seems to have been resolved years ago yet I'm still having the issue so I'm not sure it's the same.
So in short, how do I set up the skill host so that it doesn't generate new conversation IDs every turn?
Not sure this will help as it's almost exactly the same as the sample, but here's a snippet of the code where it appears conversation ID is being generated by the host. It seems maybe I need some way to NOT call createSkillConversationIdWithOptions, but if that's what is required I'm not sure what I need to do to generate the skillConversationId other than what is currently in the sample.
async sendToSkill(context, targetSkill) {
// NOTE: Always SaveChanges() before calling a skill so that any activity generated by the skill
// will have access to current accurate state.
await this.conversationState.saveChanges(context, true);
// Create a conversationId to interact with the skill and send the activity
const skillConversationId = await this.conversationIdFactory.createSkillConversationIdWithOptions({
fromBotOAuthScope: context.turnState.get(context.adapter.OAuthScopeKey),
fromBotId: this.botId,
activity: context.activity,
botFrameworkSkill: this.targetSkill
});
// route the activity to the skill
const response = await this.skillClient.postActivity(this.botId, targetSkill.appId, targetSkill.skillEndpoint, this.skillsConfig.skillHostEndpoint, skillConversationId, context.activity);
// Check response status
if (!(response.status >= 200 && response.status <= 299)) {
throw new Error(`[RootBot]: Error invoking the skill id: "${ targetSkill.id }" at "${ targetSkill.skillEndpoint }" (status is ${ response.status }). \r\n ${ JSON.stringify(response.body) }`);
}
}

Proactive messaging bot in Teams without mentioning the bot beforehand

I'm using the Microsoft bot-framework to create a bot and integrate it into teams.
Part of the bot's requirements include proactively messaging users once per day. From what I understand, I can only message users that has been added to the team/groupChat after the bot, or that have messaged the bot directly.
My question is - can I somehow bypass this limitation?
A friend of my referred me to a new feature of graphAPI, as part of the new beta version - https://learn.microsoft.com/en-us/graph/api/user-add-teamsappinstallation?view=graph-rest-beta&tabs=http.
To me it doesn't seem like it could be related to the solution since I'm not getting any data back in the response, so if I have no conversationReference object I still can't message the user.
At the moment my solution is to simply broadcast a message in the channel when it's added, asking users to "register" with it by messaging it. Anyone has any other suggestion?
The easiest way is to:
Install the bot for the team
Query the Team Roster -- The link in Step 3 has an alternative way to do this towards the bottom
Create a conversation with the user and send a proactive message
There's a lot of code in those links and it's better to just visit them than to copy/paste it here.
The end of Step 3 also mentions trustServiceUrl, which you may find handy if you run into permissions/auth issues when trying to send a proactive message.
Edit for Node:
Install Necessary Packages
npm i -S npm install botbuilder-teams#4.0.0-beta1 botframework-connector
Note: The #<version> is important!
Prepare the Adapter
In index.js
const teams = require('botbuilder-teams');
adapter.use(new teams.TeamsMiddleware());
Get the Roster
// Get Team Roster
const credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
const connector = new ConnectorClient(credentials, { baseUri: context.activity.serviceUrl });
const roster = await connector.conversations.getConversationMembers(context.activity.conversation.id);
Send the Proactive Message
const { TeamsContext } = require('botbuilder-teams');
// Send Proactive Message
const teamsCtx = TeamsContext.from(context);
const parameters = {
members: [
roster[0] // Replace with appropriate user
],
channelData: {
tenant: {
id: teamsCtx.tenant.id
}
}
};
const conversationResource = await connector.conversations.createConversation(parameters);
const message = MessageFactory.text('This is a proactive message');
await connector.conversations.sendToConversation(conversationResource.id, message);
Trust the ServiceUrl, as Necessary
Read about it. You'd want this before the message is sent.
MicrosoftAppCredentials.trustServiceUrl(context.activity.serviceUrl);
EDIT: The Graph API you've referenced is only necessary if you wish to proactively message a user who is not in a channel/groupChat where the bot is installed. If you need to proactively message only people who are in context where the bot is installed already, the answer from mdrichardson is the easiest possible method.
We've identified a couple of issues with the Graph API beta endpoint you referenced that should be fixed in the near term. In the meantime workarounds are as follows:
Calling:
POST https://graph.microsoft.com/beta/me/teamwork/installedApps/
{"teamsapp#odata.bind":"https://graph.microsoft.com/beta/appcatalogs/teamsapps/APP-GUID"}
Will install an app in the personal scope of a user.
Known issue: Currently, if the app contains a bot, then installation will not lead to creation of thread between the bot and the user. However to ensure that any missing chat threads, get created, call:
GET https://graph.microsoft.com/beta/me/chats?$filter=installedApps/any(x:x/teamsApp/id eq 'APP-GUID')
Calling:
GET https://graph.microsoft.com/beta/me/chats?$filter=installedApps/any(x:x/teamsApp/id eq 'APP-GUID')
Gets the chat between a user and an app containing a bot.
Known issue: Calling this API will lead to sending a conversation update event to the bot even though there were no updates to the conversation. Your bot will essentially get two install events and you'll need to make sure you don't send the welcome message twice.
We'll also be adding more detailed documentation for the proactive messaging flow using these Graph APIs

How to pass to an intent if Permission request is denied

I have an Action that integrates with Dialogflow which as part of the conversation requests access to the user's location.
This is fulfilled via a webhook:
app.intent('actions_intent_PERMISSION', async (conv, params, permissionGranted) => {
if (!permissionGranted) {
app.intent('actions_intent_PERMISSION - no', (conv, params) => {
conv.ask('sad face, you said no to my permission request!');
});
// conv.ask(`Ok, no worries. I'll have to figure out how to get your postcode. follow-up intent I suppose`);
} else {
conv.data.postcode = conv.device.location.zipCode;
conv.ask(`Ok great - please give me a minute, I have to get data from a few different places.`);
//use postcode to make some other API calls
}
});
Everything is fine when the user gives permission but when they don't give permission I would like to pass off to an intent that asks for their location manually ('what is your postcode/zipcode?').
As per the screenshot I tried creating a followup intent to actions_intent_PERMISSION called actions_intent_PERMISSION - no but this causes the app to crash.
What is the best way to pass the conversation to another intent is the value of permissionGranted is false?
Your question doesn't quite make sense the way you've asked it. Intents represent what the user has said and not what you do with it - that is what your webhook does in an Intent Handler. There is nothing (technically) stopping you from replying to the user asking for their zip code by just replying differently.
If you want users to be able to trigger some Intents if they have given permissions, and other Intents if they have not, you can set a different Context for each. Then you would set some Intents to only be triggered if the "permitted" context was set, and others only if the "notpermitted" context was set.
However, you have a non-technical problem to consider. If they aren't giving you permission to get their location, why would they tell you their location? It also is likely that the reviewers would reject it, saying that you should be getting location information through the provided API.

How can I delegate the LaunchRequest to an IntentRequest using the alexa-sdk from npm

I am building an Alexa skill in node using the alexa-sdk. I am using a dialog model to handle the user interaction. I am having some trouble passing the flow along to new request types, such as from the launch request to an intent request.
Below is an example of my handlers and what I want ideally. My specific usecase is that I would like to ask some questions of the user and then send them to different intents based on what they answer. In the intents I would like to have access to the request objects, as if they entered that intent originally, so the dialog model can do its work.
const handlers = {
'LaunchRequest': function () {
this.emit('Entry'); // this does not do what I want
},
'Entry': function () {
let request = this.event.request; // this is the launch request object.
// I would like to get the request object for Entry, like if the user started here
// ask some questions, potentially passing the torch to a new intent based on the answers
}
};
So, is there any way to "call" an intent like the user originally made a request to that intent? Sorry if I missed something obvious in the documentation, I searched around pretty thoroughly I think, but there is A LOT of documentation. ps: I could manually construct the request object of course, but I really should not have to I feel.
I am pretty sure there is no way yet to call on an intent as you are asking.
If you go through the syntax description of dialog directieves here, it says:
Note that you cannot change intents when returning a Dialog directive, so the intent name and set of slots must match the intent sent to your skill.
With returning a dialog directive you are able to 'elicit' or 'confirm' slots or intents, or even let a delegate handle your dialog for you, with prompts and reprompts set in the Skill Builder.
As far as i know, the only solution to trigger a specific intent is to make the user invoke it. You can guide the user into saying a specific utternace to trigger your intent.
As for saving older requests, you can use session attributes. Just build a response after your Launch with a session attribute containing the whole LaunchRequest.
"sessionAttributes": {
"oldRequest": this.event.request
}

How to detect when bot was added to conversation and other events?

I am testing a bot that I am building using the Bot Framework. The emulator for local testing that Microsoft created has several events that can be provided to the bot to solicit a response.
I looked at the GitHub samples provided for Node.js here, but I can not find any example that responds to the different events within the Bot Framework Emulator.
The states are:
Bot Added to Conversation
Bot Removed from Conversation
User Added to Conversation
User Removed from Conversation
End of Conversation
Ping
Delete User Data
The API also does not make it clear how to achieve any of these actions.
Does anyone have any insight on where I should be looking for a example, or the API entries that I should be using?
In response to one of the answers, I did try code -
.onDefault(function (session) { console.log(session.message.type); }
But it only ever display "message" if a message was sent by the user.
The incoming message.type field will have "BotAddedToConversation" etc.
For the Node SDK, the botConnectorBot is able to trigger custom listeners on events using the on() handler.
Example
var builder = require('botbuilder');
var bot = new builder.BotConnectorBot({ appId: 'APPID', appSecret: 'APPSECRET' });
bot.on('DeleteUserData', function(message) {
// Handle Deleting User Data
});
More information can be found here.
You are also able to configure some standard messages using the configure() method.
Example
bot.configure({
userWelcomeMessage: "Hello... Welcome to the group.",
goodbyeMessage: "Goodbye..."
});
More information on what can be configured through options is located here.
Concerns
This is not part of the question, as the question was to identify how to listen to these events. But as a general concern, the event listener does not return a session object. It is unclear how to act once you handle the event.

Resources