public async Task Should_throw_exception_if_number_of_apps_reached()
        {
            var userId = Guid.NewGuid().ToString();

            var command = new CreateApp
            {
                Actor = RefToken.User(userId)
            };

            var commandContext = new CommandContext(command, commandBus);

            options.MaximumNumberOfApps = 3;

            var user = A.Fake <IUser>();

            A.CallTo(() => user.Id)
            .Returns(userId);

            A.CallTo(() => user.Claims)
            .Returns(Enumerable.Repeat(new Claim(SquidexClaimTypes.TotalApps, "5"), 1).ToList());

            A.CallTo(() => userResolver.FindByIdAsync(userId, default))
            .Returns(user);

            var isNextCalled = false;

            await Assert.ThrowsAsync <ValidationException>(() => sut.HandleAsync(commandContext, x =>
            {
                isNextCalled = true;

                return(Task.CompletedTask);
            }));

            Assert.False(isNextCalled);
        }
Example #2
0
        public GuardAppContributorsTests()
        {
            A.CallTo(() => user1.Id)
            .Returns("1");

            A.CallTo(() => user2.Id)
            .Returns("2");

            A.CallTo(() => user3.Id)
            .Returns("3");

            A.CallTo(() => users.FindByIdAsync("1", default))
            .Returns(user1);

            A.CallTo(() => users.FindByIdAsync("2", default))
            .Returns(user2);

            A.CallTo(() => users.FindByIdAsync("3", default))
            .Returns(user3);

            A.CallTo(() => users.FindByIdAsync("notfound", default))
            .Returns(Task.FromResult <IUser?>(null));

            A.CallTo(() => appPlan.MaxContributors)
            .Returns(10);
        }
        public GuardAppContributorsTests()
        {
            A.CallTo(() => users.FindByIdAsync(A <string> .Ignored))
            .Returns(A.Fake <IUser>());

            A.CallTo(() => appPlan.MaxContributors)
            .Returns(10);
        }
        public async Task On(Envelope <IEvent> @event)
        {
            if (!emailSender.IsActive)
            {
                return;
            }

            if (@event.Headers.EventStreamNumber() <= 1)
            {
                return;
            }

            var now = SystemClock.Instance.GetCurrentInstant();

            var timestamp = @event.Headers.Timestamp();

            if (now - timestamp > MaxAge)
            {
                return;
            }

            if (@event.Payload is AppContributorAssigned appContributorAssigned)
            {
                if (!appContributorAssigned.Actor.IsUser || !appContributorAssigned.IsAdded)
                {
                    return;
                }

                var assignerId = appContributorAssigned.Actor.Identifier;
                var assigneeId = appContributorAssigned.ContributorId;

                var assigner = await userResolver.FindByIdAsync(assignerId);

                if (assigner == null)
                {
                    log.LogWarning("Failed to invite user: Assigner {assignerId} not found.", assignerId);
                    return;
                }

                var assignee = await userResolver.FindByIdAsync(appContributorAssigned.ContributorId);

                if (assignee == null)
                {
                    log.LogWarning("Failed to invite user: Assignee {assigneeId} not found.", assigneeId);
                    return;
                }

                var appName = appContributorAssigned.AppId.Name;

                await emailSender.SendInviteAsync(assigner, assignee, appName);
            }
        }
        public InvitationEventConsumerTests()
        {
            A.CallTo(() => notificatíonSender.IsActive)
                .Returns(true);

            A.CallTo(() => userResolver.FindByIdAsync(assignerId))
                .Returns(assigner);

            A.CallTo(() => userResolver.FindByIdAsync(assigneeId))
                .Returns(assignee);

            sut = new InvitationEventConsumer(notificatíonSender, userResolver, log);
        }
