Example #1
0
        public async Task TestCrowdactionUpdate()
        {
            var user = await context.Users.FirstAsync();

            var         newCrowdaction = new NewCrowdactionInternal("test" + Guid.NewGuid(), 100, "test", "test", "test", null, DateTime.UtcNow, DateTime.UtcNow.AddDays(1), null, null, null, null, new[] { Category.Community }, Array.Empty <string>(), CrowdactionDisplayPriority.Bottom, CrowdactionStatus.Running, 0, user.Id);
            Crowdaction crowdaction    = await crowdactionService.CreateCrowdactionInternal(newCrowdaction, CancellationToken.None);

            Assert.NotNull(crowdaction);

            Crowdaction currentCrowdaction = await context.Crowdactions.Include(c => c.Owner).FirstAsync(c => c.OwnerId != null);

            var owner = await signInManager.CreateUserPrincipalAsync(currentCrowdaction.Owner ?? throw new InvalidOperationException("Owner is null"));

            var r = new Random();
            var updatedCrowdaction =
                new UpdatedCrowdaction()
            {
                Name = Guid.NewGuid().ToString(),
                BannerImageFileId      = currentCrowdaction.BannerImageFileId,
                Categories             = new[] { Category.Community, Category.Environment },
                CreatorComments        = currentCrowdaction.CreatorComments,
                Description            = currentCrowdaction.Description,
                OwnerId                = currentCrowdaction.OwnerId,
                DescriptionVideoLink   = "https://www.youtube-nocookie.com/embed/xY0XTysJUDY",
                DescriptiveImageFileId = currentCrowdaction.DescriptiveImageFileId,
                DisplayPriority        = CrowdactionDisplayPriority.Top,
                End   = DateTime.Now.AddDays(30),
                Start = DateTime.Now.AddDays(10),
                Goal  = Guid.NewGuid().ToString(),
                Tags  = new string[3] {
                    $"a{r.Next(1000)}", $"b{r.Next(1000)}", $"c{r.Next(1000)}"
                },
                Id = currentCrowdaction.Id,
                NumberCrowdactionEmailsSent = 3,
                Proposal = currentCrowdaction.Proposal,
                Status   = CrowdactionStatus.Running,
                Target   = 33
            };
            var newCrowdactionResult = await crowdactionService.UpdateCrowdaction(updatedCrowdaction, CancellationToken.None);

            Assert.True(newCrowdactionResult.Succeeded);
            int?newCrowdactionId = newCrowdactionResult.Crowdaction?.Id;

            Assert.NotNull(newCrowdactionId);
            Crowdaction retrievedCrowdaction = await context.Crowdactions.Include(c => c.Tags).ThenInclude(t => t.Tag).FirstOrDefaultAsync(c => c.Id == newCrowdactionId);

            Assert.NotNull(retrievedCrowdaction);
            Assert.Equal(updatedCrowdaction.Name, retrievedCrowdaction.Name);
            Assert.True(Enumerable.SequenceEqual(updatedCrowdaction.Tags.OrderBy(t => t), retrievedCrowdaction.Tags.Select(t => t.Tag.Name).OrderBy(t => t)));

            await crowdactionService.DeleteCrowdaction(newCrowdactionId ?? -1, CancellationToken.None);

            retrievedCrowdaction = await context.Crowdactions.Include(c => c.Tags).ThenInclude(t => t.Tag).FirstOrDefaultAsync(c => c.Id == newCrowdactionId);

            Assert.Equal(CrowdactionStatus.Deleted, retrievedCrowdaction.Status);
        }
        public async Task <CrowdactionResult> UpdateCrowdaction(UpdatedCrowdaction updatedCrowdaction, CancellationToken token)
        {
            logger.LogInformation("Validating updated crowdaction");

            IEnumerable <ValidationResult> validationResults = ValidationHelper.Validate(updatedCrowdaction, serviceProvider);

            if (validationResults.Any())
            {
                return(new CrowdactionResult(validationResults));
            }

            ApplicationUser?owner = await userManager.FindByIdAsync(updatedCrowdaction.OwnerId).ConfigureAwait(false);

            if (owner == null && updatedCrowdaction.OwnerId != null)
            {
                return(new CrowdactionResult(new ValidationResult("New user owner does not exist")));
            }

            Crowdaction?crowdaction = await context
                                      .Crowdactions
                                      .Include(c => c.Tags).ThenInclude(t => t.Tag)
                                      .Include(c => c.Categories)
                                      .FirstOrDefaultAsync(c => c.Id == updatedCrowdaction.Id, token).ConfigureAwait(false);

            if (crowdaction == null)
            {
                return(new CrowdactionResult(new ValidationResult("Crowdaction not found", new[] { nameof(Crowdaction.Id) })));
            }

            if (crowdaction.Name != updatedCrowdaction.Name && await context.Crowdactions.AnyAsync(c => c.Name == updatedCrowdaction.Name, token).ConfigureAwait(false))
            {
                return(new CrowdactionResult(new ValidationResult("A crowdaction with this name already exists", new[] { nameof(Crowdaction.Name) })));
            }

            logger.LogInformation("Updating crowdaction: {0}", updatedCrowdaction.Name);

            bool approved        = updatedCrowdaction.Status == CrowdactionStatus.Running && crowdaction.Status != CrowdactionStatus.Running;
            bool changeFinishJob = (approved || crowdaction.End != updatedCrowdaction.End) && updatedCrowdaction.End > DateTime.UtcNow;
            bool removeFinishJob = updatedCrowdaction.Status != CrowdactionStatus.Running && crowdaction.FinishJobId != null;
            bool deleted         = updatedCrowdaction.Status == CrowdactionStatus.Deleted;

            crowdaction.Name                        = updatedCrowdaction.Name;
            crowdaction.Description                 = updatedCrowdaction.Description;
            crowdaction.Proposal                    = updatedCrowdaction.Proposal;
            crowdaction.Goal                        = updatedCrowdaction.Goal;
            crowdaction.CreatorComments             = updatedCrowdaction.CreatorComments;
            crowdaction.Target                      = updatedCrowdaction.Target;
            crowdaction.Start                       = updatedCrowdaction.Start;
            crowdaction.End                         = updatedCrowdaction.End.Date.AddHours(23).AddMinutes(59).AddSeconds(59);
            crowdaction.BannerImageFileId           = updatedCrowdaction.BannerImageFileId;
            crowdaction.CardImageFileId             = updatedCrowdaction.CardImageFileId;
            crowdaction.DescriptiveImageFileId      = updatedCrowdaction.DescriptiveImageFileId;
            crowdaction.DescriptionVideoLink        = updatedCrowdaction.DescriptionVideoLink?.Replace("www.youtube.com", "www.youtube-nocookie.com", StringComparison.Ordinal);
            crowdaction.Status                      = updatedCrowdaction.Status;
            crowdaction.DisplayPriority             = updatedCrowdaction.DisplayPriority;
            crowdaction.NumberCrowdactionEmailsSent = updatedCrowdaction.NumberCrowdactionEmailsSent;
            crowdaction.OwnerId                     = updatedCrowdaction.OwnerId;
            context.Crowdactions.Update(crowdaction);

            var crowdactionTags = crowdaction.Tags.Select(t => t.Tag !.Name);
            var tags            = updatedCrowdaction.Tags.Distinct().ToList();

            if (!Enumerable.SequenceEqual(tags.OrderBy(t => t), crowdactionTags.OrderBy(t => t)))
            {
                IEnumerable <string> missingTags =
                    tags.Except(await context.Tags
                                .Where(t => tags.Contains(t.Name))
                                .Select(t => t.Name)
                                .ToListAsync(token).ConfigureAwait(false));

                if (missingTags.Any())
                {
                    context.Tags.AddRange(missingTags.Select(t => new Tag(t)));
                    await context.SaveChangesAsync(token).ConfigureAwait(false);
                }

                var tagMap =
                    await context.Tags
                    .Where(t => tags.Contains(t.Name) || crowdactionTags.Contains(t.Name))
                    .ToDictionaryAsync(t => t.Name, t => t.Id, token).ConfigureAwait(false);

                IEnumerable <CrowdactionTag> newTags =
                    tags.Except(crowdactionTags)
                    .Select(t => new CrowdactionTag(crowdactionId: crowdaction.Id, tagId: tagMap[t]));

                IEnumerable <CrowdactionTag> removedTags =
                    crowdaction.Tags
                    .Where(t => crowdactionTags.Except(tags).Contains(t.Tag !.Name));
                context.CrowdactionTags.AddRange(newTags);
                context.CrowdactionTags.RemoveRange(removedTags);
            }

            var categories = crowdaction.Categories.Select(c => c.Category);

            if (!Enumerable.SequenceEqual(categories.OrderBy(c => c), updatedCrowdaction.Categories.OrderBy(c => c)))
            {
                IEnumerable <Category>            newCategories     = updatedCrowdaction.Categories.Except(categories);
                IEnumerable <CrowdactionCategory> removedCategories = crowdaction.Categories.Where(pc => !updatedCrowdaction.Categories.Contains(pc.Category));

                context.CrowdactionCategories.RemoveRange(removedCategories);
                context.CrowdactionCategories.AddRange(newCategories.Select(c => new CrowdactionCategory(crowdactionId: crowdaction.Id, category: c)));
            }

            if (approved && owner != null)
            {
                await emailSender.SendEmailTemplated(owner.Email, $"Approval - {crowdaction.Name}", "CrowdactionApproval").ConfigureAwait(false);
            }
            else if (deleted && owner != null)
            {
                await emailSender.SendEmailTemplated(owner.Email, $"Deleted - {crowdaction.Name}", "CrowdactionDeleted").ConfigureAwait(false);
            }

            if (changeFinishJob)
            {
                if (crowdaction.FinishJobId != null)
                {
                    jobClient.Delete(crowdaction.FinishJobId);
                }

                crowdaction.FinishJobId = jobClient.Schedule(() => CrowdactionEndProcess(crowdaction.Id, CancellationToken.None), crowdaction.End);
            }
            else if (removeFinishJob)
            {
                jobClient.Delete(crowdaction.FinishJobId);
            }

            await context.SaveChangesAsync(token).ConfigureAwait(false);

            logger.LogInformation("Updated crowdaction: {0}", updatedCrowdaction.Name);

            return(new CrowdactionResult(crowdaction));
        }