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)); }