/// <inheritdoc/>
        public async Task <string> PublishAsync(InfectionReport report, Region region, CancellationToken cancellationToken = default)
        {
            // Validate inputs
            if (report == null)
            {
                throw new ArgumentNullException(nameof(report));
            }
            if (region == null)
            {
                throw new ArgumentNullException(nameof(region));
            }

            RequestValidationResult validationResult = report.Validate();

            validationResult.Combine(region.Validate());

            if (validationResult.Passed)
            {
                // Push to upstream data repository
                return(await this._reportRepo.InsertAsync(report, region, cancellationToken));
            }
            else
            {
                throw new RequestValidationFailedException(validationResult);
            }
        }
        public async Task PublishAsync_ArgumentNullOnNullRegion()
        {
            // Arrange
            InfectionReport request   = new InfectionReport();
            AreaReport      areaMatch = new AreaReport
            {
                UserMessage = "Test user message"
            };

            areaMatch.Areas.Add(new InfectionArea
            {
                BeginTimestamp = 0,
                EndTimestamp   = 1,
                Location       = new Coordinates
                {
                    Latitude  = 10.1234,
                    Longitude = -10.1234
                },
                RadiusMeters = 100
            });
            request.AreaReports.Add(areaMatch);
            request.BluetoothSeeds.Add(new BluetoothSeed
            {
                EndTimestamp   = 1,
                BeginTimestamp = 0,
                Seed           = "00000000-0000-0000-0000-000000000000"
            });

            // Act
            string result = await this._service
                            .PublishAsync(request, null, CancellationToken.None);

            // Assert
            // Exception caught by decorator
        }
Ejemplo n.º 3
0
        /// <inheritdoc/>
        public async Task <string> InsertAsync(InfectionReport report, Region region, CancellationToken cancellationToken = default)
        {
            if (report == null)
            {
                throw new ArgumentNullException(nameof(report));
            }
            if (region == null)
            {
                throw new ArgumentNullException(nameof(region));
            }

            region = RegionHelper.AdjustToPrecision(region);

            // Get allowed region boundary
            RegionBoundary boundary = RegionHelper.GetRegionBoundary(region);

            var record = new InfectionReportRecord(report)
            {
                RegionBoundary = new RegionBoundary(boundary),
                PartitionKey   = InfectionReportRecord.GetPartitionKey(region)
            };

            ItemResponse <InfectionReportRecord> response = await this.Container
                                                            .CreateItemAsync <InfectionReportRecord>(
                record,
                new PartitionKey(record.PartitionKey),
                cancellationToken : cancellationToken
                );

            return(response.Resource.Id);
        }
        /// <inheritdoc/>
        public async Task PublishAreaAsync(AreaReport areaReport, CancellationToken cancellationToken = default)
        {
            // Validate inputs
            if (areaReport == null)
            {
                throw new ArgumentNullException(nameof(areaReport));
            }

            RequestValidationResult validationResult = areaReport.Validate();

            if (validationResult.Passed)
            {
                // Build an InfectionReport containing the submitted areas
                InfectionReport message = new InfectionReport();
                message.AreaReports.Add(areaReport);

                // Define a regions for the published message
                IEnumerable <Region> messageRegions = RegionHelper.GetRegionsCoverage(areaReport.Areas, this.RegionPrecision);

                // Publish
                await this._reportRepo.InsertAsync(message, messageRegions, cancellationToken);
            }
            else
            {
                throw new RequestValidationFailedException(validationResult);
            }
        }
Ejemplo n.º 5
0
        public async Task NewInfectionReport(ApplicationUser user, InfectionReport report)
        {
            if (user.Infected)
            {
                throw new ModelException("User already infected");
            }

            report.ApplicationUserId = user.Id;
            report.DischargedDate    = null;

            if (report.DiagnosisDate > Time.Now())
            {
                throw new ModelException("Diagnosis date more recent than Discharge date",
                                         (ModelState => { ModelState.AddModelError("DiagnosisDate", "La fecha de diagnosis no puede ser posterior a la fecha actual."); })
                                         );
            }

            _context.Add(report);
            await _context.SaveChangesAsync();

            await _userInfoManager.UpdateStatus(user, InfectionStatus.Infected, report.DiagnosisDate);

            var userStays = (from stay in _context.Stay
                             where stay.UserId == user.Id &&
                             (stay.TimeOfExit == null || stay.TimeOfExit > report.DiagnosisDate.AddDays(-15))
                             select stay);


            await UpdateRiskStatusFromStays(userStays, user.Id);


            await notifyOtherServers(userStays);
        }
