Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make exhibits accessible only within a certain range. #76

Merged
merged 10 commits into from
Oct 31, 2017
3 changes: 3 additions & 0 deletions HiP-DataStore.Model/Entity/Exhibit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class Exhibit : ContentBase

public float Longitude { get; set; }

public float AccessRadius { get; set; }

[BsonElement]
public DocRef<MediaElement> Image { get; private set; } =
new DocRef<MediaElement>(ResourceType.Media.Name);
Expand All @@ -42,6 +44,7 @@ public Exhibit(ExhibitArgs args)
Status = args.Status;
Tags.Add(args.Tags?.Select(id => (BsonValue)id));
Pages.Add(args.Pages?.Select(id => (BsonValue)id));
AccessRadius = args.AccessRadius;
}
}
}
6 changes: 6 additions & 0 deletions HiP-DataStore.Model/Rest/ExhibitArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ public class ExhibitArgs

public List<int> Pages { get; set; }

/// <summary>
/// The radius (in km) in which the exhibit can be accessed.
/// </summary>
[Range(0.001, 1000)]
public float AccessRadius { get; set; }

public IEnumerable<EntityId> GetReferences()
{
if (Image != null)
Expand Down
4 changes: 4 additions & 0 deletions HiP-DataStore.Model/Rest/ExhibitQueryArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@ namespace PaderbornUniversity.SILab.Hip.DataStore.Model.Rest
public class ExhibitQueryArgs : QueryArgs
{
public IList<int> OnlyRoutes { get; set; }

public float? Latitude { get; set; }

public float? Longitude { get; set; }
}
}
3 changes: 3 additions & 0 deletions HiP-DataStore.Model/Rest/ExhibitResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public class ExhibitResult

public float Longitude { get; set; }

public float AccessRadius { get; set; }

public bool Used { get; set; }

public string UserId { get; set; }
Expand All @@ -46,6 +48,7 @@ public ExhibitResult(Exhibit x)
Image = (int?)x.Image.Id;
Latitude = x.Latitude;
Longitude = x.Longitude;
AccessRadius = x.AccessRadius;
Used = x.Referencers.Count > 0; // an exhibit is in use if it is contained in (i.e. referenced by) a route
Pages = x.Pages.Ids.Select(id => (int)id).ToArray();
Status = x.Status;
Expand Down
1 change: 1 addition & 0 deletions HiP-DataStore/Controllers/ExhibitsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public IActionResult Get([FromQuery]ExhibitQueryArgs args)

var exhibits = query
.FilterByIds(args.Exclude, args.IncludeOnly)
.FilterByLocation(args.Latitude, args.Longitude)
.FilterByUser(args.Status,User.Identity)
.FilterByStatus(args.Status, User.Identity)
.FilterByTimestamp(args.Timestamp)
Expand Down
31 changes: 31 additions & 0 deletions HiP-DataStore/Controllers/QueryHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using PaderbornUniversity.SILab.Hip.DataStore.Model.Rest;
using System.Security.Principal;
using PaderbornUniversity.SILab.Hip.DataStore.Utility;
using static System.Math;

namespace PaderbornUniversity.SILab.Hip.DataStore.Controllers
{
Expand Down Expand Up @@ -57,6 +58,36 @@ public static IQueryable<T> FilterByUser<T>(this IQueryable<T> query, ContentSta
return query.FilterIf(!isAllowedGetAll, x =>
((status == ContentStatus.All) && (x.Status == ContentStatus.Published)) || (x.UserId == user.GetUserIdentity()));
}

/// <summary>
/// Returns all entries that are located within the radius, defined within the entry itself, around the given latitude and longitude.
/// If none or only one coordinate is given, all entries are returned.
/// </summary>
public static IQueryable<Exhibit> FilterByLocation(this IQueryable<Exhibit> query, float? latitude, float? longitude)
{
if (latitude != null && longitude != null)
{
return query.ToList()
.Where(o => GetDistanceFromLatLonInKm(o.Latitude, o.Longitude, latitude.Value, longitude.Value) <= o.AccessRadius)
.AsQueryable();
}
return query;
}

/// <summary>
/// Calculates the distance between two points of latitude and longitude in km.
/// </summary>
private static double GetDistanceFromLatLonInKm(float lat1, float lon1, float lat2, float lon2)
{
float dLat = (lat2 - lat1) * (float)PI / 180;
float dLon = (lon2 - lon1) * (float)PI / 180;

double a = Sin(dLat / 2) * Sin(dLat / 2)
+ Cos(lat1 * PI / 180) * Cos(lat2 * PI / 180)
* Sin(dLon / 2) * Sin(dLon / 2);
return 2 * Atan2(Sqrt(a), Sqrt(1-a)) * 6378;
}

/// <summary>
/// Executes the query to determine the number of results, then retrieves a subset of the results
/// (determined by <paramref name="page"/> and <paramref name="pageSize"/>) and projects them to objects of
Expand Down
32 changes: 32 additions & 0 deletions HiP-DataStore/Migrations/Migration6AccessRadius.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using PaderbornUniversity.SILab.Hip.DataStore.Model.Events;
using PaderbornUniversity.SILab.Hip.EventSourcing.Migrations;
using System.Threading.Tasks;

namespace PaderbornUniversity.SILab.Hip.DataStore.Migrations
{
/// <summary>
/// Updating to version 6. Version 6 adds the ability to specify an access radius (in km) for an exhibit.
/// In prior versions, exhibits don't have this property, so a default value is assigned in this migration.
/// </summary>
[StreamMigration(from: 5, to: 6)]
public class Migration6AccessRadius : IStreamMigration
{
public async Task MigrateAsync(IStreamMigrationArgs e)
{
var events = e.GetExistingEvents();

while (await events.MoveNextAsync())
{
// ReSharper disable once CompareOfFloatsByEqualityOperator
if (events.Current is ExhibitCreated exhibitCreated && exhibitCreated.Properties.AccessRadius == 0)
{
// If AccessRadius is still 0, we assume that this exhibit was created in an earlier version
// of DataStore => thus, we now assign it a default radius of 10 meters
exhibitCreated.Properties.AccessRadius = .01f;
}

e.AppendEvent(events.Current);
}
}
}
}