public bool CanDownGrade(Organization organization, BillingPlan plan, User user, out string message) {
            if (organization == null || String.IsNullOrWhiteSpace(organization.Id)) {
                message = "Invalid Organization";
                return false;
            }

            int currentNumberOfUsers = _userRepository.GetByOrganizationId(organization.Id).Count() + organization.Invites.Count;
            int maxUsers = plan.MaxUsers != -1 ? plan.MaxUsers : int.MaxValue;
            if (currentNumberOfUsers > maxUsers) {
                message = String.Format("Please remove {0} user{1} and try again.", currentNumberOfUsers - maxUsers, (currentNumberOfUsers - maxUsers) > 0 ? "s" : String.Empty);
                return false;
            }

            int maxProjects = plan.MaxProjects != -1 ? plan.MaxProjects : int.MaxValue;
            long projectCount = _projectRepository.GetCountByOrganizationId(organization.Id);
            if (projectCount > maxProjects) {
                message = String.Format("Please remove {0} project{1} and try again.", projectCount - maxProjects, (projectCount - maxProjects) > 0 ? "s" : String.Empty);
                return false;
            }

            // Ensure the user can't be apart of more than one free plan.
            if (String.Equals(plan.Id, FreePlan.Id) && user != null && _organizationRepository.GetByIds(user.OrganizationIds).Any(o => String.Equals(o.PlanId, FreePlan.Id))) {
                message = "You already have one free account. You are not allowed to create more than one free account.";
                return false;
            }

            message = String.Empty;
            return true;
        }
        public bool CanDownGrade(Organization organization, BillingPlan plan, User user, out string message) {
            if (organization == null || String.IsNullOrWhiteSpace(organization.Id)) {
                message = "Invalid Organization";
                return false;
            }

            int currentNumberOfUsers = _userRepository.GetByOrganizationId(organization.Id).Count() + organization.Invites.Count;
            int maxUsers = plan.MaxUsers != -1 ? plan.MaxUsers : int.MaxValue;
            if (currentNumberOfUsers > maxUsers) {
                message = String.Format("Please remove {0} user{1} and try again.", currentNumberOfUsers - maxUsers, (currentNumberOfUsers - maxUsers) > 0 ? "s" : String.Empty);
                return false;
            }

            int maxProjects = plan.MaxProjects != -1 ? plan.MaxProjects : int.MaxValue;
            if (organization.ProjectCount > maxProjects) {
                message = String.Format("Please remove {0} project{1} and try again.", organization.ProjectCount - maxProjects, (organization.ProjectCount - maxProjects) > 0 ? "s" : String.Empty);
                return false;
            }

            // TODO: We need to make this smarter.
            if (organization.OverageDays != null && organization.OverageDays.Count(d => d.Day > DateTime.Now.AddDays(-30)) > 0 && plan.MaxErrorsPerDay < GetBillingPlan(organization.PlanId).MaxErrorsPerDay) {
                message = "You would exceed the maximum errors per day plan limit.";
                return false;
            }

            // Ensure the user can't be apart of more than one free plan.
            if (String.Equals(plan.Id, FreePlan.Id) && user != null && _organizationRepository.GetByIds(user.OrganizationIds).Any(o => String.Equals(o.PlanId, FreePlan.Id))) {
                message = "You already have one free account. You are not allowed to create more than one free account.";
                return false;
            }

            message = String.Empty;
            return true;
        }
        public bool CanAddUser(Organization organization) {
            if (organization == null || String.IsNullOrWhiteSpace(organization.Id))
                return false;

            List<User> users = _userRepository.GetByOrganizationId(organization.Id).ToList();
            return organization.MaxUsers <= -1 || users.Count < organization.MaxUsers;
        }
        public bool CanAddUser(Organization organization) {
            if (organization == null || String.IsNullOrWhiteSpace(organization.Id))
                return false;

            int numberOfUsers = _userRepository.GetByOrganizationId(organization.Id).Count + organization.Invites.Count;
            return organization.MaxUsers <= -1 || numberOfUsers < organization.MaxUsers;
        }
Beispiel #5
0
 public async Task SendPaymentFailedAsync(User owner, Organization organization) {
     MailMessage msg = _emailGenerator.GenerateMessage(new PaymentModel {
         Owner = owner,
         Organization = organization,
         BaseUrl = Settings.Current.BaseURL
     }, "PaymentFailed");
     msg.To.Add(owner.EmailAddress);
     await QueueMessage(msg);
 }
