Пример #1
0
        private async Task <IResolvedSetup <CollectionSetup> > ConvertConfigAsync(CollectionConfig config)
        {
            var repositoryAlias = _repositoryTypeResolver.GetAlias(config.RepositoryType);

            var collection = new CollectionSetup(
                config.Icon,
                config.Color,
                config.Name,
                config.Alias,
                repositoryAlias)
            {
                DataViews       = config.DataViews,
                DataViewBuilder = config.DataViewBuilder,
                UsageType       = GetCollectionUsage(config),
                Validators      = config.Validators.ToList(x => new ValidationSetup(x.Type, x.Configuration))
            };

            if (!_cmsConfig.Advanced.RemoveDataAnnotationEntityValidator)
            {
                collection.Validators.Insert(0, new ValidationSetup(typeof(DataAnnotationEntityValidator), default));
            }

            var cacheable = true;

            if (!string.IsNullOrWhiteSpace(config.ParentAlias) && _collectionMap.TryGetValue(config.ParentAlias, out var collectionConfig))
            {
                collection.Parent = new TreeElementSetup(collectionConfig.Alias, collectionConfig.Name, PageType.Collection); // TODO: this assumes nesting is always with collections
            }
            collection.Collections = (await _treeElementResolver.ResolveSetupAsync(config.CollectionsAndPages, collection)).CheckIfCachable(ref cacheable).ToList();

            collection.EntityVariant = (await _entityVariantResolver.ResolveSetupAsync(config.EntityVariant, collection)).CheckIfCachable(ref cacheable);
            if (config.SubEntityVariants.Any())
            {
                collection.SubEntityVariants = (await _entityVariantResolver.ResolveSetupAsync(config.SubEntityVariants, collection)).CheckIfCachable(ref cacheable).ToList();
            }

            collection.TreeView = config.TreeView == null ? null : (await _treeViewResolver.ResolveSetupAsync(config.TreeView, collection)).CheckIfCachable(ref cacheable);

            collection.ElementSetup = config.ElementConfig == null ? null : (await _elementResolver.ResolveSetupAsync(config.ElementConfig, collection)).CheckIfCachable(ref cacheable);

            collection.ListView   = config.ListView == null ? null : (await _listResolver.ResolveSetupAsync(config.ListView, collection)).CheckIfCachable(ref cacheable);
            collection.ListEditor = config.ListEditor == null ? null : (await _listResolver.ResolveSetupAsync(config.ListEditor, collection)).CheckIfCachable(ref cacheable);

            collection.NodeView   = config.NodeView == null ? null : (await _nodeResolver.ResolveSetupAsync(config.NodeView, collection)).CheckIfCachable(ref cacheable);
            collection.NodeEditor = config.NodeEditor == null ? null : (await _nodeResolver.ResolveSetupAsync(config.NodeEditor, collection)).CheckIfCachable(ref cacheable);

            return(new ResolvedSetup <CollectionSetup>(collection, cacheable));
        }
