public override async Task Execute(CancellationToken cancellationToken) { string returnText = "Your [GivenName] [Surname] working from Tenant: [TenantId]"; try { IList <ChannelAccount> teamMembers = (await TurnContext.TurnState.Get <IConnectorClient>().Conversations .GetConversationMembersAsync(TurnContext.Activity.GetChannelData <TeamsChannelData>().Team.Id) .ConfigureAwait(false)); foreach (ChannelAccount ca in teamMembers) { MicrosoftTeamUser u = Newtonsoft.Json.JsonConvert.DeserializeObject <MicrosoftTeamUser>(ca.Properties.ToString()); if (u.ObjectId == TurnContext.Activity.From.AadObjectId) { returnText = returnText.Replace("[ObjectId]", u.ObjectId); returnText = returnText.Replace("[UserPrincipalName]", u.UserPrincipalName); returnText = returnText.Replace("[GivenName]", u.GivenName); returnText = returnText.Replace("[Surname]", u.Surname); returnText = returnText.Replace("[TenantId]", u.TenantId); } } } catch (Exception ex) { returnText = "The Command returned the following error: " + ex.Message; } await TurnContext.SendActivityAsync(MessageFactory.Text(returnText), cancellationToken); }
public async Task AllowInterceptionOfDeliveryOnSend() { bool responsesSent = false; void ValidateResponses(Activity[] activities) { responsesSent = true; Assert.True(false); // Should not be called. Interceptor did not work } var a = new SimpleAdapter(ValidateResponses); var c = new TurnContext(a, new Activity()); int count = 0; c.OnSendActivities((context, activities, next) => { Assert.NotNull(activities); // Null Array passed in count = activities.Count(); // Do not call next. return(Task.FromResult <ResourceResponse[]>(null)); }); await c.SendActivityAsync(TestMessage.Message()); Assert.True(count == 1); Assert.False(responsesSent, "Responses made it to the adapter."); }
public async Task InterceptAndMutateOnSend() { bool foundIt = false; void ValidateResponses(Activity[] activities) { Assert.NotNull(activities); Assert.True(activities.Length == 1); Assert.True(activities[0].Id == "changed"); foundIt = true; } var a = new SimpleAdapter(ValidateResponses); var c = new TurnContext(a, new Activity()); c.OnSendActivities(async(context, activities, next) => { Assert.NotNull(activities); // Null Array passed in Assert.True(activities.Count() == 1); Assert.True(activities[0].Id == "1234", "Unknown Id Passed In"); activities[0].Id = "changed"; return(await next()); }); await c.SendActivityAsync(TestMessage.Message()); // Intercepted the message, changed it, and sent it on to the Adapter Assert.True(foundIt); }
public async Task TraceActivitiesDoNoSetResponded() { var a = new SimpleAdapter(); var c = new TurnContext(a, new Activity()); Assert.False(c.Responded); // Send a Trace Activity, and make sure responded is NOT set. var trace = Activity.CreateTraceActivity("trace"); await c.SendActivityAsync(trace); Assert.False(c.Responded); // Just to sanity check everything, send a Message and verify the // responded flag IS set. var msg = TestMessage.Message().AsMessageActivity(); await c.SendActivityAsync(msg); Assert.True(c.Responded); }
public async Task SendAndSetResponded() { var a = new SimpleAdapter(); var c = new TurnContext(a, new Activity()); Assert.False(c.Responded); var response = await c.SendActivityAsync(TestMessage.Message("testtest")); Assert.True(c.Responded); Assert.True(response.Id == "testtest"); }
public async Task SendAndSetRespondedUsingIMessageActivity() { var a = new SimpleAdapter(); var c = new TurnContext(a, new Activity()); Assert.False(c.Responded); var msg = TestMessage.Message().AsMessageActivity(); await c.SendActivityAsync(msg); Assert.True(c.Responded); }
public async Task ProcessActivityAsync(Activity activity, string msAppId, ConversationReference conversationRef, BotCallbackHandler callback, CancellationToken cancellationToken) { BotAssert.ActivityNotNull(activity); activity.ApplyConversationReference(conversationRef, true); await ContinueConversationAsync( msAppId, conversationRef, async (ITurnContext proactiveContext, CancellationToken ct) => { using (var contextWithActivity = new TurnContext(this, activity)) { contextWithActivity.TurnState.Add(proactiveContext.TurnState.Get <IConnectorClient>()); await base.RunPipelineAsync(contextWithActivity, callback, cancellationToken); if (contextWithActivity.Activity.Name == "handoff.status") { var conversationStateAccessors = _conversationState.CreateProperty <LoggingConversationData>(nameof(LoggingConversationData)); var conversationData = await conversationStateAccessors.GetAsync(contextWithActivity, () => new LoggingConversationData()); Activity replyActivity; var state = (contextWithActivity.Activity.Value as JObject)?.Value <string>("state"); if (state == "typing") { replyActivity = new Activity { Type = ActivityTypes.Typing, Text = "agent is typing", }; } else if (state == "accepted") { replyActivity = MessageFactory.Text("An agent has accepted the conversation and will respond shortly."); await _conversationState.SaveChangesAsync(contextWithActivity); } else if (state == "completed") { replyActivity = MessageFactory.Text("The agent has closed the conversation."); } else { replyActivity = MessageFactory.Text($"Conversation status changed to '{state}'"); } await contextWithActivity.SendActivityAsync(replyActivity); } } }, cancellationToken).ConfigureAwait(false); }
public async Task SendOneActivityToAdapter() { bool foundActivity = false; void ValidateResponses(Activity[] activities) { Assert.True(activities.Count() == 1, "Incorrect Count"); Assert.True(activities[0].Id == "1234"); foundActivity = true; } var a = new SimpleAdapter(ValidateResponses); var c = new TurnContext(a, new Activity()); await c.SendActivityAsync(TestMessage.Message()); Assert.True(foundActivity); }
public async Task CallOnSendBeforeDelivery() { var a = new SimpleAdapter(); var c = new TurnContext(a, new Activity()); int count = 0; c.OnSendActivities(async(context, activities, next) => { Assert.NotNull(activities); // Null Array passed in count = activities.Count(); return(await next()); }); await c.SendActivityAsync(TestMessage.Message()); Assert.True(count == 1); }
public async Task PassResourceResponsesThrough() { void ValidateResponses(Activity[] activities) { // no need to do anything. } var a = new SimpleAdapter(ValidateResponses); var c = new TurnContext(a, new Activity()); var activityId = Guid.NewGuid().ToString(); var activity = TestMessage.Message(); activity.Id = activityId; var resourceResponse = await c.SendActivityAsync(activity); Assert.IsTrue(resourceResponse.Id == activityId, "Incorrect response Id returned"); }
public async Task ThrowExceptionInOnSend() { var a = new SimpleAdapter(); var c = new TurnContext(a, new Activity()); c.OnSendActivities((context, activities, next) => { throw new Exception("test"); }); try { await c.SendActivityAsync(TestMessage.Message()); Assert.True(false); // Should not get here } catch (Exception ex) { Assert.True(ex.Message == "test"); } }
public async Task OutgoingActivityIdsAreNotSent() { // Arrange var mockCredentialProvider = new Mock <ICredentialProvider>(); var mockConnector = new MemoryConnectorClient(); var mockHttpMessageHandler = new Mock <HttpMessageHandler>(); var httpClient = new HttpClient(mockHttpMessageHandler.Object); var adapter = new BotFrameworkAdapter(mockCredentialProvider.Object, customHttpClient: httpClient); var incomingActivity = new Activity("test") { Id = "testid", ChannelId = Channels.Directline, ServiceUrl = "https://fake.service.url", Conversation = new ConversationAccount { Id = "cid", } }; var reply = MessageFactory.Text("test"); reply.Id = "TestReplyId"; // Act using (var turnContext = new TurnContext(adapter, incomingActivity)) { turnContext.TurnState.Add <IConnectorClient>(mockConnector); var responseIds = await turnContext.SendActivityAsync(reply, default); } var sentActivity = mockConnector.MemoryConversations.SentActivities.FirstOrDefault(f => f.Type == ActivityTypes.Message); // Assert - assert the reply's id is not sent Assert.IsNull(sentActivity.Id); }
public override async Task Execute(CancellationToken cancellationToken) { QueryExpression q = new QueryExpression("contact"); q.ColumnSet = new ColumnSet("fullname", "firstname", "lastname", "jobtitle", "mobilephone", "emailaddress1", "telephone1"); q.Criteria.FilterOperator = LogicalOperator.And; // get the contacts for the Account that matches our current Channel LinkEntity le = new LinkEntity("contact", "account", "parentcustomerid", "accountid", JoinOperator.Inner); le.LinkCriteria.AddCondition("crmcs_msteams_channelid", ConditionOperator.Equal, base.ChannelId); q.LinkEntities.Add(le); if (!String.IsNullOrEmpty(base.ValueTitle)) { FilterExpression f = new FilterExpression(); f.FilterOperator = LogicalOperator.Or; f.AddCondition("fullname", ConditionOperator.Like, "%" + base.ValueTitle + "%"); q.Criteria.AddFilter(f); } else { // just get all the Contacts back } EntityCollection contacts = base.DynamicsService.RetrieveMultiple(q); if (contacts.Entities.Count == 0) { // nothing to return await TurnContext.SendActivityAsync(MessageFactory.Text("Sorry - I couldn't find any matching contacts"), cancellationToken); } else { var card = new ListCard(); card.content = new Content(); List <Item> items = new List <Item>(); int itemNo = 0; // loop through the information we have and display into Teams foreach (Microsoft.Xrm.Sdk.Entity c in contacts.Entities) { string openUrl = string.Empty; string subTitle = string.Empty; openUrl = base.ToDynamicsConnection.dynamicsUrl + "/main.aspx?forceUCI=1&etn=" + "contact" + "&id=" + c.Id + "&pagetype=entityrecord"; var item = new Item(); item.id = itemNo.ToString(); item.type = "resultItem"; item.title = c.GetValue <string>("fullname", string.Empty); // quick routine to summarise the attributes from Dynamics as an Info List in Teams if (c.Contains("jobtitle")) { subTitle += "<p><b>Job Title:</b> " + c.GetValue("jobtitle", string.Empty) + "</p>"; } if (c.Contains("mobilephone")) { subTitle += "<p><b>Mobille:</b> " + c.GetValue("mobilephone", string.Empty) + "</p>"; } else { // only show telephone if mobile is blank if (c.Contains("telephone1")) { subTitle += "<p><b>Telephone:</b> " + c.GetValue("telephone1", string.Empty) + "</p>"; } } if (c.Contains("emailaddress1")) { subTitle += "<p><b>Email Address:</b> " + c.GetValue("emailaddress1", string.Empty) + "</p>"; } item.subtitle = subTitle; openUrl = openUrl.Replace(" ", "%20"); item.tap = new Tap() { type = "openUrl", value = openUrl }; itemNo++; items.Add(item); } card.content.items = items.ToArray(); Attachment attachment = new Attachment(); attachment.ContentType = card.contentType; attachment.Content = card.content; await TurnContext.SendActivityAsync(MessageFactory.Attachment(attachment)); } }
public async Task SendTextAsync(string textActivity) { await TurnContext.SendActivityAsync(MessageFactory.Text(textActivity), CancellationToken); }
public override async Task Execute(CancellationToken cancellationToken) { QueryExpression q = new QueryExpression(this.Table); // determine what columns to pull back from Dynamics q.ColumnSet = new ColumnSet(); foreach (ColumnDefinition ra in this.Columns) { q.ColumnSet.AddColumn(ra.DatabaseName); } q.Criteria.FilterOperator = LogicalOperator.And; q.Criteria.AddCondition("statecode", ConditionOperator.Equal, 0); // get the contacts for the Account that matches our current Channel LinkEntity le = new LinkEntity(this.Table, "account", this.RelationshipToAccount, "accountid", JoinOperator.Inner); le.LinkCriteria.AddCondition("crmcs_msteams_channelid", ConditionOperator.Equal, base.ChannelId); q.LinkEntities.Add(le); if (!String.IsNullOrEmpty(base.ValueTitle)) { FilterExpression f = new FilterExpression(); f.FilterOperator = LogicalOperator.Or; foreach (ColumnDefinition ra in this.Columns) { if (ra.Searchable) { f.AddCondition(ra.DatabaseName, ConditionOperator.Like, "%" + base.ValueTitle + "%"); } } q.Criteria.AddFilter(f); } else { // just get all the Contacts back } EntityCollection records = base.DynamicsService.RetrieveMultiple(q); if (records.Entities.Count == 0) { // nothing to return await TurnContext.SendActivityAsync(MessageFactory.Text("Sorry - I couldn't find any matching records"), cancellationToken); } else { var card = new ListCard(); card.content = new Content(); List <Item> items = new List <Item>(); int itemNo = 0; // loop through the information we have and display into Teams foreach (Microsoft.Xrm.Sdk.Entity c in records.Entities) { string openUrl = string.Empty; string title = string.Empty; string subTitle = string.Empty; openUrl = base.ToDynamicsConnection.dynamicsUrl + "/main.aspx?forceUCI=1&etn=" + this.Table + "&id=" + c.Id + "&pagetype=entityrecord"; // note - this is simplifed to be a good example // if you were taking this to production - you would look at the Metadata Service to avoid manual entry of the foreach (ColumnDefinition ra in this.Columns) { if (ra.Title == true) { if (!String.IsNullOrEmpty(title)) { title += ", "; } title += c.GetValue <string>(ra.DatabaseName, string.Empty); } else { // quick routine to summarise the attributes from Dynamics as an Info List in Teams if (c.Contains(ra.DatabaseName)) { if (!String.IsNullOrEmpty(ra.DisplayName)) { subTitle += "<p><b>" + ra.DisplayName + ":</b> " + c.GetValue(ra.DatabaseName, string.Empty) + "</p>"; } else { // sometimes we may want a description field shown as a Memo and avoid a Column Title subTitle += "<p>" + c.GetValue(ra.DatabaseName, string.Empty) + "</p>"; } } } } var item = new Item(); item.id = itemNo.ToString(); item.type = "resultItem"; item.title = title; item.subtitle = subTitle; // needed for Teams to process the URL as an Action correctly openUrl = openUrl.Replace(" ", "%20"); item.tap = new Tap() { type = "openUrl", value = openUrl }; itemNo++; items.Add(item); } card.content.items = items.ToArray(); Attachment attachment = new Attachment(); attachment.ContentType = card.contentType; attachment.Content = card.content; await TurnContext.SendActivityAsync(MessageFactory.Attachment(attachment)); } }
public override async Task Execute(CancellationToken cancellationToken) { await TurnContext.SendActivityAsync(MessageFactory.Text("Finished the Example Action!"), cancellationToken); }
public override async Task Execute(CancellationToken cancellationToken) { // our first step is to parse the user's input from Teams // we can do this in multiple ways // and ideally could use a Task in Teams or a Simple Form to collect the information // but if we want a quick flowing command from a Bot that avoids Fields and Data Types, we can do it this way // Parse the input from the User in the following steps: // (1) Remove the Command Name from the incoming Command // (2) Divide the command by a comma (,) or semi-colon (;) // (3) Interpret the first section of the Command as the Title // (4) Interpret the second section as the Description // This is not as good as it could be - we could use better data in Teams - or use follow-up commands to further detail the Record // we are creating in Dynamics (and so allowing a CREATE then UPDATE style approach) // but gives a simple interface to use when say capturing Tasks or Cases from a Meeting in quick time HttpClient client = new HttpClient(); HttpRequestMessage webRequest = new HttpRequestMessage(new System.Net.Http.HttpMethod("POST"), FlowHttpTrigger); string requestJSON = string.Empty; try { FlowRequest request = new FlowRequest(); request.TeamId = base.TeamId; request.ChannelId = base.ChannelId; request.UserId = string.Empty; request.ConversationId = base.ConversationId; request.Content = base.ValueTitle; request.Description = base.ValueDescription; requestJSON = request.ToJSON(); if (!string.IsNullOrEmpty(requestJSON)) { webRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); //webRequest.Headers.Add("content-type", "application/json"); webRequest.Content = new StringContent(requestJSON, Encoding.UTF8, "application/json"); } if (!String.IsNullOrEmpty(_startingMessage)) { TurnContext.SendActivityAsync(MessageFactory.Text(_startingMessage), cancellationToken); } } catch (Exception prepEx) { // error calling out to the Flow Http Trigger await TurnContext.SendActivityAsync(MessageFactory.Text("Error whilst building the Request: " + prepEx.Message), cancellationToken); } try { HttpResponseMessage webResponse = await client.SendAsync(webRequest).ConfigureAwait(false); FlowResponse response = null; string responseContent = "No Response"; if (webResponse.Content != null) { responseContent = await webResponse.Content.ReadAsStringAsync().ConfigureAwait(false); // response = Newtonsoft.Json.JsonConvert.DeserializeObject<FlowResponse>(responseContent); } if (response != null) { // do something with the response from outcome of our Flow? } if (_debugMode) { await TurnContext.SendActivityAsync(MessageFactory.Text("Response from Flow: " + responseContent + " - RequestJSON: " + requestJSON), cancellationToken); } } catch (Exception ex) { // error calling out to the Flow Http Trigger await TurnContext.SendActivityAsync(MessageFactory.Text("Error when placing the Request to Flow: " + ex.Message), cancellationToken); } if (!String.IsNullOrEmpty(_finishingMessage)) { TurnContext.SendActivityAsync(MessageFactory.Text(_finishingMessage), cancellationToken); } }
public static async Task Send(string id) { Context.Activity.Conversation.Id = id; await Context.SendActivityAsync("abc"); }
public override async Task Execute(CancellationToken cancellationToken) { string output = "Finished the Example Action at " + DateTime.Now.ToString("dd/MM/YYYY") + "."; await TurnContext.SendActivityAsync(MessageFactory.Text(output), cancellationToken); }