Exemple #1
0
        public async Task <ICommandResultBase> UninstallAsync()
        {
            var output = new CommandResultBase();

            foreach (var descriptor in Descriptors)
            {
                // Ensure the feature is enabled
                var feature = await _featureFacade.GetFeatureByIdAsync(descriptor.ModuleId);

                if (feature == null)
                {
                    continue;
                }

                var result = await UninstallLabelsAsync(feature);

                if (!result.Succeeded)
                {
                    return(output.Failed(result.Errors.ToArray()));
                }
            }

            return(output.Success());
        }
        async Task <ICommandResultBase> DropIndexesInternalAsync()
        {
            // Build result
            var result = new CommandResultBase();

            // Get provided indexes
            var providedIndexes = _fullTextIndexManager.GetIndexes();

            // Drop all provided indexes
            foreach (var providedIndex in providedIndexes)
            {
                var deleteIndex = await _fullTextIndexCommand.DeleteAsync(new SchemaFullTextIndex()
                {
                    TableName = providedIndex.TableName
                });

                if (!deleteIndex.Succeeded)
                {
                    return(result.Failed(deleteIndex.Errors.ToArray()));
                }
            }

            return(result.Success());
        }
Exemple #3
0
        public async Task <ICommandResultBase> InitialMigrationsAsync()
        {
            // Our result
            var output = new CommandResultBase();

            // Get all installed features
            var features = await _shellFeatureStore.SelectFeatures();

            // We need features to upgrade
            if (features == null)
            {
                return(output.Failed("No features could be found within the shell features store."));
            }

            // Attempt to update each found feature and compile any errors
            var errors = new List <CommandError>();

            foreach (var feature in features)
            {
                var result = await _shellFeatureUpdater.UpdateAsync(feature.ModuleId);

                if (result.Errors.Any())
                {
                    errors.AddRange(result.Errors);
                }
            }

            // Did any feature upgrade encounter errors?
            if (errors.Count > 0)
            {
                return(output.Failed(errors.ToArray()));
            }

            // Return success
            return(output.Success());
        }
Exemple #4
0
        private async Task <ICommandResultBase> UninstallInternalAsync(IShellSettings shellSettings)
        {
            // Our result
            var result = new CommandResultBase();

            var errors = new List <CommandError>();

            // ----------------------
            // 1. Attempt to delete App_Data/{SiteName} folder
            // ----------------------

            var deleted = true;

            try
            {
                deleted = _shellSettingsManager.DeleteSettings(shellSettings);
            }
            catch (Exception e)
            {
                errors.Add(new CommandError(e.Message));
            }

            // Report any errors
            if (errors.Count > 0)
            {
                return(result.Failed(errors.ToArray()));
            }

            // Ensure we could delete the directory
            if (deleted == false)
            {
                return(result.Failed($"Cannot delete tenant folder with the name \"{shellSettings.Location}\"!"));
            }

            // ----------------------
            // 2. Attempt to drop all tables and stored procedures with our table prefix
            // ----------------------

            using (var shellContext = _shellContextFactory.CreateMinimalShellContext(shellSettings))
            {
                using (var scope = shellContext.ServiceProvider.CreateScope())
                {
                    using (var dbContext = scope.ServiceProvider.GetRequiredService <IDbContext>())
                    {
                        // update dbContext confirmation
                        dbContext.Configure(options =>
                        {
                            options.ConnectionString = shellSettings.ConnectionString;
                            options.DatabaseProvider = shellSettings.DatabaseProvider;
                            options.TablePrefix      = shellSettings.TablePrefix;
                        });

                        var logger   = scope.ServiceProvider.GetRequiredService <ILogger <TenantSetUpService> >();
                        var dbHelper = scope.ServiceProvider.GetRequiredService <IDbHelper>();

                        try
                        {
                            await dbHelper.ExecuteScalarAsync <int>(UninstallSql, new Dictionary <string, string>()
                            {
                                ["{prefix}"] = shellSettings.TablePrefix
                            });
                        }
                        catch (Exception e)
                        {
                            errors.Add(new CommandError(e.Message));
                        }
                    }
                }
            }

            // ----------------------
            // 3. Dispose the tenant
            // ----------------------

            // Ensure no errors occurred
            if (errors.Count == 0)
            {
                _platoHost.DisposeShell(shellSettings);
            }

            return(errors.Count > 0
                ? result.Failed(errors.ToArray())
                : result.Success());
        }
