public async Task AddNotificationRequest(NotificationRequest request)
        {
            // Validate various pieces of the request
            if (request.EmailAddress == null && request.PhoneNumber == null)
            {
                throw new Exception("Either e-mail address or phone number needs to be supplied");
            }

            if (request.EmailAddress != null && !IsValidEmail(request.EmailAddress))
            {
                throw new Exception("Email address is improperly formatted");
            }

            if (request.RainThreshold < 0 || request.RainThreshold > 100)
            {
                throw new Exception("Rain threshold needs to be between 0 and 100 (inclusive)");
            }

            await Db.NotificationRequests.AddAsync(request);

            await Db.SaveChangesAsync();
        }
        public async Task Run([TimerTrigger("0 */15 * * * *")] TimerInfo myTimer)
        {
            var processTime = DateTime.UtcNow;

            // Load most recent task run information
            var lastRun = await Db.TaskRecords.OrderByDescending(x => x.TimeProcessed).FirstOrDefaultAsync();

            // If no run is detected, just assume 15 minutes ago
            var timeSpan = lastRun?.TimeProcessed.TimeOfDay ?? processTime.TimeOfDay.Add(new TimeSpan(0, -15, 0));

            // Load any records that have send times after our last run up until right now
            var recordsToProcess = await Db.NotificationRequests.Where(x => x.TimeToSend > timeSpan && x.TimeToSend <= processTime.TimeOfDay).ToListAsync();

            var weatherService = new WeatherService();

            var emailsToSend = new Dictionary <string, DailyData>();
            var textsToSend  = new Dictionary <PhoneNumber, DailyData>();

            foreach (var record in recordsToProcess)
            {
                var weather = await weatherService.GetWeatherByLocation(record.Latitude, record.Longitude);

                // Today's weather will always be the first entry in the daily list
                var weatherToday = weather.Daily.Data[0];

                var temp = weatherToday.PrecipProbability * 100;

                // Convert the precipitation probability to an int value for comparison
                // and make sure the threshold is less than the chance
                if (record.RainThreshold <= (weatherToday.PrecipProbability * 100))
                {
                    if (record.EmailAddress != null)
                    {
                        emailsToSend.Add(record.EmailAddress, weatherToday);
                    }

                    if (record.PhoneNumber != null)
                    {
                        var parsedPhoneNumber = record.PhoneNumber.ParsePhoneNumber(record.PhoneNumberCountryCode);

                        textsToSend.Add(parsedPhoneNumber, weatherToday);
                    }
                }
            }

            // Send emails and texts where necessary
            await SendEmails(emailsToSend);

            SendTexts(textsToSend);

            // Save the record of this process
            var taskRecord = new TaskRecord
            {
                TimeProcessed    = processTime,
                RecordsProcessed = recordsToProcess.Count,
            };

            await Db.TaskRecords.AddAsync(taskRecord);

            await Db.SaveChangesAsync();
        }