Beispiel #6
0
 public async Task SendInviteAsync(User sender, Organization organization, Invite invite) {
     MailMessage msg = _emailGenerator.GenerateMessage(new InviteModel {
         Sender = sender,
         Organization = organization,
         Invite = invite,
         BaseUrl = Settings.Current.BaseURL
     }, "Invite");
     msg.To.Add(invite.EmailAddress);
     await QueueMessage(msg);
 }
Beispiel #7
0
        public async Task SendAddedToOrganizationAsync(User sender, Organization organization, User user) {
            MailMessage msg = _emailGenerator.GenerateMessage(new AddedToOrganizationModel {
                Sender = sender,
                Organization = organization,
                User = user,
                BaseUrl = Settings.Current.BaseURL
            }, "AddedToOrganization");
            msg.To.Add(user.EmailAddress);

            await QueueMessage(msg);
        }
        public WebHookDataContext(Version version, Stack stack, Organization organization = null, Project project = null, bool isNew = false, bool isRegression = false)
        {
            if (version == null)
                throw new ArgumentException("Version cannot be null.", "version");

            if (stack == null)
                throw new ArgumentException("Stack cannot be null.", "stack");

            Version = version;
            Organization = organization;
            Project = project;
            Stack = stack;
            IsNew = isNew;
            IsRegression = isRegression;
        }
        public static Organization GenerateOrganization(bool generateId = false, string name = null, string id = null, string inviteEmail = null, bool isSuspended = false) {
            var organization = new Organization {
                Id = id.IsNullOrEmpty() ? generateId ? ObjectId.GenerateNewId().ToString() : TestConstants.OrganizationId : id,
                Name = name ?? String.Format("Organization{0}", id),
                IsSuspended = isSuspended
            };

            if (!String.IsNullOrEmpty(inviteEmail)) {
                organization.Invites.Add(new Invite {
                    EmailAddress = inviteEmail,
                    Token = Guid.NewGuid().ToString()
                });
            }

            return organization;
        }
        public WebHookDataContext(Version version, PersistentEvent ev, Organization organization = null, Project project = null, Stack stack = null, bool isNew = false, bool isRegression = false)
        {
            if (version == null)
                throw new ArgumentException("Version cannot be null.", "version");

            if (ev == null)
                throw new ArgumentException("Event cannot be null.", "ev");

            Version = version;
            Organization = organization;
            Project = project;
            Stack = stack;
            Event = ev;
            IsNew = isNew;
            IsRegression = isRegression;
        }
        public void CanCreateUpdateRemove() {
            _repository.RemoveAll();
            Assert.Equal(0, _repository.Count());

            var organization = new Organization();
            Assert.Null(organization.Id);

            _repository.Add(organization);
            Assert.NotNull(organization.Id);
            
            organization = _repository.GetById(organization.Id);
            Assert.NotNull(organization);

            organization.Name = "New organization";
            _repository.Save(organization);

            _repository.Remove(organization.Id);
        }
        public void CanCreateUpdateRemove() {
            _repository.RemoveAll();
            Assert.Equal(0, _repository.Count());

            var organization = new Organization { Name = "Test Organization", PlanId = BillingManager.FreePlan.Id };
            Assert.Null(organization.Id);

            _repository.Add(organization);
            Assert.NotNull(organization.Id);
            
            organization = _repository.GetById(organization.Id);
            Assert.NotNull(organization);

            organization.Name = "New organization";
            _repository.Save(organization);

            _repository.Remove(organization.Id);
        }
        private void TryDeleteOrganization(Organization organization) {
            try {
                Log.Info().Message("Removing existing empty projects for the organization '{0}' with Id: '{1}'.", organization.Name, organization.Id).Write();
                List<Project> projects = _projectRepository.GetByOrganizationId(organization.Id).ToList();
                if (projects.Any(project => project.TotalEventCount > 0)) {
                    Log.Info().Message("Organization '{0}' with Id: '{1}' has a project with existing data. This organization will not be deleted.", organization.Name, organization.Id).Write();
                    return;
                }

                foreach (Project project in projects) {
                    Log.Info().Message("Resetting all project data for project '{0}' with Id: '{1}'.", project.Name, project.Id).Write();
                    _stackRepository.RemoveAllByProjectIdAsync(project.Id).Wait();
                    _eventRepository.RemoveAllByProjectIdAsync(project.Id).Wait();
                    _dayStackStats.RemoveAllByProjectIdAsync(project.Id).Wait();
                    _monthStackStats.RemoveAllByProjectIdAsync(project.Id).Wait();
                    _dayProjectStats.RemoveAllByProjectIdAsync(project.Id).Wait();
                    _monthProjectStats.RemoveAllByProjectIdAsync(project.Id).Wait();
                }

                Log.Info().Message("Deleting all projects for organization '{0}' with Id: '{1}'.", organization.Name, organization.Id).Write();
                _projectRepository.Remove(projects);

                Log.Info().Message("Removing users from organization '{0}' with Id: '{1}'.", organization.Name, organization.Id).Write();
                List<User> users = _userRepository.GetByOrganizationId(organization.Id).ToList();
                foreach (User user in users) {
                    if (user.OrganizationIds.All(oid => String.Equals(oid, organization.Id))) {
                        Log.Info().Message("Removing user '{0}' as they do not belong to any other organizations.", user.Id, organization.Name, organization.Id).Write();
                        _userRepository.Remove(user.Id);
                    } else {
                        Log.Info().Message("Removing user '{0}' from organization '{1}' with Id: '{2}'", user.Id, organization.Name, organization.Id).Write();
                        user.OrganizationIds.Remove(organization.Id);
                        _userRepository.Save(user);
                    }
                }

                Log.Info().Message("Deleting organization '{0}' with Id: '{1}'.", organization.Name, organization.Id).Write();
                _organizationRepository.Remove(organization);

                // TODO: Send notifications that the organization and projects have been updated.
            } catch (Exception ex) {
                ex.ToExceptionless().MarkAsCritical().AddTags("Remove Stale Accounts").AddObject(organization).Submit();
            }
        }
        private void EnforceEventCountLimits(Organization organization) {
            Log.Info().Message("Enforcing event count limits for organization '{0}' with Id: '{1}'", organization.Name, organization.Id).Write();

            try {
                // use the next higher plans retention days to enable us to upsell them
                BillingPlan nextPlan = BillingManager.Plans
                    .Where(p => p.RetentionDays > organization.RetentionDays)
                    .OrderByDescending(p => p.RetentionDays)
                    .FirstOrDefault();

                int retentionDays = organization.RetentionDays;
                if (nextPlan != null)
                    retentionDays = nextPlan.RetentionDays;

                DateTime cutoff = DateTime.UtcNow.Date.AddDays(-retentionDays);
                _eventRepository.RemoveAllByDate(organization.Id, cutoff);
            } catch (Exception ex) {
                ex.ToExceptionless().MarkAsCritical().AddTags("Enforce Limits").AddObject(organization).Submit();
            }
        }
        public void CanAddAndGetByCached() {
            var cache = IoC.GetInstance<ICacheClient>() as InMemoryCacheClient;
            Assert.NotNull(cache);
            cache.FlushAll();
            
            var organization = new Organization { Name = "Test Organization", PlanId = BillingManager.FreePlan.Id };
            Assert.Null(organization.Id);

            Assert.Equal(0, cache.Count);
            _repository.Add(organization, true);
            Assert.NotNull(organization.Id);
            Assert.Equal(1, cache.Count);

            cache.FlushAll();
            Assert.Equal(0, cache.Count);
            _repository.GetById(organization.Id, true);
            Assert.NotNull(organization.Id);
            Assert.Equal(1, cache.Count);

            _repository.RemoveAll();
            Assert.Equal(0, cache.Count);
        }
        public void CanAddAndGetByCached() {
            var cache = IoC.GetInstance<ICacheClient>() as InMemoryCacheClient;
            Assert.NotNull(cache);
            cache.FlushAll();
            
            var organization = new Organization();
            Assert.Null(organization.Id);

            Assert.Equal(0, cache.Count);
            _repository.Add(organization, true);
            Assert.NotNull(organization.Id);
            Assert.Equal(1, cache.Count);

            cache.FlushAll();
            Assert.Equal(0, cache.Count);
            _repository.GetById(organization.Id, true);
            Assert.NotNull(organization.Id);
            Assert.Equal(1, cache.Count);

            _repository.RemoveAll();
            Assert.Equal(0, cache.Count);
        }
