public async override Task <ActionResult> Index(ContentModel contentModel) { if (contentModel is null) { throw new ArgumentNullException(nameof(contentModel)); } var model = new EditScorecardViewModel(contentModel.Content, Services?.UserService) { Match = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false), InningsOrderInMatch = _matchInningsUrlParser.ParseInningsOrderInMatchFromUrl(new Uri(Request.RawUrl, UriKind.Relative)), DateFormatter = _dateFormatter, Autofocus = true }; if (model.Match == null || !model.InningsOrderInMatch.HasValue || model.Match.Tournament != null) { return(new HttpNotFoundResult()); } else { // This page is only for matches in the past if (model.Match.StartTime > DateTime.UtcNow) { return(new HttpNotFoundResult()); } // This page is not for matches not played if (model.Match.MatchResultType.HasValue && new List <MatchResultType> { MatchResultType.HomeWinByForfeit, MatchResultType.AwayWinByForfeit, MatchResultType.Postponed, MatchResultType.Cancelled }.Contains(model.Match.MatchResultType.Value)) { return(new HttpNotFoundResult()); } model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Match); model.CurrentInnings.MatchInnings = model.Match.MatchInnings.Single(x => x.InningsOrderInMatch == model.InningsOrderInMatch); if (!model.Match.PlayersPerTeam.HasValue) { model.Match.PlayersPerTeam = model.Match.Tournament != null ? 8 : 11; } _playerInningsScaffolder.ScaffoldPlayerInnings(model.CurrentInnings.MatchInnings.PlayerInnings, model.Match.PlayersPerTeam.Value); // Convert player innings to a view model, purely to change the field names to ones which will not trigger pop-up contact/password managers // while retaining the benefits of ASP.NET model binding. Using the "search" keyword in the property name also helps to disable contact/password managers. model.CurrentInnings.PlayerInningsSearch.AddRange(model.CurrentInnings.MatchInnings.PlayerInnings.Select(x => new PlayerInningsViewModel { Batter = x.Batter?.PlayerIdentityName, DismissalType = x.DismissalType, DismissedBy = x.DismissedBy?.PlayerIdentityName, Bowler = x.Bowler?.PlayerIdentityName, RunsScored = x.RunsScored, BallsFaced = x.BallsFaced })); model.Metadata.PageTitle = "Edit " + model.Match.MatchFullName(x => _dateFormatter.FormatDate(x, false, false, false)); if (model.Match.Season != null) { model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Competitions, Url = new Uri(Constants.Pages.CompetitionsUrl, UriKind.Relative) }); model.Breadcrumbs.Add(new Breadcrumb { Name = model.Match.Season.Competition.CompetitionName, Url = new Uri(model.Match.Season.Competition.CompetitionRoute, UriKind.Relative) }); model.Breadcrumbs.Add(new Breadcrumb { Name = model.Match.Season.SeasonName(), Url = new Uri(model.Match.Season.SeasonRoute, UriKind.Relative) }); } else { model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Matches, Url = new Uri(Constants.Pages.MatchesUrl, UriKind.Relative) }); } model.Breadcrumbs.Add(new Breadcrumb { Name = model.Match.MatchName, Url = new Uri(model.Match.MatchRoute, UriKind.Relative) }); return(CurrentTemplate(model)); } }
public async Task <ActionResult> UpdateMatch([Bind(Prefix = "CurrentInnings", Include = "MatchInnings,PlayerInningsSearch")] MatchInningsViewModel postedData) { if (postedData is null) { throw new ArgumentNullException(nameof(postedData)); } var beforeUpdate = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false); if (beforeUpdate.StartTime > DateTime.UtcNow || beforeUpdate.Tournament != null) { return(new HttpNotFoundResult()); } if (beforeUpdate.MatchResultType.HasValue && new List <MatchResultType> { MatchResultType.HomeWinByForfeit, MatchResultType.AwayWinByForfeit, MatchResultType.Postponed, MatchResultType.Cancelled }.Contains(beforeUpdate.MatchResultType.Value)) { return(new HttpNotFoundResult()); } var i = 0; foreach (var innings in postedData.PlayerInningsSearch) { // The batter name is required if any other fields are filled in for an innings if (string.IsNullOrWhiteSpace(innings.Batter) && (innings.DismissalType.HasValue && innings.DismissalType != DismissalType.DidNotBat || !string.IsNullOrWhiteSpace(innings.DismissedBy) || !string.IsNullOrWhiteSpace(innings.Bowler) || innings.RunsScored != null || innings.BallsFaced != null)) { ModelState.AddModelError($"CurrentInnings.PlayerInningsSearch[{i}].Batter", $"You've added details for the {(i + 1).Ordinalize(CultureInfo.CurrentCulture)} batter. Please name the batter."); } // The batter must have batted if any other fields are filled in for an innings if ((innings.DismissalType == DismissalType.DidNotBat || innings.DismissalType == DismissalType.TimedOut) && (!string.IsNullOrWhiteSpace(innings.DismissedBy) || !string.IsNullOrWhiteSpace(innings.Bowler) || innings.RunsScored != null || innings.BallsFaced != null)) { ModelState.AddModelError($"CurrentInnings.PlayerInningsSearch[{i}].DismissalType", $"You've said the {(i + 1).Ordinalize(CultureInfo.CurrentCulture)} batter did not bat, but you added batting details."); } // The batter can't be not out if a a bowler or fielder is named if ((innings.DismissalType == DismissalType.NotOut || innings.DismissalType == DismissalType.Retired || innings.DismissalType == DismissalType.RetiredHurt) && (!string.IsNullOrWhiteSpace(innings.DismissedBy) || !string.IsNullOrWhiteSpace(innings.Bowler) )) { ModelState.AddModelError($"CurrentInnings.PlayerInningsSearch[{i}].DismissalType", $"You've said the {(i + 1).Ordinalize(CultureInfo.CurrentCulture)} batter was not out, but you named a fielder and/or bowler."); } // Caught and bowled by the same person is caught and bowled if (innings.DismissalType == DismissalType.Caught && !string.IsNullOrWhiteSpace(innings.DismissedBy) && innings.DismissedBy?.Trim() == innings.Bowler?.Trim()) { innings.DismissalType = DismissalType.CaughtAndBowled; innings.DismissedBy = null; } // If there's a fielder, the dismissal type should be caught or run-out if (innings.DismissalType != DismissalType.Caught && innings.DismissalType != DismissalType.RunOut && !string.IsNullOrWhiteSpace(innings.DismissedBy)) { ModelState.AddModelError($"CurrentInnings.PlayerInningsSearch[{i}].DismissalType", $"You've named the fielder for the {(i + 1).Ordinalize(CultureInfo.CurrentCulture)} batter, but they were not caught or run-out."); } i++; } var model = new EditScorecardViewModel(CurrentPage, Services.UserService) { Match = beforeUpdate, InningsOrderInMatch = _matchInningsUrlParser.ParseInningsOrderInMatchFromUrl(new Uri(Request.RawUrl, UriKind.Relative)), DateFormatter = _dateTimeFormatter, Autofocus = true }; model.CurrentInnings.MatchInnings = model.Match.MatchInnings.Single(x => x.InningsOrderInMatch == model.InningsOrderInMatch); model.CurrentInnings.MatchInnings.PlayerInnings = postedData.PlayerInningsSearch.Where(x => !string.IsNullOrWhiteSpace(x.Batter)).Select(x => new PlayerInnings { Batter = new PlayerIdentity { PlayerIdentityName = x.Batter.Trim(), Team = model.CurrentInnings.MatchInnings.BattingTeam.Team }, DismissalType = x.DismissalType, DismissedBy = string.IsNullOrWhiteSpace(x.DismissedBy) ? null : new PlayerIdentity { PlayerIdentityName = x.DismissedBy.Trim(), Team = model.CurrentInnings.MatchInnings.BowlingTeam.Team }, Bowler = string.IsNullOrWhiteSpace(x.Bowler) ? null : new PlayerIdentity { PlayerIdentityName = x.Bowler.Trim(), Team = model.CurrentInnings.MatchInnings.BowlingTeam.Team }, RunsScored = x.RunsScored, BallsFaced = x.BallsFaced }).ToList(); model.CurrentInnings.PlayerInningsSearch = postedData.PlayerInningsSearch; model.CurrentInnings.MatchInnings.Byes = postedData.MatchInnings.Byes; model.CurrentInnings.MatchInnings.Wides = postedData.MatchInnings.Wides; model.CurrentInnings.MatchInnings.NoBalls = postedData.MatchInnings.NoBalls; model.CurrentInnings.MatchInnings.BonusOrPenaltyRuns = postedData.MatchInnings.BonusOrPenaltyRuns; model.CurrentInnings.MatchInnings.Runs = postedData.MatchInnings.Runs; model.CurrentInnings.MatchInnings.Wickets = postedData.MatchInnings.Wickets; if (!model.Match.PlayersPerTeam.HasValue) { model.Match.PlayersPerTeam = model.Match.Tournament != null ? 8 : 11; } if (model.Match.PlayersPerTeam.Value < postedData.MatchInnings.PlayerInnings.Count) { model.Match.PlayersPerTeam = postedData.MatchInnings.PlayerInnings.Count; } _playerInningsScaffolder.ScaffoldPlayerInnings(model.CurrentInnings.MatchInnings.PlayerInnings, model.Match.PlayersPerTeam.Value); model.CurrentInnings.MatchInnings.BowlingFigures = _bowlingFiguresCalculator.CalculateBowlingFigures(model.CurrentInnings.MatchInnings); model.IsAuthorized = _authorizationPolicy.IsAuthorized(beforeUpdate); if (model.IsAuthorized[AuthorizedAction.EditMatchResult] && ModelState.IsValid) { var currentMember = Members.GetCurrentMember(); await _matchRepository.UpdateBattingScorecard(model.Match, model.CurrentInnings.MatchInnings.MatchInningsId.Value, currentMember.Key, currentMember.Name).ConfigureAwait(false); // redirect to the bowling scorecard for this innings return(Redirect($"{model.Match.MatchRoute}/edit/innings/{model.InningsOrderInMatch.Value}/bowling")); } model.Metadata.PageTitle = "Edit " + model.Match.MatchFullName(x => _dateTimeFormatter.FormatDate(x, false, false, false)); while (model.CurrentInnings.MatchInnings.OversBowled.Count < model.CurrentInnings.MatchInnings.OverSets.Sum(x => x.Overs)) { model.CurrentInnings.MatchInnings.OversBowled.Add(new Over()); } if (model.Match.Season != null) { model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Competitions, Url = new Uri(Constants.Pages.CompetitionsUrl, UriKind.Relative) }); model.Breadcrumbs.Add(new Breadcrumb { Name = model.Match.Season.Competition.CompetitionName, Url = new Uri(model.Match.Season.Competition.CompetitionRoute, UriKind.Relative) }); model.Breadcrumbs.Add(new Breadcrumb { Name = model.Match.Season.SeasonName(), Url = new Uri(model.Match.Season.SeasonRoute, UriKind.Relative) }); } else { model.Breadcrumbs.Add(new Breadcrumb { Name = Constants.Pages.Matches, Url = new Uri(Constants.Pages.MatchesUrl, UriKind.Relative) }); } model.Breadcrumbs.Add(new Breadcrumb { Name = model.Match.MatchName, Url = new Uri(model.Match.MatchRoute, UriKind.Relative) }); return(View("EditBattingScorecard", model)); }