public async Task <ActionResult> UpdateSeasons() { var beforeUpdate = await _tournamentDataSource.ReadTournamentByRoute(Request.RawUrl).ConfigureAwait(false); var model = new EditTournamentViewModel(CurrentPage, Services.UserService) { Tournament = beforeUpdate }; model.Tournament.Seasons = Request.Form["Tournament.Seasons"]?.Split(',').Select(x => new Season { SeasonId = new Guid(x) }).ToList() ?? new List <Season>(); model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Tournament); if (model.IsAuthorized[AuthorizedAction.EditTournament]) { var currentMember = Members.GetCurrentMember(); var updatedTournament = await _tournamentRepository.UpdateSeasons(model.Tournament, currentMember.Key, Members.CurrentUserName, currentMember.Name).ConfigureAwait(false); await _cacheClearer.ClearCacheFor(updatedTournament).ConfigureAwait(false); } return(_postSaveRedirector.WorkOutRedirect(model.Tournament.TournamentRoute, model.Tournament.TournamentRoute, "/edit", Request.Form["UrlReferrer"], null)); }
public async override Task <ActionResult> Index(ContentModel contentModel) { if (contentModel is null) { throw new System.ArgumentNullException(nameof(contentModel)); } var model = new TournamentViewModel(contentModel.Content, Services?.UserService) { Tournament = await _tournamentDataSource.ReadTournamentByRoute(Request.RawUrl).ConfigureAwait(false), DateTimeFormatter = _dateFormatter }; if (model.Tournament == null) { return(new HttpNotFoundResult()); } else { model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Tournament); model.Metadata.PageTitle = model.Tournament.TournamentFullNameAndPlayerType(x => _dateFormatter.FormatDate(x, false, false, false)); model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative) }); model.Breadcrumbs.Add(new Breadcrumb { Name = model.Tournament.TournamentName, Url = new Uri(model.Tournament.TournamentRoute, UriKind.Relative) }); return(CurrentTemplate(model)); } }
public async Task <ActionResult> DeleteTournament([Bind(Prefix = "ConfirmDeleteRequest", Include = "RequiredText,ConfirmationText")] MatchingTextConfirmation postedModel) { if (postedModel is null) { throw new ArgumentNullException(nameof(postedModel)); } var model = new DeleteTournamentViewModel(CurrentPage, Services.UserService) { Tournament = await _tournamentDataSource.ReadTournamentByRoute(Request.RawUrl).ConfigureAwait(false), DateTimeFormatter = _dateTimeFormatter }; model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Tournament); if (model.IsAuthorized[AuthorizedAction.DeleteTournament] && ModelState.IsValid) { var currentMember = Members.GetCurrentMember(); await _tournamentRepository.DeleteTournament(model.Tournament, currentMember.Key, currentMember.Name).ConfigureAwait(false); await _cacheClearer.ClearCacheFor(model.Tournament).ConfigureAwait(false); model.Deleted = true; } else { model.TotalComments = await _commentsDataSource.ReadTotalComments(model.Tournament.TournamentId.Value).ConfigureAwait(false); model.Matches = new MatchListingViewModel(CurrentPage, Services?.UserService) { Matches = await _matchListingDataSource.ReadMatchListings(new MatchFilter { TournamentId = model.Tournament.TournamentId, IncludeTournamentMatches = true, IncludeTournaments = false }, MatchSortOrder.MatchDateEarliestFirst).ConfigureAwait(false) }; } model.Metadata.PageTitle = "Delete " + model.Tournament.TournamentFullNameAndPlayerType(x => _dateTimeFormatter.FormatDate(x, false, false, false)); model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative) }); if (!model.Deleted) { model.Breadcrumbs.Add(new Breadcrumb { Name = model.Tournament.TournamentName, Url = new Uri(model.Tournament.TournamentRoute, UriKind.Relative) }); } return(View("DeleteTournament", model)); }
public async override Task <ActionResult> Index(ContentModel contentModel) { if (contentModel is null) { throw new ArgumentNullException(nameof(contentModel)); } var model = new TournamentViewModel(contentModel.Content, Services?.UserService) { Tournament = await _tournamentDataSource.ReadTournamentByRoute(Request.Url.AbsolutePath).ConfigureAwait(false), DateTimeFormatter = _dateFormatter }; if (model.Tournament == null) { return(new HttpNotFoundResult()); } else { model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Tournament); model.Tournament.Comments = await _commentsDataSource.ReadComments(model.Tournament.TournamentId.Value).ConfigureAwait(false); foreach (var comment in model.Tournament.Comments) { comment.Comment = _emailProtector.ProtectEmailAddresses(comment.Comment, User.Identity.IsAuthenticated); comment.Comment = _badLanguageFilter.Filter(comment.Comment); } var filter = _matchFilterFactory.MatchesForTournament(model.Tournament.TournamentId.Value); model.Matches = new MatchListingViewModel(contentModel.Content, Services?.UserService) { Matches = await _matchDataSource.ReadMatchListings(filter.filter, filter.sortOrder).ConfigureAwait(false), ShowMatchDate = false, HighlightNextMatch = false, DateTimeFormatter = _dateFormatter }; model.Metadata.PageTitle = model.Tournament.TournamentFullNameAndPlayerType(x => _dateFormatter.FormatDate(x, false, false, false)); model.Metadata.Description = model.Tournament.Description(); model.Tournament.TournamentNotes = _emailProtector.ProtectEmailAddresses(model.Tournament.TournamentNotes, User.Identity.IsAuthenticated); model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative) }); return(CurrentTemplate(model)); } }
public async override Task <ActionResult> Index(ContentModel contentModel) { if (contentModel is null) { throw new System.ArgumentNullException(nameof(contentModel)); } var model = new DeleteTournamentViewModel(contentModel.Content, Services?.UserService) { Tournament = await _tournamentDataSource.ReadTournamentByRoute(Request.RawUrl).ConfigureAwait(false), DateTimeFormatter = _dateFormatter }; if (model.Tournament == null) { return(new HttpNotFoundResult()); } else { model.TotalComments = await _tournamentCommentsDataSource.ReadTotalComments(model.Tournament.TournamentId.Value).ConfigureAwait(false); model.Matches = new MatchListingViewModel(contentModel.Content, Services?.UserService) { Matches = await _matchDataSource.ReadMatchListings(new MatchFilter { TournamentId = model.Tournament.TournamentId, IncludeTournamentMatches = true, IncludeTournaments = false }, MatchSortOrder.MatchDateEarliestFirst).ConfigureAwait(false) }; model.ConfirmDeleteRequest.RequiredText = model.Tournament.TournamentName; model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Tournament); model.Metadata.PageTitle = "Delete " + model.Tournament.TournamentFullNameAndPlayerType(x => _dateFormatter.FormatDate(x, false, false, false)); model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative) }); model.Breadcrumbs.Add(new Breadcrumb { Name = model.Tournament.TournamentName, Url = new Uri(model.Tournament.TournamentRoute, UriKind.Relative) }); return(CurrentTemplate(model)); } }
public async Task <ActionResult> UpdateTeams([Bind(Prefix = "Tournament", Include = "MaximumTeamsInTournament,Teams")] Tournament postedTournament) { if (postedTournament is null) { throw new ArgumentNullException(nameof(postedTournament)); } var beforeUpdate = await _tournamentDataSource.ReadTournamentByRoute(Request.RawUrl).ConfigureAwait(false); var model = new EditTournamentViewModel(CurrentPage, Services.UserService) { Tournament = beforeUpdate, DateFormatter = _dateTimeFormatter }; model.Tournament.MaximumTeamsInTournament = postedTournament.MaximumTeamsInTournament; model.Tournament.Teams = postedTournament.Teams; // We're not interested in validating other details of the tournament or the selected teams foreach (var key in ModelState.Keys.Where(x => x != "Tournament.MaximumTeamsInTournament")) { ModelState[key].Errors.Clear(); } model.IsAuthorized = _authorizationPolicy.IsAuthorized(beforeUpdate); if (model.IsAuthorized[AuthorizedAction.EditTournament] && ModelState.IsValid) { var currentMember = Members.GetCurrentMember(); var updatedTournament = await _tournamentRepository.UpdateTeams(model.Tournament, currentMember.Key, Members.CurrentUserName, currentMember.Name).ConfigureAwait(false); await _cacheClearer.ClearCacheFor(updatedTournament).ConfigureAwait(false); return(_postSaveRedirector.WorkOutRedirect(model.Tournament.TournamentRoute, updatedTournament.TournamentRoute, "/edit", Request.Form["UrlReferrer"], null)); } model.Metadata.PageTitle = "Teams in the " + model.Tournament.TournamentFullName(x => _dateTimeFormatter.FormatDate(x, false, false, false)); model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative) }); model.Breadcrumbs.Add(new Breadcrumb { Name = model.Tournament.TournamentName, Url = new Uri(model.Tournament.TournamentRoute, UriKind.Relative) }); return(View("EditTournamentTeams", model)); }
public async override Task <ActionResult> Index(ContentModel contentModel) { if (contentModel is null) { throw new ArgumentNullException(nameof(contentModel)); } var model = new EditTournamentViewModel(contentModel.Content, Services?.UserService) { Tournament = await _tournamentDataSource.ReadTournamentByRoute(Request.RawUrl).ConfigureAwait(false), DateFormatter = _dateFormatter, UrlReferrer = Request.UrlReferrer }; if (model.Tournament == null) { return(new HttpNotFoundResult()); } else { model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Tournament); model.Tournament.Matches = (await _matchDataSource.ReadMatchListings(new MatchFilter { TournamentId = model.Tournament.TournamentId, IncludeTournamentMatches = true, IncludeTournaments = false }, MatchSortOrder.MatchDateEarliestFirst).ConfigureAwait(false)) .Select(x => new MatchInTournament { MatchId = x.MatchId, MatchName = x.MatchName }).ToList(); model.Metadata.PageTitle = "Matches in the " + model.Tournament.TournamentFullName(x => _dateFormatter.FormatDate(x, false, false, false)); model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative) }); model.Breadcrumbs.Add(new Breadcrumb { Name = model.Tournament.TournamentName, Url = new Uri(model.Tournament.TournamentRoute, UriKind.Relative) }); return(CurrentTemplate(model)); } }
public async override Task <ActionResult> Index(ContentModel contentModel) { if (contentModel is null) { throw new ArgumentNullException(nameof(contentModel)); } var model = new EditTournamentViewModel(contentModel.Content, Services?.UserService) { Tournament = await _tournamentDataSource.ReadTournamentByRoute(Request.RawUrl).ConfigureAwait(false), DateFormatter = _dateFormatter }; if (model.Tournament == null) { return(new HttpNotFoundResult()); } else { model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Tournament); model.TournamentDate = model.Tournament.StartTime; if (model.Tournament.StartTimeIsKnown) { model.StartTime = model.Tournament.StartTime; } model.TournamentLocationId = model.Tournament.TournamentLocation?.MatchLocationId; model.TournamentLocationName = model.Tournament.TournamentLocation?.NameAndLocalityOrTownIfDifferent(); if (!model.Tournament.DefaultOverSets.Any()) { model.Tournament.DefaultOverSets.Add(new OverSet()); } model.Metadata.PageTitle = "Edit " + model.Tournament.TournamentFullName(x => _dateFormatter.FormatDate(x, false, false, false)); model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative) }); model.Breadcrumbs.Add(new Breadcrumb { Name = model.Tournament.TournamentName, Url = new Uri(model.Tournament.TournamentRoute, UriKind.Relative) }); return(CurrentTemplate(model)); } }
public async Task <ActionResult> UpdateMatches([Bind(Prefix = "Tournament", Include = "Matches")] Tournament postedTournament) { var beforeUpdate = await _tournamentDataSource.ReadTournamentByRoute(Request.RawUrl).ConfigureAwait(false); var model = new EditTournamentViewModel(CurrentPage, Services.UserService) { Tournament = beforeUpdate, DateFormatter = _dateTimeFormatter }; model.Tournament.Matches = postedTournament?.Matches ?? new List <MatchInTournament>(); // We're not interested in validating anything with a data annotation attribute foreach (var key in ModelState.Keys) { ModelState[key].Errors.Clear(); } var teamsInTournament = model.Tournament.Teams.Select(x => x.TournamentTeamId.Value); foreach (var added in model.Tournament.Matches.Where(x => !x.MatchId.HasValue)) { if (added.Teams.Count < 2 || !added.Teams[0].TournamentTeamId.HasValue || !added.Teams[1].TournamentTeamId.HasValue || added.Teams[0].TournamentTeamId == added.Teams[1].TournamentTeamId) { ModelState.AddModelError(string.Empty, $"Please remove '{added.MatchName}'. A match must be between two different teams."); } // Check for a TournamentTeamId that's not in the tournament. Pretty unlikely since it would require editing the request or a race where // the team is removed before this page is submitted, but since we can test we should. if (ModelState.IsValid) { foreach (var team in added.Teams) { if (!teamsInTournament.Contains(team.TournamentTeamId.Value)) { ModelState.AddModelError(string.Empty, $"Please remove '{added.MatchName}'. We cannot add a match for a team that's not in the tournament."); } } } } model.IsAuthorized = _authorizationPolicy.IsAuthorized(beforeUpdate); if (model.IsAuthorized[AuthorizedAction.EditTournament] && ModelState.IsValid) { var currentMember = Members.GetCurrentMember(); var updatedTournament = await _tournamentRepository.UpdateMatches(model.Tournament, currentMember.Key, Members.CurrentUserName, currentMember.Name).ConfigureAwait(false); await _cacheClearer.ClearCacheFor(updatedTournament).ConfigureAwait(false); // Use a regex to prevent part 4 of the journey Edit Matches > Edit Teams > Edit Matches > Edit Teams return(_postSaveRedirector.WorkOutRedirect(model.Tournament.TournamentRoute, updatedTournament.TournamentRoute, "/edit", Request.Form["UrlReferrer"], $"^({updatedTournament.TournamentRoute}|{updatedTournament.TournamentRoute}/edit)$")); } model.Metadata.PageTitle = "Matches in the " + model.Tournament.TournamentFullName(x => _dateTimeFormatter.FormatDate(x, false, false, false)); model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative) }); model.Breadcrumbs.Add(new Breadcrumb { Name = model.Tournament.TournamentName, Url = new Uri(model.Tournament.TournamentRoute, UriKind.Relative) }); return(View("EditTournamentMatches", model)); }
public async override Task <ActionResult> Index(ContentModel contentModel) { if (contentModel is null) { throw new ArgumentNullException(nameof(contentModel)); } var model = new MatchListingViewModel(contentModel.Content, Services?.UserService) { DefaultMatchFilter = new MatchFilter { FromDate = DateTimeOffset.UtcNow.Date, IncludeMatches = true, IncludeTournaments = true, IncludeTournamentMatches = false }, DateTimeFormatter = _dateFormatter }; model.AppliedMatchFilter = _matchFilterQueryStringParser.ParseQueryString(model.DefaultMatchFilter, HttpUtility.ParseQueryString(Request.Url.Query)); // Don't allow matches in the past - this is a calendar for planning future events if (model.AppliedMatchFilter.FromDate < model.DefaultMatchFilter.FromDate) { model.AppliedMatchFilter.FromDate = model.DefaultMatchFilter.FromDate; } var pageTitle = "Stoolball matches and tournaments"; var legacyTournamentsCalendarUrl = Regex.Match(Request.RawUrl, "/tournaments/(all|mixed|ladies|junior)/calendar.ics", RegexOptions.IgnoreCase); if (Request.RawUrl.StartsWith("/matches.ics", StringComparison.OrdinalIgnoreCase)) { model.AppliedMatchFilter.IncludeTournaments = false; pageTitle = "Stoolball matches"; } else if (legacyTournamentsCalendarUrl.Success || Request.RawUrl.StartsWith("/tournaments.ics", StringComparison.OrdinalIgnoreCase)) { model.AppliedMatchFilter.IncludeMatches = false; pageTitle = "Stoolball tournaments"; if (legacyTournamentsCalendarUrl.Success) { switch (legacyTournamentsCalendarUrl.Groups[1].Value.ToUpperInvariant()) { case "MIXED": model.AppliedMatchFilter.PlayerTypes.Add(PlayerType.Mixed); break; case "LADIES": model.AppliedMatchFilter.PlayerTypes.Add(PlayerType.Ladies); break; case "JUNIOR": model.AppliedMatchFilter.PlayerTypes.Add(PlayerType.JuniorMixed); model.AppliedMatchFilter.PlayerTypes.Add(PlayerType.JuniorGirls); model.AppliedMatchFilter.PlayerTypes.Add(PlayerType.JuniorBoys); break; default: break; } } } else if (Request.RawUrl.StartsWith("/tournaments/", StringComparison.OrdinalIgnoreCase)) { var tournament = await _tournamentDataSource.ReadTournamentByRoute(Request.RawUrl).ConfigureAwait(false); if (tournament == null) { return(new HttpNotFoundResult()); } pageTitle = tournament.TournamentFullName(x => tournament.StartTimeIsKnown ? _dateFormatter.FormatDateTime(tournament.StartTime, true, false) : _dateFormatter.FormatDate(tournament.StartTime, true, false)); model.Matches.Add(tournament.ToMatchListing()); } else if (Request.RawUrl.StartsWith("/matches/", StringComparison.OrdinalIgnoreCase)) { var match = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false); if (match == null) { return(new HttpNotFoundResult()); } pageTitle = match.MatchFullName(x => match.StartTimeIsKnown ? _dateFormatter.FormatDateTime(match.StartTime, true, false) : _dateFormatter.FormatDate(match.StartTime, true, false)); model.Matches.Add(match.ToMatchListing()); } else if (Request.RawUrl.StartsWith("/clubs/", StringComparison.OrdinalIgnoreCase)) { var club = await _clubDataSource.ReadClubByRoute(Request.RawUrl).ConfigureAwait(false); if (club == null) { return(new HttpNotFoundResult()); } pageTitle += " for " + club.ClubName; model.AppliedMatchFilter.TeamIds.AddRange(club.Teams.Select(x => x.TeamId.Value)); } else if (Request.RawUrl.StartsWith("/teams/", StringComparison.OrdinalIgnoreCase)) { var team = await _teamDataSource.ReadTeamByRoute(Request.RawUrl).ConfigureAwait(false); if (team == null) { return(new HttpNotFoundResult()); } pageTitle += " for " + team.TeamName; model.AppliedMatchFilter.TeamIds.Add(team.TeamId.Value); } else if (Request.RawUrl.StartsWith("/competitions/", StringComparison.OrdinalIgnoreCase)) { var competition = await _competitionDataSource.ReadCompetitionByRoute(Request.RawUrl).ConfigureAwait(false); if (competition == null) { return(new HttpNotFoundResult()); } pageTitle += " in the " + competition.CompetitionName; model.AppliedMatchFilter.CompetitionIds.Add(competition.CompetitionId.Value); } else if (Request.RawUrl.StartsWith("/locations/", StringComparison.OrdinalIgnoreCase)) { var location = await _matchLocationDataSource.ReadMatchLocationByRoute(Request.RawUrl).ConfigureAwait(false); if (location == null) { return(new HttpNotFoundResult()); } pageTitle += " at " + location.NameAndLocalityOrTown(); model.AppliedMatchFilter.MatchLocationIds.Add(location.MatchLocationId.Value); } // Remove from date from filter if it's the default, and describe the remainder in the feed title. var clonedFilter = model.AppliedMatchFilter.Clone(); if (clonedFilter.FromDate == model.DefaultMatchFilter.FromDate) { clonedFilter.FromDate = null; } model.Metadata.PageTitle = pageTitle + _matchFilterHumanizer.MatchingFilter(clonedFilter); if (model.AppliedMatchFilter.PlayerTypes.Any()) { model.Metadata.PageTitle = $"{model.AppliedMatchFilter.PlayerTypes.First().Humanize(LetterCasing.Sentence).Replace("Junior mixed", "Junior")} {model.Metadata.PageTitle.ToLower(CultureInfo.CurrentCulture)}"; } if (!model.Matches.Any()) { model.Matches = await _matchListingDataSource.ReadMatchListings(model.AppliedMatchFilter, MatchSortOrder.LatestUpdateFirst).ConfigureAwait(false); } return(CurrentTemplate(model)); }
public async override Task <ActionResult> Index(ContentModel contentModel) { if (contentModel is null) { throw new ArgumentNullException(nameof(contentModel)); } var model = new EditTournamentViewModel(contentModel.Content, Services?.UserService) { Tournament = await _tournamentDataSource.ReadTournamentByRoute(Request.RawUrl).ConfigureAwait(false), DateFormatter = _dateFormatter, UrlReferrer = Request.UrlReferrer }; if (model.Tournament == null) { return(new HttpNotFoundResult()); } else { // By filtering for all match types it excludes seasons for annual tournaments like Expo and Seaford, which may support training sessions // but otherwise no match types. Although those tournaments can be listed in other seasons (they're of interest to the league teams), we // don't want other tournaments listed on pages which are supposed to be just about those annual tournaments. For any tournaments which // actually are meant to be in those seasons, they will be added back when the tournament's current seasons are added to the list. var seasonDates = _seasonEstimator.EstimateSeasonDates(model.Tournament.StartTime); var filter = new CompetitionFilter { FromYear = seasonDates.fromDate.Year, UntilYear = seasonDates.untilDate.Year, PlayerTypes = new List <PlayerType> { model.Tournament.PlayerType }, MatchTypes = new List <MatchType> { MatchType.FriendlyMatch, MatchType.KnockoutMatch, MatchType.LeagueMatch }, EnableTournaments = true }; model.PossibleSeasons.AddRange(await _seasonDataSource.ReadSeasons(filter).ConfigureAwait(false)); foreach (var season in model.Tournament.Seasons) { if (!model.PossibleSeasons.Select(x => x.SeasonId.Value).Contains(season.SeasonId.Value)) { model.PossibleSeasons.Add(season); } } model.PossibleSeasons.Sort(new SeasonComparer()); model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Tournament); model.TournamentDate = model.Tournament.StartTime; model.Metadata.PageTitle = "Where to list " + model.Tournament.TournamentFullName(x => _dateFormatter.FormatDate(x, false, false, false)); model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative) }); model.Breadcrumbs.Add(new Breadcrumb { Name = model.Tournament.TournamentName, Url = new Uri(model.Tournament.TournamentRoute, UriKind.Relative) }); return(CurrentTemplate(model)); } }
public async Task <ActionResult> UpdateTournament([Bind(Prefix = "Tournament", Include = "TournamentName,QualificationType,PlayerType,PlayersPerTeam,DefaultOverSets")] Tournament postedTournament) { if (postedTournament is null) { throw new ArgumentNullException(nameof(postedTournament)); } var beforeUpdate = await _tournamentDataSource.ReadTournamentByRoute(Request.RawUrl).ConfigureAwait(false); postedTournament.DefaultOverSets.RemoveAll(x => !x.Overs.HasValue); var model = new EditTournamentViewModel(CurrentPage, Services.UserService) { Tournament = beforeUpdate, DateFormatter = _dateTimeFormatter }; model.Tournament.TournamentName = postedTournament.TournamentName; model.Tournament.QualificationType = postedTournament.QualificationType; model.Tournament.PlayerType = postedTournament.PlayerType; model.Tournament.PlayersPerTeam = postedTournament.PlayersPerTeam; model.Tournament.DefaultOverSets = postedTournament.DefaultOverSets; // get this from the unvalidated form instead of via modelbinding so that HTML can be allowed model.Tournament.TournamentNotes = Request.Unvalidated.Form["Tournament.TournamentNotes"]; if (!string.IsNullOrEmpty(Request.Form["TournamentDate"]) && DateTimeOffset.TryParse(Request.Form["TournamentDate"], out var parsedDate)) { model.TournamentDate = parsedDate; model.Tournament.StartTime = model.TournamentDate.Value; if (!string.IsNullOrEmpty(Request.Form["StartTime"])) { if (DateTimeOffset.TryParse(Request.Form["StartTime"], out var parsedTime)) { model.StartTime = parsedTime; model.Tournament.StartTime = model.Tournament.StartTime.Add(model.StartTime.Value.TimeOfDay); model.Tournament.StartTimeIsKnown = true; } else { // This may be seen in browsers that don't support <input type="time" />, mainly Safari. // Each browser that supports <input type="time" /> may have a very different interface so don't advertise // this format up-front as it could confuse the majority. Instead, only reveal it here. ModelState.AddModelError("StartTime", "Enter a time in 24-hour HH:MM format."); } } else { // If no start time specified, use a typical one but don't show it model.Tournament.StartTime.AddHours(11); model.Tournament.StartTimeIsKnown = false; } } else { // This may be seen in browsers that don't support <input type="date" />, mainly Safari. // This is the format <input type="date" /> expects and posts, so we have to repopulate the field in this format, // so although this code _can_ parse other formats we don't advertise that. We also don't want YYYY-MM-DD in // the field label as it would confuse the majority, so only reveal it here. ModelState.AddModelError("TournamentDate", "Enter a date in YYYY-MM-DD format."); } _matchValidator.DateIsValidForSqlServer(() => model.TournamentDate, ModelState, "TournamentDate", "tournament"); _matchValidator.DateIsWithinTheSeason(() => model.TournamentDate, model.Tournament.Seasons.FirstOrDefault(), ModelState, "TournamentDate", "tournament"); if (!string.IsNullOrEmpty(Request.Form["TournamentLocationId"])) { model.TournamentLocationId = new Guid(Request.Form["TournamentLocationId"]); model.TournamentLocationName = Request.Form["TournamentLocationName"]; model.Tournament.TournamentLocation = new MatchLocation { MatchLocationId = model.TournamentLocationId }; } model.IsAuthorized = _authorizationPolicy.IsAuthorized(beforeUpdate); if (model.IsAuthorized[AuthorizedAction.EditTournament] && ModelState.IsValid) { var currentMember = Members.GetCurrentMember(); var updatedTournament = await _tournamentRepository.UpdateTournament(model.Tournament, currentMember.Key, currentMember.Name).ConfigureAwait(false); await _cacheClearer.ClearCacheFor(updatedTournament).ConfigureAwait(false); // Redirect to the tournament return(Redirect(updatedTournament.TournamentRoute)); } model.Metadata.PageTitle = "Edit " + model.Tournament.TournamentFullName(x => _dateTimeFormatter.FormatDate(x, false, false, false)); model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative) }); model.Breadcrumbs.Add(new Breadcrumb { Name = model.Tournament.TournamentName, Url = new Uri(model.Tournament.TournamentRoute, UriKind.Relative) }); return(View("EditTournament", model)); }