Exemple #5
0
        // ----------

        async Task <ICommandResultBase> InstallInternalAsync(IShellFeature feature)
        {
            // Validate

            if (feature == null)
            {
                throw new ArgumentNullException(nameof(feature));
            }

            if (string.IsNullOrEmpty(feature.ModuleId))
            {
                throw new ArgumentNullException(nameof(feature.ModuleId));
            }

            var user = await _contextFacade.GetAuthenticatedUserAsync();

            // Get all feature tags
            var labels = await _labelStore.QueryAsync()
                         .Select <LabelQueryParams>(Q =>
            {
                Q.FeatureId.Equals(feature.Id);
            })
                         .ToList();

            // Associate every tag with at least 1 entity

            var output = new CommandResultBase();

            if (labels != null)
            {
                var entities = await _entityStore.QueryAsync()
                               .Select <EntityQueryParams>(q =>
                {
                    q.FeatureId.Equals(feature.Id);
                })
                               .ToList();

                var alreadyAdded = new Dictionary <int, Entity>();
                foreach (var label in labels?.Data)
                {
                    var randomEntities = GetRandomEntities(entities?.Data, alreadyAdded);
                    if (randomEntities == null)
                    {
                        return(output.Success());
                    }
                    foreach (var entity in randomEntities)
                    {
                        var result = await _entityLabelManager.CreateAsync(new EntityLabel()
                        {
                            EntityId      = entity.Id,
                            LabelId       = label.Id,
                            CreatedUserId = user?.Id ?? 0,
                            CreatedDate   = DateTime.UtcNow
                        });

                        if (!result.Succeeded)
                        {
                            return(output.Failed(result.Errors.ToArray()));
                        }
                    }
                }
            }

            return(output.Success());
        }
Exemple #6
0
        // --------------------

        async Task <ICommandResultBase> ApplyLatestHistoryPoint(Idea entity, IdeaComment reply)
        {
            // Get current user
            var user = await _contextFacade.GetAuthenticatedUserAsync();

            // We need to be authenticated to make changes
            if (user == null)
            {
                return(await ResetEditDetails(entity, reply, user));
            }

            // Get newest / most recent history entry
            var histories = await _entityHistoryStore.QueryAsync()
                            .Take(1, false)
                            .Select <EntityHistoryQueryParams>(q =>
            {
                q.EntityId.Equals(entity.Id);
                q.EntityReplyId.Equals(reply?.Id ?? 0);
            })
                            .OrderBy("Id", OrderBy.Desc)
                            .ToList();

            // No history point, return success
            if (histories == null)
            {
                return(await ResetEditDetails(entity, reply, user));
            }

            // No history point, return success
            if (histories.Data == null)
            {
                return(await ResetEditDetails(entity, reply, user));
            }

            // No history point, return success
            if (histories.Data.Count == 0)
            {
                return(await ResetEditDetails(entity, reply, user));
            }

            var history = histories.Data[0];

            // No history available reset edit details
            if (history == null)
            {
                return(await ResetEditDetails(entity, reply, user));
            }

            // Update edit details based on latest history point

            var result = new CommandResultBase();

            if (reply != null)
            {
                reply.ModifiedUserId = user.Id;
                reply.ModifiedDate   = DateTimeOffset.UtcNow;
                reply.EditedUserId   = history.CreatedUserId;
                reply.EditedDate     = history.CreatedDate;

                // Update reply to history point
                var updateResult = await _entityReplyStore.UpdateAsync(reply);

                if (updateResult != null)
                {
                    return(result.Success());
                }
            }
            else
            {
                entity.ModifiedUserId = user.Id;
                entity.ModifiedDate   = DateTimeOffset.UtcNow;
                entity.EditedUserId   = history.CreatedUserId;
                entity.EditedDate     = history.CreatedDate;

                // Update entity to history point
                var updateResult = await _entityStore.UpdateAsync(entity);

                if (updateResult != null)
                {
                    return(result.Success());
                }
            }

            return(result.Success());
        }
