public static RegisteredCredential From(EthEventDTO eventDto)
        {
            var ret = new RegisteredCredential()
            {
                IsRevoked          = false,
                HashId             = eventDto.IndexedParameters[0].Value,
                CitizenAddress     = eventDto.NonIndexedParameters[0].Value,
                SubjectHashId      = eventDto.NonIndexedParameters[1].Value,
                StartDate          = DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(eventDto.NonIndexedParameters[2].Value)).DateTime.ToUniversalTime(),
                CredentialCreation = DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(eventDto.NonIndexedParameters[3].Value)).DateTime.ToUniversalTime(),
                Sex            = Enum.Parse <Sex>(eventDto.NonIndexedParameters[4].Value),
                Age            = short.Parse(eventDto.NonIndexedParameters[5].Value),
                CredentialType = Enum.Parse <CredentialType>(eventDto.NonIndexedParameters[7].Value),
                Reason         = Enum.Parse <InterruptionReason>(eventDto.NonIndexedParameters[8].Value)
            };

            var hasher  = new Geohasher();
            var hash    = Hex.HexToString(eventDto.NonIndexedParameters[6].Value);
            var decoded = hasher.Decode(hash);

            ret.Location = new Point(decoded.Item2, decoded.Item1);
            ret.Lat      = ret.Location.Coordinate.X;
            ret.Lon      = ret.Location.Coordinate.Y;
            SetSymptoms(ret, eventDto.NonIndexedParameters[9].Value);
            return(ret);
        }
예제 #2
0
        public void Should_Decode_Precision12()
        {
            var hasher = new Geohasher();

            var hash = hasher.Decode("u33dc07zzzzx");

            Assert.Equal(52.51739494, Math.Round(hash.Item1, 8));
            Assert.Equal(13.40881297, Math.Round(hash.Item2, 8));
        }
예제 #3
0
        public void Should_Decode_Precision6()
        {
            var hasher = new Geohasher();

            var hash = hasher.Decode("u33dc0");

            Assert.Equal(52.5174, Math.Round(hash.Item1, 4));
            Assert.Equal(13.409, Math.Round(hash.Item2, 3));
        }
예제 #4
0
        public Point Decode(string geohash)
        {
            var result = hasher.Decode(geohash);

            return(new Point(result.Item2, result.Item1));
        }