Example #6
0
        public static Task CanAssign(AppContributors contributors, AssignContributor command, IUserResolver users, IAppLimitsPlan plan)
        {
            Guard.NotNull(command, nameof(command));

            return(Validate.It(() => "Cannot assign contributor.", async error =>
            {
                if (!command.Permission.IsEnumValue())
                {
                    error(new ValidationError("Permission is not valid.", nameof(command.Permission)));
                }

                if (string.IsNullOrWhiteSpace(command.ContributorId))
                {
                    error(new ValidationError("Contributor id not assigned.", nameof(command.ContributorId)));
                }
                else
                {
                    if (await users.FindByIdAsync(command.ContributorId) == null)
                    {
                        error(new ValidationError("Cannot find contributor id.", nameof(command.ContributorId)));
                    }
                    else if (contributors.TryGetValue(command.ContributorId, out var existing))
                    {
                        if (existing == command.Permission)
                        {
                            error(new ValidationError("Contributor has already this permission.", nameof(command.Permission)));
                        }
                    }
                    else if (plan.MaxContributors == contributors.Count)
                    {
                        error(new ValidationError("You have reached the maximum number of contributors for your plan."));
                    }
                }
            }));
        }
        public async Task HandleAsync(CommandContext context, NextDelegate next)
        {
            if (usageOptions.MaximumNumberOfApps <= 0 || context.Command is not CreateApp createApp || createApp.Actor.IsClient)
            {
                await next(context);

                return;
            }

            var totalApps = 0;

            var user = await userResolver.FindByIdAsync(createApp.Actor.Identifier);

            if (user != null)
            {
                totalApps = user.Claims.GetTotalApps();

                if (totalApps >= usageOptions.MaximumNumberOfApps)
                {
                    throw new ValidationException(T.Get("apps.maximumTotalReached"));
                }
            }

            await next(context);

            if (context.IsCompleted && user != null)
            {
                var newApps      = totalApps + 1;
                var newAppsValue = newApps.ToString(CultureInfo.InvariantCulture);

                await userResolver.SetClaimAsync(user.Id, SquidexClaimTypes.TotalApps, newAppsValue, true);
            }
        }
        protected async Task On(AssignContributor command, CommandContext context)
        {
            if (await userResolver.FindByIdAsync(command.ContributorId) == null)
            {
                var error =
                    new ValidationError("Cannot find contributor the contributor",
                                        nameof(AssignContributor.ContributorId));

                throw new ValidationException("Cannot assign contributor to app", error);
            }

            await handler.UpdateAsync <AppDomainObject>(context, a =>
            {
                var oldContributors = a.ContributorCount;
                var maxContributors = appPlansProvider.GetPlan(a.PlanId).MaxContributors;

                a.AssignContributor(command);

                if (maxContributors > 0 && a.ContributorCount > oldContributors && a.ContributorCount > maxContributors)
                {
                    var error = new ValidationError("You have reached your max number of contributors");

                    throw new ValidationException("Cannot assign contributor to app", error);
                }
            });
        }
Example #9
0
        public async Task AssignContributor_should_throw_exception_if_user_not_found()
        {
            CreateApp();

            var context = CreateContextForCommand(new AssignContributor {
                ContributorId = contributorId
            });

            A.CallTo(() => userResolver.FindByIdAsync(contributorId))
            .Returns((IUser)null);

            await TestUpdate(app, async _ =>
            {
                await Assert.ThrowsAsync <ValidationException>(() => sut.HandleAsync(context));
            }, false);
        }
Example #10
0
        private Task <IUser?> FindUserAsync(RefToken actor)
        {
            var key = $"EventEnrichers_Users_{actor.Identifier}";

            return(userCache.GetOrCreateAsync(key, async x =>
            {
                x.AbsoluteExpirationRelativeToNow = UserCacheDuration;

                IUser?user;
                try
                {
                    user = await userResolver.FindByIdAsync(actor.Identifier);
                }
                catch
                {
                    user = null;
                }

                if (user == null && actor.IsClient)
                {
                    user = new ClientUser(actor);
                }

                return user;
            }));
        }
        public AppCommandMiddlewareTests()
        {
            A.CallTo(() => appProvider.GetAppAsync(AppName))
            .Returns((IAppEntity)null);

            A.CallTo(() => userResolver.FindByIdAsync(contributorId))
            .Returns(A.Fake <IUser>());

            sut = new AppCommandMiddleware(Handler, appProvider, appPlansProvider, appPlansBillingManager, userResolver);
        }
Example #12
0
        public async Task Should_not_enrich_with_user_if_token_is_null()
        {
            RefToken actor = null !;

            var @event =
                Envelope.Create <AppEvent>(new ContentCreated
            {
                Actor = actor
            });

            var enrichedEvent = new EnrichedContentEvent();

            await sut.EnrichAsync(enrichedEvent, @event);

            Assert.Null(enrichedEvent.User);

            A.CallTo(() => userResolver.FindByIdAsync(A <string> ._))
            .MustNotHaveHappened();
        }
Example #13
0
        public GuardAppTests()
        {
            A.CallTo(() => apps.GetAppAsync("new-app"))
            .Returns(Task.FromResult <IAppEntity>(null));

            A.CallTo(() => users.FindByIdAsync(A <string> .Ignored))
            .Returns(A.Fake <IUser>());

            A.CallTo(() => appPlans.GetPlan("free"))
            .Returns(A.Fake <IAppLimitsPlan>());
        }
Example #14
0
        public AppGrainTests()
        {
            A.CallTo(() => appProvider.GetAppAsync(AppName))
            .Returns((IAppEntity)null);

            A.CallTo(() => userResolver.FindByIdAsync(contributorId))
            .Returns(A.Fake <IUser>());

            initialPatterns = new InitialPatterns
            {
                { patternId1, new AppPattern("Number", "[0-9]") },
                { patternId2, new AppPattern("Numbers", "[0-9]*") }
            };

            sut = new AppGrain(initialPatterns, Store, appProvider, appPlansProvider, appPlansBillingManager, userResolver);
            sut.OnActivateAsync(Id).Wait();
        }