Ejemplo n.º 6
0
        public async Task <IActionResult> InfectionReport([Bind("Id,DiagnosisDate")] InfectionReport infectionReport)
        {
            var currentUser = await _userInfoManager.FindUser(User);

            try { await _infectionManager.NewInfectionReport(currentUser, infectionReport); }
            catch (ModelException ex)
            {
                ex.UpdateModelState(ModelState);
                return(View(infectionReport));
            }

            return(RedirectToAction(nameof(Index)));
        }
        public async Task PublishAsync_SucceedsOnValidMessage()
        {
            // Arrange
            string repoResponse = "00000000-0000-0000-0000-000000000002";
            Region region       = new Region
            {
                LatitudePrefix  = 10.1234,
                LongitudePrefix = -10.1234,
                Precision       = 4
            };
            InfectionReport request    = new InfectionReport();
            AreaReport      areaReport = new AreaReport
            {
                UserMessage = "Test user message"
            };

            areaReport.Areas.Add(new InfectionArea
            {
                BeginTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                EndTimestamp   = DateTimeOffset.UtcNow.AddHours(1).ToUnixTimeMilliseconds(),
                Location       = new Coordinates
                {
                    Latitude  = 10.1234,
                    Longitude = -10.1234
                },
                RadiusMeters = 100
            });
            request.AreaReports.Add(areaReport);
            request.BluetoothSeeds.Add(new BluetoothSeed
            {
                BeginTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                EndTimestamp   = DateTimeOffset.UtcNow.AddHours(1).ToUnixTimeMilliseconds(),
                Seed           = "00000000-0000-0000-0000-000000000001"
            });

            this._repo
            .Setup(r => r.InsertAsync(It.IsAny <InfectionReport>(), It.IsAny <Region>(), CancellationToken.None))
            .Returns(Task.FromResult(repoResponse));

            // Act
            string result = await this._service
                            .PublishAsync(request, region, CancellationToken.None);

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(repoResponse, result);
        }
        public async Task PostAsync_OkWithMatchedParameters()
        {
            // Arrange
            IEnumerable <string> ids = new string[]
            {
                "00000000-0000-0000-0000-000000000001",
                "00000000-0000-0000-0000-000000000002"
            };
            InfectionReport result1 = new InfectionReport();
            InfectionReport result2 = new InfectionReport();
            IEnumerable <InfectionReport> toReturn = new List <InfectionReport>
            {
                result1,
                result2
            };

            this._repo
            .Setup(s => s.GetRangeAsync(ids, CancellationToken.None))
            .Returns(Task.FromResult(toReturn));

            MessageRequest request = new MessageRequest();

            request.RequestedQueries.Add(new MessageInfo
            {
                MessageId        = ids.ElementAt(0),
                MessageTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            });
            request.RequestedQueries.Add(new MessageInfo
            {
                MessageId        = ids.ElementAt(1),
                MessageTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            });

            // Act
            ActionResult <IEnumerable <MatchMessage> > controllerResponse = await this._controller
                                                                            .PostAsync(request, CancellationToken.None);

            // Assert
            Assert.IsNotNull(controllerResponse);
            Assert.IsInstanceOfType(controllerResponse.Result, typeof(OkObjectResult));
            OkObjectResult castedResult = controllerResponse.Result as OkObjectResult;

            Assert.IsInstanceOfType(castedResult.Value, typeof(List <MatchMessage>));
            List <MatchMessage> listResult = castedResult.Value as List <MatchMessage>;

            Assert.AreEqual(toReturn.Count(), listResult.Count());
        }
        /// <inheritdoc/>
        public async Task <string> PublishAsync(IEnumerable <BluetoothSeed> seeds, Region region, long timeAtRequest, CancellationToken cancellationToken = default)
        {
            // Validate inputs
            if (seeds == null || seeds.Count() == 0)
            {
                throw new ArgumentNullException(nameof(seeds));
            }
            if (region == null)
            {
                throw new ArgumentNullException(nameof(region));
            }

            // Validate timestamp
            RequestValidationResult validationResult = Validator.ValidateTimestamp(timeAtRequest);

            // Validate seeds
            foreach (BluetoothSeed seed in seeds)
            {
                validationResult.Combine(seed.Validate());
            }

            if (validationResult.Passed)
            {
                // Build MatchMessage from submitted content
                InfectionReport report = new InfectionReport();

                if (report.BluetoothSeeds is List <BluetoothSeed> asList)
                {
                    asList.AddRange(seeds);
                }
                else
                {
                    foreach (BluetoothSeed seed in seeds)
                    {
                        report.BluetoothSeeds.Add(seed);
                    }
                }

                // Store in data repository
                return(await this._reportRepo.InsertAsync(report, region, cancellationToken));
            }
            else
            {
                throw new RequestValidationFailedException(validationResult);
            }
        }
Ejemplo n.º 10
0
        public async Task InsertAsync(InfectionReport report, IEnumerable <Region> regions, CancellationToken cancellationToken = default)
        {
            // Validate inputs
            if (report == null)
            {
                throw new ArgumentNullException(nameof(report));
            }

            // Prepare records to insert (grouped by partition key)
            var recordGroups = regions.Select(
                r => new InfectionReportRecord(report)
            {
                RegionBoundary = new RegionBoundary(
                    RegionHelper.GetRegionBoundary(r)
                    ),
                PartitionKey = InfectionReportRecord.GetPartitionKey(r)
            }).GroupBy(r => r.PartitionKey);

            // Begin batch operation
            // All MatchMessageRecords will have same PartitionID in this batch
            var batches = recordGroups.Select(g => g.Aggregate(
                                                  this.Container.CreateTransactionalBatch(new PartitionKey(g.Key)),
                                                  (result, item) => result.CreateItem <InfectionReportRecord>(item)));

            // Execute transactions
            // TODO: make a single transaction.
            var responses = await Task.WhenAll(batches.Select(b => b.ExecuteAsync(cancellationToken)));

            var failed = responses.Where(r => !r.IsSuccessStatusCode);

            if (failed.Any())
            {
                throw new Exception(
                          String.Format(
                              "{0} out of {1} insertions failed. Cosmos bulk insert failed with HTTP Status Code {2}.",
                              responses.Count(),
                              failed.Count(),
                              failed.First().StatusCode.ToString()
                              )
                          );
            }
        }