Пример #2
0
        public async Task <IReadOnlyList <IElement> > GetAvailableElementsAsync(IView view)
        {
            if (_editContext?.Parent?.Entity is ModelEntity modelEntity)
            {
                var collection = await _collectionSetupResolver.ResolveSetupAsync(modelEntity.Alias);

                var relatedCollectionAlias = _property?.Details.SelectNotNull(x => x.Config?.RelatedCollectionAlias).FirstOrDefault();
                if (relatedCollectionAlias is string alias)
                {
                    var model = await _modelResolver.HandleAsync(new GetByIdRequest <ModelEntity>(alias));

                    if (model.Entity != null)
                    {
                        var possibleProperties = model.Entity.Properties.Where(x => (x.IsRelationToMany || x.IsRelationToOne) && x.Type == collection.EntityVariant.Type.FullName);

                        return(possibleProperties.Select(x => new Element
                        {
                            Id = x.Name,
                            Labels = new[] { x.Name }
                        }).ToList());
                    }
                }
            }

            return(new List <IElement>());
        }
        public async Task <IResolvedSetup <PaneSetup> > ResolveSetupAsync(PaneConfig config, CollectionSetup?collection = default)
        {
            if (collection == null)
            {
                throw new ArgumentNullException(nameof(collection));
            }

            var cacheable = true;

            var buttons                = (await _buttonSetupResolver.ResolveSetupAsync(config.Buttons, collection)).CheckIfCachable(ref cacheable).ToList();
            var fields                 = (await _fieldSetupResolver.ResolveSetupAsync(config.Fields, collection)).CheckIfCachable(ref cacheable).ToList();
            var subCollectionLists     = (await _subCollectionSetupResolver.ResolveSetupAsync(config.SubCollectionLists, collection)).CheckIfCachable(ref cacheable).ToList();
            var relatedCollectionLists = (await _relatedCollectionSetupResolver.ResolveSetupAsync(config.RelatedCollectionLists, collection)).CheckIfCachable(ref cacheable).ToList();

            return(new ResolvedSetup <PaneSetup>(new PaneSetup(
                                                     config.CustomType,
                                                     config.Label,
                                                     config.IsVisible,
                                                     config.VariantType,
                                                     buttons,
                                                     fields,
                                                     subCollectionLists,
                                                     relatedCollectionLists),
                                                 cacheable));
        }
        public override async Task <CrudType> ButtonClickBeforeRepositoryActionAsync(ButtonSetup button, FormEditContext editContext, ButtonContext context)
        {
            var request = await _navigationHandler.CreateNavigationRequestAsync(button, editContext);

            if (request != null)
            {
                var collection = request.IsPage ? null : await _collectionResolver.ResolveSetupAsync(request.CollectionAlias);

                var usageType = request.IsNew ? UsageType.New
                    : request.IsEdit ? UsageType.Edit
                    : UsageType.View;

                NavigationState navigationState;

                if (request.IsPage)
                {
                    navigationState = new NavigationState(request.CollectionAlias, usageType);
                }
                else if (request.IsList)
                {
                    navigationState = new NavigationState(request.CollectionAlias, request.ParentPath, usageType);
                }
                else
                {
                    navigationState = new NavigationState(request.CollectionAlias, request.ParentPath, request.VariantAlias ?? collection !.EntityVariant.Alias, request.Id, usageType);
                }

                _navigationStateProvider.AppendNavigationState(navigationState);
            }

            return(CrudType.None);
        }
        public async Task <IResolvedSetup <ListSetup> > ResolveSetupAsync(ListConfig config, CollectionSetup?collection = default)
        {
            if (collection == null)
            {
                throw new ArgumentNullException(nameof(collection));
            }

            if (config is IIsConventionBased isConventionBasedConfig)
            {
                config = await _conventionListConfigResolver.ResolveByConventionAsync(config.BaseType, isConventionBasedConfig.GetFeatures(), collection);
            }

            var cacheable = true;

            var panes   = (await _paneSetupResolver.ResolveSetupAsync(config.Panes, collection)).CheckIfCachable(ref cacheable).ToList();
            var buttons = (await _buttonSetupResolver.ResolveSetupAsync(config.Buttons, collection)).CheckIfCachable(ref cacheable).ToList();

            return(new ResolvedSetup <ListSetup>(new ListSetup(
                                                     config.PageSize,
                                                     config.SearchBarVisible,
                                                     config.ReorderingAllowed,
                                                     config.ListEditorType,
                                                     config.EmptyVariantColumnVisibility,
                                                     panes,
                                                     buttons), cacheable));
        }
        async Task <PageSetup> ISetupResolver <PageSetup> .ResolveSetupAsync(string alias)
        {
            if (_cache.TryGetValue(alias, out var pageSetup))
            {
                return(pageSetup);
            }

            var config = _cmsConfig.CollectionsAndPages.SelectNotNull(x => x as IPageConfig).FirstOrDefault(x => x.Alias == alias);

            if (config == null)
            {
                throw new InvalidOperationException($"Cannot find page with alias {alias}.");
            }

            var cacheable = true;

            pageSetup = new PageSetup
            {
                Name     = config.Name,
                Alias    = config.Alias,
                Icon     = config.Icon,
                Color    = config.Color,
                Sections = (await _typeRegistrationSetupResolver.ResolveSetupAsync(config.SectionRegistrations)).CheckIfCachable(ref cacheable).ToList()
            };

            if (cacheable)
            {
                _cache[alias] = pageSetup;
            }

            return(pageSetup);
        }
        public async Task <INodeUIResolver> GetNodeUIResolverAsync(NavigationState navigationState)
        {
            var collection = await _collectionResolver.ResolveSetupAsync(navigationState.CollectionAlias);

            var node = navigationState.UsageType.HasFlag(UsageType.View)
                ? collection.NodeView ?? collection.NodeEditor
                : collection.NodeEditor ?? collection.NodeView;

            if (node == null)
            {
                throw new InvalidOperationException($"Failed to get UI configuration from collection {navigationState.CollectionAlias} for action {navigationState.UsageType}");
            }

            INodeUIResolver nodeUI = new NodeUIResolver(node, _dataProviderResolver, _buttonActionHandlerResolver, _navigationStateProvider, _authService);

            return(nodeUI);
        }
        public static async Task <IResolvedSetup <IEnumerable <TSetup> > > ResolveSetupAsync <TSetup, TConfig>(this ISetupResolver <TSetup, TConfig> resolver, IEnumerable <TConfig> configs, CollectionSetup?collection = default)
            where TConfig : notnull
        {
            var allCachable = true;

            return(new ResolvedSetup <IEnumerable <TSetup> >(
                       await configs.ToListAsync(async config => (await resolver.ResolveSetupAsync(config, collection)).CheckIfCachable(ref allCachable)), allCachable));
        }
        public async Task <NodeSetup> ResolveByConventionAsync(Type subject, Features features, CollectionSetup?collection)
        {
            var node = await _nodeResolver.ResolveByConventionAsync(subject, features, collection);

            var pane = await _nodeSetupResolver.ResolveSetupAsync(node, collection);

            return(pane.Setup);
        }
        public async Task <IEditContext> GetEditContextWrapperAsync(FormEditContext editContext)
        {
            var collection = await _collectionResolver.ResolveSetupAsync(editContext.CollectionAlias);

            var contextType = typeof(FormEditContextWrapper <>).MakeGenericType(collection.EntityVariant.Type);
            var instance    = Activator.CreateInstance(contextType, editContext);

            return(instance as IEditContext ?? throw new InvalidOperationException("Cannot create FormEditContextWrapper"));
        }
