예제 #1
0
        public async Task TestCommentCreate()
        {
            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, null);
            Crowdaction crowdaction    = await crowdactionService.CreateCrowdactionInternal(newCrowdaction, CancellationToken.None);

            Assert.NotNull(crowdaction);

            ApplicationUser user = await context.Users.FirstAsync();

            ClaimsPrincipal userPrincipal = await signInManager.CreateUserPrincipalAsync(user);

            CrowdactionComment firstComment = await crowdactionService.CreateComment("test test", crowdaction.Id, userPrincipal, CancellationToken.None);

            Assert.NotNull(firstComment);

            await Assert.ThrowsAnyAsync <Exception>(() => crowdactionService.CreateComment("test test <script />", crowdaction.Id, userPrincipal, CancellationToken.None));

            await Assert.ThrowsAnyAsync <Exception>(() => crowdactionService.CreateComment("test test <a href=\"javascript:alert('hello')\" />", crowdaction.Id, userPrincipal, CancellationToken.None));

            await crowdactionService.DeleteComment(firstComment.Id, CancellationToken.None);

            CrowdactionComment retrievedComment = await context.CrowdactionComments.FirstOrDefaultAsync(c => c.Id == firstComment.Id);

            Assert.Null(retrievedComment);

            CrowdactionComment sanitizedComment = await crowdactionService.CreateComment("test test <p><a href=\"www.google.com\" /></p>", crowdaction.Id, userPrincipal, CancellationToken.None);

            Assert.Equal("test test <p><a href=\"https://www.google.com\" rel=\"nofollow ugc\"></a></p>", sanitizedComment.Comment);
            await crowdactionService.DeleteComment(sanitizedComment.Id, CancellationToken.None);
        }
예제 #2
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);
        }
예제 #3
0
        public async Task TestCrowdactionList()
        {
            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, null);
            Crowdaction createdCrowdaction = await crowdactionService.CreateCrowdactionInternal(newCrowdaction, CancellationToken.None);

            Assert.NotNull(createdCrowdaction);

            const string QueryCrowdactions = @"
                query {
                    crowdactions {
                        id
                        name
                        categories {
                          category
                        }
                        descriptiveImage {
                            filepath
                        }
                    }
                }";

            HttpResponseMessage response = await PerformGraphQlQuery(QueryCrowdactions, null);

            string content = await response.Content.ReadAsStringAsync();

            Assert.True(response.IsSuccessStatusCode, content);
            JsonDocument result = JsonDocument.Parse(content);

            Assert.Throws <KeyNotFoundException>(() => result.RootElement.GetProperty("errors"));
            JsonElement.ArrayEnumerator crowdactions = result.RootElement.GetProperty("data").GetProperty("crowdactions").EnumerateArray();
            Assert.True(crowdactions.Any(), content);

            string       crowdactionId    = crowdactions.First().GetProperty("id").GetString();
            const string QueryCrowdaction = @"
                query($crowdactionId : ID!) {
                    crowdaction(id: $crowdactionId) {
                        id
                        name
                        descriptiveImage {
                            filepath
                        }
                    }
                }";
            dynamic      variables        = new { crowdactionId };

            response = await PerformGraphQlQuery(QueryCrowdaction, variables);

            content = await response.Content.ReadAsStringAsync();

            Assert.True(response.IsSuccessStatusCode, content);
            result = JsonDocument.Parse(content);
            Assert.Throws <KeyNotFoundException>(() => result.RootElement.GetProperty("errors"));
            JsonElement crowdaction = result.RootElement.GetProperty("data").GetProperty("crowdaction");

            Assert.Equal(crowdactionId.ToString(CultureInfo.InvariantCulture), crowdaction.GetProperty("id").GetString());
        }