Exemple #7
0
        async Task <ICommandResultBase> InstallEntityInternalAsync(SampleDataDescriptor descriptor, IList <User> users, int sortOrder = 0)
        {
            // Validate

            if (descriptor == null)
            {
                throw new ArgumentNullException(nameof(descriptor));
            }

            if (string.IsNullOrEmpty(descriptor.ModuleId))
            {
                throw new ArgumentNullException(nameof(descriptor.ModuleId));
            }

            // Our result
            var result = new CommandResultBase();

            // Ensure the feature is enabled
            var feature = await _featureFacade.GetFeatureByIdAsync(descriptor.ModuleId);

            if (feature == null)
            {
                return(result.Failed($"The feature {descriptor.ModuleId} is not enabled!"));
            }

            // Get a random user for the post
            var randomUser = users[_random.Next(0, users.Count)];

            // Capitalize the first character of our entity type
            var entityTypeCapitalized = char.ToUpper(descriptor.EntityType[0]).ToString() + descriptor.EntityType.Substring(1);

            // Create the post
            var entity = new Entity()
            {
                Title         = $"Example {entityTypeCapitalized} {_random.Next(0, 2000).ToString()}",
                Message       = GetEntityText(descriptor),
                FeatureId     = feature?.Id ?? 0,
                SortOrder     = sortOrder + 1,
                CreatedUserId = randomUser?.Id ?? 0,
                CreatedDate   = DateTimeOffset.UtcNow
            };

            // Create entity
            var entityResult = await _entityManager.CreateAsync(entity);

            if (entityResult.Succeeded)
            {
                var lastReplyId       = string.Empty;
                var lastReplyUserName = string.Empty;
                var lastReplyMessage  = string.Empty;

                // Create entity replies
                for (var i = 0; i < descriptor.EntityRepliesToCreate; i++)
                {
                    randomUser = users[_random.Next(0, users.Count - 1)];

                    var message = GetReplyText(descriptor);

                    message = message.Replace("{replyUserName}", randomUser?.UserName ?? "");

                    message = message.Replace("{lastReplyId}", lastReplyId ?? "");
                    message = message.Replace("{lastReplyMessage}", lastReplyMessage ?? "");
                    message = message.Replace("{lastReplyQuotedMessage}", lastReplyMessage.Replace(System.Environment.NewLine, System.Environment.NewLine + "> ") ?? "");
                    message = message.Replace("{lastReplyUserName}", lastReplyUserName ?? "");

                    message = message.Replace("{entityId}", entityResult.Response.Id.ToString() ?? "");
                    message = message.Replace("{entityTitle}", entityResult.Response.Title ?? "");
                    message = message.Replace("{entityUserName}", entityResult.Response.CreatedBy.UserName);

                    message = message.Replace("{mentionSample}", BuildMentionSampleMarkUp());

                    message = message.Replace("{lastReplyUrl}", _contextFacade.GetRouteUrl(new RouteValueDictionary()
                    {
                        ["area"]         = descriptor.ModuleId,
                        ["controller"]   = "Home",
                        ["action"]       = "Reply",
                        ["opts.id"]      = entityResult.Response.Id.ToString() ?? "",
                        ["opts.alias"]   = entityResult.Response.Alias.ToString() ?? "",
                        ["opts.replyId"] = lastReplyId ?? ""
                    }));

                    // Create reply
                    var reply = new EntityReply()
                    {
                        EntityId      = entityResult.Response.Id,
                        Message       = message,
                        CreatedUserId = randomUser?.Id ?? 0,
                        CreatedDate   = DateTimeOffset.UtcNow
                    };

                    // Add reply
                    var replyResult = await _entityReplyManager.CreateAsync(reply);

                    if (!replyResult.Succeeded)
                    {
                        return(result.Failed());
                    }

                    lastReplyId       = replyResult.Response.Id.ToString();
                    lastReplyMessage  = replyResult.Response.Message;
                    lastReplyUserName = replyResult.Response.CreatedBy.UserName;
                }
            }
            else
            {
                return(result.Failed(result.Errors.ToArray()));
            }

            return(result.Success());
        }
        // ----------

        async Task <ICommandResultBase> InstallInternalAsync(IShellFeature feature)
        {
            // Validate

            if (feature == null)
            {
                throw new ArgumentNullException(nameof(feature));
            }

            if (string.IsNullOrEmpty(feature.ModuleId))
            {
                throw new ArgumentNullException(nameof(feature.ModuleId));
            }

            var user = await _contextFacade.GetAuthenticatedUserAsync();

            // Get all feature tags
            var categories = await _categoryStore.QueryAsync()
                             .Select <CategoryQueryParams>(Q =>
            {
                Q.FeatureId.Equals(feature.Id);
            })
                             .ToList();

            // Associate every category with at least 1 entity

            var output = new CommandResultBase();

            if (categories != null)
            {
                var entityFeature = await GetEntityFeatureAsync(feature);

                if (entityFeature == null)
                {
                    return(output.Failed($"A feature named {feature.ModuleId.Replace(".Categories", "")} is not enabled!"));
                }

                // Get entities for feature
                var entities = await _entityStore.QueryAsync()
                               .Select <EntityQueryParams>(q =>
                {
                    q.FeatureId.Equals(entityFeature.Id);
                    q.CategoryId.Equals(0);
                })
                               .ToList();

                // Keeps track of entities already added to categories
                var alreadyAdded = new Dictionary <int, Entity>();

                // Interate categories building random entities
                // not already added to a category and adding
                // those random entities to the current category
                foreach (var category in categories?.Data)
                {
                    // Get random entities
                    var randomEntities = GetRandomEntities(entities?.Data, alreadyAdded);

                    // Ensure we have some random entities, they may have already al been added
                    if (randomEntities == null)
                    {
                        return(output.Success());
                    }

                    // Add random entities to category
                    foreach (var randomEntity in randomEntities)
                    {
                        // Get the full entity
                        var entity = await _entityStore.GetByIdAsync(randomEntity.Id);

                        // Update
                        entity.CategoryId     = category.Id;
                        entity.ModifiedUserId = user?.Id ?? 0;
                        entity.ModifiedDate   = DateTime.UtcNow;

                        // Persist
                        var entityResult = await _entityManager.UpdateAsync(entity);

                        if (entityResult.Succeeded)
                        {
                            // Add entity / category relationship
                            var result = await _entityCategoryManager.CreateAsync(new EntityCategory()
                            {
                                EntityId      = entityResult.Response.Id,
                                CategoryId    = category.Id,
                                CreatedUserId = user?.Id ?? 0,
                                CreatedDate   = DateTime.UtcNow
                            });

                            if (!result.Succeeded)
                            {
                                return(output.Failed(result.Errors.ToArray()));
                            }
                        }
                        else
                        {
                            return(output.Failed(entityResult.Errors.ToArray()));
                        }
                    }
                }
            }

            return(output.Success());
        }
