private async Task <List <LatestWinner> > GetLatestWinners()
        {
            var latestWinners = new List <LatestWinner>();

            var projects = await _projectRepository.GetProjectsAsync();

            var archiveProjects = projects.Where(x => x.ProjectStatus == Status.Archive.ToString()).OrderByDescending(x => x.VotingDeadline);

            foreach (var project in archiveProjects)
            {
                var winners = await _winnersRepository.GetWinnersAsync(project.Id);

                foreach (var winner in winners)
                {
                    if (string.IsNullOrEmpty(winner.WinnerIdentifier))
                    {
                        var profile = await _personalDataService.FindClientsByEmail(winner.WinnerId);

                        if (profile != null)
                        {
                            winner.WinnerIdentifier = profile.Id;
                            await _winnersRepository.UpdateAsync(winner);
                        }
                    }

                    if (winner.Budget != null)
                    {
                        var winnerStreamsId = await _streamsIdRepository.GetOrCreateAsync(winner.WinnerIdentifier);

                        latestWinners.Add(
                            new LatestWinner
                        {
                            Name        = winner.FullName,
                            ProjectId   = project.Id,
                            ProjectName = project.Name,
                            Amount      = (double)winner.Budget,
                            Id          = winner.WinnerIdentifier,
                            StreamsId   = winnerStreamsId.StreamsId
                        });
                    }
                }
                if (latestWinners.Count >= 4)
                {
                    break;
                }
            }

            var winnersIdList    = latestWinners.Select(winner => winner.Id).ToList();
            var winnerAvatarUrls = await _personalDataService.GetClientAvatarsAsync(winnersIdList);

            foreach (var winner in latestWinners)
            {
                winnerAvatarUrls.TryGetValue(winner.Id, out var avatarUrl);
                winner.AvatarUrl = avatarUrl;
            }

            return(latestWinners.Take(4).ToList());
        }
        public async Task <IActionResult> SaveEditedProject(ProjectViewModel projectViewModel, bool draft = false,
                                                            bool enableVoting = false, bool enableRegistration = false)
        {
            if (projectViewModel.ProjectUrl == null)
            {
                projectViewModel.ProjectUrl = projectViewModel.Id;
            }

            projectViewModel.Tags = SerializeTags(projectViewModel.Tags);

            projectViewModel.ProjectStatus = projectViewModel.Status.ToString();

            var sanitizer = new HtmlSanitizer();

            projectViewModel.PrizeDescription = sanitizer.Sanitize(projectViewModel.PrizeDescription);
            projectViewModel.Description      = sanitizer.Sanitize(projectViewModel.Description);

            projectViewModel.SkipVoting       = !enableVoting;
            projectViewModel.SkipRegistration = !enableRegistration;
            if (projectViewModel.CompetitionRegistrationDeadline == DateTime.MinValue)
            {
                projectViewModel.CompetitionRegistrationDeadline = DateTime.UtcNow.Date;
            }

            if (projectViewModel.VotingDeadline == DateTime.MinValue)
            {
                projectViewModel.VotingDeadline = DateTime.UtcNow.Date;
            }

            var project = await _projectRepository.GetAsync(projectViewModel.Id);

            if (projectViewModel.AuthorId == null)
            {
                projectViewModel.AuthorId = project.AuthorId;
            }

            if (projectViewModel.AuthorFullName == null)
            {
                projectViewModel.AuthorFullName = project.AuthorFullName;
            }

            if (projectViewModel.AuthorIdentifier == null)
            {
                projectViewModel.AuthorIdentifier = project.AuthorIdentifier;

                var profile = await _personalDataService.FindClientsByEmail(projectViewModel.AuthorId);

                if (profile != null)
                {
                    projectViewModel.AuthorIdentifier = profile.Id;
                }
            }

            project.Status = StatusHelper.GetProjectStatusFromString(project.ProjectStatus);

            var user     = UserModel.GetAuthenticatedUser(User.Identity);
            var userRole = await _userRolesRepository.GetAsync(user.Email.ToLower());

            //Don't let non-admin users edit their draft projects to Initiative status
            if (userRole == null || userRole.Role != "ADMIN")
            {
                if (await IsOkKycStatusAsync(user) && projectViewModel.Status != Status.Draft)
                {
                    return(View("CreateInitiativeClosed"));
                }
            }

            projectViewModel.LastModified = DateTime.UtcNow;

            projectViewModel.UserAgent = HttpContext.Request.Headers["User-Agent"].ToString();

            projectViewModel.ParticipantsCount = project.ParticipantsCount;

            var projectId           = projectViewModel.Id;
            var statusAndUrlChanged = projectViewModel.Status != Status.Draft &&
                                      projectViewModel.ProjectUrl != projectId;

            if (!statusAndUrlChanged)
            {
                var currentProjectIsInStream     = false;
                var currentProjectWasInOldStream = false;
                var streamId = "";

                if (projectViewModel.StreamType == "New")
                {
                    var streamProjects = JsonConvert.DeserializeObject <List <StreamProject> >(projectViewModel.SerializedStream);

                    if (streamProjects.Any())
                    {
                        var newStream = new StreamEntity
                        {
                            Name        = projectViewModel.NewStreamName,
                            AuthorId    = user.Id,
                            AuthorEmail = user.Email,
                            Stream      = projectViewModel.SerializedStream
                        };

                        streamId = await _streamRepository.SaveAsync(newStream);

                        foreach (var proj in streamProjects)
                        {
                            var streamProject = await _projectRepository.GetAsync(proj.ProjectId);

                            streamProject.StreamId = streamId;
                            await _projectRepository.UpdateAsync(streamProject);
                        }

                        currentProjectIsInStream = streamProjects.Any(p => p.ProjectId == projectViewModel.Id);
                    }
                }
                if (projectViewModel.StreamType == "Existing")
                {
                    var existingStream = await _streamRepository.GetAsync(projectViewModel.ExistingStreamId);

                    var oldProjects = JsonConvert.DeserializeObject <List <StreamProject> >(existingStream.Stream);
                    currentProjectWasInOldStream = oldProjects.Any(p => p.ProjectId == projectViewModel.Id);

                    foreach (var oldProj in oldProjects)
                    {
                        var oldProject = await _projectRepository.GetAsync(oldProj.ProjectId);

                        oldProject.StreamId = null;
                        await _projectRepository.UpdateAsync(oldProject);
                    }

                    existingStream.Stream = projectViewModel.SerializedStream;
                    await _streamRepository.UpdateAsync(existingStream);

                    var newProjects = JsonConvert.DeserializeObject <List <StreamProject> >(projectViewModel.SerializedStream);

                    foreach (var newProj in newProjects)
                    {
                        var streamProject = await _projectRepository.GetAsync(newProj.ProjectId);

                        streamProject.StreamId = existingStream.Id;
                        await _projectRepository.UpdateAsync(streamProject);
                    }

                    currentProjectIsInStream = newProjects.Any(p => p.ProjectId == projectViewModel.Id);
                    streamId = existingStream.Id;
                }

                if (currentProjectIsInStream)
                {
                    projectViewModel.StreamId = streamId;
                }
                else if (currentProjectWasInOldStream)
                {
                    projectViewModel.StreamId = null;
                }
                await _projectRepository.UpdateAsync(projectViewModel);
            }


            if (project.Status == Status.Draft && projectViewModel.Status == Status.Initiative)
            {
                await SendProjectCreateNotification(projectViewModel);
            }

            var idValid = false;

            if (!string.IsNullOrEmpty(projectViewModel.ProjectUrl))
            {
                idValid = Regex.IsMatch(projectViewModel.ProjectUrl, @"^[a-z0-9-]+$");
            }
            else
            {
                return(await EditWithProjectUrlError(projectViewModel.Id, "Project Url cannot be empty!"));
            }

            if (!idValid)
            {
                return(await EditWithProjectUrlError(projectViewModel.Id, "Project Url can only contain lowercase letters, numbers and the dash symbol!"));
            }

            if (projectViewModel.ProjectUrl != projectId)
            {
                if (projectViewModel.Status != Status.Draft)
                {
                    var oldProjUrl = projectViewModel.ProjectUrl;
                    projectViewModel = await GetProjectViewModel(projectId);

                    projectViewModel.ProjectUrl        = oldProjUrl;
                    projectViewModel.ProjectCategories = _categoriesRepository.GetCategories();
                    ModelState.AddModelError("Status", "Status cannot be changed while changing Project Url!");
                    return(View("EditProject", projectViewModel));
                }

                if (!string.IsNullOrEmpty(projectViewModel.ProjectUrl))
                {
                    idValid = Regex.IsMatch(projectViewModel.ProjectUrl, @"^[a-z0-9-]+$");
                }
                else
                {
                    return(await EditWithProjectUrlError(projectViewModel.Id, "Project Url cannot be empty!"));
                }

                if (!idValid)
                {
                    return(await EditWithProjectUrlError(projectViewModel.Id, "Project Url can only contain lowercase letters, numbers and the dash symbol!"));
                }

                var projectExists = await _projectRepository.GetAsync(projectViewModel.ProjectUrl);

                if (projectExists != null)
                {
                    return(await EditWithProjectUrlError(projectViewModel.Id, "Project with that Project Url already exists!"));
                }

                projectViewModel.Id      = projectViewModel.ProjectUrl;
                projectViewModel.Created = DateTime.UtcNow;

                await _projectRepository.SaveAsync(projectViewModel);

                await _projectRepository.DeleteAsync(projectId);

                return(RedirectToAction("ProjectDetails", "Project", new { id = projectViewModel.ProjectUrl }));
            }

            if (project.Status != Status.Registration && projectViewModel.Status == Status.Registration)
            {
                await AddCompetitionMailToQueue(project);
            }

            if (project.Status != Status.Submission && projectViewModel.Status == Status.Submission)
            {
                await AddImplementationMailToQueue(project);
            }

            if (project.Status != Status.Voting && projectViewModel.Status == Status.Voting)
            {
                await AddVotingMailToQueue(project);
            }

            if (projectViewModel.Status == Status.Archive)
            {
                if (!project.SkipVoting)
                {
                    await _winnersService.SaveWinners(projectViewModel.Id, projectViewModel.Winners);
                }
                else
                {
                    await _winnersService.SaveCustomWinners(projectViewModel.Id, projectViewModel.Winners);
                }

                await AddArchiveMailToQueue(project);
            }

            await _expertsService.SaveExperts(projectViewModel.Id, projectViewModel.Experts);

            await SaveProjectFile(projectViewModel.File, projectId);

            return(RedirectToAction("ProjectDetails", "Project", new { id = projectViewModel.Id }));
        }
        private async Task <List <ProjectCompactViewModel> > GetCompactProjectsList(IEnumerable <IProjectData> projects)
        {
            var compactModels = new List <ProjectCompactViewModel>();
            var user          = UserModel.GetAuthenticatedUser(User.Identity);

            foreach (var project in projects)
            {
                var projectCommentsCount = await _commentsRepository.GetProjectCommentsCountAsync(project.Id);

                var participantsCount = await _participantsRepository.GetProjectParticipantsCountAsync(project.Id);

                var resultsCount = await _resultsRepository.GetResultsCountAsync(project.Id);

                var winnersCount = await _winnersRepository.GetWinnersCountAsync(project.Id);

                var tagsList = new List <string>();
                if (!string.IsNullOrEmpty(project.Tags))
                {
                    tagsList = JsonConvert.DeserializeObject <List <string> >(project.Tags);
                }

                var following = false;
                if (user.Email != null)
                {
                    var follow = await _projectFollowRepository.GetAsync(user.Email, project.Id);

                    if (follow != null)
                    {
                        following = true;
                    }
                }

                if (string.IsNullOrEmpty(project.AuthorIdentifier))
                {
                    var profile = await _personalDataService.FindClientsByEmail(project.AuthorId);

                    if (profile != null)
                    {
                        project.AuthorIdentifier = profile.Id;
                        await _projectRepository.UpdateAsync(project);
                    }
                }

                var compactModel = new ProjectCompactViewModel
                {
                    CommentsCount     = projectCommentsCount,
                    ParticipantsCount = participantsCount,
                    ResultsCount      = resultsCount,
                    WinnersCount      = winnersCount,
                    Tags            = tagsList,
                    BaseProjectData = project
                };

                if (!string.IsNullOrEmpty(project.ProjectStatus))
                {
                    compactModel.BaseProjectData.Status = StatusHelper.GetProjectStatusFromString(project.ProjectStatus);
                }

                compactModels.Add(compactModel);
            }
            compactModels = await CompactProjectList.FetchAuthorAvatars(compactModels, _personalDataService);

            compactModels = await CompactProjectList.FetchAuthorStreamsIds(compactModels, _streamsIdRepository);

            return(compactModels);
        }