Пример #11
0
        public async Task <TreePageUI?> GetPageAsync(string alias)
        {
            var page = await _pageResolver.ResolveSetupAsync(alias);

            if (page == null)
            {
                throw new InvalidOperationException($"Failed to get page for given alias ({alias}).");
            }

            return(new TreePageUI(page.Name, page.Icon, page.Color, new NavigationState(page.Alias, UsageType.View)));
        }
Пример #12
0
        public async Task <ListContext> GetAsync(GetEntitiesRequestModel request)
        {
            var collection = await _collectionResolver.ResolveSetupAsync(request.CollectionAlias);

            var variant    = collection.GetEntityVariant(request.VariantAlias);
            var repository = _repositoryResolver.GetRepository(collection);

            var requestedEntityVariantIsDefaultVariant = variant.Alias == collection.EntityVariant.Alias;

            var parent = request is GetEntitiesOfParentRequestModel parentRequest ? await _parentService.GetParentAsync(parentRequest.ParentPath) : default;

            var relatedEntity = (request as GetEntitiesOfRelationRequestModel)?.Related;

            var protoEntity = await _concurrencyService.EnsureCorrectConcurrencyAsync(() => repository.NewAsync(new ViewContext(collection.Alias, parent), collection.EntityVariant.Type));

            var newEntity = requestedEntityVariantIsDefaultVariant
                ? protoEntity
                : await _concurrencyService.EnsureCorrectConcurrencyAsync(() => repository.NewAsync(new ViewContext(collection.Alias, parent), variant.Type));

            await _authService.EnsureAuthorizedUserAsync(request.UsageType, protoEntity);

            await _dataViewResolver.ApplyDataViewToViewAsync(request.View);

            var action = (request.UsageType & ~(UsageType.List)) switch
            {
                UsageType.Add when relatedEntity != null => () => repository.GetAllNonRelatedAsync(new RelatedViewContext(relatedEntity !, collection.Alias, parent), request.View),
                _ when relatedEntity != null => () => repository.GetAllRelatedAsync(new RelatedViewContext(relatedEntity !, collection.Alias, parent), request.View),
                _ when relatedEntity == null => () => repository.GetAllAsync(new ViewContext(collection.Alias, parent), request.View),

                _ => default(Func <Task <IEnumerable <IEntity> > >)
            };

            if (action == default)
            {
                throw new InvalidOperationException($"UsageType {request.UsageType} is invalid for this method");
            }

            var isRoot = parent == null || request.IsEmbedded;

            var protoEditContextUsage = request.UsageType | (isRoot ? UsageType.Root : UsageType.NotRoot);

            var protoEditContext = new FormEditContext(request.CollectionAlias, collection.RepositoryAlias, collection.EntityVariant.Alias, protoEntity, parent, protoEditContextUsage | UsageType.List, collection.Validators, _serviceProvider);
            var newEditContext   = new FormEditContext(request.CollectionAlias, collection.RepositoryAlias, variant.Alias, newEntity, parent, request.UsageType | UsageType.Node, collection.Validators, _serviceProvider);

            var existingEntities = await _concurrencyService.EnsureCorrectConcurrencyAsync(action);

            return(new ListContext(
                       request.CollectionAlias,
                       protoEditContext,
                       parent,
                       request.UsageType,
                       ConvertEditContexts(request, protoEditContext, newEditContext, existingEntities),
                       _serviceProvider));
        }
        public async Task ApplyDataViewToViewAsync(IView view)
        {
            if (string.IsNullOrEmpty(view.CollectionAlias))
            {
                throw new ArgumentNullException($"{nameof(view)}.{nameof(view.CollectionAlias)}");
            }

            var collection = await _collectionResolver.ResolveSetupAsync(view.CollectionAlias);

            if (collection.DataViewBuilder != null || collection.DataViews?.Count > 0)
            {
                var dataViews = await GetDataViewsAsync(collection);

                var dataView = dataViews.FirstOrDefault(x => x.Id == view.ActiveTab)
                               ?? dataViews.FirstOrDefault();

                if (dataView != null)
                {
                    view.SetDataView(dataView);
                }
            }
        }