Exemple #9
0
        public async Task <ICommandResultBase> UpdateAsync(string moduleId)
        {
            var output = new CommandResultBase();

            // Get installed feature
            var feature = await _featureFacade.GetFeatureByIdAsync(moduleId);

            // Ensure we found the feature
            if (feature == null)
            {
                return(output.Failed(
                           $"A feature named '{moduleId}' could not be found within the ShellFeatures table."));
            }

            // Get available module
            var module = await _shellDescriptorManager.GetFeatureAsync(moduleId);

            // Ensure we found the module
            if (module == null)
            {
                return(output.Failed($"A module named '{moduleId}' could not be found on the file system. Please ensure the '{moduleId}' module exists within the root/modules folder."));
            }

            // ------------------------------------------------------------------
            // 1. Check to ensure we have a newer version of the module
            // ------------------------------------------------------------------

            var from = feature.Version.ToVersion();
            var to   = module.Descriptor.Version.ToVersion();

            if (from == null)
            {
                return(output.Failed(
                           $"Could not convert version for feature {feature.ModuleId} of {feature.Version} to a valid version. Please check the version within the shell features database table."));
            }

            if (to == null)
            {
                return(output.Failed(
                           $"Could not convert version for module {module.Descriptor.Id} of {module.Descriptor.Version} to a valid version. Please check the version within the modules manifest file."));
            }

            // No newer version simply return
            if (from >= to)
            {
                return(output.Success());
            }

            // ------------------------------------------------------------------
            // 2. Check to ensure the module we are updating is compatible
            // with the current version of Plato we are running
            // ------------------------------------------------------------------

            var modulePlatoVersion = module.Descriptor.PlatoVersion.ToVersion();

            // Does the module have a Plato version defined?
            if (modulePlatoVersion != null)
            {
                // Get current Plato version
                var currentPlatoVersion = _platoOptions.Value.Version.ToVersion();
                if (currentPlatoVersion != null)
                {
                    // Does the module require a newer version of Plato?
                    if (modulePlatoVersion > currentPlatoVersion)
                    {
                        return(output.Failed(
                                   $"{moduleId} {module.Descriptor.Version} requires Plato {modulePlatoVersion.ToString()} whilst you are running Plato {currentPlatoVersion.ToString()}. Please upgrade to Plato {modulePlatoVersion.ToString()} and try updating {moduleId} again."));
                    }
                }
            }

            // ------------------------------------------------------------------
            // 3. Invoke FeatureEventHandlers & database migrations
            // ------------------------------------------------------------------

            var results = await InvokeFeatureEventHandlersAsync(
                feature, async context =>
            {
                // The result to return
                var result = new CommandResultBase();

                // Perform migrations from current installed feature version
                // to latest available version defined via the modules IMigrationProvider

                // All versions between from and to
                var versions = from.GetVersionsBetween(to);

                // Compile versions to search
                var versionsToSearch = versions != null
                        ? versions?.ToList().Select(v => v.ToString())
                        : new List <string>();

                // Build migrations for feature & versions
                var migrations = _migrationBuilder.BuildMigrations(moduleId, versionsToSearch.ToArray());

                // Apply migrations
                var migrationResults = await migrations.ApplyMigrationsAsync();

                // We may not have migrations
                if (migrationResults != null)
                {
                    // Did any errors occur whilst applying the migration?
                    if (migrationResults.Errors.Any())
                    {
                        var errors = new List <CommandError>();
                        foreach (var error in migrationResults.Errors)
                        {
                            errors.Add(new CommandError(error.Message));
                        }

                        return(result.Failed(errors.ToArray()));
                    }
                }

                // If we reach this point everything went OK, Migrations applied
                // successfully and no errors occurred within the features update handlers.
                // Finally update the features version within the ShellFeatures table to reflect
                // the new version of the module we've just updated to, also update
                // shell descriptor to reflect version changes within dictionary store

                var updateResult = await UpdateShellFeatureVersionAsync(feature, module.Descriptor.Version);
                if (updateResult.Errors.Any())
                {
                    return(result.Failed(updateResult.Errors.ToArray()));
                }

                // Return success
                return(result.Success());
            });

            // Did any errors occur?
            var handlerErrors = results
                                .Where(c => c.Value.Errors.Any())
                                .SelectMany(h => h.Value.Errors)
                                .ToList();

            if (handlerErrors.Count > 0)
            {
                var errors = new List <CommandError>();
                foreach (var error in handlerErrors)
                {
                    errors.Add(new CommandError(error.Value));
                }
                return(output.Failed(errors.ToArray()));
            }

            // No errors, recycle shell context to apply updates
            RecycleShell();

            return(output.Success());
        }
