Ejemplo n.º 1
0
        public async override Task <ActionResult> Index(ContentModel contentModel)
        {
            if (contentModel is null)
            {
                throw new ArgumentNullException(nameof(contentModel));
            }

            var model = new MatchViewModel(contentModel.Content, Services?.UserService)
            {
                Match             = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false),
                DateTimeFormatter = _dateFormatter
            };

            if (model.Match == null)
            {
                return(new HttpNotFoundResult());
            }
            else
            {
                model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Match);

                model.Metadata.PageTitle = model.Match.MatchFullName(x => _dateFormatter.FormatDate(x, false, false, false)) + " - stoolball match";

                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 if (model.Match.Tournament != null)
                {
                    model.Breadcrumbs.Add(new Breadcrumb {
                        Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative)
                    });
                    model.Breadcrumbs.Add(new Breadcrumb {
                        Name = model.Match.Tournament.TournamentName, Url = new Uri(model.Match.Tournament.TournamentRoute, 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 override Task <ActionResult> Index(ContentModel contentModel)
        {
            if (contentModel is null)
            {
                throw new ArgumentNullException(nameof(contentModel));
            }

            var model = new EditMatchFormatViewModel(contentModel.Content, Services?.UserService)
            {
                Match         = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false),
                DateFormatter = _dateFormatter
            };

            if (model.Match == null || model.Match.Tournament != null || model.Match.MatchType == MatchType.TrainingSession)
            {
                return(new HttpNotFoundResult());
            }
            else
            {
                model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Match);

                model.Metadata.PageTitle = "Edit " + model.Match.MatchFullName(x => _dateFormatter.FormatDate(x, false, false, false));

                model.FormData.Overs        = model.Match.MatchInnings.FirstOrDefault()?.OverSets.FirstOrDefault()?.Overs;
                model.FormData.MatchInnings = model.Match.MatchInnings.Count;

                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 = "Match", Include = "Season,Teams,MatchResultType")] Match postedMatch)
        {
            if (postedMatch is null)
            {
                throw new ArgumentNullException(nameof(postedMatch));
            }

            var beforeUpdate = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false);

            var model = new EditTrainingSessionViewModel(CurrentPage, Services.UserService)
            {
                Match         = postedMatch,
                DateFormatter = _dateTimeFormatter
            };

            model.Match.MatchId    = beforeUpdate.MatchId;
            model.Match.MatchType  = MatchType.TrainingSession;
            model.Match.MatchRoute = beforeUpdate.MatchRoute;
            model.Match.UpdateMatchNameAutomatically = beforeUpdate.UpdateMatchNameAutomatically;
            _editMatchHelper.ConfigureModelFromRequestData(model, Request.Unvalidated.Form, Request.Form, ModelState);

            if (model.Match.Season != null && !model.Match.Season.SeasonId.HasValue)
            {
                model.Match.Season = null;
            }
            else if (model.Match.Season != null)
            {
                // Get the season, to support validation against season dates
                model.Match.Season = await _seasonDataSource.ReadSeasonById(model.Match.Season.SeasonId.Value).ConfigureAwait(false);
            }

            _matchValidator.DateIsValidForSqlServer(() => model.MatchDate, ModelState, "MatchDate", "match");
            _matchValidator.DateIsWithinTheSeason(() => model.MatchDate, model.Match.Season, ModelState, "MatchDate", "match");
            _matchValidator.AtLeastOneTeamInMatch(model.Match.Teams, ModelState);

            foreach (var team in model.Match.Teams)
            {
                team.TeamRole = TeamRole.Training;
            }

            model.IsAuthorized = _authorizationPolicy.IsAuthorized(beforeUpdate);

            if (model.IsAuthorized[AuthorizedAction.EditMatch] && ModelState.IsValid &&
                (model.Season == null || model.Season.MatchTypes.Contains(MatchType.TrainingSession)))
            {
                if ((int?)model.Match.MatchResultType == -1)
                {
                    model.Match.MatchResultType = null;
                }

                var currentMember = Members.GetCurrentMember();
                var updatedMatch  = await _matchRepository.UpdateMatch(model.Match, currentMember.Key, currentMember.Name).ConfigureAwait(false);

                await _cacheClearer.ClearCacheFor(updatedMatch).ConfigureAwait(false);

                return(Redirect(updatedMatch.MatchRoute));
            }

            model.Match.MatchName    = beforeUpdate.MatchName;
            model.Metadata.PageTitle = "Edit " + model.Match.MatchFullName(x => _dateTimeFormatter.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(View("EditTrainingSession", 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 DeleteMatchViewModel(contentModel.Content, Services?.UserService)
            {
                Match             = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false),
                DateTimeFormatter = _dateFormatter
            };

            if (model.Match == null)
            {
                return(new HttpNotFoundResult());
            }
            else
            {
                model.TotalComments = await _matchCommentsDataSource.ReadTotalComments(model.Match.MatchId.Value).ConfigureAwait(false);

                // Find the player identities in the match, then reselect them with details of how many matches they've played
                model.PlayerIdentities = _playerIdentityFinder.PlayerIdentitiesInMatch(model.Match).ToList();
                if (model.PlayerIdentities.Any())
                {
                    model.PlayerIdentities = await _playerDataSource.ReadPlayerIdentities(
                        new PlayerFilter
                    {
                        PlayerIdentityIds = model.PlayerIdentities.Select(x => x.PlayerIdentityId.Value).ToList()
                    }
                        ).ConfigureAwait(false);
                }

                model.ConfirmDeleteRequest.RequiredText = model.Match.MatchName;

                model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Match);

                model.Metadata.PageTitle = "Delete " + model.Match.MatchFullName(x => _dateFormatter.FormatDate(x, false, false, false)) + " - stoolball match";

                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 if (model.Match.Tournament != null)
                {
                    model.Breadcrumbs.Add(new Breadcrumb {
                        Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative)
                    });
                    model.Breadcrumbs.Add(new Breadcrumb {
                        Name = model.Match.Tournament.TournamentName, Url = new Uri(model.Match.Tournament.TournamentRoute, 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));
            }
        }
Ejemplo n.º 6
0
        public async override Task <ActionResult> Index(ContentModel contentModel)
        {
            if (contentModel is null)
            {
                throw new ArgumentNullException(nameof(contentModel));
            }

            var model = new MatchViewModel(contentModel.Content, Services?.UserService)
            {
                Match             = await _matchDataSource.ReadMatchByRoute(Request.Url.AbsolutePath).ConfigureAwait(false),
                DateTimeFormatter = _dateFormatter
            };

            if (model.Match == null)
            {
                return(new HttpNotFoundResult());
            }
            else
            {
                model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Match);

                model.Match.Comments = await _commentsDataSource.ReadComments(model.Match.MatchId.Value).ConfigureAwait(false);

                foreach (var comment in model.Match.Comments)
                {
                    comment.Comment = _emailProtector.ProtectEmailAddresses(comment.Comment, User.Identity.IsAuthenticated);
                    comment.Comment = _badLanguageFilter.Filter(comment.Comment);
                }

                model.Metadata.PageTitle   = model.Match.MatchFullName(x => _dateFormatter.FormatDate(x, false, false, false)) + " - stoolball match";
                model.Metadata.Description = model.Match.Description();

                model.Match.MatchNotes = _emailProtector.ProtectEmailAddresses(model.Match.MatchNotes, User.Identity.IsAuthenticated);

                // If a team was all out, convert wickets to -1. This value is used by the view, and also by matches imported from the old website.
                foreach (var innings in model.Match.MatchInnings)
                {
                    if (innings.Wickets.HasValue)
                    {
                        if ((innings.Wickets == model.Match.PlayersPerTeam - 1 && !model.Match.LastPlayerBatsOn) ||
                            (innings.Wickets == model.Match.PlayersPerTeam && model.Match.LastPlayerBatsOn))
                        {
                            innings.Wickets = -1;
                        }
                    }
                }

                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 if (model.Match.Tournament != null)
                {
                    model.Breadcrumbs.Add(new Breadcrumb {
                        Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative)
                    });
                    model.Breadcrumbs.Add(new Breadcrumb {
                        Name = model.Match.Tournament.TournamentName, Url = new Uri(model.Match.Tournament.TournamentRoute, UriKind.Relative)
                    });
                }
                else
                {
                    model.Breadcrumbs.Add(new Breadcrumb {
                        Name = Constants.Pages.Matches, Url = new Uri(Constants.Pages.MatchesUrl, UriKind.Relative)
                    });
                }

                return(CurrentTemplate(model));
            }
        }
