/// <inheritdoc/> public Task SendMessageAsync(string text, GoogleChatAddress address, params Card[] cards) { Contract.Ensures(address != null, "Chat address is required!"); Contract.Ensures(address.Sender != null, "When async responder is called, sender is required!"); Contract.Ensures(address.Space != null, "When async responder is called, space is required!"); var message = new Message { Sender = new User { Name = address.Sender.Name, DisplayName = address.Sender.DisplayName }, Space = new Space { Name = address.Space.Name, DisplayName = address.Space.DisplayName, Type = address.Space.Type }, Text = text, Cards = new List <Card>(cards) }; if (address.ThreadName != null) { message.Thread = new Thread { Name = address.ThreadName }; } var createRequest = RequestCreator.SpacesMessagesCreate(message, address.Space.Name); return(createRequest?.ExecuteAsync() ?? Task.CompletedTask); }
private GoogleChatAddress CreateChatAddress(Space space) { if (space == null) { return(null); } User user = null; try { var response = RequestCreator.SpacesMembersList(space.Name, 2).Execute(); user = response.Memberships.FirstOrDefault(it => it.Member.Type == "HUMAN")?.Member; } catch (Exception) { // If there is request exception just provide empty user to be stored. user = new User(); } if (user == null) { return(null); } var address = new GoogleChatAddress(space.Name, space.DisplayName, space.Type, user.Name, user.DisplayName); return(address); }
/// <inheritdoc/> public IReadOnlyList <GoogleChatAddress> GetPrivateAddress(IReadOnlyList <string> filterSpaces) { var res = RequestCreator.SpacesList(1000).Execute(); var spaces = res.Spaces.Where(it => it.Type == "DM" && !filterSpaces.Contains(it.Name)); var addresses = new List <GoogleChatAddress>(); foreach (var space in spaces) { User user = null; try { var response = RequestCreator.SpacesMembersList(space.Name, 2).Execute(); user = response.Memberships.FirstOrDefault(it => it.Member.Type == "HUMAN")?.Member; } catch (Exception) { // If there is request exception just provide empty user to be stored. user = new User(); } if (user == null) { continue; } var address = new GoogleChatAddress(space.Name, space.DisplayName, space.Type, user.Name, user.DisplayName); addresses.Add(address); } return(addresses); }
private async Task SendNotificationsAsync( Dictionary <string, IReadOnlyList <Timesheet> > timesheets, string key, string email, bool notify, TimesheetStates state, DateTime scheduleDate, GoogleChatAddress address, IReadOnlyList <string> customerToExcludes, ITimesheetProcessor processor) { if (!timesheets.TryGetValue(key, out var timesheetValues)) { timesheetValues = await processor.GetTimesheetsAsync(scheduleDate, state, email, true, customerToExcludes); timesheets.Add(key, timesheetValues); } await processor.SendTimesheetNotificationsToUsersAsync( timesheetValues, email, department : null, notify : notify, notifyByEmail : false, state, address, _hangoutsChatConnector); }
/// <summary>Get timesheets and notifies by message or email the users asynchronous.</summary> public async Task NotifyAsync( DateTime date, TimesheetStates state, string email, IReadOnlyList <string> customersToExclude, string department, bool notify, bool notifyByEmail, bool filterOutSender, GoogleChatAddress address, IHangoutsChatConnector connector) => await SendTimesheetNotificationsToUsersAsync( await _openAirConnector.GetUnsubmittedTimesheetsAsync( date, Contract.LocalDateTime.Date, state, email, filterOutSender, TimesheetsProperties.UserMaxHours, customersToExclude), email, department, notify, notifyByEmail, state, address, connector);
public async Task SendTimesheetNotificationsToUsersShouldSendAllSubmitted() { var responder = Substitute.For <IHangoutsChatConnector>(); var address = new GoogleChatAddress("space/B", "MentorBot", null, "A", "Jhon"); var responses = new[] { "<b>If you're reading this, probably MentorBot has encountered internal server error or everybody submitted their timesheets on time. The second one Is highly unlikely, so please review the log.</b>", "<b>I spent 2 hours looking for unsubmitted timesheets and I couldn't find any! How should I log this time?</b>", "<b>It must be the end of the world, because everyone submitted their timesheet on time!</b>", }; // Act await _processor.SendTimesheetNotificationsToUsersAsync( Array.Empty <Timesheet>(), "[email protected]", null, false, false, TimesheetStates.Unsubmitted, address, responder); // Test responder.Received() .SendMessageAsync( null, Arg.Is <GoogleChatAddress>(it => it.Space.Name == "space/B"), Arg.Is <Card[]>(cards => Array.IndexOf(responses, cards[0].Sections[0].Widgets[0].TextParagraph.Text) > -1)); }
public async Task WhenAskedNotifyForTimesheets() { var date = new DateTime(2000, 1, 1, 1, 1, 1); var customers = new[] { "D" }; var responder = Substitute.For <IHangoutsChatConnector>(); var address = new GoogleChatAddress("space/B", "MentorBot", null, "A", "Jhon"); var timesheet = new Timesheet { Name = "A", UserName = "******", UserEmail = "[email protected]", DepartmentName = "F", Total = 20 }; var timesheet2 = new Timesheet { Name = "E", UserName = "******", UserEmail = "[email protected]", DepartmentName = "F", Total = 15 }; responder.GetPrivateAddress(Arg.Any <IReadOnlyList <string> >()).Returns(new[] { address }); _storageService.GetAddressesAsync().Returns(new GoogleAddress[0]); _connector.GetUnsubmittedTimesheetsAsync(date, TimesheetStates.Unsubmitted, "[email protected]", null) .ReturnsForAnyArgs(new[] { timesheet, timesheet2 }); // Act await _processor.NotifyAsync( new DateTime(2000, 1, 1, 1, 1, 1), TimesheetStates.Unsubmitted, "[email protected]", new[] { "D" }, "F", true, true, null, responder); // Test responder.Received() .SendMessageAsync( "Jhon, You have unsubmitted timesheet. Please, submit your timesheet.", Arg.Is <GoogleChatAddress>(it => it.Space.Name == "space/B")); _mailService.Received() .SendMailAsync( "Timesheet is pending", ", You have unsubmitted timesheet. Please, submit your timesheet.", Arg.Is <string[]>(it => it[0] == "[email protected]")); _storageService.Received() .AddAddressesAsync(Arg.Is <IReadOnlyList <GoogleAddress> >(arr => arr[0].SpaceName == "space/B")); _mailService.Received() .SendMailAsync("Users not notified", "All users with unsibmitted timesheets are notified! Total of 2.<br/><br/><b>The following people where notified by a direct massage or email:<br/><b>Jhon</b><br/><b>ElA</b>", "[email protected]"); }
public async Task HangoutsChatConnector_CreatesMessage() { var address = new GoogleChatAddress("S1", "S2", "S3", "U1", "U2"); var requestCreator = Substitute.For <HangoutsChatConnector.IRequestCreator>(); var connector = new HangoutsChatConnector(new Lazy <HangoutsChatService>(() => null)); connector.RequestCreator = requestCreator; await connector.SendMessageAsync("A", address); requestCreator .Received() .SpacesMessagesCreate(Arg.Is <Message>(it => it.Text.Equals("A")), "S1"); }
/// <inheritdoc/> public ValueTask <ChatEventResult> ProcessCommandAsync( TextDeconstructionInformation info, ChatEvent originalChatEvent, IAsyncResponder responder, IPluginPropertiesAccessor accessor) { var notify = info.TextSentenceChunk.StartsWith("Notify", StringComparison.InvariantCultureIgnoreCase); var departmentValue = info .Entities .GetValueOrDefault(nameof(Department)) ?.FirstOrDefault() ?.Replace(". ", ".", StringComparison.InvariantCulture); var customersValue = info.Entities.GetValueOrDefault(nameof(Customer), new string[0]); var period = OpenAirText.GetPeriod(info.Entities.GetValueOrDefault("Period")?.FirstOrDefault()); var state = OpenAirText.GetTimesheetState(info.Entities.GetValueOrDefault("State")?.FirstOrDefault()); var today = Contract.LocalDateTime.Date; var date = period == OpenAirPeriodTypes.LastWeek ? today.AddDays(-((int)today.DayOfWeek + 1)) : today; var senderEmail = originalChatEvent.Message.Sender.Email; var customersSetting = accessor.GetAllPluginPropertyValues <string>(TimesheetsProperties.FilterByCustomer); var customersToExclude = customersValue.Concat(customersSetting ?? new string[0]).ToArray(); if (state == TimesheetStates.None) { return(new ValueTask <ChatEventResult>( new ChatEventResult("Provide a state of the time sheets, like unsubmitted or unapproved!"))); } var address = new GoogleChatAddress(originalChatEvent); NotifyAsync( date, state, senderEmail, customersToExclude, departmentValue, notify, false, true, address, responder as IHangoutsChatConnector) .ConfigureAwait(false); return(new ValueTask <ChatEventResult>( new ChatEventResult(text: null))); }
/// <summary>Get timesheets and notifies by message or email the users asynchronous.</summary> public Task NotifyAsync( DateTime date, TimesheetStates state, string email, string[] customersToExclude, string department, bool notify, bool notifyByEmail, GoogleChatAddress address, IHangoutsChatConnector connector) => _openAirConnector.GetUnsubmittedTimesheetsAsync(date, state, email, customersToExclude) .ContinueWith(task => ProcessNotifyAsync( task.Result, email, department, notify, notifyByEmail, state, address, connector));
/// <inheritdoc/> public Task SendMessageAsync(string text, GoogleChatAddress address, params Card[] cards) { if (address == null || address.Sender == null || address.Space == null) { throw new InvalidOperationException("When async responder is called, space and sender are requireired."); } var message = new Message { Sender = new User { Name = address.Sender.Name, DisplayName = address.Sender.DisplayName }, Space = new Space { Name = address.Space.Name, DisplayName = address.Space.DisplayName, Type = address.Space.Type }, Text = text, Cards = new List <Card>(cards) }; if (address.ThreadName != null) { message.Thread = new Thread { Name = address.ThreadName }; } var createRequest = RequestCreator.SpacesMessagesCreate(message, address.Space.Name); return(createRequest?.ExecuteAsync() ?? Task.CompletedTask); }
/// <summary>Processes the specified timesheets.</summary> public async Task SendTimesheetNotificationsToUsersAsync( IReadOnlyList <Timesheet> timesheets, string email, string department, bool notify, bool notifyByEmail, TimesheetStates state, GoogleChatAddress address, IHangoutsChatConnector connector) { string text; var filteredTimesheet = timesheets .Where(it => department == null || department.Equals(it.DepartmentName, StringComparison.InvariantCultureIgnoreCase)) .OrderBy(it => it.ManagerName) .ThenBy(it => it.UserName) .ToArray(); var notifiedUserList = new List <string>(); if (filteredTimesheet.Length == 0) { var responses = OpenAirText.GetText(state, OpenAirTextTypes.AllAreDone).Split('|', StringSplitOptions.RemoveEmptyEntries); var rand = new Random(); text = responses[rand.Next(0, responses.Length - 1)]; } else if (notify && filteredTimesheet.Length > 0) { notifiedUserList.AddRange( await NotifyUsersOverChatAsync(connector, state, filteredTimesheet)); if (notifyByEmail) { var textMessage = OpenAirText.GetText(state, OpenAirTextTypes.Notify); var emails = filteredTimesheet .Where(it => !notifiedUserList.Contains(it.UserName)) .Apply(it => notifiedUserList.Add(it.UserName)) .Select(it => it.UserEmail) .Distinct() .ToArray(); await _mailService.SendMailAsync("Timesheet is pending", textMessage, emails); } text = notifiedUserList.Count == filteredTimesheet.Length ? string.Format( CultureInfo.InvariantCulture, OpenAirText.GetText(state, OpenAirTextTypes.AllAreNotified), notifiedUserList.Count) : OpenAirText.GetText(state, OpenAirTextTypes.SomeAreNotified) + GetCardText(filteredTimesheet, notifiedUserList); } else { text = OpenAirText.GetText(state, OpenAirTextTypes.SomeAreDone) + GetCardText(filteredTimesheet, notifiedUserList); } var paragraph = new TextParagraph { Text = text }; var card = ChatEventFactory.CreateCard(paragraph); if (address != null) { await connector.SendMessageAsync(null, address, card); } else if (email != null) { var emailedUsers = string.Join("</b><br/><b>", notifiedUserList); var emailText = $"{text}<br/><br/><b>The following people where notified by a direct massage or email:" + $"<br/><b>{emailedUsers}</b>"; await _mailService.SendMailAsync("Users not notified", emailText, email); } }
public async Task SendScheduledTimesheetShouldSendToSpace() { var date = new DateTime(2020, 7, 1, 20, 0, 0, DateTimeKind.Local); var timesheetProcessor = Substitute.For <ITimesheetProcessor>(); var propertiesAccessor = Substitute.For <IPluginPropertiesAccessor>(); var deconstructionInformation = new TextDeconstructionInformation(null, null); var analysisResult = new CognitiveTextAnalysisResult(deconstructionInformation, timesheetProcessor, propertiesAccessor); var address = new GoogleChatAddress("S1", "Space 1", "RM", "U1", "User 1"); var timesheet = new Timesheet { UserEmail = "[email protected]", UserName = "******", DepartmentName = "Account", ManagerName = "*****@*****.**", Total = 5, UtilizationInHours = 10 }; var excludeCustomers = new[] { "C1" }; _cognitiveService.GetCognitiveTextAnalysisResultAsync(null, null).ReturnsForAnyArgs(analysisResult); propertiesAccessor.GetAllPluginPropertyValues <string>("OpenAir.Filters.Customer").Returns(excludeCustomers); propertiesAccessor .GetPluginPropertyGroup("OpenAir.AutoNotifications") .Returns( new[] { new [] { new PluginPropertyValue { Key = "OpenAir.AutoNotifications.Spaces", Value = "S1" }, new PluginPropertyValue { Key = "OpenAir.AutoNotifications.Email", Value = "[email protected]" }, new PluginPropertyValue { Key = "OpenAir.AutoNotifications.ReportName", Value = "unsubmitted" }, new PluginPropertyValue { Key = "OpenAir.AutoNotifications.Cron", Value = "20 Wed" }, new PluginPropertyValue { Key = "OpenAir.AutoNotifications.Notify", Value = false }, } }); _hangoutsChatConnector.GetAddressByName("spaces/S1").Returns(address); timesheetProcessor .GetTimesheetsAsync(Arg.Any <DateTime>(), TimesheetStates.Unsubmitted, "[email protected]", true, excludeCustomers) .Returns(new[] { timesheet }); await _timesheetService.SendScheduledTimesheetNotificationsAsync(date); timesheetProcessor .Received() .SendTimesheetNotificationsToUsersAsync( Arg.Is <IReadOnlyList <Timesheet> >(it => it[0].UserName == "Jhon Doe"), "[email protected]", null, false, false, TimesheetStates.Unsubmitted, address, _hangoutsChatConnector); }
/// <summary>Processes the specified timesheets.</summary> private async Task ProcessNotify( IReadOnlyList <Timesheet> timesheets, string department, bool notify, GoogleChatAddress address, IHangoutsChatConnector connector) { string text; var filteredTimesheet = department == null ? timesheets : timesheets .Where(it => it.DepartmentName.Equals(department, StringComparison.InvariantCultureIgnoreCase)) .ToArray(); var notifiedUserList = new List <string>(); if (filteredTimesheet.Count == 0) { text = "<b>All user have submitted timesheets.</b>"; } else if (notify && filteredTimesheet.Count > 0) { var emails = filteredTimesheet.Select(it => it.UserEmail).ToArray(); var storeAddresses = _storageService.GetAddresses(); var filteredAddresses = storeAddresses.Where(it => emails.Contains(it.UserEmail)).ToArray(); var addressesForUpdate = new List <GoogleAddress>(); IReadOnlyList <GoogleAddress> privateAddresses = new GoogleAddress[0]; if (filteredAddresses.Length < timesheets.Count) { var storeAddressesNames = storeAddresses.Select(it => it.SpaceName).ToArray(); privateAddresses = connector .GetPrivateAddress(storeAddressesNames) .Select(it => new GoogleAddress { SpaceName = it.Space.Name, UserName = it.Sender.Name, UserDisplayName = it.Sender.DisplayName }) .ToArray(); // Store inactive spaces, so not to be requested the next time addressesForUpdate.AddRange(privateAddresses.Where(it => it.UserName == null)); } foreach (var timesheet in filteredTimesheet) { var message = $"{timesheet.UserName}, Please submit your timesheet. Your current hours are {timesheet.Total}."; var addr = filteredAddresses.FirstOrDefault(it => it.UserEmail == timesheet.UserEmail); if (addr == null) { addr = privateAddresses.FirstOrDefault(it => it.UserDisplayName == timesheet.UserName); if (addr == null) { continue; } addr.UserEmail = timesheet.UserEmail; addressesForUpdate.Add(addr); } notifiedUserList.Add(timesheet.UserName); await connector.SendMessageAsync( message, new GoogleChatAddress(addr.SpaceName, string.Empty, "DM", addr.UserName, addr.UserDisplayName)); } if (addressesForUpdate.Count > 0) { await _storageService.AddAddressesAsync(addressesForUpdate); } text = notifiedUserList.Count == filteredTimesheet.Count ? "All users width unsubmitted timesheets are notified! Total of " + notifiedUserList.Count : "The following people where not notified: <br>" + GetCardText(filteredTimesheet, notifiedUserList); } else { text = "The following people have to submit timesheet: <br>" + GetCardText(filteredTimesheet, notifiedUserList); } var paragraph = new TextParagraph { Text = text }; var card = ChatEventFactory.CreateCard(paragraph); await connector.SendMessageAsync(null, address, card); }