Example #15
0
        public static Task CanAssign(AssignContributor command, IAppEntity app, IUserResolver users, IAppLimitsPlan plan)
        {
            Guard.NotNull(command, nameof(command));

            var contributors = app.Contributors;

            return(Validate.It(async e =>
            {
                if (!app.Roles.Contains(command.Role))
                {
                    e(Not.Valid(nameof(command.Role)), nameof(command.Role));
                }

                if (string.IsNullOrWhiteSpace(command.ContributorId))
                {
                    e(Not.Defined(nameof(command.ContributorId)), nameof(command.ContributorId));
                }
                else
                {
                    var user = await users.FindByIdAsync(command.ContributorId);

                    if (user == null)
                    {
                        throw new DomainObjectNotFoundException(command.ContributorId);
                    }

                    if (!command.Restoring)
                    {
                        if (string.Equals(command.ContributorId, command.Actor?.Identifier, StringComparison.OrdinalIgnoreCase))
                        {
                            throw new DomainForbiddenException(T.Get("apps.contributors.cannotChangeYourself"));
                        }

                        if (!contributors.TryGetValue(command.ContributorId, out _))
                        {
                            if (plan.MaxContributors > 0 && contributors.Count >= plan.MaxContributors)
                            {
                                e(T.Get("apps.contributors.maxReached"));
                            }
                        }
                    }
                }
            }));
        }
Example #16
0
        public static Task CanAssign(AppContributors contributors, Roles roles, AssignContributor command, IUserResolver users, IAppLimitsPlan?plan)
        {
            Guard.NotNull(command);

            return(Validate.It(() => "Cannot assign contributor.", async e =>
            {
                if (!roles.Contains(command.Role))
                {
                    e(Not.Valid("role"), nameof(command.Role));
                }

                if (string.IsNullOrWhiteSpace(command.ContributorId))
                {
                    e(Not.Defined("Contributor id"), nameof(command.ContributorId));
                }
                else
                {
                    var user = await users.FindByIdAsync(command.ContributorId);

                    if (user == null)
                    {
                        throw new DomainObjectNotFoundException(command.ContributorId, "Contributors", typeof(IAppEntity));
                    }

                    if (!command.Restoring)
                    {
                        if (string.Equals(command.ContributorId, command.Actor?.Identifier, StringComparison.OrdinalIgnoreCase))
                        {
                            throw new DomainForbiddenException("You cannot change your own role.");
                        }

                        if (!contributors.TryGetValue(command.ContributorId, out var role))
                        {
                            if (plan != null && plan.MaxContributors > 0 && contributors.Count >= plan.MaxContributors)
                            {
                                e("You have reached the maximum number of contributors for your plan.");
                            }
                        }
                    }
                }
            }));
        }
Example #17
0
        public async Task HandleEventAsync(Envelope <IEvent> @event)
        {
            Guard.NotNull(@event, nameof(@event));

            if (client == null)
            {
                return;
            }

            switch (@event.Payload)
            {
            case CommentCreated comment:
            {
                if (IsTooOld(@event.Headers))
                {
                    return;
                }

                if (comment.Mentions == null || comment.Mentions.Length == 0)
                {
                    break;
                }

                using (var stream = client.PublishMany())
                {
                    foreach (var userId in comment.Mentions)
                    {
                        var publishRequest = new PublishRequest
                        {
                            AppId = options.AppId
                        };

                        publishRequest.Topic = $"users/{userId}";

                        publishRequest.Properties["SquidexApp"]   = comment.AppId.Name;
                        publishRequest.Preformatted               = new NotificationFormattingDto();
                        publishRequest.Preformatted.Subject["en"] = comment.Text;

                        if (comment.Url?.IsAbsoluteUri == true)
                        {
                            publishRequest.Preformatted.LinkUrl["en"] = comment.Url.ToString();
                        }

                        SetUser(comment, publishRequest);

                        await stream.RequestStream.WriteAsync(publishRequest);
                    }

                    await stream.RequestStream.CompleteAsync();

                    await stream.ResponseAsync;
                }

                break;
            }

            case AppContributorAssigned contributorAssigned:
            {
                var user = await userResolver.FindByIdAsync(contributorAssigned.ContributorId);

                if (user != null)
                {
                    await UpsertUserAsync(user);
                }

                var request = BuildAllowedTopicRequest(contributorAssigned, contributorAssigned.ContributorId);

                try
                {
                    await client.AddAllowedTopicAsync(request);
                }
                catch (RpcException ex) when(ex.StatusCode == StatusCode.NotFound)
                {
                    break;
                }

                break;
            }

            case AppContributorRemoved contributorRemoved:
            {
                var request = BuildAllowedTopicRequest(contributorRemoved, contributorRemoved.ContributorId);

                try
                {
                    await client.RemoveAllowedTopicAsync(request);
                }
                catch (RpcException ex) when(ex.StatusCode == StatusCode.NotFound)
                {
                    break;
                }

                break;
            }
            }
        }