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); }
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)); }
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)); }
public Point Decode(string geohash) { var result = hasher.Decode(geohash); return(new Point(result.Item2, result.Item1)); }
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 })); }