// ---------- async Task <ICommandResultBase> InstallLabelsAsync(IShellFeature feature) { // Validate if (feature == null) { throw new ArgumentNullException(nameof(feature)); } if (string.IsNullOrEmpty(feature.ModuleId)) { throw new ArgumentNullException(nameof(feature.ModuleId)); } // Our result var result = new CommandResultBase(); for (var i = 0; i < 10; i++) { var categoryResult = await InstallLabelAsync(feature, i); if (!categoryResult.Succeeded) { return(result.Failed(categoryResult.Errors.ToArray())); } } return(result.Success()); }
/* General Idea... * * public static IEnumerable<T> Traverse<T>(T item, Func<T, IEnumerable<T>> childSelector) * { * var stack = new Stack<T>(); * stack.Push(item); * while (stack.Any()) * { * var next = stack.Pop(); * yield return next; * foreach (var child in childSelector(next)) * stack.Push(child); * } * } * */ IEnumerable <IShellFeature> QueryDependencies( IShellFeature feature, IShellFeature[] features, Func <IShellFeature, IShellFeature[], IShellFeature[]> query) { var dependencies = new HashSet <IShellFeature>() { feature }; var stack = new Stack <IShellFeature[]>(); stack.Push(query(feature, features)); while (stack.Count > 0) { var next = stack.Pop(); foreach (var dependency in next.Where(dependency => !dependencies.Contains(dependency))) { dependencies.Add(dependency); stack.Push(query(dependency, features)); } } return(_features .Where(f => dependencies.Any(d => d.ModuleId == f.Value.ModuleId)) .Select(f => f.Value)); }
// ---------- async Task <ICommandResultBase> InstallCategoriesAsync(IShellFeature feature) { // Validate if (feature == null) { throw new ArgumentNullException(nameof(feature)); } if (string.IsNullOrEmpty(feature.ModuleId)) { throw new ArgumentNullException(nameof(feature.ModuleId)); } // Our result var result = new CommandResultBase(); foreach (var tag in ExampleTags) { var categoryResult = await InstallInternalAsync(feature, tag); if (!categoryResult.Succeeded) { return(result.Failed(categoryResult.Errors.ToArray())); } } return(result.Success()); }
async Task <ICommandResultBase> InstallInternalAsync(IShellFeature feature, string tag) { // 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(); // Our result var result = new CommandResultBase(); var categoryResult = await _tagManager.CreateAsync(new TagBase() { FeatureId = feature.Id, Name = tag, Description = $"An example desccription for the '{tag}' tag within '{feature.ModuleId}'.", CreatedUserId = user?.Id ?? 0, CreatedDate = DateTimeOffset.UtcNow }); if (!categoryResult.Succeeded) { return(result.Failed(result.Errors.ToArray())); } return(result.Success()); }
async Task <ICommandResultBase> UninstallInternalAsync(IShellFeature feature) { // Validate if (feature == null) { throw new ArgumentNullException(nameof(feature)); } if (string.IsNullOrEmpty(feature.ModuleId)) { throw new ArgumentNullException(nameof(feature.ModuleId)); } // Our result var result = new CommandResultBase(); // Get entities feature for categories feature var entityFeature = await GetEntityFeatureAsync(feature); if (entityFeature == null) { return(result.Failed($"A feature named {feature.ModuleId.Replace(".Categories", "")} is not enabled!")); } // Replacements for SQL script var replacements = new Dictionary <string, string>() { ["{featureId}"] = feature.Id.ToString(), ["{entityFeatureId}"] = entityFeature.Id.ToString() }; // Sql to execute var sql = @" DELETE FROM {prefix}_EntityCategories WHERE CategoryId IN ( SELECT Id FROM {prefix}_Categories WHERE FeatureId = {featureId} ); DELETE FROM {prefix}_CategoryData WHERE CategoryId IN ( SELECT Id FROM {prefix}_Categories WHERE FeatureId = {featureId} ); UPDATE {prefix}_Entities SET CategoryId = 0 WHERE FeatureId = {entityFeatureId} "; // Execute and return result var error = string.Empty; try { await _dbHelper.ExecuteScalarAsync <int>(sql, replacements); } catch (Exception e) { error = e.Message; } return(!string.IsNullOrEmpty(error) ? result.Failed(error) : result.Success()); }
async Task <CommandResultBase> UpdateShellFeatureVersionAsync(IShellFeature feature, string newVersion) { var result = new CommandResultBase(); // Ensure the version is valid if (newVersion.ToVersion() == null) { return(result.Failed( $"The version '{newVersion}' for feature '{feature.ModuleId}' is not a valid version. Versions must contain major, minor & build numbers. For example 1.0.0, 2.4.0 or 3.2.1")); } // Update version feature.Version = newVersion; // Update shell features var shellFeature = await _shellFeatureStore.UpdateAsync((ShellFeature)feature); // Ensure the update was successful before updating shell descriptor if (shellFeature == null) { return(result.Failed( $"Could not update shell feature. An error occurred whilst updating the version for feature {feature.ModuleId} to version {newVersion}.")); } // First get all existing enabled features var enabledFeatures = await _shellDescriptorManager.GetEnabledFeaturesAsync(); // Update version for enabled feature var descriptor = new ShellDescriptor(); foreach (var enabledFeature in enabledFeatures) { if (enabledFeature.ModuleId.Equals(feature.ModuleId, StringComparison.OrdinalIgnoreCase)) { enabledFeature.Version = newVersion; } descriptor.Modules.Add(new ShellModule(enabledFeature)); } // Ensure we have a descriptor if (descriptor.Modules?.Count == 0) { return(result.Failed("A valid shell descriptor could not be constructed.")); } // Update shell descriptor var updatedDescriptor = await _shellDescriptorStore.SaveAsync(descriptor); if (updatedDescriptor == null) { return(result.Failed( $"Could not update shell descriptor. An error occurred whilst updating the version for feature {feature.ModuleId} to version {newVersion}.")); } return(result.Success()); }
async Task <ICommandResultBase> UninstallCategoriesAsync(IShellFeature feature) { // Validate if (feature == null) { throw new ArgumentNullException(nameof(feature)); } if (string.IsNullOrEmpty(feature.ModuleId)) { throw new ArgumentNullException(nameof(feature.ModuleId)); } // Our result var result = new CommandResultBase(); // Replacements for SQL script var replacements = new Dictionary <string, string>() { ["{featureId}"] = feature.Id.ToString() }; // Sql to execute var sql = @" DELETE FROM {prefix}_CategoryData WHERE CategoryId IN ( SELECT Id FROM {prefix}_Categories WHERE FeatureId = {featureId} ); DELETE FROM {prefix}_CategoryRoles WHERE CategoryId IN ( SELECT Id FROM {prefix}_Categories WHERE FeatureId = {featureId} ); DELETE FROM {prefix}_Categories WHERE FeatureId = {featureId}; "; // Execute and return result var error = string.Empty; try { await _dbHelper.ExecuteScalarAsync <int>(sql, replacements); } catch (Exception e) { error = e.Message; } return(!string.IsNullOrEmpty(error) ? result.Failed(error) : result.Success()); }
async Task <IShellFeature> FeatureInstalled(IShellFeature feature) { if (feature == null) { return(feature); } TourStep stepToUpdate = null; if (ShellDescriptors.CoreModules.Contains(feature.Descriptor.Id)) { stepToUpdate = DefaultSteps.EnablleCoreFeature; } if (ShellDescriptors.OptionalModules.Contains(feature.Descriptor.Id)) { stepToUpdate = DefaultSteps.EnablleOptionalFeature; } if (ShellDescriptors.SearchModules.Contains(feature.Descriptor.Id)) { stepToUpdate = DefaultSteps.EnableSearch; } // We need a step to update if (stepToUpdate == null) { return(feature); } // Update step var step = await _tourDescriptorStore.GetStepAsync(stepToUpdate.Id); if (step != null) { if (!step.CompletedDate.HasValue) { step.CompletedDate = DateTimeOffset.Now; await _tourDescriptorStore.UpdateStepAsync(step); } } // Return return(feature); }
async Task <ICommandResultBase> InstallCategoryAsync(IShellFeature feature, int sortOrder = 0) { // Validate if (feature == null) { throw new ArgumentNullException(nameof(feature)); } if (string.IsNullOrEmpty(feature.ModuleId)) { throw new ArgumentNullException(nameof(feature.ModuleId)); } // Our result var result = new CommandResultBase(); var icons = new DefaultIcons(); var foreColor = "#ffffff"; var backColor = $"#{_colorProvider.GetColor()}"; var iconCss = $"fal fa-{icons.GetIcon()}"; var categoryResult = await _categoryManager.CreateAsync(new CategoryBase() { FeatureId = feature.Id, ParentId = 0, Name = $"Example Category {_random.Next(0, 2000).ToString()}", Description = $"This is just an example category desccription.", ForeColor = foreColor, BackColor = backColor, IconCss = iconCss, SortOrder = sortOrder }); if (!categoryResult.Succeeded) { return(result.Failed(result.Errors.ToArray())); } return(result.Success()); }
async Task <ICommandResultBase> InstallLabelAsync(IShellFeature feature, int sortOrder = 0) { // 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(); // Our result var result = new CommandResultBase(); var foreColor = "#ffffff"; var backColor = $"#{_colorProvider.GetColor()}"; var categoryResult = await _labelManager.CreateAsync(new LabelBase() { FeatureId = feature.Id, ParentId = 0, Name = $"Example Label {_random.Next(0, 2000).ToString()}", Description = $"This is an example label description.", ForeColor = foreColor, BackColor = backColor, SortOrder = sortOrder, CreatedUserId = user?.Id ?? 0, CreatedDate = DateTimeOffset.UtcNow }); if (!categoryResult.Succeeded) { 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 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()); }
public FeatureEventContext(IShellFeature feature) { this.Feature = feature; }
// ---------- 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()); }
// ------------------------ async Task <IDictionary <string, IFeatureEventContext> > InvokeFeatureEventHandlersAsync( IShellFeature feature, Func <IFeatureEventContext, Task <CommandResultBase> > configure) { var output = new CommandResultBase(); // Get available module var module = await _shellDescriptorManager.GetFeatureAsync(feature.ModuleId); // Raise updating & updated event handlers for features return(await InvokeFeatureEvents(new[] { feature }, async (context, handler) => { var contexts = new ConcurrentDictionary <string, IFeatureEventContext>(); try { // Ensure we only invoke handlers for the feature we are updating if (context.Feature.ModuleId.Equals(feature.ModuleId, StringComparison.OrdinalIgnoreCase)) { await handler.UpdatingAsync(context); } contexts.AddOrUpdate(context.Feature.ModuleId, context, (k, v) => { foreach (var error in context.Errors) { v.Errors.Add(error.Key, error.Value); } return v; }); } catch (Exception e) { contexts.AddOrUpdate(context.Feature.ModuleId, context, (k, v) => { v.Errors.Add(context.Feature.ModuleId, e.Message); return v; }); } // Did any event encounter errors? var hasErrors = contexts .Where(c => c.Value.Errors.Any()); // No errors raise UpdatedAsync if (!hasErrors.Any()) { // Execute upgrade configuration var configureResult = await configure(context); if (!configureResult.Errors.Any()) { try { // Ensure we only invoke handlers for the feature we've updated if (context.Feature.ModuleId.Equals(feature.ModuleId, StringComparison.OrdinalIgnoreCase)) { await handler.UpdatedAsync(context); } contexts.AddOrUpdate(context.Feature.ModuleId, context, (k, v) => { foreach (var error in context.Errors) { v.Errors.Add(error.Key, error.Value); } return v; }); } catch (Exception e) { contexts.AddOrUpdate(context.Feature.ModuleId, context, (k, v) => { v.Errors.Add(context.Feature.ModuleId, e.Message); return v; }); } } else { foreach (var error in configureResult.Errors) { if (context.Errors == null) { context.Errors = new Dictionary <string, string>(); } if (!context.Errors.ContainsKey(error.Code)) { context.Errors.Add(error.Code, error.Description); } } contexts.AddOrUpdate(context.Feature.ModuleId, context, (k, v) => { foreach (var error in configureResult.Errors) { if (!v.Errors.ContainsKey(error.Code)) { v.Errors.Add(error.Code, error.Description); } } return v; }); } } return contexts; }, async context => { var contexts = new ConcurrentDictionary <string, IFeatureEventContext>(); // Execute upgrade configuration var configureResult = await configure(context); if (configureResult.Errors.Any()) { foreach (var error in configureResult.Errors) { if (context.Errors == null) { context.Errors = new Dictionary <string, string>(); } if (!context.Errors.ContainsKey(error.Code)) { context.Errors.Add(error.Code, error.Description); } } contexts.AddOrUpdate(context.Feature.ModuleId, context, (k, v) => { foreach (var error in configureResult.Errors) { if (!v.Errors.ContainsKey(error.Code)) { v.Errors.Add(error.Code, error.Description); } } return v; }); } return contexts; })); }
public async Task <IActionResult> Index([FromBody] TagApiParams parameters) { // Get tags var tags = await GetTags(parameters); // Build results IPagedResults <TagApiResult> results = null; if (tags != null) { // Get feature for tags IShellFeature feature = null; if (parameters.FeatureId > 0) { feature = await _shellFeatureStore.GetByIdAsync(parameters.FeatureId); } results = new PagedResults <TagApiResult> { Total = tags.Total }; var baseUrl = await _contextFacade.GetBaseUrlAsync(); foreach (var tag in tags.Data) { var url = _contextFacade.GetRouteUrl(new RouteValueDictionary() { ["area"] = feature?.ModuleId ?? "Plato.Tags", ["controller"] = "Home", ["action"] = "Tag", ["opts.id"] = tag.Id, ["opts.alias"] = tag.Alias }); results.Data.Add(new TagApiResult() { Id = tag.Id, Name = tag.Name, Entities = tag.TotalEntities.ToPrettyInt(), Follows = tag.TotalFollows.ToPrettyInt(), Url = url }); } } IPagedApiResults <TagApiResult> output = null; if (results != null) { output = new PagedApiResults <TagApiResult>() { Page = parameters.Page, Size = parameters.Size, Total = results.Total, TotalPages = results.Total.ToSafeCeilingDivision(parameters.Size), Data = results.Data }; } return(output != null ? base.Result(output) : base.NoResults()); }
async Task <IShellFeature> GetEntityFeatureAsync(IShellFeature feature) { var featureId = feature.ModuleId.Replace(".Categories", ""); return(await _featureFacade.GetFeatureByIdAsync(featureId)); }
public ShellModule(IShellFeature feature) { this.Id = feature.Id; this.ModuleId = feature.ModuleId; this.Version = feature.Version; }