public async Task Telemetry_LogTeamsProperties() { // Arrange var mockTelemetryClient = new Mock <IBotTelemetryClient>(); var adapter = new TestAdapter(Channels.Msteams) .Use(new TelemetryLoggerMiddleware(mockTelemetryClient.Object)); var teamInfo = new TeamInfo("teamId", "teamName"); var channelData = new TeamsChannelData(null, null, teamInfo, null, new TenantInfo("tenantId")); var activity = MessageFactory.Text("test"); activity.ChannelData = channelData; activity.From = new ChannelAccount("userId", "userName", null, "aadId"); // Act await new TestFlow(adapter) .Send(activity) .StartTestAsync(); // Assert Assert.Equal("BotMessageReceived", mockTelemetryClient.Invocations[0].Arguments[0]); Assert.True(((Dictionary <string, string>)mockTelemetryClient.Invocations[0].Arguments[1])["TeamsUserAadObjectId"] == "aadId"); Assert.True(((Dictionary <string, string>)mockTelemetryClient.Invocations[0].Arguments[1])["TeamsTenantId"] == "tenantId"); Assert.True(((Dictionary <string, string>)mockTelemetryClient.Invocations[0].Arguments[1])["TeamsTeamInfo"] == JsonConvert.SerializeObject(teamInfo)); }
public void TeamsChannelDataInitsWithNoArgs() { var channelData = new TeamsChannelData(); Assert.NotNull(channelData); Assert.IsType <TeamsChannelData>(channelData); }
/// <summary> /// When implemented in middleware, processess an incoming activity. /// </summary> /// <param name="turnContext">The context object for this turn.</param> /// <param name="next">The delegate to call to continue the bot middleware pipeline.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns> /// A task that represents the work queued to execute. /// </returns> /// <remarks> /// Middleware calls the <paramref name="next" /> delegate to pass control to /// the next middleware in the pipeline. If middleware doesn’t call the next delegate, /// the adapter does not call any of the subsequent middleware’s request handlers or the /// bot’s receive handler, and the pipeline short circuits. /// <para>The <paramref name="turnContext" /> provides information about the /// incoming activity, and other data needed to process the activity.</para> /// </remarks> /// <seealso cref="ITurnContext" /> /// <seealso cref="Schema.IActivity" /> public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken = default(CancellationToken)) { if (!turnContext.Activity.ChannelId.Equals(Channels.Msteams, StringComparison.OrdinalIgnoreCase)) { // If the goal is to NOT process messages from other channels, comment out the following line // and message processing will be 'short circuited'. await next(cancellationToken).ConfigureAwait(false); return; } TeamsChannelData teamsChannelData = turnContext.Activity.GetChannelData <TeamsChannelData>(); string tenantId = teamsChannelData?.Tenant?.Id; if (string.IsNullOrEmpty(tenantId)) { throw new UnauthorizedAccessException("Tenant Id is missing."); } if (!this.tenantMap.Contains(tenantId)) { throw new UnauthorizedAccessException("Tenant Id '" + tenantId + "' is not allowed access."); } await next(cancellationToken).ConfigureAwait(false); }
private async Task <Activity> HandleTeamsMessageAsync(Activity payload) { TeamEventBase eventData = payload.GetConversationUpdateData(); ChannelAccount botAccount = payload.Recipient; string tenantId = payload.GetTenantId(); TeamsChannelData channelData = payload.GetChannelData <TeamsChannelData>(); switch (eventData.EventType) { // send a welcome message case TeamEventType.MembersAdded: var connector = new ConnectorClient(new Uri(payload.ServiceUrl)); IEnumerable <TeamsChannelAccount> newMembers = payload.MembersAdded.AsTeamsChannelAccounts(); string welcomeMessage = "Welcome Teams, I am Jarvis. How can I help you?"; foreach (TeamsChannelAccount member in newMembers) { // send a 1:1 message to new members await MessageHelpers.SendOneToOneMessage(connector, channelData, botAccount, member, tenantId, welcomeMessage); } break; } return(null); }
public static async Task SendOneToOneWelcomeMessage( ConnectorClient connector, TeamsChannelData channelData, ChannelAccount botAccount, ChannelAccount userAccount, string tenantId) { string welcomeMessage = CreateHelpMessage($"The team {channelData.Team.Name} has the Invnetory Management bot- helping your team to order inventories and find suppliers."); // create or get existing chat conversation with user var response = connector.Conversations.CreateOrGetDirectConversation(botAccount, userAccount, tenantId); // Construct the message to post to conversation Activity newActivity = new Activity() { Text = welcomeMessage, Type = ActivityTypes.Message, Conversation = new ConversationAccount { Id = response.Id }, }; // Post the message to chat conversation with user await connector.Conversations.SendToConversationAsync(newActivity); }
private async Task SetModerators(IDialogContext context, Activity activity, TeamsChannelData channelData) { // TODO: Updated DB var details = JsonConvert.DeserializeObject <ModeratorActionDetails>(activity.Value.ToString()); if (details == null || details.Moderators == null) { details = JsonConvert.DeserializeObject <TaskModule.BotFrameworkCardValue <ModeratorActionDetails> > (activity.Value.ToString()).Data; } var moderatorList = details.Moderators.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(m => m.ToLower().Trim()).ToList(); if (moderatorList.Count == 0) { await context.PostAsync("Please set at least one moderator."); return; } Tenant tenantData = await Common.CheckAndAddTenantDetails(channelData.Tenant.Id); tenantData.Moderators = moderatorList; await Cache.Tenants.AddOrUpdateItemAsync(tenantData.Id, tenantData); await context.PostAsync("Moderators are set successfully. These users can now create message and post."); }
// Handle team members removed event (in team scope) private async Task HandleTeamMembersRemovedAsync(Activity activity, TeamsChannelData channelData) { var teamId = channelData.Team.Id; this.logProvider.LogInfo($"Handling team members removed event in team {teamId}"); var isBotRemoved = activity.MembersRemoved.Any(member => member.Id == activity.Recipient.Id); if (isBotRemoved) { this.logProvider.LogInfo($"Bot removed from team {teamId}"); // Delete team details and membership records await this.userManagementHelper.DeleteTeamDetailsAsync(teamId); await this.userManagementHelper.DeleteUserTeamMembershipByTeamIdAsync(teamId); } else { foreach (var member in activity.MembersRemoved) { this.logProvider.LogInfo($"User {member.Id} removed from team {teamId}."); // Delete membership records for the users who were removed await this.userManagementHelper.DeleteUserTeamMembershipAsync(member.Id, teamId); } } }
internal async static Task <User> CheckAndAddUserDetails(Activity activity, TeamsChannelData channelData) { var currentUser = await GetCurrentUser(activity); // User not present in cache var userDetails = await Cache.Users.GetItemAsync(currentUser.UserPrincipalName.ToLower()); if (userDetails == null && currentUser != null) { userDetails = new User() { BotConversationId = activity.From.Id, Id = currentUser.UserPrincipalName.ToLower(), Name = currentUser.Name ?? currentUser.GivenName }; await Cache.Users.AddOrUpdateItemAsync(userDetails.Id, userDetails); Tenant tenantData = await Common.CheckAndAddTenantDetails(channelData.Tenant.Id); if (!tenantData.Users.Contains(userDetails.Id)) { tenantData.Users.Add(userDetails.Id); await Cache.Tenants.AddOrUpdateItemAsync(tenantData.Id, tenantData); } } return(userDetails); }
public static async Task SendOneToOneWelcomeMessage(ConnectorClient connector, TeamsChannelData channelData, ChannelAccount botAccount, ChannelAccount userAccount, string tenantId) { // Construct the message here string welcomeMessage = CreateHelpMessage($"The team {channelData.Team.Name} has added the Calculator Chat Bot - helping with some basic math stuff."); // Create or get existing chat conversation with the user var response = connector.Conversations.CreateOrGetDirectConversation(botAccount, userAccount, tenantId); // Construct the message to post to the conversation Activity newActivity = new Activity { Text = welcomeMessage, Type = ActivityTypes.Message, Conversation = new ConversationAccount { Id = response.Id } }; // Finally post the message await connector.Conversations.SendToConversationAsync(newActivity); }
public IceBreakerBotTests() { this.botAdapter = new TestAdapter(Channels.Msteams) { Conversation = { Conversation = new ConversationAccount { ConversationType = "channel", }, }, }; ConfigurationManager.AppSettings[DisableTenantFilterKey] = true.ToString().ToLower(); this.telemetryClient = new TelemetryClient(); this.conversationHelper = new ConversationHelperMock(); this.dataProvider = new Mock <IBotDataProvider>(); this.dataProvider.Setup(x => x.GetInstalledTeamAsync(It.IsAny <string>())) .Returns(() => Task.FromResult(new TeamInstallInfo())); this.sut = new IcebreakerBot(this.dataProvider.Object, this.conversationHelper, MicrosoftAppCredentials.Empty, this.telemetryClient); this.userAccount = new TeamsChannelAccount { Id = Guid.NewGuid().ToString(), Properties = JObject.FromObject(new { Id = Guid.NewGuid().ToString() }) }; this.botAccount = new TeamsChannelAccount { Id = "bot", Properties = JObject.FromObject(new { Id = "bot" }) }; this.teamsChannelData = new TeamsChannelData { Team = new TeamInfo { Id = "TeamId", }, Tenant = new TenantInfo(), }; }
/// <summary> /// Save member details in database /// </summary> /// <param name="member">ChannelAccount information of team member</param> /// <param name="channelData">TeamsChannelData</param> /// <param name="conversationId">Conversation id</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> private async Task SaveMemberDetailsAsync(ChannelAccount member, TeamsChannelData channelData, string conversationId) { // Add UserTeamMembership await this.AddUserTeamMembershipAsync(channelData.Team.Id, member); // Add user if it does not exist. await this.AddUserDetailsAsync(channelData, member, conversationId); }
private async Task ShowAllDrafts(IDialogContext context, Activity activity, TeamsChannelData channelData) { var tenatInfo = await Cache.Tenants.GetItemAsync(channelData.Tenant.Id); var myTenantAnnouncements = new List <Campaign>(); var listCard = new ListCard(); listCard.content = new Content(); listCard.content.title = "Here are all draft and scheduled announcements:";; var list = new List <Item>(); foreach (var announcementId in tenatInfo.Announcements) { var announcement = await Cache.Announcements.GetItemAsync(announcementId); if (announcement != null && (announcement.Status == Status.Draft || announcement.Status == Status.Scheduled)) { var item = new Item { icon = announcement.Author.ProfilePhoto, type = "resultItem", id = announcement.Id, title = announcement.Title, subtitle = "Author: " + announcement.Author?.Name + $" | Created Date: {announcement.CreatedTime.ToShortDateString()} | { (announcement.Status == Status.Scheduled ? "Scheduled" : "Draft") }", tap = new Tap() { type = ActionTypes.MessageBack, title = "Id", value = JsonConvert.SerializeObject(new AnnouncementActionDetails() { Id = announcement.Id, ActionType = Constants.ShowAnnouncement }) // "Show Announcement " + announcement.Title + " (" + announcement.Id + ")" } }; list.Add(item); } } if (list.Count > 0) { listCard.content.items = list.ToArray(); var attachment = new Attachment { ContentType = listCard.contentType, Content = listCard.content }; var reply = activity.CreateReply(); reply.Attachments.Add(attachment); await context.PostAsync(reply); } else { await context.PostAsync("Thre are no drafts. Please go ahead and create new announcement."); } }
/// <summary> /// Called in the activity processing pipeline to process incoming activity. /// </summary> /// <param name="context">The context.</param> /// <param name="next">The next delegate to execute.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task tracking operation.</returns> public async Task OnTurnAsync(ITurnContext context, NextDelegate next, CancellationToken cancellationToken = default(CancellationToken)) { TeamsChannelData teamsChannelData = context.Activity.GetChannelData <TeamsChannelData>(); if (teamsChannelData.Team == null) { await next(cancellationToken).ConfigureAwait(false); } }
private static async Task RenameTeam(TeamsChannelData channelData, Tenant tenant) { var team = await GetTeam(channelData, tenant); if (team != null) { team.Name = channelData.Team.Name; await Cache.Teams.AddOrUpdateItemAsync(team.Id, team); } }
private static async Task <Team> GetTeam(TeamsChannelData channelData, Tenant tenant) { var teamId = channelData.Team.Id; if (tenant.Teams.Contains(channelData.Team.Id)) { return(await Cache.Teams.GetItemAsync(channelData.Team.Id)); } return(null); }
private static async Task RemoveTeamDetails(TeamsChannelData channelData, Tenant tenant) { var team = await GetTeam(channelData, tenant); if (team != null) { await Cache.Teams.DeleteItemAsync(team.Id); } tenant.Teams.Remove(channelData.Team.Id); await Cache.Tenants.AddOrUpdateItemAsync(tenant.Id, tenant); }
public void ChannelData_GetGeneralChannel() { Activity sampleActivity = JsonConvert.DeserializeObject <Activity>(File.ReadAllText(@"Jsons\SampleActivityAtMention.json")); ChannelInfo generalChannel = sampleActivity.GetGeneralChannel(); TeamsChannelData channelData = sampleActivity.GetChannelData <TeamsChannelData>(); Assert.IsNotNull(generalChannel); Assert.IsNotNull(generalChannel.Id); Assert.IsTrue(generalChannel.Id == channelData.Team.Id); }
/// <summary> /// Gets the Teams channel data associated with the current activity. /// </summary> /// <returns>Teams channel data <see cref="TeamsChannelData"/>Teams channel data for current activity.</returns> /// <exception cref="ArgumentNullException">ChannelData missing in Activity.</exception> public TeamsChannelData GetTeamsChannelData() { if (this.turnContext.Activity.ChannelData != null) { TeamsChannelData channelData = this.turnContext.Activity.GetChannelData <TeamsChannelData>(); return(channelData); } else { throw new ArgumentNullException("ChannelData missing in Activity"); } }
private static async Task UpdateTeamCount(Activity message, TeamsChannelData channelData, Tenant tenant) { if (tenant.Teams.Contains(channelData.Team.Id)) { ConnectorClient connector = new ConnectorClient(new Uri(message.ServiceUrl)); var members = await connector.Conversations.GetConversationMembersAsync(channelData.Team.Id); var team = await Cache.Teams.GetItemAsync(channelData.Team.Id); team.Members = members.Select(m => m.AsTeamsChannelAccount().UserPrincipalName.ToLower()).ToList(); await Cache.Teams.AddOrUpdateItemAsync(team.Id, team); } }
public void ChannelData_PropertyCheck() { Activity sampleActivity = JsonConvert.DeserializeObject <Activity>(File.ReadAllText(@"Jsons\SampleActivityAtMention.json")); TeamsChannelData channelData = JsonConvert.DeserializeObject <TeamsChannelData>(sampleActivity.ChannelData.ToString()); Assert.IsNotNull(channelData); Assert.IsNotNull(channelData.Channel); Assert.IsNotNull(channelData.Channel.Id); Assert.IsNotNull(channelData.Team); Assert.IsNotNull(channelData.Team.Id); Assert.IsNotNull(channelData.Tenant); Assert.IsNotNull(channelData.Tenant.Id); }
private static async Task AddNewChannelDetails(TeamsChannelData channelData, Tenant tenant) { var team = await GetTeam(channelData, tenant); if (team != null) { team.Channels.Add(new Channel() { Id = channelData.Channel.Id, Name = channelData.Channel.Name }); await Cache.Teams.AddOrUpdateItemAsync(team.Id, team); } }
/// <summary> /// Gets the key to use when reading and writing state to and from storage. /// </summary> /// <param name="turnContext">The context object for this turn.</param> /// <returns>The storage key.</returns> protected override string GetStorageKey(ITurnContext turnContext) { TeamsChannelData teamsChannelData = turnContext.Activity.GetChannelData <TeamsChannelData>(); if (string.IsNullOrEmpty(teamsChannelData.Team?.Id)) { return($"chat/{turnContext.Activity.ChannelId}/{turnContext.Activity.Conversation.Id}"); } else { return($"team/{turnContext.Activity.ChannelId}/{teamsChannelData.Team.Id}"); } }
/// <summary> /// Creates a reply for the General channel of the team. /// </summary> /// <param name="text">Reply text.</param> /// <param name="locale">Locale information.</param> /// <returns>New reply activity with General channel channel data.</returns> public Activity CreateReplyToGeneralChannel(string text = null, string locale = null) { TeamsChannelData channelData = this.turnContext.Activity.GetChannelData <TeamsChannelData>(); Activity replyActivity = this.turnContext.Activity.CreateReply(text, locale); replyActivity.ChannelData = new TeamsChannelData { Channel = this.GetGeneralChannel(), Team = channelData.Team, Tenant = channelData.Tenant, }.AsJObject(); return(replyActivity); }
private static async Task RenameChannel(TeamsChannelData channelData, Tenant tenant) { var team = await GetTeam(channelData, tenant); if (team != null) { var channel = team.Channels.FirstOrDefault(c => c.Id == channelData.Channel.Id); if (channel != null) { channel.Name = channelData.Channel.Name; await Cache.Teams.AddOrUpdateItemAsync(team.Id, team); } } }
/// <summary> /// Creates a reply for the General channel of the team. /// </summary> /// <param name="activity">Incoming activity.</param> /// <param name="text">Reply text.</param> /// <param name="locale">Locale information.</param> /// <returns>New reply activity with General channel channel data.</returns> public static Activity CreateReplyToGeneralChannel(this Activity activity, string text = null, string locale = null) { TeamsChannelData channelData = activity.GetChannelData <TeamsChannelData>(); Activity replyActivity = activity.CreateReply(text, locale); replyActivity.ChannelData = JObject.FromObject(new TeamsChannelData { Channel = activity.GetGeneralChannel(), Team = channelData.Team, Tenant = channelData.Tenant }); return(replyActivity); }
/// <summary> /// Notifies the user in direct conversation. /// </summary> /// <typeparam name="T">Type of message activity.</typeparam> /// <param name="replyActivity">The reply activity.</param> /// <returns>Modified activity.</returns> public static T NotifyUser <T>(this T replyActivity) where T : IMessageActivity { TeamsChannelData channelData = replyActivity.ChannelData == null ? new TeamsChannelData() : replyActivity.GetChannelData <TeamsChannelData>(); channelData.Notification = new NotificationInfo { Alert = true }; replyActivity.ChannelData = JObject.FromObject(channelData); return(replyActivity); }
public void ConnectorExtensions_Create1on1() { JsonSerializerSettings serializerSettings = new JsonSerializerSettings(); serializerSettings.NullValueHandling = NullValueHandling.Ignore; var botAccount = new ChannelAccount { Id = "BotId", Name = "BotName" }; var userAccount = new ChannelAccount { Id = "UserId", Name = "UserName" }; TestDelegatingHandler testDelegatingHandler = new TestDelegatingHandler((request) => { string data = (request.Content as StringContent).ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult(); ConversationParameters receivedRequest = JsonConvert.DeserializeObject <ConversationParameters>(data, serializerSettings); Assert.AreEqual(receivedRequest.Bot.Id, botAccount.Id); Assert.IsNotNull(receivedRequest.Members); Assert.IsTrue(receivedRequest.Members.Count == 1); Assert.AreEqual(receivedRequest.Members[0].Id, userAccount.Id); TeamsChannelData channelData = JsonConvert.DeserializeObject <TeamsChannelData>(receivedRequest.ChannelData.ToString()); Assert.IsNotNull(channelData); Assert.IsNotNull(channelData.Tenant); Assert.IsNotNull(channelData.Tenant.Id); Assert.AreEqual(channelData.Tenant.Id, "TestTenantId"); ConversationResourceResponse resourceResponse = new ConversationResourceResponse() { Id = "TestId" }; StringContent responseContent = new StringContent(JsonConvert.SerializeObject(resourceResponse)); var response = new HttpResponseMessage(HttpStatusCode.OK); response.Content = responseContent; return(Task.FromResult(response)); }); ConnectorClient conClient = new ConnectorClient(new Uri("https://testservice.com"), "Test", "Test", testDelegatingHandler); Assert.IsTrue(conClient.Conversations.CreateOrGetDirectConversation(botAccount, userAccount, "TestTenantId").Id == "TestId"); }
/// <summary> /// Configures the current activity to generate a notification within Teams. /// </summary> /// <param name="activity"> The current activity. </param> public static void TeamsNotifyUser(this IActivity activity) { var teamsChannelData = activity.ChannelData as TeamsChannelData; if (teamsChannelData == null) { teamsChannelData = new TeamsChannelData(); activity.ChannelData = teamsChannelData; } teamsChannelData.Notification = new NotificationInfo { Alert = true, }; }
public async Task ChannelData_GetGeneralChannelInvalidChannelDataAsync() { Activity sampleActivity = JsonConvert.DeserializeObject <Activity>(File.ReadAllText(@"Jsons\SampleActivityAtMention.json")); TeamsChannelData channelData = JsonConvert.DeserializeObject <TeamsChannelData>(sampleActivity.ChannelData.ToString()); channelData.Team = null; sampleActivity.ChannelData = JObject.FromObject(channelData); await TestHelpers.RunTestPipelineWithActivityAsync( sampleActivity, (teamsContext) => { ChannelInfo generalChannel = teamsContext.GetGeneralChannel(); return(Task.CompletedTask); }).ConfigureAwait(false); }
public async Task SendMessageToChannel(string title, BotSubscription subscription) { var subscriptionFacade = new SubscriptionFacade(); var channelData = new TeamsChannelData { Channel = new ChannelInfo(subscription.ChannelId), Team = new TeamInfo(subscription.TeamId), Tenant = new TenantInfo(subscription.TenantId) }; var newMessageText = await Build(); var newMessage = new Activity { Type = ActivityTypes.Message, Text = newMessageText.FixNewLines(), }; var conversationParams = new ConversationParameters( isGroup: true, bot: null, members: null, topicName: title, activity: (Activity)newMessage, channelData: channelData); var connector = new ConnectorClient(new Uri(subscription.ServiceUrl), Environment.GetEnvironmentVariable("MicrosoftAppId"), Environment.GetEnvironmentVariable("MicrosoftAppPassword")); MicrosoftAppCredentials.TrustServiceUrl(subscription.ServiceUrl, DateTime.MaxValue); if (subscription.LastActivity == null) { var result = await connector.Conversations.CreateConversationAsync(conversationParams); subscription.LastActivity = new LastActivity { ConversationId = result.Id, ActitityId = result.ActivityId }; } else { var result = await connector.Conversations.UpdateActivityAsync(subscription.LastActivity.ConversationId, subscription.LastActivity.ActitityId, newMessage); subscription.LastActivity.ActitityId = result.Id; } await subscriptionFacade.UpdateBotSubscription(subscription); }