Ejemplo n.º 7
0
        public async override Task <ActionResult> Index(ContentModel contentModel)
        {
            if (contentModel is null)
            {
                throw new ArgumentNullException(nameof(contentModel));
            }

            var model = new EditStartOfPlayViewModel(contentModel.Content, Services?.UserService)
            {
                Match         = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false),
                DateFormatter = _dateFormatter
            };

            if (model.Match == null || 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());
                }

                model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Match);

                if (model.Match.MatchResultType.HasValue)
                {
                    model.MatchWentAhead = (model.Match.MatchResultType == MatchResultType.HomeWin || model.Match.MatchResultType == MatchResultType.AwayWin || model.Match.MatchResultType == MatchResultType.Tie);
                }

                if (model.Match.MatchType == MatchType.KnockoutMatch && model.Match.Season != null)
                {
                    model.Match.Season = await _seasonDataSource.ReadSeasonByRoute(model.Match.Season.SeasonRoute, true).ConfigureAwait(false);

                    model.PossibleHomeTeams = _editMatchHelper.PossibleTeamsAsListItems(model.Match.Season?.Teams);
                    model.PossibleAwayTeams = _editMatchHelper.PossibleTeamsAsListItems(model.Match.Season?.Teams);
                }

                model.HomeTeamId        = model.Match.Teams.SingleOrDefault(x => x.TeamRole == TeamRole.Home)?.Team.TeamId;
                model.AwayTeamId        = model.Match.Teams.SingleOrDefault(x => x.TeamRole == TeamRole.Away)?.Team.TeamId;
                model.MatchLocationId   = model.Match.MatchLocation?.MatchLocationId;
                model.MatchLocationName = model.Match.MatchLocation?.NameAndLocalityOrTownIfDifferent();
                model.TossWonBy         = model.Match.Teams.FirstOrDefault(x => x.WonToss.HasValue && x.WonToss.Value)?.MatchTeamId.ToString();
                model.BattedFirst       = model.Match.InningsOrderIsKnown ? model.Match.MatchInnings.First().BattingTeam.MatchTeamId.ToString() : null;

                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));
            }
        }