예제 #4
0
        public async Task TestCrowdactionSearch()
        {
            Random   r = new Random();
            Category searchCategory = (Category)r.Next(7);

            for (int i = 0; i < r.Next(10, 30); i++)
            {
                var         newCrowdaction = new NewCrowdactionInternal("test" + Guid.NewGuid(), 100, "test", "test", "test", null, DateTime.UtcNow.AddDays(r.Next(-20, 20)), DateTime.UtcNow.AddDays(r.Next(21, 50)), null, null, null, null, new[] { searchCategory }, Array.Empty <string>(), CrowdactionDisplayPriority.Bottom, (CrowdactionStatus)r.Next(3), 0, null);
                Crowdaction crowdaction    = await crowdactionService.CreateCrowdactionInternal(newCrowdaction, CancellationToken.None);
            }

            Assert.True(await crowdactionService.SearchCrowdactions(null, null).AnyAsync());

            Assert.True(await crowdactionService.SearchCrowdactions(searchCategory, null).Include(c => c.Categories).AllAsync(c => c.Categories.Any(pc => pc.Category == searchCategory)));
            Assert.True(await crowdactionService.SearchCrowdactions(null, SearchCrowdactionStatus.Closed).AllAsync(c => c.End < DateTime.UtcNow));
            Assert.True(await crowdactionService.SearchCrowdactions(searchCategory, SearchCrowdactionStatus.Closed).AllAsync(c => c.End < DateTime.UtcNow));
            Assert.True(await crowdactionService.SearchCrowdactions(null, SearchCrowdactionStatus.ComingSoon).AllAsync(c => c.Start > DateTime.UtcNow && c.Status == CrowdactionStatus.Running));
            Assert.True(await crowdactionService.SearchCrowdactions(searchCategory, SearchCrowdactionStatus.ComingSoon).AllAsync(c => c.Start > DateTime.UtcNow && c.Status == CrowdactionStatus.Running));
            Assert.True(await crowdactionService.SearchCrowdactions(null, SearchCrowdactionStatus.Open).AllAsync(c => c.Start <= DateTime.UtcNow && c.End >= DateTime.UtcNow && c.Status == CrowdactionStatus.Running));
            Assert.True(await crowdactionService.SearchCrowdactions(searchCategory, SearchCrowdactionStatus.Open).AllAsync(c => c.Start <= DateTime.UtcNow && c.End >= DateTime.UtcNow && c.Status == CrowdactionStatus.Running));
        }
        public async Task <Crowdaction> CreateCrowdactionInternal(NewCrowdactionInternal newCrowdaction, CancellationToken token)
        {
            if (await context.Crowdactions.AnyAsync(c => c.Name == newCrowdaction.Name, token).ConfigureAwait(false))
            {
                throw new InvalidOperationException($"A crowdaction with this name already exists: {newCrowdaction.Name}");
            }

            logger.LogInformation("Creating crowdaction: {0}", newCrowdaction.Name);
            var           tagMap = new Dictionary <string, int>();
            List <string> tags   = newCrowdaction.Tags.Distinct().ToList();

            if (tags.Any())
            {
                var missingTags = tags.Except(
                    await context.Tags
                    .Where(t => tags.Contains(t.Name))
                    .Select(t => t.Name)
                    .ToListAsync(token).ConfigureAwait(false))
                                  .Select(t => new Tag(t));

                if (missingTags.Any())
                {
                    context.Tags.AddRange(missingTags);
                    await context.SaveChangesAsync(token).ConfigureAwait(false);
                }

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

            List <CrowdactionTag> crowdactionTags =
                tags.Select(t => new CrowdactionTag(tagId: tagMap[t]))
                .ToList();

            var crowdaction = new Crowdaction(
                name: newCrowdaction.Name,
                status: newCrowdaction.Status,
                ownerId: newCrowdaction.OwnerId,
                target: newCrowdaction.Target,
                start: newCrowdaction.Start,
                end: newCrowdaction.End.Date.AddHours(23).AddMinutes(59).AddSeconds(59),
                description: newCrowdaction.Description,
                goal: newCrowdaction.Goal,
                proposal: newCrowdaction.Proposal,
                creatorComments: newCrowdaction.CreatorComments,
                descriptionVideoLink: newCrowdaction.DescriptionVideoLink?.Replace("www.youtube.com", "www.youtube-nocookie.com", StringComparison.Ordinal),
                displayPriority: newCrowdaction.DisplayPriority,
                anonymousUserParticipants: newCrowdaction.AnonymousUserParticipants,
                bannerImageFileId: newCrowdaction.BannerImageFileId,
                cardImageFileId: newCrowdaction.CardImageFileId,
                descriptiveImageFileId: newCrowdaction.DescriptiveImageFileId,
                categories: newCrowdaction.Categories.Select(c => new CrowdactionCategory((c))).ToList(),
                tags: crowdactionTags);

            context.Crowdactions.Add(crowdaction);
            await context.SaveChangesAsync(token).ConfigureAwait(false);

            await RefreshParticipantCount(token).ConfigureAwait(false);

            if (!crowdaction.IsClosed)
            {
                crowdaction.FinishJobId = jobClient.Schedule(() => CrowdactionEndProcess(crowdaction.Id, CancellationToken.None), crowdaction.End);
                await context.SaveChangesAsync(token).ConfigureAwait(false);
            }

            return(crowdaction);
        }
예제 #6
0
        private async Task SeedRandomCrowdactions(IEnumerable <ApplicationUser> users, CancellationToken cancellationToken)
        {
            Random   r   = new Random();
            DateTime now = DateTime.UtcNow;

            string?[] videoLinks = new[]
            {
                "https://www.youtube-nocookie.com/embed/aLzM_L5fjCQ",
                "https://www.youtube-nocookie.com/embed/Zvugem-tKyI",
                "https://www.youtube-nocookie.com/embed/xY0XTysJUDY",
                "https://www.youtube-nocookie.com/embed/2yfPLxQQG-k",
                null
            };

            List <(Uri bannerImageUrl, Task <byte[]> bannerImageBytes)> bannerImages = new[]
            {
                "https://collaction-production.s3.eu-central-1.amazonaws.com/57136ed4-b7f6-4dd2-a822-9341e2e60d1e.png",
                "https://collaction-production.s3.eu-central-1.amazonaws.com/765bc57b-748e-4bb8-a27e-08db6b99ea3e.png",
                "https://collaction-production.s3.eu-central-1.amazonaws.com/e06bbc2d-02f7-4a9b-a744-6923d5b21f51.png",
            }.Select(b => new Uri(b)).Select(b => (b, DownloadFile(b, cancellationToken))).ToList();

            List <(Uri descriptiveImageUrl, Task <byte[]> descriptiveImageBytes)> descriptiveImages = new[]
            {
                "https://collaction-production.s3.eu-central-1.amazonaws.com/107104bc-deeb-4f48-b3a5-f25585bebf89.png",
                "https://collaction-production.s3.eu-central-1.amazonaws.com/365f2dc9-1784-45ea-9cc7-d5f0ef1a480c.png",
                "https://collaction-production.s3.eu-central-1.amazonaws.com/6e6c12b1-eaae-4811-aa1c-c169d10f1a59.png",
            }.Select(b => new Uri(b)).Select(b => (b, DownloadFile(b, cancellationToken))).ToList();

            await Task.WhenAll(descriptiveImages.Select(d => d.descriptiveImageBytes).Concat(bannerImages.Select(b => b.bannerImageBytes))).ConfigureAwait(false);

            List <string> tags = Enumerable.Range(0, seedOptions.NumberSeededTags)
                                 .Select(r => Faker.Internet.DomainWord())
                                 .Distinct()
                                 .ToList();

            var crowdactionNames =
                Enumerable.Range(0, seedOptions.NumberSeededCrowdactions)
                .Select(i => Faker.Company.Name())
                .Distinct()
                .ToList();

            List <string> userIds = await context.Users.Select(u => u.Id).ToListAsync(cancellationToken).ConfigureAwait(false);

            List <Crowdaction> crowdactions = new List <Crowdaction>(crowdactionNames.Count);

            // Generate random crowdactions
            foreach (string crowdactionName in crowdactionNames)
            {
                DateTime start = now.Date.AddDays(r.Next(-10, 20));

                const int            MaxTagsForCrowdaction = 4;
                IEnumerable <string> crowdactionTags       =
                    Enumerable.Range(0, r.Next(MaxTagsForCrowdaction + 1))
                    .Select(i => r.Next(tags.Count))
                    .Distinct()
                    .Select(i => tags[i])
                    .ToList();

                int             numberCategories = Enum.GetValues(typeof(Category)).Length;
                List <Category> categories       =
                    new[]
                {
                    (Category)r.Next(numberCategories),
                    (Category)r.Next(numberCategories)
                }.Distinct().ToList();

                (Uri descriptiveImageUrl, Task <byte[]> descriptiveImageBytes) = descriptiveImages[r.Next(descriptiveImages.Count)];
                ImageFile?descriptiveImage = r.Next(3) == 0
                                                  ? null
                                                  : await imageService.UploadImage(ToFormFile(descriptiveImageBytes.Result, descriptiveImageUrl), Faker.Company.BS(), MaxImageBannerDimensionPixels, cancellationToken).ConfigureAwait(false);

                (Uri bannerImageUrl, Task <byte[]> bannerImageBytes) = bannerImages[r.Next(bannerImages.Count)];
                ImageFile?bannerImage = r.Next(3) == 0
                                             ? null
                                             : await imageService.UploadImage(ToFormFile(bannerImageBytes.Result, bannerImageUrl), Faker.Company.BS(), MaxImageBannerDimensionPixels, cancellationToken).ConfigureAwait(false);

                ImageFile?cardImage = bannerImage == null
                                          ? null
                                          : await imageService.UploadImage(ToFormFile(bannerImageBytes.Result, bannerImageUrl), Faker.Company.BS(), MaxImageCardDimensionPixels, cancellationToken).ConfigureAwait(false);

                ApplicationUser        owner           = users.ElementAt(users.Count() - 1);
                int                    numberStatusses = Enum.GetValues(typeof(CrowdactionStatus)).Length;
                CrowdactionStatus      status          = (CrowdactionStatus)r.Next(numberStatusses);
                NewCrowdactionInternal newCrowdaction  =
                    new NewCrowdactionInternal(
                        name: crowdactionName,
                        description: $"<p>{string.Join("</p><p>", Faker.Lorem.Paragraphs(r.Next(3) + 1))}</p>",
                        start: start,
                        end: start.AddDays(r.Next(10, 40)).AddHours(23).AddMinutes(59).AddSeconds(59),
                        categories: categories,
                        tags: crowdactionTags,
                        bannerImageFileId: bannerImage?.Id,
                        descriptiveImageFileId: descriptiveImage?.Id,
                        cardImageFileId: cardImage?.Id,
                        creatorComments: r.Next(4) == 0 ? null : $"<p>{string.Join("</p><p>", Faker.Lorem.Paragraphs(r.Next(3) + 1))}</p>",
                        goal: Faker.Company.CatchPhrase(),
                        proposal: Faker.Company.BS(),
                        target: r.Next(1, 10000),
                        descriptionVideoLink: videoLinks.ElementAt(r.Next(videoLinks.Length)),
                        displayPriority: (CrowdactionDisplayPriority)r.Next(3),
                        status: (CrowdactionStatus)r.Next(3),
                        ownerId: owner.Id,
                        anonymousUserParticipants: r.Next(1, 8000));

                Crowdaction crowdaction = await crowdactionService.CreateCrowdactionInternal(newCrowdaction, cancellationToken).ConfigureAwait(false);

                context.CrowdactionParticipants.AddRange(
                    userIds.Where(userId => r.Next(2) == 0)
                    .Select(userId => new CrowdactionParticipant(userId, crowdaction.Id, r.Next(2) == 1, now, Guid.NewGuid())));
                await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);

                IEnumerable <CrowdactionComment> comments =
                    Enumerable.Range(-24 * seedOptions.NumberDaysSeededForComments, 24 * seedOptions.NumberDaysSeededForComments)
                    .Where(i => r.NextDouble() <= seedOptions.ProbabilityCommentSeededPerHour)
                    .Select(i =>
                {
                    DateTime commentedAt = DateTime.Now.AddHours(i).AddMinutes(r.Next(-30, 30)).AddSeconds(r.Next(-30, 30));
                    string comment       = $"<p>{string.Join("</p><p>", Faker.Lorem.Paragraphs(r.Next(2) + 1))}</p>";
                    string anonymousName = Faker.Name.First();
                    (string?userId, string?anonymousUser) = r.Next(3) == 0 ? ((string?)null, anonymousName.Substring(0, Math.Min(20, anonymousName.Length))) : (userIds[r.Next(userIds.Count)], null);
                    var status = (CrowdactionCommentStatus)r.Next(3);
                    return(new CrowdactionComment(comment, userId, anonymousUser, crowdaction.Id, commentedAt, status));
                });
                foreach (var comment in comments) // Insert one-by-one to preserve insertion order
                {
                    context.CrowdactionComments.Add(comment);
                    await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
                }
            }
        }