Пример #14
0
        private async Task <(IButtonActionHandler handler, ButtonSetup button)> FindButtonHandlerAsync(string collectionAlias, string buttonId)
        {
            var collection = await _collectionResolver.ResolveSetupAsync(collectionAlias);

            var button = collection.FindButton(buttonId);

            if (button == null)
            {
                throw new Exception($"Cannot determine which button triggered action for collection {collectionAlias}");
            }

            return(_buttonActionHandlerResolver.GetButtonActionHandler(button), button);
        }
Пример #15
0
        public async Task <IReadOnlyList <IElement> > GetAvailableElementsAsync(IView view)
        {
            var treeElements = await _setupResolver.ResolveSetupAsync();

            return(treeElements
                   .Where(treeElement => treeElement.Type == PageType.Collection)
                   .Where(treeElement => treeElement.Alias != Constants.ModelMakerAdminCollectionAlias)
                   .Select(treeElement => new Element
            {
                Id = treeElement.Alias,
                Labels = new[] { treeElement.Name }
            })
                   .ToList());
        }
        async Task <IEnumerable <TreeElementSetup> > ISetupResolver <IEnumerable <TreeElementSetup> > .ResolveSetupAsync()
        {
            var results = new List <TreeElementSetup>();

            foreach (var plugin in _plugins)
            {
                var treeElements = await _pluginTreeElementResolver.ResolveSetupAsync(plugin);

                results.AddRange(treeElements.Setup);
            }

            results.AddRange((await _treeElementResolver.ResolveSetupAsync(_cmsConfig.CollectionsAndPages?.Skip(1) ?? Enumerable.Empty <ITreeElementConfig>())).Setup);

            return(results);
        }