Ejemplo n.º 8
0
        public async Task <ActionResult> UpdateMatch([Bind(Prefix = "Match", Include = "MatchResultType")] Match postedMatch)
        {
            if (postedMatch is null)
            {
                postedMatch = new Match();
            }

            var beforeUpdate = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false);

            if (beforeUpdate.StartTime > DateTime.UtcNow || beforeUpdate.Tournament != null)
            {
                return(new HttpNotFoundResult());
            }

            var model = new EditStartOfPlayViewModel(CurrentPage, Services.UserService)
            {
                Match         = beforeUpdate,
                DateFormatter = _dateTimeFormatter
            };

            model.Match.MatchResultType = postedMatch.MatchResultType;

            await AddMissingTeamsFromRequest(model, ModelState).ConfigureAwait(false);

            ReadMatchLocationFromRequest(model);

            ReadTossWonByFromRequest(model);

            ReadBattedFirstFromRequest(model);

            if (bool.TryParse(Request.Form["MatchWentAhead"], out var matchWentAhead))
            {
                // Reset the fields which are not compatible with the selection for whether the match went ahead.
                // They may have been set, then the match went ahead option was changed, and their values would now be misleading.
                model.MatchWentAhead = matchWentAhead;
                if (model.MatchWentAhead.Value && model.Match.MatchResultType != MatchResultType.HomeWin && model.Match.MatchResultType != MatchResultType.AwayWin && model.Match.MatchResultType != MatchResultType.Tie)
                {
                    model.Match.MatchResultType = null;
                }

                if (!model.MatchWentAhead.Value)
                {
                    model.TossWonBy   = null;
                    model.BattedFirst = null;
                }

                if (bool.TryParse(Request.Form["HasScorecard"], out var hasScorecard))
                {
                    model.HasScorecard = hasScorecard;
                }

                // Validate this field as required, but conditionally based on whether the match went ahead
                if (!model.MatchWentAhead.Value && !model.Match.MatchResultType.HasValue)
                {
                    ModelState.AddModelError("Match.MatchResultType", "The Why didn't the match go ahead? field is required");
                }
            }

            model.IsAuthorized = _authorizationPolicy.IsAuthorized(beforeUpdate);

            if (model.IsAuthorized[AuthorizedAction.EditMatchResult] && ModelState.IsValid)
            {
                var currentMember = Members.GetCurrentMember();
                var updatedMatch  = await _matchRepository.UpdateStartOfPlay(model.Match, currentMember.Key, currentMember.Name).ConfigureAwait(false);

                await _cacheClearer.ClearCacheFor(updatedMatch).ConfigureAwait(false);

                if (model.Match.MatchResultType.HasValue && new List <MatchResultType> {
                    MatchResultType.HomeWinByForfeit,
                    MatchResultType.AwayWinByForfeit,
                    MatchResultType.Postponed,
                    MatchResultType.Cancelled
                }.Contains(model.Match.MatchResultType.Value))
                {
                    // There's no scorecard to complete - redirect to the match
                    return(Redirect(updatedMatch.MatchRoute));
                }
                else if (model.HasScorecard)
                {
                    // Redirect to batting scorecard
                    return(Redirect(updatedMatch.MatchRoute + "/edit/innings/1/batting"));
                }
                else
                {
                    // Skip scorecard editing and redirect to close of play
                    return(Redirect(updatedMatch.MatchRoute + "/edit/close-of-play"));
                }
            }

            // Reset model.Match.Teams to trigger reappearance of fields, but preserve the values selected in model.*TeamId and model.*TeamName
            var selectedHomeTeam = model.Match.Teams.SingleOrDefault(x => !x.MatchTeamId.HasValue && x.TeamRole == TeamRole.Home);

            if (selectedHomeTeam != null)
            {
                model.HomeTeamId   = selectedHomeTeam.Team.TeamId;
                model.HomeTeamName = selectedHomeTeam.Team.TeamName;
                model.Match.Teams.Remove(selectedHomeTeam);
            }

            var selectedAwayTeam = model.Match.Teams.SingleOrDefault(x => !x.MatchTeamId.HasValue && x.TeamRole == TeamRole.Away);

            if (selectedAwayTeam != null)
            {
                model.AwayTeamId   = selectedAwayTeam.Team.TeamId;
                model.AwayTeamName = selectedAwayTeam.Team.TeamName;
                model.Match.Teams.Remove(selectedAwayTeam);
            }

            model.Match.MatchName    = beforeUpdate.MatchName;
            model.Metadata.PageTitle = "Edit " + model.Match.MatchFullName(x => _dateTimeFormatter.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(View("EditStartOfPlay", model));
        }