Exemple #10
0
        public async Task <ICommandResultBase> ValidateCompanyNameAsync(string companyName)
        {
            var result = new CommandResultBase();
            var error  = "The company name is invalid or is already in use. Please try a different company name.";

            // We always need a company name
            if (string.IsNullOrEmpty(companyName))
            {
                return(result.Failed("A company name is required!"));
            }

            // Validate characters
            var valid = true;

            foreach (var c in companyName)
            {
                // Not a letter, digit or space
                if (!c.IsLetterDigitOrSpace())
                {
                    valid = false;
                    break;
                }
            }

            // Only allow letters digits and spaces
            if (valid == false)
            {
                return(result.Failed("The company name cannot contain special characters. Only letters, numbers and spaces are allowed. Please try a different company name."));
            }

            // Create the company name alias to compare with our blacklist
            var companyNameAlias = _aliasCrator.Create(companyName);

            // We need an alias
            if (string.IsNullOrEmpty(companyNameAlias))
            {
                return(result.Failed(error));
            }

            // Does the company name appear in the blacklist?
            var blackList = GetBlackListedCompanyNames();

            foreach (var item in blackList)
            {
                if (item.Equals(companyName, StringComparison.OrdinalIgnoreCase))
                {
                    return(result.Failed(error));
                }
                if (item.Equals(companyNameAlias, StringComparison.OrdinalIgnoreCase))
                {
                    return(result.Failed(error));
                }
            }

            // ---------------
            // Does the company name already exist?
            // We need company names to be unique as the
            // tenant RequestedPrefixUrl uses CompanyNameAlias
            // ---------------

            var signUps = await _signUpStore.QueryAsync()
                          .Select <SignUpQueryParams>(q =>
            {
                q.CompanyName.Or().Equals(companyName);
                q.CompanyNameAlias.Or().Equals(companyName);
            })
                          .ToList();

            if (signUps?.Data != null)
            {
                return(result.Failed(error));
            }

            return(result.Success());
        }