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

Add distance from user location to venue #89

Merged
merged 8 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Src/TournamentCalendar/Configuration/Navigation.config
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
<NavNode key="AddTournament" controller="Calendar" action="NewEntry" text="Turnier eintragen" preservedRouteParameters="">
<Children />
</NavNode>
<NavNode key="GeoLocation" controller="GeoLocation" action="Index" text="Entfernungen anzeigen" preservedRouteParameters="">
<Children />
</NavNode>
<NavNode key="AboutUs" controller="Calendar" action="Integrate" text="In eigene Homepage integrieren">
<Children />
</NavNode>
Expand Down
4 changes: 2 additions & 2 deletions Src/TournamentCalendar/Controllers/Admin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ namespace TournamentCalendar.Controllers;
[Route(nameof(Admin))]
public class Admin : ControllerBase
{
private readonly Microsoft.Extensions.Hosting.IHostApplicationLifetime _applicationLifetime;
private readonly IHostApplicationLifetime _applicationLifetime;

public Admin(Microsoft.Extensions.Hosting.IHostApplicationLifetime appLifetime)
public Admin(IHostApplicationLifetime appLifetime)
{
_applicationLifetime = appLifetime;
}
Expand Down
3 changes: 2 additions & 1 deletion Src/TournamentCalendar/Controllers/Auth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using TournamentCalendar.Models.AccountViewModels;
using TournamentCalendar.Services;
using TournamentCalendar.Views;

namespace TournamentCalendar.Controllers;

public class Auth : ControllerBase
{
public readonly IConfiguration _configuration;
private readonly IConfiguration _configuration;

public Auth(IConfiguration configuration)
{
Expand Down
12 changes: 8 additions & 4 deletions Src/TournamentCalendar/Controllers/Calendar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using TournamentCalendar.Models.Calendar;
using TournamentCalendar.Views;
using TournamentCalendar.Data;
using TournamentCalendar.Services;

namespace TournamentCalendar.Controllers;

Expand All @@ -12,13 +13,15 @@ public class Calendar : ControllerBase
{
private readonly IMailMergeService _mailMergeService;
private readonly string _domainName;
private readonly UserLocation _userLocation;
private readonly ILogger<Calendar> _logger;
private readonly IAppDb _appDb;

public Calendar(IWebHostEnvironment hostingEnvironment, IConfiguration configuration, IAppDb appDb, ILogger<Calendar> logger, IMailMergeService mailMergeService) : base(hostingEnvironment, configuration)
public Calendar(IWebHostEnvironment hostingEnvironment, IConfiguration configuration, IAppDb appDb, ILogger<Calendar> logger, IMailMergeService mailMergeService, UserLocationService locationService) : base(hostingEnvironment, configuration)
{
_mailMergeService = mailMergeService;
_domainName = configuration["DomainName"]!;
_userLocation = locationService.GetLocation();
_appDb = appDb;
_logger = logger;
}
Expand All @@ -33,8 +36,9 @@ public IActionResult Index(CancellationToken cancellationToken)
public async Task<IActionResult> All(CancellationToken cancellationToken)
{
ViewBag.TitleTagText = "Volleyball-Turnierkalender";
var model = new BrowseModel(_appDb);
var model = new BrowseModel(_appDb, _userLocation);
await model.Load(cancellationToken);

return View(ViewName.Calendar.Overview, model);
}

Expand All @@ -46,7 +50,7 @@ public async Task<IActionResult> Id(long id, CancellationToken cancellationToken
if (!ModelState.IsValid)
return new StatusCodeResult(404);

var model = new BrowseModel(_appDb);
var model = new BrowseModel(_appDb, _userLocation);
try
{
await model.Load(id, cancellationToken);
Expand Down Expand Up @@ -138,7 +142,7 @@ public async Task<IActionResult> Entry([FromForm] EditModel model, CancellationT
Configuration.Bind(nameof(GoogleConfiguration), googleApi);
await model.TryGetLongitudeLatitude(googleApi);
model.Normalize();
if (model.IsNew && User.Identity != null && User.Identity.IsAuthenticated)
if (model.IsNew && User.Identity is { IsAuthenticated: true })
{
model.CreatedByUser = User.Identity.Name;
}
Expand Down
3 changes: 2 additions & 1 deletion Src/TournamentCalendar/Controllers/ContentSynd.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.Extensions.Primitives;
using TournamentCalendar.Data;
using TournamentCalendar.Services;
using TournamentCalendar.Views;

namespace TournamentCalendar.Controllers;
Expand Down Expand Up @@ -28,7 +29,7 @@ public async Task<IActionResult> CalendarList([FromHeader(Name = "Referrer")] st
// Cross Origin Request Sharing (CORS) - allow request from any domain:
Response.Headers.Append("Access-Control-Allow-Origin", "*");
_logger.LogInformation("Host: {RemoteIp}, Referrer: {Referrer}", GetRemoteIpAddress(xForwardedFor, remoteAddr), referrer);
var model = new Models.Calendar.BrowseModel(_appDb);
var model = new Models.Calendar.BrowseModel(_appDb, new UserLocation(null, null));
await model.Load(cancellationToken);
return PartialView(ViewName.ContentSynd.CalendarListPartial, model);
}
Expand Down
93 changes: 93 additions & 0 deletions Src/TournamentCalendar/Controllers/GeoLocation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using TournamentCalendar.Data;
using TournamentCalendar.Services;
using TournamentCalendar.Views;
using TournamentCalendar.Models.GeoLocation;
using TournamentCalendar.Library;

namespace TournamentCalendar.Controllers;

/// <summary>
/// The GeoLocation controller is responsible for handling the user's location.
/// </summary>
[Route(nameof(GeoLocation))]
public class GeoLocation : ControllerBase
{
private readonly UserLocationService _locationService;
private readonly IAppDb _appDb;

/// <summary>
/// Initializes a new instance of the <see cref="GeoLocation"/> class.
/// </summary>
/// <param name="appDb"></param>
/// <param name="locationService"></param>
public GeoLocation(IAppDb appDb, UserLocationService locationService, IConfiguration configuration)
{
_appDb = appDb;
_locationService = locationService;
Configuration = configuration;
}

[HttpGet("")]
public IActionResult Index()
{
ViewBag.TitleTagText = "Entfernungen anzeigen";
var model = new EditModel();
model.SetAppDb(_appDb);
return View(ViewName.GeoLocation.Index, model);
}

/// <summary>
/// Sets the location from a user's GUID.
/// </summary>
/// <param name="guid"></param>
[HttpGet("location/{guid}")]
public IActionResult Location(Guid guid)
{
if (!ModelState.IsValid)
return RedirectToAction(nameof(Calendar.All), nameof(Controllers.Calendar));

_locationService.SetFromUserGuid(guid);

return RedirectToAction(nameof(Calendar.All), nameof(Controllers.Calendar));
}

[HttpPost("location/{model}")]
public async Task<IActionResult> Location([FromForm] EditModel model)
{
model.SetAppDb(_appDb);

if (!ModelState.IsValid)
return View(ViewName.GeoLocation.Index, model);

var googleApi = new GoogleConfiguration();
Configuration.Bind(nameof(GoogleConfiguration), googleApi);
var userLocation = await model.TryGetLongitudeLatitude(googleApi);
_locationService.SetGeoLocation(userLocation);

return RedirectToAction(nameof(GeoLocation.Index), nameof(Controllers.GeoLocation));
}

[HttpGet("location/{latitude}/{longitude}")]
public IActionResult Location(double latitude, double longitude)
{
if(!UserLocationService.IsValidLatitude(latitude))
ModelState.AddModelError(nameof(latitude), "Latitude is invalid.");

if (!UserLocationService.IsValidLongitude(longitude))
ModelState.AddModelError(nameof(longitude), "Longitude is invalid.");

if (!ModelState.IsValid)
_locationService.ClearGeoLocation();

_locationService.SetGeoLocation(latitude, longitude);

return NoContent();
}

[HttpGet("clear")]
public IActionResult ClearLocation()
{
_locationService.ClearGeoLocation();
return RedirectToAction(nameof(GeoLocation.Index), nameof(Controllers.GeoLocation));
}
}
65 changes: 39 additions & 26 deletions Src/TournamentCalendar/Controllers/InfoService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using TournamentCalendar.Views;
using TournamentCalendar.Library;
using TournamentCalendar.Data;
using TournamentCalendar.Services;

namespace TournamentCalendar.Controllers;

Expand All @@ -13,10 +14,12 @@ public class InfoService : ControllerBase
private readonly IMailMergeService _mailMergeService;
private readonly ILogger<InfoService> _logger;
private readonly IAppDb _appDb;
private readonly UserLocationService _locationService;

public InfoService(IAppDb appDb, IWebHostEnvironment hostingEnvironment, IConfiguration configuration, ILogger<InfoService> logger, IMailMergeService mailMergeService) : base(hostingEnvironment, configuration)
public InfoService(IAppDb appDb, IWebHostEnvironment hostingEnvironment, IConfiguration configuration, ILogger<InfoService> logger, UserLocationService locationService, IMailMergeService mailMergeService) : base(hostingEnvironment, configuration)
{
_appDb = appDb;
_locationService = locationService;
_domainName = configuration["DomainName"]!;
_mailMergeService = mailMergeService;
_logger = logger;
Expand All @@ -32,7 +35,9 @@ public IActionResult Index()
public IActionResult Register()
{
ViewBag.TitleTagText = "Volley-News abonnieren";
return View(ViewName.InfoService.Edit, new Models.InfoService.EditModel(_appDb) { EditMode = Models.InfoService.EditMode.New });
var model = new Models.InfoService.EditModel { EditMode = Models.InfoService.EditMode.New };
model.SetAppDb(_appDb);
return View(ViewName.InfoService.Edit, model);
}

[HttpGet(nameof(Entry))]
Expand All @@ -50,7 +55,12 @@ public IActionResult Entry(string guid)
return RedirectToAction(nameof(InfoService.Index), nameof(Controllers.InfoService));
}

var model = new Models.InfoService.EditModel(_appDb, guid) { EditMode = Models.InfoService.EditMode.Change };
var model = new Models.InfoService.EditModel { EditMode = Models.InfoService.EditMode.Change };
model.SetAppDb(_appDb, guid);

if (!model.IsNew && !_locationService.GetLocation().IsSet)
_locationService.SetGeoLocation(new UserLocation(model.Latitude, model.Longitude));

return model.IsNew // id not found
? RedirectToAction(nameof(InfoService.Index), nameof(Controllers.InfoService))
: View(ViewName.InfoService.Edit, model);
Expand All @@ -62,34 +72,33 @@ public IActionResult Entry(string guid)
[HttpPost(nameof(InfoService.Entry)), ValidateAntiForgeryToken]
public async Task<IActionResult> Entry([FromForm] Models.InfoService.EditModel model, CancellationToken cancellationToken)
{
model = new Models.InfoService.EditModel(_appDb);
_ = await TryUpdateModelAsync<Models.InfoService.EditModel>(model);

ViewBag.TitleTagText = "Volley-News abonnieren";

model.SetAppDb(_appDb);
_ = await TryUpdateModelAsync(model);

model.EditMode = string.IsNullOrWhiteSpace(model.Guid) ? Models.InfoService.EditMode.New : Models.InfoService.EditMode.Change;

if (!ModelState.IsValid && model.ExistingEntryWithSameEmail != null)
{
if (!ModelState.IsValid && model.ExistingEntryWithSameEmail is { ConfirmedOn: null })
// if the entry with this email address was not yet confirmed, just redirect there
if (!model.ExistingEntryWithSameEmail.ConfirmedOn.HasValue)
{
return RedirectToAction(nameof(InfoService.Entry), nameof(Controllers.InfoService), new {guid = model.ExistingEntryWithSameEmail.Guid });
}

// todo: what to do, if the email was already confirmed? Re-send confirmation email without asking?
{
return RedirectToAction(nameof(InfoService.Entry), nameof(Controllers.InfoService), new {guid = model.ExistingEntryWithSameEmail.Guid });
}

// todo: what to do, if the email was already confirmed? Re-send confirmation email without asking?
if (!ModelState.IsValid)
{
model.Normalize(ModelState);
return View(ViewName.InfoService.Edit, model);
}

ModelState.Clear();
if (model.EditMode == Models.InfoService.EditMode.Change)
if (model.TryRefetchEntity())
if (!await TryUpdateModelAsync<Models.InfoService.EditModel>(model))
return View(ViewName.InfoService.Edit, model);
if (model.EditMode == Models.InfoService.EditMode.Change
&& (!model.TryFetchEntity()
|| !await TryUpdateModelAsync<Models.InfoService.EditModel>(model)))
{
return View(ViewName.InfoService.Edit, model);
}

var googleApi = new GoogleConfiguration();
Configuration.Bind(nameof(GoogleConfiguration), googleApi);
Expand All @@ -102,14 +111,18 @@ public async Task<IActionResult> Entry([FromForm] Models.InfoService.EditModel m
{
HttpContext.Session.Remove(Axuno.Web.CaptchaSvgGenerator.CaptchaSessionKeyName);

if ((confirmationModel = await model.Save(cancellationToken)).SaveSuccessful)
confirmationModel = await model.Save(cancellationToken);
if (!confirmationModel.SaveSuccessful)
return View(ViewName.InfoService.Confirm, confirmationModel);

if (confirmationModel.Entity?.UnSubscribedOn == null)
{
if (confirmationModel.Entity?.UnSubscribedOn == null)
{
confirmationModel = await new Mailer(_mailMergeService, _domainName).MailInfoServiceRegistrationForm(confirmationModel,
Url.Action(nameof(Approve), nameof(Controllers.InfoService), new {guid = model.Guid})!,
Url.Action(nameof(Entry), nameof(Controllers.InfoService), new { guid = model.Guid})!);
}
if (model is { Latitude: not null, Longitude: not null })
_locationService.SetGeoLocation(model.Latitude.Value, model.Longitude.Value);

confirmationModel = await new Mailer(_mailMergeService, _domainName).MailInfoServiceRegistrationForm(confirmationModel,
Url.Action(nameof(Approve), nameof(Controllers.InfoService), new {guid = model.Guid})!,
Url.Action(nameof(Entry), nameof(Controllers.InfoService), new { guid = model.Guid})!);
}

return View(ViewName.InfoService.Confirm, confirmationModel);
Expand All @@ -129,7 +142,7 @@ public async Task<IActionResult> Unsubscribe([FromForm] Models.InfoService.EditM
{
if (!ModelState.IsValid)
{
// We unregister the subsc
// We unregister the subscription
}

ViewBag.TitleTagText = "Volley-News abbestellen";
Expand Down
7 changes: 5 additions & 2 deletions Src/TournamentCalendar/Controllers/Newsletter.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
using TournamentCalendar.Data;
using TournamentCalendar.Models.Newsletter;
using TournamentCalendar.Services;

namespace TournamentCalendar.Controllers;

[Route("nl")]
public class Newsletter : ControllerBase
{
private readonly IAppDb _appDb;
private readonly UserLocation _userLocation;

public Newsletter(IAppDb appDb)
public Newsletter(IAppDb appDb, UserLocationService locationService)
{
_appDb = appDb;
_userLocation = locationService.GetLocation();
}

[HttpGet("show")]
public async Task<IActionResult> Show(CancellationToken cancellationToken)
{
var model = await new NewsletterModel(_appDb).InitializeAndLoad(cancellationToken);
var model = await new NewsletterModel(_appDb, _userLocation).InitializeAndLoad(cancellationToken);

return View("Show", model);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Globalization;
using System.Globalization;

namespace Axuno.Tools.GeoSpatial;

Expand Down Expand Up @@ -389,7 +388,7 @@ internal static NumberFormatInfo GetNumberFormatInfo(IFormatProvider? provider)
numberFormat = provider.GetFormat(typeof(NumberFormatInfo)) as NumberFormatInfo;
}

return numberFormat ?? CultureInfo.CurrentUICulture.NumberFormat;
return numberFormat ?? CultureInfo.CurrentUICulture.NumberFormat;
}

/// <summary>
Expand Down
Loading