Ejemplo n.º 9
0
        public async Task <ActionResult> DeleteMatch([Bind(Prefix = "ConfirmDeleteRequest", Include = "RequiredText,ConfirmationText")] MatchingTextConfirmation postedModel)
        {
            if (postedModel is null)
            {
                throw new ArgumentNullException(nameof(postedModel));
            }

            var model = new DeleteMatchViewModel(CurrentPage, Services.UserService)
            {
                Match             = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false),
                DateTimeFormatter = _dateTimeFormatter
            };

            model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Match);

            if (model.IsAuthorized[AuthorizedAction.DeleteMatch] && ModelState.IsValid)
            {
                var currentMember = Members.GetCurrentMember();
                await _matchRepository.DeleteMatch(model.Match, currentMember.Key, currentMember.Name).ConfigureAwait(false);

                await _cacheClearer.ClearCacheFor(model.Match).ConfigureAwait(false);

                model.Deleted = true;
            }
            else
            {
                model.TotalComments = await _matchCommentsDataSource.ReadTotalComments(model.Match.MatchId.Value).ConfigureAwait(false);
            }

            model.Metadata.PageTitle = "Delete " + model.Match.MatchFullName(x => _dateTimeFormatter.FormatDate(x, false, false, false)) + " - stoolball match";

            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 if (model.Match.Tournament != null)
            {
                model.Breadcrumbs.Add(new Breadcrumb {
                    Name = Constants.Pages.Tournaments, Url = new Uri(Constants.Pages.TournamentsUrl, UriKind.Relative)
                });
                model.Breadcrumbs.Add(new Breadcrumb {
                    Name = model.Match.Tournament.TournamentName, Url = new Uri(model.Match.Tournament.TournamentRoute, UriKind.Relative)
                });
            }
            else
            {
                model.Breadcrumbs.Add(new Breadcrumb {
                    Name = Constants.Pages.Matches, Url = new Uri(Constants.Pages.MatchesUrl, UriKind.Relative)
                });
            }
            if (!model.Deleted)
            {
                model.Breadcrumbs.Add(new Breadcrumb {
                    Name = model.Match.MatchName, Url = new Uri(model.Match.MatchRoute, UriKind.Relative)
                });
            }

            return(View("DeleteMatch", model));
        }
