diff --git a/zero.Core/Api/SpacesApi.cs b/zero.Core/Api/SpacesApi.cs index e19dbc28..4fd32dad 100644 --- a/zero.Core/Api/SpacesApi.cs +++ b/zero.Core/Api/SpacesApi.cs @@ -1,6 +1,4 @@ -using FluentValidation.Results; -using Microsoft.Extensions.Options; -using Raven.Client.Documents; +using Raven.Client.Documents; using Raven.Client.Documents.Linq; using Raven.Client.Documents.Session; using System; @@ -9,90 +7,60 @@ using System.Linq; using System.Threading.Tasks; using zero.Core.Entities; using zero.Core.Extensions; -using zero.Core.Options; -using zero.Core.Plugins; namespace zero.Core.Api { - public class SpacesApi : ISpacesApi + public class SpacesApi : AppAwareBackofficeApi, ISpacesApi { - protected IDocumentStore Raven { get; private set; } - protected IPermissionsApi PermissionsApi { get; private set; } - protected IZeroOptions Options { get; set; } - - public SpacesApi(IDocumentStore raven, IPermissionsApi permissionsApi, IZeroOptions options) + public SpacesApi(IBackofficeStore store, IPermissionsApi permissionsApi) : base(store) { - Raven = raven; + Scope.IncludeShared = true; PermissionsApi = permissionsApi; - Options = options; } /// public Space GetByAlias(string alias) { - return Options.Spaces.GetAllItems().FirstOrDefault(x => x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase)); + return GetAll().FirstOrDefault(x => x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase)); } /// public IReadOnlyCollection GetAll() { - return Options.Spaces.GetAllItems(); + return Backoffice.Options.Spaces.GetAllItems(); } /// - public async Task GetItem(string alias) where T : SpaceContent + public async Task GetItem(string alias, string id = null) { + Space space = GetByAlias(alias); + using (IAsyncDocumentSession session = Raven.OpenAsyncSession()) { - return await session.Query() - .Where(x => x.SpaceAlias == alias) - .ProjectInto() + return await session.Query() + .Scope(Scope) + .Where(x => x.SpaceAlias == space.Alias) + .WhereIf(x => x.Id == id, !id.IsNullOrEmpty()) .FirstOrDefaultAsync(); } } /// - public async Task GetItem(string alias, string id) where T : SpaceContent - { - using (IAsyncDocumentSession session = Raven.OpenAsyncSession()) - { - return await session.Query() - .Where(x => x.SpaceAlias == alias && x.Id == id) - .ProjectInto() - .FirstOrDefaultAsync(); - } - } - - - /// - public async Task> GetList(string alias) where T : SpaceContent - { - using (IAsyncDocumentSession session = Raven.OpenAsyncSession()) - { - return await session.Query() - .Where(x => x.SpaceAlias == alias) - .ProjectInto() - .ToListAsync(); - } - } - - - /// - public async Task> GetListByQuery(string alias, ListQuery query, string appId = null) where T : SpaceContent + public async Task> GetListByQuery(string alias, ListQuery query) { query.SearchSelector = item => item.Name; using (IAsyncDocumentSession session = Raven.OpenAsyncSession()) { - return await session.Query() - .Scope(appId) + return await session.Query() + .Scope(Scope) .Where(x => x.SpaceAlias == alias) .ToQueriedListAsync(query); } @@ -100,58 +68,17 @@ namespace zero.Core.Api /// - public async Task> Save(string alias, T model) where T : SpaceContent + public async Task> Save(string alias, ISpaceContent model) { - Space space = GetByAlias(alias); - //RendererConfig config = GetEditorConfig(alias); - - //if (config.Validator != null) - //{ - // ValidationResult validation = await config.Validator.ValidateAsync(model); - - // if (!validation.IsValid) - // { - // return EntityResult.Fail(validation); - // } - //} - - if (model.Id.IsNullOrEmpty()) - { - model.AppId = "zero.applications.1-A"; // TODO real app id - model.CreatedDate = DateTimeOffset.Now; - } - - model.SpaceAlias = alias; - model.Alias = Safenames.Alias(model.Name); - - using (IAsyncDocumentSession session = Raven.OpenAsyncSession()) - { - await session.StoreAsync(model); - await session.SaveChangesAsync(); - } - - return EntityResult.Success(model); + model.SpaceAlias = GetByAlias(alias)?.Alias; + return await SaveModel(model, null); } /// - public async Task> Delete(string alias, string id) + public async Task> Delete(string alias, string id) { - using (IAsyncDocumentSession session = Raven.OpenAsyncSession()) - { - SpaceContent spaceContent = await session.LoadAsync(id); - - if (spaceContent == null || !spaceContent.SpaceAlias.Equals(alias, StringComparison.InvariantCultureIgnoreCase)) - { - return EntityResult.Fail("@errors.ondelete.idnotfound"); - } - - session.Delete(spaceContent); - - await session.SaveChangesAsync(); - } - - return EntityResult.Success(); + return await DeleteById(id); } } @@ -171,31 +98,21 @@ namespace zero.Core.Api /// /// Get editor item for a space /// - Task GetItem(string alias) where T : SpaceContent; - - /// - /// Get editor item for a space - /// - Task GetItem(string alias, string id) where T : SpaceContent; - - /// - /// Get all list items by space alias - /// - Task> GetList(string alias) where T : SpaceContent; + Task GetItem(string alias, string id = null); /// /// Get all list items for a space (with query) /// - Task> GetListByQuery(string alias, ListQuery query, string appId = null) where T : SpaceContent; + Task> GetListByQuery(string alias, ListQuery query); /// /// Saves a content item in a space /// - Task> Save(string alias, T model) where T : SpaceContent; + Task> Save(string alias, ISpaceContent model); /// /// Deletes a space content item /// - Task> Delete(string alias, string id); + Task> Delete(string alias, string id); } } diff --git a/zero.Core/Entities/Spaces/SpaceContent.cs b/zero.Core/Entities/Spaces/SpaceContent.cs index 005e33d4..df23e519 100644 --- a/zero.Core/Entities/Spaces/SpaceContent.cs +++ b/zero.Core/Entities/Spaces/SpaceContent.cs @@ -1,17 +1,31 @@ -namespace zero.Core.Entities +using zero.Core.Attributes; + +namespace zero.Core.Entities { /// /// A list item can consist of unlimited properties and be rendered as you wish /// The backoffice rendering is done by an IRenderer /// - public class SpaceContent : ZeroEntity, IAppAwareEntity, IZeroDbConventions + public class SpaceContent : ZeroEntity, ISpaceContent { - /// - /// Associated space - /// + /// public string SpaceAlias { get; set; } /// public string AppId { get; set; } } + + + /// + /// A list item can consist of unlimited properties and be rendered as you wish + /// The backoffice rendering is done by an IRenderer + /// + [Collection("SpaceContents")] + public interface ISpaceContent : IZeroEntity, IAppAwareEntity, IZeroDbConventions + { + /// + /// Associated space + /// + string SpaceAlias { get; set; } + } } \ No newline at end of file diff --git a/zero.Debug/Renderers/space.social.js b/zero.Debug/Renderers/space.social.js new file mode 100644 index 00000000..958d7e3b --- /dev/null +++ b/zero.Debug/Renderers/space.social.js @@ -0,0 +1,22 @@ + +export default { + alias: 'space.social', + + fields: [ + { + field: 'twitter', + display: 'text', + label: 'Twitter' + }, + { + field: 'facebook', + display: 'text', + label: 'Facebook' + }, + { + field: 'youtube', + display: 'text', + label: 'YouTube' + }, + ] +}; \ No newline at end of file diff --git a/zero.Debug/Renderers/space.team.js b/zero.Debug/Renderers/space.team.js new file mode 100644 index 00000000..0305bf30 --- /dev/null +++ b/zero.Debug/Renderers/space.team.js @@ -0,0 +1,24 @@ + +export default { + alias: 'space.team', + + fields: [ + { + field: 'name', + display: 'text', + label: 'Name', + required: true + }, + { + field: 'position', + display: 'text', + label: 'Position' + }, + { + field: 'email', + display: 'text', + label: 'Email', + required: true + } + ] +}; \ No newline at end of file diff --git a/zero.Web.UI/App/components/forms/form.vue b/zero.Web.UI/App/components/forms/form.vue index 3ca1590c..a38cf41f 100644 --- a/zero.Web.UI/App/components/forms/form.vue +++ b/zero.Web.UI/App/components/forms/form.vue @@ -27,7 +27,7 @@ default: () => [ 'uiProperty' ] }, route: { - type: String, + type: [String, Object], default: null } }, @@ -173,10 +173,11 @@ if (response.model && this.route && this.$route.name !== this.route) { - this.$router.replace({ - name: this.route, - params: { id: response.model.id } - }); + let routeObj = typeof this.route === 'object' ? this.route : { name: this.route }; + routeObj.params = routeObj.params || {}; + routeObj.params.id = response.model.id; + + this.$router.replace(routeObj); } } else diff --git a/zero.Web.UI/App/editor/editor.vue b/zero.Web.UI/App/editor/editor.vue index 0484fef5..5f735cc9 100644 --- a/zero.Web.UI/App/editor/editor.vue +++ b/zero.Web.UI/App/editor/editor.vue @@ -22,7 +22,7 @@ -
+
{{value.id}} diff --git a/zero.Web.UI/App/pages/spaces/routes.js b/zero.Web.UI/App/pages/spaces/routes.js index c29ede6b..0beaadaf 100644 --- a/zero.Web.UI/App/pages/spaces/routes.js +++ b/zero.Web.UI/App/pages/spaces/routes.js @@ -20,6 +20,16 @@ if (section) component: () => import('zero/pages/' + alias + '/spaces') }); + routes.push({ + path: ':alias/create', + props: true, + name: 'space-create', + component: () => import('zero/pages/' + alias + '/spaces'), + meta: { + create: true + } + }); + //routes.push({ // path: 'list/:id', // props: true, diff --git a/zero.Web.UI/App/pages/spaces/spaces.vue b/zero.Web.UI/App/pages/spaces/spaces.vue index d52f6222..ad6e8c10 100644 --- a/zero.Web.UI/App/pages/spaces/spaces.vue +++ b/zero.Web.UI/App/pages/spaces/spaces.vue @@ -1,7 +1,7 @@