예제 #5
0
        public async Task <IActionResult> Upload(
            [FromBody] DailyStats stats
            )
        {
            if (!ModelState.IsValid)
            {
                Logger.LogError("Failed to parse input data: {0}", ModelState);
                return(BadRequest(ModelState));
            }

            Logger.LogInformation("Receiving daily stats from device {0} for {1}", stats.InstallationId, stats.Date.ToString("d", CultureInfo.InvariantCulture));

            // Safety checks
            if (stats.Date < MinDate)
            {
                Logger.LogError("Daily statistics for unacceptable date {0}", stats.Date);
                return(UnprocessableEntity(ProblemDetailsFactory.CreateProblemDetails(HttpContext,
                                                                                      title: "Unacceptable date (out of valid range)",
                                                                                      type: "https://arianna.digit.srl/api/problems/invalid-date"
                                                                                      )));
            }
            if (stats.TotalMinutesTracked > MinutesADay)
            {
                Logger.LogError("Total minutes tracked ({0}) exceeds minutes in a day", stats.TotalMinutesTracked);
                return(UnprocessableEntity(ProblemDetailsFactory.CreateProblemDetails(HttpContext,
                                                                                      title: "Total minutes tracked exceeds minutes in a day",
                                                                                      type: "https://arianna.digit.srl/api/problems/invalid-data"
                                                                                      )));
            }
            if (stats.Date >= DateTime.UtcNow.Date)
            {
                Logger.LogError("Daily statistics for non-elapsed day {0}", stats.Date.Date);
                return(UnprocessableEntity(ProblemDetailsFactory.CreateProblemDetails(HttpContext,
                                                                                      title: "Unacceptable date (future date)",
                                                                                      type: "https://arianna.digit.srl/api/problems/invalid-date"
                                                                                      )));
            }

            GeoJsonPoint <GeoJson2DGeographicCoordinates> position;
            string geohash;

            try {
                geohash = stats.CentroidHash.Substring(0, 5);
                var decoded = Geohasher.Decode(geohash);
                position = new GeoJsonPoint <GeoJson2DGeographicCoordinates>(new GeoJson2DGeographicCoordinates(decoded.Item2, decoded.Item1));
                Logger.LogInformation("GeoHash {0} decoded as {1:F5},{2:F5}", geohash, position.Coordinates.Latitude, position.Coordinates.Longitude);
            }
            catch (Exception ex) {
                return(UnprocessableEntity(ProblemDetailsFactory.CreateProblemDetails(HttpContext,
                                                                                      title: "Cannot decode geohash",
                                                                                      type: "https://arianna.digit.srl/api/problems/invalid-data",
                                                                                      detail: ex.Message
                                                                                      )));
            }

            if (stats.LocationTracking == null)
            {
                Logger.LogError("Payload does not contain location tracking section");
                return(UnprocessableEntity(ProblemDetailsFactory.CreateProblemDetails(HttpContext,
                                                                                      title: "Payload does not contain location tracking section",
                                                                                      type: "https://arianna.digit.srl/api/problems/invalid-data"
                                                                                      )));
            }
            if (stats.LocationTracking.MinutesAtHome < 0 ||
                stats.LocationTracking.MinutesAtWork < 0 ||
                stats.LocationTracking.MinutesAtSchool < 0 ||
                stats.LocationTracking.MinutesAtOtherKnownLocations < 0 ||
                stats.LocationTracking.MinutesElsewhere < 0)
            {
                Logger.LogError("Location tracking minutes cannot be negative");
                return(UnprocessableEntity(ProblemDetailsFactory.CreateProblemDetails(HttpContext,
                                                                                      title: "Negative location tracking value",
                                                                                      type: "https://arianna.digit.srl/api/problems/invalid-data"
                                                                                      )));
            }
            if (stats.LocationTracking.MinutesAtHome > MinutesADay ||
                stats.LocationTracking.MinutesAtWork > MinutesADay ||
                stats.LocationTracking.MinutesAtSchool > MinutesADay ||
                stats.LocationTracking.MinutesAtOtherKnownLocations > MinutesADay ||
                stats.LocationTracking.MinutesElsewhere > MinutesADay)
            {
                Logger.LogError("One entry in the location tracking section exceeds minutes in a day");
                return(UnprocessableEntity(ProblemDetailsFactory.CreateProblemDetails(HttpContext,
                                                                                      title: "One entry in the location tracking section exceeds minutes in a day",
                                                                                      type: "https://arianna.digit.srl/api/problems/invalid-data"
                                                                                      )));
            }

            // Check for duplicates
            var existingStats = await Mongo.GetDailyStats(stats.InstallationId, stats.Date);

            if (existingStats != null)
            {
                Logger.LogError("Duplicate statistics from device ID {0} for date {1}", stats.InstallationId, stats.Date.ToString("d", CultureInfo.InvariantCulture));
                return(Conflict(ProblemDetailsFactory.CreateProblemDetails(HttpContext,
                                                                           title: "Duplicate statistics for date",
                                                                           type: "https://arianna.digit.srl/api/problems/duplicate"
                                                                           )));
            }

            // Compute voucher amounts
            int stayAtHomeBonus = 0;
            int womCount        = (int)Math.Ceiling(stats.TotalMinutesTracked / 60.0) + stayAtHomeBonus;

            Logger.LogInformation("Generating {0} WOM vouchers for {1} total minutes and {2} minutes at home ({3} stay at home bonus)",
                                  womCount, stats.TotalMinutesTracked, stats.LocationTracking.MinutesAtHome, stayAtHomeBonus);
            var voucherRequest = await Wom.Instrument.RequestVouchers(new VoucherCreatePayload.VoucherInfo[] {
                new VoucherCreatePayload.VoucherInfo {
                    Aim       = "P",
                    Count     = womCount,
                    Latitude  = position.Coordinates.Latitude,
                    Longitude = position.Coordinates.Longitude,
                    Timestamp = stats.Date.Date.AddHours(23.999)
                }
            });

            // OK-dokey
            await Mongo.AddDailyStats(new DataModels.DailyStats {
                InstallationId         = stats.InstallationId,
                Date                   = stats.Date.Date,
                TotalMinutesTracked    = stats.TotalMinutesTracked,
                TotalWomVouchersEarned = womCount,
                Centroid               = position,
                CentroidHash           = geohash,
                LocationCount          = stats.LocationCount,
                VehicleCount           = stats.VehicleCount,
                EventCount             = stats.EventCount,
                SampleCount            = stats.SampleCount,
                DiscardedSampleCount   = stats.DiscardedSampleCount,
                BoundingBoxDiagonal    = stats.BoundingBoxDiagonal,
                LocationTracking       = new DataModels.LocationTrackingStats {
                    MinutesAtHome   = stats.LocationTracking.MinutesAtHome,
                    MinutesAtWork   = stats.LocationTracking.MinutesAtWork,
                    MinutesAtSchool = stats.LocationTracking.MinutesAtSchool,
                    MinutesAtOtherKnownLocations = stats.LocationTracking.MinutesAtOtherKnownLocations,
                    MinutesElsewhere             = stats.LocationTracking.MinutesElsewhere
                }
            });

            return(Ok(new UploadConfirmation {
                WomLink = voucherRequest.Link,
                WomPassword = voucherRequest.Password,
                WomCount = womCount
            }));
        }