Ejemplo n.º 10
0
        public async Task <ActionResult> UpdateMatch([Bind(Prefix = "CurrentInnings", Include = "MatchInnings,OversBowledSearch")] 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());
            }

            // The bowler name is required if any other fields are filled in for an over
            var i = 0;

            foreach (var over in postedData.OversBowledSearch)
            {
                if (string.IsNullOrWhiteSpace(over.BowledBy) &&
                    (over.BallsBowled.HasValue ||
                     over.Wides.HasValue ||
                     over.NoBalls.HasValue ||
                     over.RunsConceded.HasValue))
                {
                    ModelState.AddModelError($"CurrentInnings.OversBowledSearch[{i}].Bowler", $"You've added the {(i + 1).Ordinalize(CultureInfo.CurrentCulture)} over. Please name the bowler.");
                }
                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.OversBowled = postedData.OversBowledSearch.Where(x => x.BowledBy?.Trim().Length > 0).Select((x, index) => new Over
            {
                Bowler = new PlayerIdentity
                {
                    PlayerIdentityName = x.BowledBy.Trim(),
                    Team = model.CurrentInnings.MatchInnings.BowlingTeam.Team
                },
                OverNumber   = index + 1,
                BallsBowled  = x.BallsBowled,
                Wides        = x.Wides,
                NoBalls      = x.NoBalls,
                RunsConceded = x.RunsConceded
            }).ToList();

            model.CurrentInnings.OversBowledSearch = postedData.OversBowledSearch;

            _overSetScaffolder.ScaffoldOverSets(model.CurrentInnings.MatchInnings.OverSets, model.Match.Tournament != null ? 6 : 12, model.CurrentInnings.MatchInnings.OversBowled);

            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.UpdateBowlingScorecard(model.Match, model.CurrentInnings.MatchInnings.MatchInningsId.Value, currentMember.Key, currentMember.Name).ConfigureAwait(false);

                // redirect to the next innings or close of play
                if (model.InningsOrderInMatch.Value < model.Match.MatchInnings.Count)
                {
                    return(Redirect($"{model.Match.MatchRoute}/edit/innings/{model.InningsOrderInMatch.Value + 1}/batting"));
                }
                else
                {
                    return(Redirect(model.Match.MatchRoute + "/edit/close-of-play"));
                }
            }

            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("EditBowlingScorecard", model));
        }
Ejemplo n.º 11
0
        public async override Task <ActionResult> Index(ContentModel contentModel)
        {
            if (contentModel is null)
            {
                throw new ArgumentNullException(nameof(contentModel));
            }

            var model = new EditTrainingSessionViewModel(contentModel.Content, Services?.UserService)
            {
                Match         = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false),
                DateFormatter = _dateFormatter
            };

            if (model.Match == null)
            {
                return(new HttpNotFoundResult());
            }
            else
            {
                model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Match);

                if (model.Match.Season != null)
                {
                    model.Match.Season = await _seasonDataSource.ReadSeasonByRoute(model.Match.Season.SeasonRoute, true).ConfigureAwait(false);

                    model.SeasonFullName = model.Match.Season.SeasonFullName();
                }

                model.MatchDate = model.Match.StartTime;
                if (model.Match.StartTimeIsKnown)
                {
                    model.StartTime = model.Match.StartTime;
                }
                model.MatchLocationId   = model.Match.MatchLocation?.MatchLocationId;
                model.MatchLocationName = model.Match.MatchLocation?.NameAndLocalityOrTownIfDifferent();

                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 override Task <ActionResult> Index(ContentModel contentModel)
        {
            if (contentModel is null)
            {
                throw new ArgumentNullException(nameof(contentModel));
            }

            var model = new EditCloseOfPlayViewModel(contentModel.Content, Services?.UserService)
            {
                Match         = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false),
                DateFormatter = _dateFormatter
            };

            if (model.Match == null || 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.FormData.MatchResultType = model.Match.MatchResultType;
                model.FormData.Awards          = model.Match.Awards.Select(x => new MatchAwardViewModel
                {
                    MatchAwardId = x.AwardedToId,
                    PlayerSearch = x.PlayerIdentity.PlayerIdentityName,
                    TeamId       = model.Match.Teams.First(team => team.Team.TeamId == x.PlayerIdentity.Team.TeamId).Team.TeamId,
                    Reason       = x.Reason
                }).ToList();

                if (!model.Match.MatchResultType.HasValue)
                {
                    model.Match.MatchResultType = _matchResultEvaluator.EvaluateMatchResult(model.Match);
                }

                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));
            }
        }
