/// <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);
        }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
 /// <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);
Esempio n. 6
0
        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));
        }
Esempio n. 7
0
        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]");
        }
Esempio n. 8
0
        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");
        }
Esempio n. 9
0
        /// <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)));
        }
Esempio n. 10
0
 /// <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);
        }
Esempio n. 12
0
        /// <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);
            }
        }
Esempio n. 13
0
        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);
        }
Esempio n. 14
0
        /// <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);
        }