public async Task <IActionResult> VoteForResult(ResultVoteViewModel model) { if (model.ProjectId == null) { return(RedirectToAction("Index", "Home")); } var voterId = GetAuthenticatedUser().Email; var vote = await _resultVoteRepository.GetAsync(model.ProjectId, model.ParticipantId, voterId); if (vote == null) { model.VoterUserId = voterId; await _resultVoteRepository.SaveAsync(model); var votes = await _resultVoteRepository.GetProjectResultVotesAsync(model.ProjectId); var totalVotes = votes.Count(); var result = await _resultRepository.GetAsync(model.ProjectId, model.ParticipantId); result.Votes += 1; await _resultRepository.UpdateAsync(result); await CalculateScores(totalVotes, model.ProjectId); } return(RedirectToAction("ProjectDetails", "Project", new { id = model.ProjectId })); }
private async Task <ProjectViewModel> GetProjectViewModel(string id) { var projectCategories = _categoriesRepository.GetCategories(); var project = await _projectRepository.GetAsync(id); //var resources = JsonConvert.DeserializeObject<List<ProgrammingResource>>(project.ProgrammingResources); project.Status = StatusHelper.GetProjectStatusFromString(project.ProjectStatus); var comments = await _commentsRepository.GetProjectCommentsAsync(id); foreach (var comment in comments) { if (!string.IsNullOrEmpty(comment.Comment)) { comment.Comment = Regex.Replace(comment.Comment, @"\r\n?|\n", "<br />"); } } var participants = await _participantsRepository.GetProjectParticipantsAsync(id); var results = await _resultRepository.GetResultsAsync(id); var user = GetAuthenticatedUser(); var participant = (user.Email == null) ? null : await _participantsRepository.GetAsync(id, user.Email); var userRole = (user.Email == null) ? null : await _userRolesRepository.GetAsync(user.Email.ToLower()); var isAdmin = (userRole != null) && userRole.Role == "ADMIN"; var isAuthor = (user.Email != null) && user.Email == project.AuthorId; var participantId = ""; var isParticipant = false; var hasResult = false; if (participant != null) { participantId = user.Email; isParticipant = true; hasResult = results.Any(r => r.ParticipantId == user.Email); } var projectFollowing = (user.Email == null) ? null : await _projectFollowRepository.GetAsync(user.Email, id); var isFollowing = projectFollowing != null; comments = SortComments(comments); var commenterIsModerator = new Dictionary <string, bool>(); foreach (var comment in comments) { var role = await _userRolesRepository.GetAsync(comment.UserId); var isModerator = role != null && role.Role == "ADMIN"; commenterIsModerator.Add(comment.Id, isModerator); } var userVotedForResults = new Dictionary <string, bool>(); var resultVotes = await _resultVoteRepository.GetProjectResultVotesAsync(project.Id); foreach (var result in results) { var match = resultVotes.FirstOrDefault(x => x.ParticipantId == result.ParticipantId && x.VoterUserId == user.Email); userVotedForResults.Add(result.ParticipantId, match != null && user.Email != null); } var statusBarPartial = new ProjectDetailsStatusBarViewModel { Status = project.Status, ParticipantsCount = participants.Count(), CompetitionRegistrationDeadline = project.CompetitionRegistrationDeadline, ImplementationDeadline = project.ImplementationDeadline, VotingDeadline = project.VotingDeadline, StatusCompletionPercent = CalculateStatusCompletionPercent(project) }; var commentsPartial = new ProjectCommentPartialViewModel { ProjectId = project.Id, UserId = user.Email, Comments = comments, IsAdmin = isAdmin, IsAuthor = isAuthor, CommenterIsModerator = commenterIsModerator, ProjectAuthorId = project.AuthorId }; var participantsPartial = new ProjectParticipantsPartialViewModel { CurrentUserId = user.Email, Participants = participants, Status = project.Status, HasResult = hasResult }; var resultsPartial = new ResultsPartialViewModel { Status = project.Status, Results = results, IsAdmin = isAdmin, SkipVoting = project.SkipVoting, UserVotedForResults = userVotedForResults, SubmissionsDeadline = project.ImplementationDeadline }; var projectViewModel = new ProjectViewModel { Id = project.Id, Name = project.Name, Overview = project.Overview, Description = project.Description, ProjectCategories = projectCategories, Category = project.Category, Status = project.Status, BudgetFirstPlace = project.BudgetFirstPlace, BudgetSecondPlace = project.BudgetSecondPlace, VotesFor = project.VotesFor, VotesAgainst = project.VotesAgainst, Created = project.Created, LastModified = project.LastModified, CompetitionRegistrationDeadline = project.CompetitionRegistrationDeadline, ImplementationDeadline = project.ImplementationDeadline, VotingDeadline = project.VotingDeadline, StatusBarPartial = statusBarPartial, CommentsPartial = commentsPartial, ParticipantsPartial = participantsPartial, ResultsPartial = resultsPartial, AuthorId = project.AuthorId, AuthorFullName = project.AuthorFullName, ParticipantId = participantId, IsParticipant = isParticipant, IsAdmin = isAdmin, IsFollowing = isFollowing, OtherProjects = await GetOtherProjects(project.Id), ProgrammingResourceName = project.ProgrammingResourceName, ProgrammingResourceLink = project.ProgrammingResourceLink, SkipVoting = project.SkipVoting, SkipRegistration = project.SkipRegistration }; if (!string.IsNullOrEmpty(project.Tags)) { projectViewModel.TagsList = JsonConvert.DeserializeObject <List <string> >(project.Tags); var builder = new StringBuilder(); foreach (var tag in projectViewModel.TagsList) { builder.Append(tag).Append(", "); } projectViewModel.Tags = builder.ToString(); } var fileInfo = await _fileInfoRepository.GetAsync(id); if (fileInfo != null) { var fileInfoViewModel = new ProjectFileInfoViewModel { ContentType = fileInfo.ContentType, FileName = fileInfo.FileName }; projectViewModel.FileInfo = fileInfoViewModel; } if (projectViewModel.Status == Status.Archive) { projectViewModel = await PopulateResultsViewModel(projectViewModel); } projectViewModel.ProjectUrl = project.Id; return(projectViewModel); }
public async Task <IActionResult> VoteForResult(ResultVoteViewModel model) { if (model.ProjectId == null) { return(RedirectToAction("Index", "Home")); } var project = await _projectRepository.GetAsync(model.ProjectId); var voterId = GetAuthenticatedUser().Email; model.UserAgent = HttpContext.Request.Headers["User-Agent"].ToString(); string voteType = null; var role = await _userRolesRepository.GetAsync(voterId); if (voterId == project.AuthorId) { voteType = "AUTHOR"; } else if (role != null && role.Role == "ADMIN") { voteType = "ADMIN"; } var vote = await _resultVoteRepository.GetAsync(model.ProjectId, model.ParticipantId, voterId); if (vote == null) { model.VoterUserId = voterId; model.Type = voteType; await _resultVoteRepository.SaveAsync(model); var votes = await _resultVoteRepository.GetProjectResultVotesAsync(model.ProjectId); var totalVotes = votes.Count(); var result = await _resultRepository.GetAsync(model.ProjectId, model.ParticipantId); result.Votes += 1; await _resultRepository.UpdateAsync(result); await CalculateScores(totalVotes, model.ProjectId); return(RedirectToAction("ProjectDetails", "Project", new { id = model.ProjectId, resultsActive = true, votedForResult = true })); } else { await _resultVoteRepository.DeleteAsync(model.ProjectId, model.ParticipantId, voterId); var votes = await _resultVoteRepository.GetProjectResultVotesAsync(model.ProjectId); var totalVotes = votes.Count(); var result = await _resultRepository.GetAsync(model.ProjectId, model.ParticipantId); result.Votes -= 1; await _resultRepository.UpdateAsync(result); await CalculateScores(totalVotes, model.ProjectId); return(RedirectToAction("ProjectDetails", "Project", new { id = model.ProjectId, resultsActive = true, votedTwice = true })); } }
// TODO: A lot of this, like the fetch methods should probably be its own ProjectModel class - it's really about the // Project, not just the ProjectView and anything that's related to the view only (like the projectCategories) // can get pushed into the separate ProjectViewModel class that has a ProjectModel property on it. private async Task <ProjectViewModel> GetProjectViewModel(string id) { var projectCategories = _categoriesRepository.GetCategories(); var project = await _projectRepository.GetAsync(id); project.Status = StatusHelper.GetProjectStatusFromString(project.ProjectStatus); var projectDetailsAvatarIds = new List <string>(); projectDetailsAvatarIds.Add(project.AuthorIdentifier); // TODO: And these type of additional fetch methods can be methods on the model - the more we break // it up, the easier it is to test and reuse. var comments = await _commentsRepository.GetProjectCommentsAsync(id); await FormatComments(id, projectDetailsAvatarIds, comments); var participants = await _participantsRepository.GetProjectParticipantsAsync(id); var results = await _resultRepository.GetResultsAsync(id); var user = UserModel.GetAuthenticatedUser(User.Identity); var participant = (user.Email == null) ? null : await _participantsRepository.GetAsync(id, user.Email); var userRole = (user.Email == null) ? null : await _userRolesRepository.GetAsync(user.Email.ToLower()); var isAdmin = (userRole != null) && userRole.Role == StreamsRoles.Admin; var isAuthor = (user.Email != null) && user.Email == project.AuthorId; var participantId = ""; var isParticipant = false; var hasResult = false; if (participant != null) { participantId = user.Email; isParticipant = true; hasResult = results.Any(r => r.ParticipantId == user.Email); } var projectFollowing = (user.Email == null) ? null : await _projectFollowRepository.GetAsync(user.Email, id); var isFollowing = projectFollowing != null; // TODO: As I go through this, wondering if we need a CommentsList model, especially since // comments are probably going to be important to the platform going forwards comments = SortComments(comments); var commenterIsModerator = new Dictionary <string, bool>(); foreach (var comment in comments) { var role = await _userRolesRepository.GetAsync(comment.UserId); var isModerator = role != null && role.Role == StreamsRoles.Admin; commenterIsModerator.Add(comment.Id, isModerator); } // TODO: The votes might also need to be broken out, especially if we want to do // 5-star or numeric scoring var userVotedForResults = new Dictionary <string, bool>(); var resultVotes = await _resultVoteRepository.GetProjectResultVotesAsync(project.Id); foreach (var part in participants) { if (string.IsNullOrEmpty(part.UserIdentifier)) { var profile = await _personalDataService.FindClientsByEmail(part.UserId); if (profile != null) { part.UserIdentifier = profile.Id; await _participantsRepository.UpdateAsync(part); } } projectDetailsAvatarIds.Add(part.UserIdentifier); var participantStreamsId = await _streamsIdRepository.GetOrCreateAsync(part.UserIdentifier); part.StreamsId = participantStreamsId.StreamsId; } foreach (var result in results) { if (string.IsNullOrEmpty(result.ParticipantIdentifier)) { var profile = await _personalDataService.FindClientsByEmail(result.ParticipantId); result.ParticipantIdentifier = profile.Id; await _resultRepository.UpdateAsync(result); } var match = resultVotes.FirstOrDefault(x => x.ParticipantId == result.ParticipantId && x.VoterUserId == user.Email); userVotedForResults.Add(result.ParticipantId, match != null && user.Email != null); var resultStreamsId = await _streamsIdRepository.GetOrCreateAsync(result.ParticipantIdentifier); result.StreamsId = resultStreamsId.StreamsId; } var statusBarPartial = ProjectDetailsStatusBarViewModel.Create(project, participants.Count()); var commentsPartial = new ProjectCommentPartialViewModel { ProjectId = project.Id, UserId = user.Email, Comments = comments, IsAdmin = isAdmin, IsAuthor = isAuthor, CommenterIsModerator = commenterIsModerator, ProjectAuthorId = project.AuthorId }; var participantsPartial = new ProjectParticipantsPartialViewModel { CurrentUserId = user.Email, Participants = participants, Status = project.Status, HasResult = hasResult }; var resultsPartial = new ResultsPartialViewModel { Status = project.Status, Results = results, IsAdmin = isAdmin, SkipVoting = project.SkipVoting, UserVotedForResults = userVotedForResults, SubmissionsDeadline = project.ImplementationDeadline }; var allExperts = await _projectExpertsRepository.GetAllUniqueAsync(); var projectExperts = await _projectExpertsRepository.GetProjectExpertsAsync(id); foreach (var expert in projectExperts) { if (string.IsNullOrEmpty(expert.UserIdentifier) && !string.IsNullOrEmpty(expert.UserId)) { var profile = await _personalDataService.FindClientsByEmail(expert.UserId); if (profile != null) { expert.UserIdentifier = profile.Id; await _projectExpertsRepository.UpdateAsync(expert); } } if (!string.IsNullOrEmpty(expert.UserIdentifier)) { projectDetailsAvatarIds.Add(expert.UserIdentifier); expert.StreamsId = (await _streamsIdRepository.GetOrCreateAsync(expert.UserIdentifier)).StreamsId; } } var avatarsDictionary = await _personalDataService.GetClientAvatarsAsync(projectDetailsAvatarIds); participantsPartial.Avatars = avatarsDictionary.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); commentsPartial.Avatars = avatarsDictionary.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); resultsPartial.Avatars = avatarsDictionary.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); projectExperts = projectExperts.OrderBy(x => x.Priority == 0).ThenBy(x => x.Priority); var authorStreamsId = await _streamsIdRepository.GetOrCreateAsync(project.AuthorIdentifier); var projectViewModel = new ProjectViewModel { Id = project.Id, Name = project.Name, Overview = project.Overview, Description = project.Description, ProjectCategories = projectCategories, Category = project.Category, Status = project.Status, BudgetFirstPlace = project.BudgetFirstPlace, BudgetSecondPlace = project.BudgetSecondPlace, VotesFor = project.VotesFor, VotesAgainst = project.VotesAgainst, Created = project.Created, LastModified = project.LastModified, CompetitionRegistrationDeadline = project.CompetitionRegistrationDeadline, ImplementationDeadline = project.ImplementationDeadline, VotingDeadline = project.VotingDeadline, StatusBarPartial = statusBarPartial, CommentsPartial = commentsPartial, ParticipantsPartial = participantsPartial, ResultsPartial = resultsPartial, AuthorId = project.AuthorId, AuthorFullName = project.AuthorFullName, AuthorIdentifier = project.AuthorIdentifier, ParticipantId = participantId, IsParticipant = isParticipant, IsAdmin = isAdmin, IsFollowing = isFollowing, OtherProjects = await GetOtherProjects(project.Id), ProgrammingResourceName = project.ProgrammingResourceName, ProgrammingResourceLink = project.ProgrammingResourceLink, SkipVoting = project.SkipVoting, SkipRegistration = project.SkipRegistration, ProjectExperts = !projectExperts.Any() ? null : projectExperts, PrizeDescription = project.PrizeDescription, StreamId = project.StreamId, AllStreamProjects = await GetStreamProjects(), CompactStreams = await GetCompactStreams(), NameTag = project.NameTag, AuthorAvatarUrl = avatarsDictionary[project.AuthorIdentifier], AuthorStreamsId = authorStreamsId.StreamsId, Experts = allExperts.Select(ExpertViewModel.Create).ToList(), InfoForKycUsers = project.InfoForKycUsers, DescriptionFooter = project.DescriptionFooter }; if (!string.IsNullOrEmpty(project.Tags)) { projectViewModel.TagsList = JsonConvert.DeserializeObject <List <string> >(project.Tags); var builder = new StringBuilder(); foreach (var tag in projectViewModel.TagsList) { builder.Append(tag).Append(", "); } projectViewModel.Tags = builder.ToString(); } projectViewModel.EditStreamProjects = new EditStreamProjects { ProjectsList = new List <StreamProject>() }; if (!string.IsNullOrEmpty(project.StreamId)) { var stream = await _streamRepository.GetAsync(project.StreamId); projectViewModel.StreamProjects = JsonConvert.DeserializeObject <List <StreamProject> >(stream.Stream); } var fileInfo = await _fileInfoRepository.GetAsync(id); if (fileInfo != null) { var fileInfoViewModel = new ProjectFileInfoViewModel { ContentType = fileInfo.ContentType, FileName = fileInfo.FileName }; projectViewModel.FileInfo = fileInfoViewModel; } if (projectViewModel.Status == Status.Archive) { projectViewModel = await PopulateResultsViewModel(projectViewModel); var winners = await _winnersRepository.GetWinnersAsync(project.Id); projectViewModel.Winners = winners.Select(x => WinnerViewModel.Create(x)).ToList(); } projectViewModel.ProjectUrl = project.Id; return(projectViewModel); }
public async Task SaveWinners(string projectId) { var project = await _projectRepository.GetAsync(projectId); var results = await _resultRepository.GetResultsAsync(projectId); var votes = await _resultVoteRepository.GetProjectResultVotesAsync(projectId); var projectResultVoteDatas = votes as IList <IProjectResultVoteData> ?? votes.ToList(); var adminVotes = projectResultVoteDatas.Where(x => x.Type == "ADMIN"); var authorVotes = projectResultVoteDatas.Where(x => x.Type == "AUTHOR"); var totalVotesCount = projectResultVoteDatas.Count; var resultVoteDatas = adminVotes as IList <IProjectResultVoteData> ?? adminVotes.ToList(); var adminVotesCount = resultVoteDatas.Count; var voteDatas = authorVotes as IList <IProjectResultVoteData> ?? authorVotes.ToList(); var authorVotesCount = voteDatas.Count; var userVotes = totalVotesCount - adminVotesCount - authorVotesCount; var resultScores = new Dictionary <string, double>(); var projectResultDatas = results as IList <IProjectResultData> ?? results.ToList(); foreach (var result in projectResultDatas) { double resultScore = 0; double adminVotesScore = 0; double userVotesScore = 0; var resultAdminVotes = resultVoteDatas.Where(x => x.ParticipantId == result.ParticipantId); var resultVotes = projectResultVoteDatas.Where(x => x.ParticipantId == result.ParticipantId && x.Type != "ADMIN" && x.Type != "AUTHOR"); var authorVote = voteDatas.FirstOrDefault(x => x.ParticipantId == result.ParticipantId); var resultAdminVotesCount = Convert.ToDouble(resultAdminVotes.Count()); var resultVotesCount = Convert.ToDouble(resultVotes.Count()); if (adminVotesCount != 0) { adminVotesScore = (resultAdminVotesCount / Convert.ToDouble(adminVotesCount)) * AdminsVoteValue; } if (userVotes != 0) { userVotesScore = (resultVotesCount / Convert.ToDouble(userVotes)) * CitizensVoteValue; } resultScore = adminVotesScore + userVotesScore; if (authorVote != null) { resultScore += AuthorVoteValue; } resultScores.Add(result.ParticipantId, resultScore); } var firstPlaceWinner = resultScores.OrderByDescending(pair => pair.Value).Take(1).FirstOrDefault(); var secondPlaceWinners = resultScores.OrderByDescending(pair => pair.Value).Skip(1).Take(3); var firstPlaceResult = projectResultDatas.FirstOrDefault(x => x.ParticipantId == firstPlaceWinner.Key); if (firstPlaceResult != null) { var firstWinner = new WinnerViewModel { ProjectId = firstPlaceResult.ProjectId, WinnerId = firstPlaceResult.ParticipantId, FullName = firstPlaceResult.ParticipantFullName, Result = firstPlaceResult.Link, Votes = firstPlaceResult.Votes, Score = firstPlaceResult.Score, Place = 1, Budget = project.BudgetFirstPlace, WinningScore = firstPlaceWinner.Value }; if (await WinnerIsEligible(firstWinner.ProjectId, firstWinner.WinnerId)) { await _winnersRepository.SaveAsync(firstWinner); } } if (project.BudgetSecondPlace != null) { foreach (var winner in secondPlaceWinners) { var secondPlaceResult = projectResultDatas.FirstOrDefault(x => x.ParticipantId == winner.Key); var secondWinner = new WinnerViewModel { ProjectId = secondPlaceResult.ProjectId, WinnerId = secondPlaceResult.ParticipantId, FullName = secondPlaceResult.ParticipantFullName, Result = secondPlaceResult.Link, Votes = secondPlaceResult.Votes, Score = secondPlaceResult.Score, Place = 2, Budget = project.BudgetSecondPlace, WinningScore = winner.Value }; if (await WinnerIsEligible(secondWinner.ProjectId, secondWinner.WinnerId)) { await _winnersRepository.SaveAsync(secondWinner); } } } }
public async Task SaveWinners(string projectId, IEnumerable <WinnerViewModel> winners = null) { var project = await _projectRepository.GetAsync(projectId); var results = await _resultRepository.GetResultsAsync(projectId); var projectResultDatas = results as IList <IProjectResultData> ?? results.ToList(); var votes = await _resultVoteRepository.GetProjectResultVotesAsync(projectId); var projectResultVoteDatas = votes as IList <IProjectResultVoteData> ?? votes.ToList(); var resultScores = CalculateScores(projectResultDatas, projectResultVoteDatas); if (winners != null && winners.Any(x => !string.IsNullOrEmpty(x.WinnerId))) { //await SaveCustomWinners(projectId, winners); foreach (var winner in winners.Where(x => !string.IsNullOrEmpty(x.WinnerId))) { var winnerResult = projectResultDatas.FirstOrDefault(x => x.ParticipantId == winner.WinnerId); var winnerScore = resultScores.First(x => x.Key == winner.WinnerId); var budget = winner.Budget; if (budget == null) { budget = winner.Place == 1 ? project.BudgetFirstPlace : project.BudgetSecondPlace; } var winnerModel = WinnerViewModel.Create(winnerResult, winner.Place, winnerScore.Value, budget); await _winnersRepository.SaveAsync(winnerModel); } return; } var firstPlaceWinner = resultScores.OrderByDescending(pair => pair.Value).Take(1).FirstOrDefault(); var firstPlaceResult = projectResultDatas.FirstOrDefault(x => x.ParticipantId == firstPlaceWinner.Key); if (firstPlaceResult != null) { var firstWinner = WinnerViewModel.Create(firstPlaceResult, 1, firstPlaceWinner.Value, project.BudgetFirstPlace); if (await WinnerIsEligible(firstWinner.ProjectId, firstWinner.WinnerId)) { await _winnersRepository.SaveAsync(firstWinner); } } var secondPlaceWinners = resultScores.OrderByDescending(pair => pair.Value).Skip(1).Take(3); if (project.BudgetSecondPlace != null) { foreach (var winner in secondPlaceWinners) { var secondPlaceResult = projectResultDatas.FirstOrDefault(x => x.ParticipantId == winner.Key); var secondWinner = WinnerViewModel.Create(secondPlaceResult, 2, winner.Value, project.BudgetSecondPlace); if (await WinnerIsEligible(secondWinner.ProjectId, secondWinner.WinnerId)) { await _winnersRepository.SaveAsync(secondWinner); } } } }
public async Task <IActionResult> VoteForResult(ResultVoteViewModel model) { if (model.ProjectId == null) { return(RedirectToAction("Index", "Home")); } var project = await _projectRepository.GetAsync(model.ProjectId); var voterId = UserModel.GetAuthenticatedUser(User.Identity).Email; model.UserAgent = HttpContext.Request.Headers["User-Agent"].ToString(); string voteType = null; var role = await _userRolesRepository.GetAsync(voterId); if (voterId == project.AuthorId) { voteType = ResultVoteTypes.Author; } else if (role != null && role.Role == StreamsRoles.Admin) { voteType = ResultVoteTypes.Admin; } var vote = await _resultVoteRepository.GetAsync(model.ProjectId, model.ParticipantId, voterId); if (vote == null) { model.VoterUserId = voterId; model.Type = voteType; await _resultVoteRepository.SaveAsync(model); var votes = await _resultVoteRepository.GetProjectResultVotesAsync(model.ProjectId); var totalVotes = votes.Count(); var result = await _resultRepository.GetAsync(model.ProjectId, model.ParticipantId); result.Votes += 1; await _resultRepository.UpdateAsync(result); await CalculateScores(totalVotes, model.ProjectId); TempData["ShowVotedForResultModal"] = true; return(RedirectToAction("ProjectDetails", "Project", new { id = model.ProjectId }, "tab_Results")); } else { await _resultVoteRepository.DeleteAsync(model.ProjectId, model.ParticipantId, voterId); var votes = await _resultVoteRepository.GetProjectResultVotesAsync(model.ProjectId); var totalVotes = votes.Count(); var result = await _resultRepository.GetAsync(model.ProjectId, model.ParticipantId); result.Votes -= 1; await _resultRepository.UpdateAsync(result); await CalculateScores(totalVotes, model.ProjectId); TempData["ShowVotedTwiceModal"] = true; return(RedirectToAction("ProjectDetails", "Project", new { id = model.ProjectId }, "tab_Results")); } }