Ejemplo n.º 13
0
        public async Task <ActionResult> UpdateMatch([Bind(Prefix = "FormData")] EditCloseOfPlayFormData 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());
            }

            var model = new EditCloseOfPlayViewModel(CurrentPage, Services.UserService)
            {
                Match         = beforeUpdate,
                FormData      = postedData,
                DateFormatter = _dateTimeFormatter
            };

            model.Match.MatchResultType = model.FormData.MatchResultType;
            model.Match.Awards          = model.FormData.Awards.Select(x => new MatchAward
            {
                AwardedToId = x.MatchAwardId,
                Award       = new Award {
                    AwardName = StatisticsConstants.PLAYER_OF_THE_MATCH_AWARD
                },
                PlayerIdentity = new PlayerIdentity
                {
                    PlayerIdentityName = x.PlayerSearch,
                    Team = new Team
                    {
                        TeamId = x.TeamId
                    }
                },
                Reason = x.Reason
            }).ToList();

            model.Match.UpdateMatchNameAutomatically = beforeUpdate.UpdateMatchNameAutomatically;
            model.Match.Teams = beforeUpdate.Teams;

            model.IsAuthorized = _authorizationPolicy.IsAuthorized(beforeUpdate);

            if (model.IsAuthorized[AuthorizedAction.EditMatchResult] && ModelState.IsValid)
            {
                if ((int)model.Match.MatchResultType == -1)
                {
                    model.Match.MatchResultType = null;
                }

                var currentMember = Members.GetCurrentMember();
                var updatedMatch  = await _matchRepository.UpdateCloseOfPlay(model.Match, currentMember.Key, currentMember.Name).ConfigureAwait(false);

                await _cacheClearer.ClearCacheFor(updatedMatch).ConfigureAwait(false);

                return(Redirect(updatedMatch.MatchRoute));
            }

            model.Match.MatchName    = beforeUpdate.MatchName;
            model.Metadata.PageTitle = "Edit " + model.Match.MatchFullName(x => _dateTimeFormatter.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(View("EditCloseOfPlay", model));
        }
        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.CurrentInnings.MatchInnings.OverSets.Any())
                {
                    model.CurrentInnings.MatchInnings.OverSets.Add(new OverSet {
                        Overs = model.Match.Tournament != null ? 6 : 12, BallsPerOver = 8
                    });
                }
                while (model.CurrentInnings.MatchInnings.OversBowled.Count < model.CurrentInnings.MatchInnings.OverSets.Sum(x => x.Overs))
                {
                    model.CurrentInnings.MatchInnings.OversBowled.Add(new Over());
                }

                // Convert overs bowled 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.OversBowledSearch.AddRange(model.CurrentInnings.MatchInnings.OversBowled.Select(x => new OverViewModel
                {
                    BowledBy     = x.Bowler?.PlayerIdentityName,
                    BallsBowled  = x.BallsBowled,
                    Wides        = x.Wides,
                    NoBalls      = x.NoBalls,
                    RunsConceded = x.RunsConceded
                }));

                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 = "Match", Include = "MatchResultType")] Match postedMatch)
        {
            if (postedMatch is null)
            {
                throw new ArgumentNullException(nameof(postedMatch));
            }

            var beforeUpdate = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false);

            // This controller is only for matches in the future
            if (beforeUpdate.StartTime <= DateTime.UtcNow || beforeUpdate.Tournament != null)
            {
                return(new HttpNotFoundResult());
            }

            var model = new EditLeagueMatchViewModel(CurrentPage, Services.UserService)
            {
                Match         = postedMatch,
                DateFormatter = _dateTimeFormatter
            };

            model.Match.MatchId    = beforeUpdate.MatchId;
            model.Match.MatchRoute = beforeUpdate.MatchRoute;
            model.Match.UpdateMatchNameAutomatically = beforeUpdate.UpdateMatchNameAutomatically;
            model.Match.Season = beforeUpdate.Season;

            _editMatchHelper.ConfigureModelFromRequestData(model, Request.Unvalidated.Form, Request.Form, ModelState);

            _matchValidator.DateIsValidForSqlServer(() => model.MatchDate, ModelState, "MatchDate", "match");
            _matchValidator.DateIsWithinTheSeason(() => model.MatchDate, model.Match.Season, ModelState, "MatchDate", "match");
            _matchValidator.TeamsMustBeDifferent(model, ModelState);

            model.IsAuthorized = _authorizationPolicy.IsAuthorized(beforeUpdate);

            if (model.IsAuthorized[AuthorizedAction.EditMatch] && ModelState.IsValid)
            {
                if ((int?)model.Match.MatchResultType == -1)
                {
                    model.Match.MatchResultType = null;
                }

                var currentMember = Members.GetCurrentMember();
                var updatedMatch  = await _matchRepository.UpdateMatch(model.Match, currentMember.Key, currentMember.Name).ConfigureAwait(false);

                await _cacheClearer.ClearCacheFor(updatedMatch).ConfigureAwait(false);

                return(Redirect(updatedMatch.MatchRoute));
            }

            model.Match.MatchName = beforeUpdate.MatchName;
            model.Match.Season    = model.Season = await _seasonDataSource.ReadSeasonByRoute(model.Match.Season.SeasonRoute, true).ConfigureAwait(false);

            model.PossibleSeasons    = _editMatchHelper.PossibleSeasonsAsListItems(new[] { model.Match.Season });
            model.PossibleHomeTeams  = _editMatchHelper.PossibleTeamsAsListItems(model.Season.Teams);
            model.PossibleAwayTeams  = _editMatchHelper.PossibleTeamsAsListItems(model.Season.Teams);
            model.Metadata.PageTitle = "Edit " + model.Match.MatchFullName(x => _dateTimeFormatter.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(View("EditLeagueMatch", model));
        }
        /// <remarks>
        /// https://devblogs.microsoft.com/aspnet/queuebackgroundworkitem-to-reliably-schedule-and-run-background-processes-in-asp-net/
        /// </remarks>
        private async Task <CancellationToken> UpdateStatistics(Guid taskId, Guid memberKey, string memberName, CancellationToken cancellationToken)
        {
            try
            {
                Logger.Info(GetType(), "Updating match statistics for all matches in {Type:l}.{Method:l}.", GetType(), nameof(UpdateStatistics));

                var matchListings = (await _matchListingDataSource.ReadMatchListings(new MatchFilter
                {
                    IncludeMatches = true,
                    IncludeTournamentMatches = true,
                    IncludeTournaments = false,
                    UntilDate = DateTime.UtcNow
                }, MatchSortOrder.MatchDateEarliestFirst).ConfigureAwait(false));

                _taskTracker.SetTarget(taskId, matchListings.Sum(x => x.MatchInnings.Count) + matchListings.Count);

                using (var connection = _databaseConnectionFactory.CreateDatabaseConnection())
                {
                    connection.Open();

                    foreach (var matchListing in matchListings)
                    {
                        if (cancellationToken.IsCancellationRequested)
                        {
                            Logger.Warn(GetType(), "Background task cancellation requested in {Type:l}.{Method:l}.", GetType(), nameof(UpdateStatistics));
                        }

                        try
                        {
                            var match = await _matchDataSource.ReadMatchByRoute(matchListing.MatchRoute).ConfigureAwait(false);

                            if (match != null)
                            {
                                using (var transaction = connection.BeginTransaction())
                                {
                                    await _statisticsRepository.DeletePlayerStatistics(match.MatchId.Value, transaction).ConfigureAwait(false);

                                    foreach (var innings in match.MatchInnings)
                                    {
                                        await _statisticsRepository.DeleteBowlingFigures(innings.MatchInningsId.Value, transaction).ConfigureAwait(false);

                                        innings.BowlingFigures = _bowlingFiguresCalculator.CalculateBowlingFigures(innings);
                                        await _statisticsRepository.UpdateBowlingFigures(innings, memberKey, memberName, transaction).ConfigureAwait(false);

                                        _taskTracker.IncrementCompletedBy(taskId, 1);
                                    }

                                    var hasPlayerData = _playerIdentityFinder.PlayerIdentitiesInMatch(match).Any();
                                    if (hasPlayerData)
                                    {
                                        var statisticsData = _playerInMatchStatisticsBuilder.BuildStatisticsForMatch(match);
                                        await _statisticsRepository.UpdatePlayerStatistics(statisticsData, transaction).ConfigureAwait(false);
                                    }
                                    _taskTracker.IncrementCompletedBy(taskId, 1);
                                    transaction.Commit();
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.Error(GetType(), "Error '{Error}' updating match statistics for '{MatchRoute}' in {Type:l}.{Method:l}.", ex.Message, matchListing.MatchRoute, GetType(), nameof(UpdateStatistics));
                            _taskTracker.IncrementErrorsBy(taskId, 1);
                        }
                    }

                    using (var transaction = connection.BeginTransaction())
                    {
                        await _statisticsRepository.UpdatePlayerProbability(null, transaction).ConfigureAwait(false);

                        transaction.Commit();
                    }

                    Logger.Info(GetType(), "Completed updating match statistics for all matches in {Type:l}.{Method:l}.", GetType(), nameof(UpdateStatistics));
                }
            }
            catch (TaskCanceledException tce)
            {
                Logger.Error(GetType(), "Caught TaskCanceledException '{Message}' in {Type:l}.{Method:l}.", tce.Message, GetType(), nameof(UpdateStatistics));
            }

            return(cancellationToken);
        }
        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));
        }
        public async override Task <ActionResult> Index(ContentModel contentModel)
        {
            if (contentModel is null)
            {
                throw new ArgumentNullException(nameof(contentModel));
            }

            var model = new EditKnockoutMatchViewModel(contentModel.Content, Services?.UserService)
            {
                Match         = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false),
                DateFormatter = _dateFormatter
            };

            if (model.Match == null)
            {
                return(new HttpNotFoundResult());
            }
            else
            {
                // This page is only for matches in the future
                if (model.Match.StartTime <= DateTime.UtcNow)
                {
                    return(new HttpNotFoundResult());
                }

                model.IsAuthorized = _authorizationPolicy.IsAuthorized(model.Match);

                model.MatchName = model.Match.UpdateMatchNameAutomatically ? string.Empty : model.Match.MatchName;
                if (model.Match.Season != null)
                {
                    model.Match.Season = model.Season = await _seasonDataSource.ReadSeasonByRoute(model.Match.Season.SeasonRoute, true).ConfigureAwait(false);

                    model.PossibleSeasons = _editMatchHelper.PossibleSeasonsAsListItems(new[] { model.Match.Season });
                }
                model.PossibleHomeTeams = _editMatchHelper.PossibleTeamsAsListItems(model.Season?.Teams);
                model.PossibleAwayTeams = _editMatchHelper.PossibleTeamsAsListItems(model.Season?.Teams);

                model.MatchDate = model.Match.StartTime;
                if (model.Match.StartTimeIsKnown)
                {
                    model.StartTime = model.Match.StartTime;
                }
                model.HomeTeamId        = model.Match.Teams.SingleOrDefault(x => x.TeamRole == TeamRole.Home)?.Team.TeamId;
                model.AwayTeamId        = model.Match.Teams.SingleOrDefault(x => x.TeamRole == TeamRole.Away)?.Team.TeamId;
                model.MatchLocationId   = model.Match.MatchLocation?.MatchLocationId;
                model.MatchLocationName = model.Match.MatchLocation?.NameAndLocalityOrTownIfDifferent();

                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));
            }
        }
