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.TournamentDate = model.Tournament.StartTime; model.Metadata.PageTitle = "Teams 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 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 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 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 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)); }
public async Task <ActionResult> CreateTournament([Bind(Prefix = "Tournament", Include = "TournamentName,QualificationType,PlayerType,PlayersPerTeam,DefaultOverSets")] Tournament postedTournament) { if (postedTournament is null) { throw new ArgumentNullException(nameof(postedTournament)); } postedTournament.DefaultOverSets.RemoveAll(x => !x.Overs.HasValue); var model = new EditTournamentViewModel(CurrentPage, Services.UserService) { Tournament = postedTournament }; // 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 could 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"); if (Request.RawUrl.StartsWith("/teams/", StringComparison.OrdinalIgnoreCase)) { model.Team = await _teamDataSource.ReadTeamByRoute(Request.RawUrl, true).ConfigureAwait(false); model.Tournament.Teams.Add(new TeamInTournament { Team = model.Team, TeamRole = TournamentTeamRole.Organiser }); model.Metadata.PageTitle = $"Add a tournament for {model.Team.TeamName}"; } else if (Request.RawUrl.StartsWith("/competitions/", StringComparison.OrdinalIgnoreCase)) { model.Season = await _seasonDataSource.ReadSeasonByRoute(Request.RawUrl, false).ConfigureAwait(false); model.Tournament.Seasons.Add(model.Season); model.Metadata.PageTitle = $"Add a tournament in the {model.Season.SeasonFullName()}"; _matchValidator.DateIsWithinTheSeason(() => model.TournamentDate, model.Season, 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[AuthorizedAction.CreateTournament] = User.Identity.IsAuthenticated; if (model.IsAuthorized[AuthorizedAction.CreateTournament] && ModelState.IsValid && (model.Team != null || (model.Season != null && model.Season.EnableTournaments))) { var currentMember = Members.GetCurrentMember(); var createdTournament = await _tournamentRepository.CreateTournament(model.Tournament, currentMember.Key, currentMember.Name).ConfigureAwait(false); await _cacheClearer.ClearCacheFor(createdTournament).ConfigureAwait(false); return(Redirect(createdTournament.TournamentRoute)); } model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative) }); return(View("CreateTournament", 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 = new Tournament { QualificationType = TournamentQualificationType.OpenTournament, PlayerType = PlayerType.Mixed, PlayersPerTeam = 8, DefaultOverSets = new List <OverSet> { new OverSet { Overs = 4, BallsPerOver = 8 } }, TournamentLocation = new MatchLocation() } }; if (Request.RawUrl.StartsWith("/teams/", StringComparison.OrdinalIgnoreCase)) { model.Team = await _teamDataSource.ReadTeamByRoute(Request.RawUrl, true).ConfigureAwait(false); if (model.Team == null) { return(new HttpNotFoundResult()); } model.Tournament.TournamentName = model.Team.TeamName; if (model.Tournament.TournamentName.IndexOf("tournament", StringComparison.OrdinalIgnoreCase) == -1) { model.Tournament.TournamentName += " tournament"; } model.TournamentLocationId = model.Team.MatchLocations.FirstOrDefault()?.MatchLocationId; model.TournamentLocationName = model.Team.MatchLocations.FirstOrDefault()?.NameAndLocalityOrTownIfDifferent(); model.Tournament.PlayerType = model.Team.PlayerType; model.Metadata.PageTitle = $"Add a tournament for {model.Team.TeamName}"; } else if (Request.RawUrl.StartsWith("/competitions/", StringComparison.OrdinalIgnoreCase)) { model.Season = await _seasonDataSource.ReadSeasonByRoute(Request.RawUrl, false).ConfigureAwait(false); if (model.Season == null || !model.Season.EnableTournaments) { return(new HttpNotFoundResult()); } model.Tournament.TournamentName = model.Season.Competition.CompetitionName; if (model.Tournament.TournamentName.IndexOf("tournament", StringComparison.OrdinalIgnoreCase) == -1) { model.Tournament.TournamentName += " tournament"; } model.Tournament.PlayerType = model.Season.Competition.PlayerType; model.Metadata.PageTitle = $"Add a tournament in the {model.Season.SeasonFullName()}"; } model.IsAuthorized[AuthorizedAction.CreateTournament] = User.Identity.IsAuthenticated; model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative) }); return(CurrentTemplate(model)); }