Пример #17
0
        private async Task <T> InvokeAsync <T>(PersistEntityRequestModel request, T response)
            where T : ViewCommandResponseModel
        {
            var collection = await _collectionResolver.ResolveSetupAsync(request.EditContext.CollectionAlias);

            var repository = _repositoryResolver.GetRepository(collection);

            var entityVariant = collection.GetEntityVariant(request.EditContext.Entity);

            var crudType = await _buttonInteraction.ValidateButtonInteractionAsync(request);

            switch (crudType)
            {
            case CrudType.View:
                _navigationStateProvider.AppendNavigationState(request.NavigationState, new NavigationState(
                                                                   request.EditContext.CollectionAlias,
                                                                   request.EditContext.Parent?.GetParentPath(),
                                                                   entityVariant.Alias,
                                                                   request.EditContext.Entity.Id,
                                                                   UsageType.View));
                break;

            case CrudType.Edit:
                _navigationStateProvider.AppendNavigationState(request.NavigationState, new NavigationState(
                                                                   request.EditContext.CollectionAlias,
                                                                   request.EditContext.Parent?.GetParentPath(),
                                                                   entityVariant.Alias,
                                                                   request.EditContext.Entity.Id,
                                                                   UsageType.Edit));
                break;

            case CrudType.Update:
                var updateContext = await _editContextFactory.GetEditContextWrapperAsync(request.EditContext);

                if (!await updateContext.IsValidAsync())
                {
                    throw new InvalidEntityException();
                }

                await _concurrencyService.EnsureCorrectConcurrencyAsync(() => repository.UpdateAsync(updateContext));

                if (request.EditContext.IsReordered())
                {
                    await _concurrencyService.EnsureCorrectConcurrencyAsync(
                        () => repository.ReorderAsync(request.EditContext.ReorderedBeforeId, request.EditContext.Entity.Id !, new ViewContext(collection.Alias, request.EditContext.Parent)));
                }

                response.RefreshIds = new[] { request.EditContext.Entity.Id ! };
        public async Task <FormEditContext> GetAsync(GetEntityRequestModel request)
        {
            if (string.IsNullOrWhiteSpace(request.Id) && (request.UsageType.HasFlag(UsageType.View) || request.UsageType.HasFlag(UsageType.Edit)))
            {
                throw new InvalidOperationException($"Cannot View/Edit Node when id is null");
            }
            if (!string.IsNullOrWhiteSpace(request.Id) && request.UsageType.HasFlag(UsageType.New))
            {
                throw new InvalidOperationException($"Cannot New Node when id is not null");
            }

            var collection = await _collectionResolver.ResolveSetupAsync(request.CollectionAlias);

            var variant    = request.VariantAlias == null ? collection.EntityVariant : collection.GetEntityVariant(request.VariantAlias);
            var repository = _repositoryResolver.GetRepository(collection);

            var parent = await _parentService.GetParentAsync(request.ParentPath);

            var action = (request.UsageType & ~(UsageType.Node)) switch
            {
                UsageType.View => () => repository.GetByIdAsync(request.Id !, new ViewContext(collection.Alias, parent)),
                UsageType.Edit => () => repository.GetByIdAsync(request.Id !, new ViewContext(collection.Alias, parent)),
                UsageType.New => () => repository.NewAsync(new ViewContext(collection.Alias, parent), variant.Type) !,

                _ => default(Func <Task <IEntity?> >)
            };

            if (action == default)
            {
                throw new InvalidOperationException($"UsageType {request.UsageType} is invalid for this method");
            }

            var entity = await _concurrencyService.EnsureCorrectConcurrencyAsync(action);

            if (entity == null)
            {
                throw new Exception("Failed to get entity for given id(s)");
            }

            await _authService.EnsureAuthorizedUserAsync(request.UsageType, entity);

            return(new FormEditContext(request.CollectionAlias, collection.RepositoryAlias, variant.Alias, entity, parent, request.UsageType | UsageType.Node, collection.Validators, _serviceProvider));
        }
    }
Пример #19
0
        public async Task <IEnumerable <TypeRegistrationSetup> > GetAsync(string request)
        {
            var currentNavigationState = _navigationStateProvider.GetCurrentState();

            var configuredSections = (await _pageResolver.ResolveSetupAsync(request)).Sections;
            var sections           = new List <TypeRegistrationSetup>();
            var isAuthorized       = default(bool?);

            foreach (var section in configuredSections)
            {
                if (section.Type == typeof(ICollectionConfig) &&
                    section.Parameters != null &&
                    section.Parameters.TryGetValue("InitialState", out var obj) &&
                    obj is NavigationState state)
                {
                    _navigationStateProvider.NestNavigationState(currentNavigationState, state);

                    var collection = await _collectionResolver.ResolveSetupAsync(state.CollectionAlias);

                    var repository = _repositoryResolver.GetRepository(collection);

                    var entity = await repository.NewAsync(new ViewContext(section.Alias, default), default);
        public async Task <IResolvedSetup <NodeSetup> > ResolveSetupAsync(NodeConfig config, CollectionSetup?collection = default)
        {
            if (collection == null)
            {
                throw new ArgumentNullException(nameof(collection));
            }

            if (config is IIsConventionBased isConventionBasedConfig)
            {
                config = await _conventionNodeConfigResolver.ResolveByConventionAsync(config.BaseType, isConventionBasedConfig.GetFeatures(), collection);
            }

            var cacheable = true;

            var panes   = (await _paneSetupResolver.ResolveSetupAsync(config.Panes, collection)).CheckIfCachable(ref cacheable).ToList();
            var buttons = (await _buttonSetupResolver.ResolveSetupAsync(config.Buttons, collection)).CheckIfCachable(ref cacheable).ToList();

            return(new ResolvedSetup <NodeSetup>(new NodeSetup(
                                                     config.BaseType,
                                                     panes,
                                                     buttons),
                                                 cacheable));
        }
        private async Task <T> InvokeAsync <T>(PersistEntitiesRequestModel request, T response)
            where T : ViewCommandResponseModel
        {
            var collection = await _collectionResolver.ResolveSetupAsync(request.ListContext.CollectionAlias);

            var repository = _repositoryResolver.GetRepository(collection);

            var(crudType, entityVariant) = await _buttonInteraction.ValidateButtonInteractionAsync(request);

            switch (crudType)
            {
            case CrudType.Create:
                if (entityVariant == null)
                {
                    throw new InvalidOperationException($"Button of type {CrudType.Create} must have an EntityVariant.");
                }

                if (response is ListViewCommandResponseModel || ShouldFallbackToNavigatingToNodeEditor(collection))
                {
                    _navigationStateProvider.AppendNavigationState(
                        request.NavigationState,
                        new NavigationState(
                            request.ListContext.CollectionAlias,
                            request.ListContext.Parent?.GetParentPath(),
                            entityVariant.Alias,
                            request.Related,
                            UsageType.New));
                }
                else
                {
                    _navigationStateProvider.AppendNavigationState(
                        request.NavigationState,
                        new NavigationState(
                            request.ListContext.CollectionAlias,
                            request.ListContext.Parent?.GetParentPath(),
                            request.Related,
                            UsageType.New,
                            PageType.Collection)
                    {
                        CollectionState = request.NavigationState.CollectionState
                    });
                }
                break;

            case CrudType.Update:
                var affectedEntities = new List <IEntity>();

                foreach (var editContext in request.ListContext.EditContexts.Where(f => f.IsModified() || f.IsReordered()))
                {
                    var innerRequest = new PersistEntityCollectionRequestModel
                    {
                        ActionId    = request.ActionId,
                        CustomData  = request.CustomData,
                        EditContext = editContext,
                        ListContext = request.ListContext
                    };
                    if (!await editContext.IsValidAsync())
                    {
                        throw new InvalidEntityException();
                    }

                    await _buttonInteraction.ValidateButtonInteractionAsync(innerRequest);

                    if (editContext.IsModified())
                    {
                        var wrapper = await _editContextFactory.GetEditContextWrapperAsync(editContext);

                        await _concurrencyService.EnsureCorrectConcurrencyAsync(() => repository.UpdateAsync(wrapper));
                    }
                    if (editContext.IsReordered())
                    {
                        await _concurrencyService.EnsureCorrectConcurrencyAsync(
                            () => repository.ReorderAsync(editContext.ReorderedBeforeId, editContext.Entity.Id !, new ViewContext(null, editContext.Parent)));
                    }

                    affectedEntities.Add(editContext.Entity);
                }

                response.RefreshIds = affectedEntities.SelectNotNull(x => x.Id);

                _mediator.NotifyEvent(this, new CollectionRepositoryEventArgs(
                                          collection.Alias,
                                          collection.RepositoryAlias,
                                          request.ListContext.ProtoEditContext.Parent?.GetParentPath(),
                                          response.RefreshIds,
                                          CrudType.Update));
                break;

            case CrudType.None:
                response.NoOp = true;
                break;

            case CrudType.Refresh:
                break;

            case CrudType.Return:
                if (!_navigationStateProvider.RemoveNavigationState(request.NavigationState))
                {
                    var parentPath = request.ListContext.Parent?.GetParentPath();
                    _navigationStateProvider.AppendNavigationState(
                        request.NavigationState,
                        new NavigationState(
                            request.ListContext.CollectionAlias,
                            parentPath,
                            request.Related,
                            collection.ListEditor == null ? UsageType.View : UsageType.Edit,
                            PageType.Collection));
                }
                break;

            case CrudType.Up:
                var(newParentPath, repositoryAlias, parentId) = ParentPath.RemoveLevel(request.ListContext.Parent?.GetParentPath());

                if (repositoryAlias == null)
                {
                    break;
                }

                var parentCollection = collection.Parent != null && collection.Parent.Type == PageType.Collection ? await _collectionResolver.ResolveSetupAsync(collection.Parent.Alias) : default;

                if (parentCollection == null)
                {
                    throw new InvalidOperationException("Cannot go Up on collection that is root.");
                }

                _navigationStateProvider.AppendNavigationState(
                    request.NavigationState,
                    new NavigationState(
                        request.ListContext.CollectionAlias,
                        newParentPath,
                        parentCollection.EntityVariant.Alias,
                        parentId,
                        collection.ListEditor == null ? UsageType.View : UsageType.Edit));
                break;

            case CrudType.Add when request.Related != null:
                _navigationStateProvider.AppendNavigationState(
                    request.NavigationState,
                    new NavigationState(
                        request.ListContext.CollectionAlias,
                        request.Related,
                        UsageType.Add));
                break;

            default:
                throw new InvalidOperationException();
            }

            await _buttonInteraction.CompleteButtonInteractionAsync(request);

            return(response);
        }
        public async Task <IEntity> GetAsync(GetEntityRequestModel request)
        {
            if (string.IsNullOrWhiteSpace(request.Subject.Id) && (request.UsageType.HasFlag(UsageType.View) || request.UsageType.HasFlag(UsageType.Edit)))
            {
                throw new InvalidOperationException($"Cannot View/Edit Node when id is null");
            }
            if (!string.IsNullOrWhiteSpace(request.Subject.Id) && request.UsageType.HasFlag(UsageType.New))
            {
                throw new InvalidOperationException($"Cannot New Node when id is not null");
            }

            var repository = _repositoryResolver.GetRepository(request.Subject.RepositoryAlias ?? throw new ArgumentNullException());

            var parent = await _parentService.GetParentAsync(ParentPath.TryParse(request.Subject.ParentPath));

            var entityVariant = request.Subject.VariantAlias == null ? default : await _entityVariantResolver.ResolveSetupAsync(request.Subject.VariantAlias);

                                var action = (request.UsageType & ~(UsageType.Node)) switch
                                {
                                    UsageType.View => () => repository.GetByIdAsync(request.Subject.Id !, new ViewContext(null, parent)),
                                    UsageType.Edit => () => repository.GetByIdAsync(request.Subject.Id !, new ViewContext(null, parent)),
                                    UsageType.New => () => repository.NewAsync(new ViewContext(null, parent), entityVariant?.Type) !,

                                    _ => default(Func <Task <IEntity?> >)
                                };

                                if (action == default)
                                {
                                    throw new InvalidOperationException($"UsageType {request.UsageType} is invalid for this method");
                                }

                                var entity = await action.Invoke();

                                if (entity == null)
                                {
                                    throw new NotFoundException("Failed to get entity for given id");
                                }

                                await _authService.EnsureAuthorizedUserAsync(request.UsageType, entity);

                                return(entity);
        }
    }
Пример #23
0
        public async Task <FormDataProvider?> GetDataProviderAsync(FieldSetup field)
        {
            if (!(field is PropertyFieldSetup propertyField && propertyField.Relation != null))
            {
                return(null);
            }

            switch (propertyField.Relation)
            {
            case RepositoryRelationSetup collectionRelation:

                var collectionSetup = collectionRelation.CollectionAlias == null
                        ? default
                        : await _collectionSetupResolver.ResolveSetupAsync(collectionRelation.CollectionAlias);

                var repo = collectionRelation.RepositoryAlias != null
                            ? _repositoryResolver.GetRepository(collectionRelation.RepositoryAlias)
                            : collectionSetup != null
                                ? _repositoryResolver.GetRepository(collectionSetup)
                                : default;

                if (repo == null)
                {
                    throw new InvalidOperationException($"Field {propertyField.Property!.PropertyName} has incorrectly configure relation, cannot find repository for alias {(collectionRelation.CollectionAlias ?? collectionRelation.RepositoryAlias)}.");
                }

                // TODO: investigate whether this can be moved to Setup to allow for better caching
                var idProperty = collectionRelation.IdProperty
                                 ?? collectionSetup?.ElementSetup?.IdProperty
                                 ?? throw new InvalidOperationException($"Field {propertyField.Property!.PropertyName} has incorrect Id property metadata.");

                var displayProperties = collectionRelation.DisplayProperties
                                        ?? collectionSetup?.ElementSetup?.DisplayProperties
                                        ?? throw new InvalidOperationException($"Field {propertyField.Property!.PropertyName} has incorrect display properties metadata.");

                var relatedElementGetter = collectionRelation.RelatedElementsGetter
                                           ?? ((collectionRelation.IsRelationToMany && propertyField.Property != null && propertyField.Property.PropertyType.IsAssignableTo(typeof(IEnumerable <IEntity>)))
                            ? PropertyMetadataHelper.GetPropertyMetadata <IEnumerable <IEntity>, IEnumerable <object?> >(x => x.Select(idProperty.Getter))
                            : default);

                var provider = new CollectionDataProvider(
                    repo,
                    _concurrencyService,
                    collectionRelation.RepositoryAlias,
                    collectionRelation.CollectionAlias,
                    relatedElementGetter,
                    collectionRelation.EntityAsParent,
                    collectionRelation.RepositoryParentSelector,
                    idProperty,
                    displayProperties,
                    collectionRelation.RelatedEntityType ?? collectionSetup?.EntityVariant.Type ?? typeof(object),
                    propertyField.Property !,
                    _mediator);

                return(new FormDataProvider(
                           propertyField.Property !,
                           provider));

            case DataProviderRelationSetup dataProviderRelation:

                var dataCollection = _serviceProvider.GetService <IDataCollection>(dataProviderRelation.DataCollectionType);
                if (dataProviderRelation.Configuration != null)
                {
                    dataCollection.Configure(dataProviderRelation.Configuration);
                }

                return(new FormDataProvider(propertyField.Property !, dataCollection));

            case ConcreteDataProviderRelationSetup concreteDataProvider:

                return(new FormDataProvider(propertyField.Property !, concreteDataProvider.DataCollection));

            default:
                throw new InvalidOperationException();
            }
            ;
        }
Пример #24
0
        public async Task <TreeCollectionUI?> GetCollectionAsync(string alias, ParentPath?parentPath)
        {
            var collection = await _collectionResolver.ResolveSetupAsync(alias);

            if (collection == null)
            {
                throw new InvalidOperationException($"Failed to get collection for given alias ({alias}).");
            }

            var parent = await _parentService.GetParentAsync(parentPath);

            var isList       = collection.UsageType.HasFlag(UsageType.List);
            var isListEditor = collection.ListEditor != null;
            var isListView   = collection.ListView != null;
            var isDetails    = collection.UsageType.HasFlag(UsageType.Details) && parent?.Entity != null;

            var respository = _repositoryResolver.GetRepository(collection);
            var entity      = await _concurrencyService.EnsureCorrectConcurrencyAsync(async() => isList
                                                                                      ?await respository.NewAsync(new ViewContext(collection.Alias, parent), collection.EntityVariant.Type)
                                                                                      : await respository.GetByIdAsync(parent !.Entity.Id !, new ViewContext(collection.Alias, parent))
                                                                                      ?? throw new InvalidOperationException($"Failed to get detail entity for given alias ({alias}) -- a detail entity should always exist."));

            var canEdit = (isList && isListEditor && await _authService.IsUserAuthorizedAsync(Operations.Update, entity)) ||
                          (isDetails && await _authService.IsUserAuthorizedAsync(Operations.Update, parent !.Entity));
            var canView = isList && isListView && await _authService.IsUserAuthorizedAsync(Operations.Read, entity);

            if (!canEdit && !canView)
            {
                return(TreeCollectionUI.None);
            }

            var tree = new TreeCollectionUI(collection.Alias, collection.RepositoryAlias, collection.Name)
            {
                EntitiesVisible     = collection.TreeView?.EntityVisibility == EntityVisibilty.Visible,
                RootVisible         = collection.TreeView?.RootVisibility == CollectionRootVisibility.Visible,
                Icon                = collection.Icon ?? "Database",
                Color               = collection.Color,
                DefaultOpenEntities = collection.TreeView?.DefaultOpenEntities ?? false
            };

            if (canEdit)
            {
                if (isList)
                {
                    tree.NavigateTo = new NavigationState(
                        collection.Alias,
                        parentPath,
                        UsageType.Edit);
                }
                else if (isDetails)
                {
                    var entityVariant = collection.GetEntityVariant(entity);

                    tree.NavigateTo = new NavigationState(
                        collection.Alias, parentPath,
                        entityVariant.Alias,
                        parent !.Entity.Id,
                        UsageType.Edit);
                }
            }
            else if (canView)
            {
                tree.NavigateTo = new NavigationState(
                    collection.Alias,
                    parentPath,
                    UsageType.View);
            }

            return(tree);
        }