Ejemplo n.º 19
0
        public async Task <ActionResult> UpdateMatch([Bind(Prefix = "FormData")] EditMatchFormatFormData postedData)
        {
            if (postedData is null)
            {
                throw new ArgumentNullException(nameof(postedData));
            }

            var beforeUpdate = await _matchDataSource.ReadMatchByRoute(Request.RawUrl).ConfigureAwait(false);

            if (beforeUpdate == null || beforeUpdate.Tournament != null || beforeUpdate.MatchType == MatchType.TrainingSession)
            {
                return(new HttpNotFoundResult());
            }

            var model = new EditMatchFormatViewModel(CurrentPage, Services.UserService)
            {
                Match         = beforeUpdate,
                DateFormatter = _dateTimeFormatter,
                FormData      = postedData
            };

            var matchIsInTheFuture = model.Match.StartTime > DateTimeOffset.UtcNow;

            if (postedData.MatchInnings < 2 || postedData.MatchInnings % 2 != 0)
            {
                ModelState.AddModelError("FormData.MatchInnings", $"A match cannot have an odd number of innings or less than 2 innings.");
            }
            else if (!matchIsInTheFuture && postedData.MatchInnings < model.Match.MatchInnings.Count)
            {
                ModelState.AddModelError("FormData.MatchInnings", $"You cannot reduce the number of innings after a match has happened.");
            }
            else
            {
                while (matchIsInTheFuture && postedData.MatchInnings < model.Match.MatchInnings.Count)
                {
                    model.Match.MatchInnings.RemoveAt(model.Match.MatchInnings.Count - 1);
                }

                if (postedData.MatchInnings > model.Match.MatchInnings.Count)
                {
                    while (postedData.MatchInnings > model.Match.MatchInnings.Count)
                    {
                        var battingMatchTeamId = model.Match.MatchInnings.Count % 2 == 0 ? model.Match.MatchInnings[0].BattingMatchTeamId : model.Match.MatchInnings[1].BattingMatchTeamId;
                        var bowlingMatchTeamId = model.Match.MatchInnings.Count % 2 == 1 ? model.Match.MatchInnings[0].BattingMatchTeamId : model.Match.MatchInnings[1].BattingMatchTeamId;
                        var addedInnings       = _matchInningsFactory.CreateMatchInnings(model.Match, battingMatchTeamId, bowlingMatchTeamId);
                        if (postedData.Overs.HasValue)
                        {
                            addedInnings.OverSets[0].Overs = postedData.Overs;
                        }
                        else
                        {
                            addedInnings.OverSets.Clear();
                        }
                        model.Match.MatchInnings.Add(addedInnings);
                    }
                }

                foreach (var innings in model.Match.MatchInnings)
                {
                    foreach (var overSet in innings.OverSets)
                    {
                        if (!matchIsInTheFuture && postedData.Overs < overSet.Overs)
                        {
                            ModelState.AddModelError("FormData.Overs", $"You cannot reduce the number of overs after a match has happened.");
                        }
                        else
                        {
                            overSet.Overs = postedData.Overs;
                        }
                    }
                }
            }

            model.IsAuthorized = _authorizationPolicy.IsAuthorized(beforeUpdate);

            if (model.IsAuthorized[AuthorizedAction.EditMatch] && ModelState.IsValid)
            {
                var currentMember = Members.GetCurrentMember();
                var updatedMatch  = await _matchRepository.UpdateMatchFormat(model.Match, currentMember.Key, currentMember.Name).ConfigureAwait(false);

                return(Redirect(updatedMatch.MatchRoute + "/edit"));
            }

            model.Metadata.PageTitle = "Edit " + model.Match.MatchFullName(x => _dateTimeFormatter.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(View("EditMatchFormat", model));
        }