Beispiel #17
0
 public void SendAddedToOrganization(User sender, Organization organization, User user) {}
Beispiel #18
0
 public void SendPaymentFailed(User owner, Organization organization) {}
Beispiel #19
0
 public void SendInvite(User sender, Organization organization, Invite invite) {}
Beispiel #20
0
 public Task SendInviteAsync(User sender, Organization organization, Invite invite)
 {
     return Task.FromResult(0);
 }
Beispiel #21
0
 public Task SendAddedToOrganizationAsync(User sender, Organization organization, User user)
 {
     return Task.FromResult(0);
 }
Beispiel #22
0
 public Task SendAddedToOrganizationAsync(User sender, Organization organization, User user) {
     return Task.Delay(0);
 }
        public void CreateSampleOrganizationAndProject(string userId) {
            if (_projectRepository.GetByApiKey(SAMPLE_API_KEY) != null)
                return;

            User user = _userRepository.GetByIdCached(userId);
            var organization = new Organization { Name = "Acme" };
            _billingManager.ApplyBillingPlan(organization, BillingManager.UnlimitedPlan, user);
            organization = _organizationRepository.Add(organization);

            var project = new Project { Name = "Disintegrating Pistol", TimeZone = TimeZone.CurrentTimeZone.StandardName, OrganizationId = organization.Id };
            project.NextSummaryEndOfDayTicks = TimeZoneInfo.ConvertTime(DateTime.Today.AddDays(1), project.DefaultTimeZone()).ToUniversalTime().Ticks;
            project.ApiKeys.Add(SAMPLE_API_KEY);
            project.Configuration.Settings.Add("IncludeConditionalData", "true");
            project.AddDefaultOwnerNotificationSettings(userId);
            project = _projectRepository.Add(project);

            _organizationRepository.IncrementStats(project.OrganizationId, projectCount: 1);

            user.OrganizationIds.Add(organization.Id);
            _userRepository.Update(user);
        }
        public void CreateSampleOrganizationAndProject(string userId) {
            if (_tokenRepository.GetById(SAMPLE_API_KEY) != null)
                return;

            User user = _userRepository.GetById(userId, true);
            var organization = new Organization { Id = "537650f3b77efe23a47914f3", Name = "Acme" };
            _billingManager.ApplyBillingPlan(organization, BillingManager.UnlimitedPlan, user);
            organization = _organizationRepository.Add(organization);

            var project = new Project { Id = "537650f3b77efe23a47914f4", Name = "Disintegrating Pistol", TimeZone = TimeZone.CurrentTimeZone.StandardName, OrganizationId = organization.Id };
            project.NextSummaryEndOfDayTicks = TimeZoneInfo.ConvertTime(DateTime.Today.AddDays(1), project.DefaultTimeZone()).ToUniversalTime().Ticks;
            project.Configuration.Settings.Add("IncludeConditionalData", "true");
            project.AddDefaultOwnerNotificationSettings(userId);
            project = _projectRepository.Add(project);

            _tokenRepository.Add(new Token {
                Id = SAMPLE_API_KEY,
                OrganizationId = organization.Id,
                ProjectId = project.Id,
                ExpiresUtc = DateTime.UtcNow.AddYears(100),
                CreatedUtc = DateTime.UtcNow,
                ModifiedUtc = DateTime.UtcNow,
                Type = TokenType.Access
            });

            _tokenRepository.Add(new Token {
                Id = SAMPLE_USER_API_KEY,
                OrganizationId = organization.Id,
                UserId = user.Id,
                ExpiresUtc = DateTime.UtcNow.AddYears(100),
                CreatedUtc = DateTime.UtcNow,
                ModifiedUtc = DateTime.UtcNow,
                Type = TokenType.Access
            });

            _organizationRepository.IncrementStats(project.OrganizationId, projectCount: 1);

            user.OrganizationIds.Add(organization.Id);
            _userRepository.Save(user);
        }
        public void ApplyBillingPlan(Organization organization, BillingPlan plan, User user, bool updateBillingPrice = true) {
            organization.PlanId = plan.Id;
            organization.BillingChangeDate = DateTime.Now;

            if (updateBillingPrice)
                organization.BillingPrice = plan.Price;

            organization.BillingChangedByUserId = user.Id;
            organization.MaxUsers = plan.MaxUsers;
            organization.MaxProjects = plan.MaxProjects;
            organization.RetentionDays = plan.RetentionDays;
            organization.MaxEventsPerMonth = plan.MaxEventsPerMonth;
            organization.HasPremiumFeatures = plan.HasPremiumFeatures;
        }
Beispiel #26
0
 public Task SendPaymentFailedAsync(User owner, Organization organization)
 {
     return Task.FromResult(0);
 }
Beispiel #27
0
 public Task SendInviteAsync(User sender, Organization organization, Invite invite) {
     return Task.Delay(0);
 }
Beispiel #28
0
 public Task SendAddedToOrganizationAsync(User sender, Organization organization, User user) {
     return Task.Run(() => SendAddedToOrganization(sender, organization, user));
 }
        private void TryDeleteOrganization(Organization organization) {
            try {
                Log.Info().Message("Checking to see if organization '{0}' with Id: '{1}' can be deleted.", organization.Name, organization.Id).Write();

                ObjectId id;
                if (String.IsNullOrWhiteSpace(organization.Id) || !ObjectId.TryParse(organization.Id, out id)) {
                    Log.Info().Message("Organization '{0}' with Id: '{1}' has an invalid id.", organization.Name, organization.Id).Write();
                    return;
                }

                if (id.CreationTime >= DateTime.Now.SubtractDays(90)) {
                    Log.Info().Message("Organization '{0}' with Id: '{1}' has been created less than 90 days ago.", organization.Name, organization.Id).Write();
                    return;
                }

                if (organization.LastErrorDate >= DateTime.Now.SubtractDays(90)) {
                    Log.Info().Message("Organization '{0}' with Id: '{1}' has had an exception newer than 90 days.", organization.Name, organization.Id).Write();
                    return;
                }

                if (!String.IsNullOrEmpty(organization.StripeCustomerId)) {
                    Log.Info().Message("Organization '{0}' with Id: '{1}' has a stripe customer id and cannot be deleted.", organization.Name, organization.Id).Write();
                    return;
                }

                Log.Info().Message("Removing existing empty projects for the organization '{0}' with Id: '{1}'.", organization.Name, organization.Id).Write();
                List<Project> projects = _projectRepository.GetByOrganizationId(organization.Id).ToList();
                if (projects.Any(project => project.TotalErrorCount > 0)) {
                    Log.Info().Message("Organization '{0}' with Id: '{1}' has a project with existing data. This organization will not be deleted.", organization.Name, organization.Id).Write();
                    return;
                }

                foreach (Project project in projects) {
                    Log.Info().Message("Resetting all project data for project '{0}' with Id: '{1}'.", project.Name, project.Id).Write();
                    _errorStackRepository.RemoveAllByProjectId(project.Id);
                    _errorRepository.RemoveAllByProjectId(project.Id);
                    _dayStackStats.RemoveAllByProjectId(project.Id);
                    _monthStackStats.RemoveAllByProjectId(project.Id);
                    _dayProjectStats.RemoveAllByProjectId(project.Id);
                    _monthProjectStats.RemoveAllByProjectId(project.Id);
                }

                Log.Info().Message("Deleting all projects for organization '{0}' with Id: '{1}'.", organization.Name, organization.Id).Write();
                _projectRepository.Delete(projects);

                Log.Info().Message("Removing users from organization '{0}' with Id: '{1}'.", organization.Name, organization.Id).Write();
                List<User> users = _userRepository.GetByOrganizationId(organization.Id).ToList();
                foreach (User user in users) {
                    if (user.OrganizationIds.All(oid => String.Equals(oid, organization.Id))) {
                        Log.Info().Message("Removing user '{0}' as they do not belong to any other organizations.", user.Id, organization.Name, organization.Id).Write();
                        _userRepository.Delete(user.Id);
                    } else {
                        Log.Info().Message("Removing user '{0}' from organization '{1}' with Id: '{2}'", user.Id, organization.Name, organization.Id).Write();
                        user.OrganizationIds.Remove(organization.Id);
                        _userRepository.Update(user);
                    }
                }

                Log.Info().Message("Deleting organization '{0}' with Id: '{1}'.", organization.Name, organization.Id).Write();
                _organizationRepository.Delete(organization);

                // TODO: Send notifications that the organization and projects have been updated.
            } catch (Exception ex) {
                ex.ToExceptionless().MarkAsCritical().AddTags("Remove Stale Accounts").AddObject(organization).Submit();
            }
        }
Beispiel #30
0
 public Task SendPaymentFailedAsync(User owner, Organization organization) {
     return Task.Delay(0);
 }