diff --git a/zero.Backoffice.UI/app/api/countries.js b/zero.Backoffice.UI/app/api/countries.js index fd723b2f..e801b4eb 100644 --- a/zero.Backoffice.UI/app/api/countries.js +++ b/zero.Backoffice.UI/app/api/countries.js @@ -1,4 +1,10 @@ -//import { collection } from '../helpers/request.ts'; -import { RequestHelper } from '../helpers/all.js'; +import { get, post, put, del } from '../helpers/request.ts'; -export default { ...RequestHelper.collection('countries/') }; \ No newline at end of file +export default { + getById: async (id, config) => await get('countries/' + id, { ...config }), + getEmpty: async config => await get('countries/empty', { ...config }), + getByQuery: async (query, config) => await get('countries', { ...config, params: { query } }), + create: async (model, config) => await post('countries', model, { ...config }), + update: async (model, config) => await put('countries/' + model.id, model, { ...config }), + delete: async (id, config) => await del('countries/' + id, { ...config, params: { id } }) +}; \ No newline at end of file diff --git a/zero.Backoffice/Configuration/BackofficeConstants.cs b/zero.Backoffice/Configuration/BackofficeConstants.cs new file mode 100644 index 00000000..61c66ea8 --- /dev/null +++ b/zero.Backoffice/Configuration/BackofficeConstants.cs @@ -0,0 +1,9 @@ +namespace zero.Backoffice.Configuration; + +public static class BackofficeConstants +{ + public static class HttpErrors + { + public const string NoIdMatchOnUpdate = "The Id as part of the URL does not match the Id of the model"; + } +} \ No newline at end of file diff --git a/zero.Backoffice/Controllers/ZeroBackofficeApiController.cs b/zero.Backoffice/Controllers/ZeroBackofficeApiController.cs index f6e27b65..b5a35646 100644 --- a/zero.Backoffice/Controllers/ZeroBackofficeApiController.cs +++ b/zero.Backoffice/Controllers/ZeroBackofficeApiController.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using AutoMapper; +using Microsoft.AspNetCore.Mvc; namespace zero.Backoffice.Controllers; @@ -7,5 +8,5 @@ namespace zero.Backoffice.Controllers; //[ServiceFilter(typeof(BackofficeFilterAttribute))] public abstract class ZeroBackofficeApiController : ZeroBackofficeController { - + protected IMapper Mapper { get; private set; } } diff --git a/zero.Backoffice/Controllers/ZeroBackofficeController.cs b/zero.Backoffice/Controllers/ZeroBackofficeController.cs index 7b673474..481cfe17 100644 --- a/zero.Backoffice/Controllers/ZeroBackofficeController.cs +++ b/zero.Backoffice/Controllers/ZeroBackofficeController.cs @@ -9,16 +9,16 @@ public abstract class ZeroBackofficeController : ControllerBase /// /// Create an edit model with associated metadata and permissions from a model /// - protected EditModel GetEditModel(T model) + protected DisplayModel GetEditModel(T model) { - return GetEditModel>(new EditModel() { Entity = model }); + return GetEditModel>(new DisplayModel() { Entity = model }); } /// /// Create an edit model with associated metadata and permissions from a model /// - protected TWrapper GetEditModel(TWrapper editModel) where TWrapper : EditModel, new() + protected TWrapper GetEditModel(TWrapper editModel) where TWrapper : DisplayModel, new() { editModel.Meta = new() { diff --git a/zero.Backoffice/Controllers/ZeroSetupController.cs b/zero.Backoffice/Controllers/ZeroSetupController.cs index 58d53c0e..51dd4088 100644 --- a/zero.Backoffice/Controllers/ZeroSetupController.cs +++ b/zero.Backoffice/Controllers/ZeroSetupController.cs @@ -37,7 +37,7 @@ public class ZeroSetupController : Controller { model.ContentRootPath = Env.ContentRootPath; - EntityResult result = await Api.Install(model); + Result result = await Api.Install(model); if (result.IsSuccess) { diff --git a/zero.Backoffice/Controllers/_ZeroBackofficeCollectionController.cs b/zero.Backoffice/Controllers/_ZeroBackofficeCollectionController.cs index 659923ba..58c963dc 100644 --- a/zero.Backoffice/Controllers/_ZeroBackofficeCollectionController.cs +++ b/zero.Backoffice/Controllers/_ZeroBackofficeCollectionController.cs @@ -34,22 +34,22 @@ public abstract class _ZeroBackofficeCollectionController } - public virtual async Task> GetById([FromQuery] string id, [FromQuery] string changeVector = null) => Edit(await Collection.Load(id, changeVector)); + public virtual async Task> GetById([FromQuery] string id, [FromQuery] string changeVector = null) => Edit(await Collection.Load(id, changeVector)); public virtual async Task> GetByIds([FromQuery] string[] ids) => await Collection.Load(ids); - public virtual async Task> GetEmpty() => Edit(await Collection.Empty()); + public virtual async Task> GetEmpty() => Edit(await Collection.Empty()); - public virtual async Task> GetByQuery([FromQuery] ListBackofficeQuery query) + public virtual async Task> GetByQuery([FromQuery] ListQuery query) { return await Collection.Load(query); } - public virtual async Task> GetRevisions([FromQuery] string id, [FromQuery] ListBackofficeQuery query) + public virtual async Task> GetRevisions([FromQuery] string id, [FromQuery] ListQuery query) { return null; // TODO //return await Collection.GetRevisions(id, query.Page, query.PageSize); @@ -63,9 +63,9 @@ public abstract class _ZeroBackofficeCollectionController [HttpPost] - public virtual async Task> Save([FromBody] TEntity model) => await Collection.Save(model); + public virtual async Task> Save([FromBody] TEntity model) => await Collection.Save(model); [HttpDelete] - public virtual async Task> Delete([FromQuery] string id) => await Collection.Delete(id); + public virtual async Task> Delete([FromQuery] string id) => await Collection.Delete(id); } \ No newline at end of file diff --git a/zero.Backoffice/Mapper/MapperExtensions.cs b/zero.Backoffice/Mapper/MapperExtensions.cs new file mode 100644 index 00000000..a998f7c8 --- /dev/null +++ b/zero.Backoffice/Mapper/MapperExtensions.cs @@ -0,0 +1,17 @@ +using AutoMapper; + +namespace zero.Backoffice.Mapper; + +public static class MapperExtensions +{ + public static Paged Map(this IMapper mapper, Paged source) + { + return source.MapTo(srcItem => mapper.Map(srcItem)); + } + + public static Result Map(this IMapper mapper, Result source) + { + TDestination model = mapper.Map(source.Model); + return source.ConvertTo(model); + } +} diff --git a/zero.Backoffice/Mapper/ZeroMapper.cs b/zero.Backoffice/Mapper/ZeroMapper.cs new file mode 100644 index 00000000..1a307112 --- /dev/null +++ b/zero.Backoffice/Mapper/ZeroMapper.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace zero.Backoffice.Mapper +{ + public class ZeroMapper : AutoMapper.Mapper + { + public ZeroMapper(AutoMapper.IConfigurationProvider provider) : base(provider) + { + + } + } +} diff --git a/zero.Backoffice/Mapper/ZeroMapperProfile.cs b/zero.Backoffice/Mapper/ZeroMapperProfile.cs new file mode 100644 index 00000000..32c9c61e --- /dev/null +++ b/zero.Backoffice/Mapper/ZeroMapperProfile.cs @@ -0,0 +1,8 @@ +using AutoMapper; + +namespace zero.Backoffice.Mapper; + +public class ZeroMapperProfile : Profile +{ + +} diff --git a/zero.Backoffice/Models/BasicModel.cs b/zero.Backoffice/Models/BasicModel.cs new file mode 100644 index 00000000..ff7774bf --- /dev/null +++ b/zero.Backoffice/Models/BasicModel.cs @@ -0,0 +1,6 @@ +namespace zero.Backoffice.Models; + +public abstract class BasicModel : ZeroIdEntity where T : ZeroIdEntity +{ + public string Name { get; set; } +} \ No newline at end of file diff --git a/zero.Backoffice/Models/EditModel.cs b/zero.Backoffice/Models/DisplayModel.cs similarity index 81% rename from zero.Backoffice/Models/EditModel.cs rename to zero.Backoffice/Models/DisplayModel.cs index 0af0f978..48b2a288 100644 --- a/zero.Backoffice/Models/EditModel.cs +++ b/zero.Backoffice/Models/DisplayModel.cs @@ -1,27 +1,20 @@ namespace zero.Backoffice.Models; -public class EditModel : EditModel { } - -public class EditModel +public abstract class DisplayModel : ZeroIdEntity where T : ZeroIdEntity { - /// - /// Model - /// - public T Entity { get; set; } - /// /// Meta data /// - public EditMetaModel Meta { get; set; } = new(); + public DisplayModelMeta Meta { get; set; } = new(); /// /// Permissions for this entity /// - public EditPermissionModel Permissions { get; set; } = new(); + public DisplayModelPermissions Permissions { get; set; } = new(); } -public class EditMetaModel +public class DisplayModelMeta { /// /// Wehther this entity is application aware @@ -44,7 +37,7 @@ public class EditMetaModel } -public class EditPermissionModel +public class DisplayModelPermissions { /// /// Whether an entity of this type can be created diff --git a/zero.Backoffice/Models/ListQuery.cs b/zero.Backoffice/Models/ListQuery.cs deleted file mode 100644 index ecf5e216..00000000 --- a/zero.Backoffice/Models/ListQuery.cs +++ /dev/null @@ -1,94 +0,0 @@ -using Newtonsoft.Json; -using System.Linq.Expressions; - -namespace zero.Backoffice.Models; - -public class ListBackofficeQuery : ListQuery -{ - public ListBackofficeQuery() - { - IncludeInactive = true; - } -} - -public class ListBackofficeQuery : ListQuery where TFilter : IListSpecificQuery -{ - public ListBackofficeQuery() - { - IncludeInactive = true; - } -} - -public class ListQuery -{ - public string Search { get; set; } = null; - - public Expression> SearchSelector { get; set; } = null; - - public Expression>[] SearchSelectors { get; private set; } = new Expression>[0] { }; - - public string OrderBy { get; set; } = "createdDate"; - - public ListQueryOrderType OrderType { get; set; } = ListQueryOrderType.String; - - public bool OrderIsDescending { get; set; } = true; - - public Func, IQueryable> OrderQuery = null; - - public int Page { get; set; } = 1; - - public int PageSize { get; set; } = 30; - - public bool IncludeInactive { get; set; } = false; - - public void SearchFor(params Expression>[] selectors) - { - SearchSelectors = selectors; - } -} - - -public class ListQuery : ListQuery where TFilter : IListSpecificQuery -{ - public TFilter Filter { get; set; } -} - - -public static class ListQueryExtensions -{ - public static ListQuery AsList(this string options) where TFilter : IListSpecificQuery - { - return JsonConvert.DeserializeObject>(options); - } - - public static ListQuery AsList(this string options) where T : IListSpecificQuery - { - return JsonConvert.DeserializeObject>(options); - } -} - - -public interface IListSpecificQuery { } - -public class EmptyListSpecificQuery : IListSpecificQuery { } - - -public class ListQueryDateRange -{ - public DateTimeOffset? From { get; set; } - - public DateTimeOffset? To { get; set; } -} - -public class ListQueryRange -{ - public decimal? From { get; set; } - - public decimal? To { get; set; } -} - -public enum ListQueryOrderType -{ - String, - Number -} \ No newline at end of file diff --git a/zero.Backoffice/Models/ListQuery/ListQuery.cs b/zero.Backoffice/Models/ListQuery/ListQuery.cs new file mode 100644 index 00000000..b267b147 --- /dev/null +++ b/zero.Backoffice/Models/ListQuery/ListQuery.cs @@ -0,0 +1,41 @@ +using System.Linq.Expressions; + +namespace zero.Backoffice.Models; + +public class ListQuery +{ + public ListQueryDisplayType DisplayType { get; set; } + + public string[] Ids { get; set; } = Array.Empty(); + + public string Search { get; set; } = null; + + public Expression> SearchSelector { get; set; } = null; + + public Expression>[] SearchSelectors { get; private set; } = new Expression>[0] { }; + + public string OrderBy { get; set; } = "createdDate"; + + public ListQueryOrderType OrderType { get; set; } = ListQueryOrderType.String; + + public bool OrderIsDescending { get; set; } = true; + + public Func, IQueryable> OrderQuery = null; + + public int Page { get; set; } = 1; + + public int PageSize { get; set; } = 30; + + //public bool IncludeInactive { get; set; } = true; + + public void SearchFor(params Expression>[] selectors) + { + SearchSelectors = selectors; + } +} + + +public class ListQuery : ListQuery where TFilter : IListSpecificQuery +{ + public TFilter Filter { get; set; } +} \ No newline at end of file diff --git a/zero.Backoffice/Models/ListQuery/ListQueryDisplayType.cs b/zero.Backoffice/Models/ListQuery/ListQueryDisplayType.cs new file mode 100644 index 00000000..fd06ae63 --- /dev/null +++ b/zero.Backoffice/Models/ListQuery/ListQueryDisplayType.cs @@ -0,0 +1,17 @@ +namespace zero.Backoffice.Models; + +public enum ListQueryDisplayType +{ + /// + /// Default output for listings + /// + Default = 0, + /// + /// Previews for collection pickers + /// + Preview = 1, + /// + /// Selection within a picker + /// + Picker = 2 +} \ No newline at end of file diff --git a/zero.Backoffice/Models/ListQuery/ListQueryExtensions.cs b/zero.Backoffice/Models/ListQuery/ListQueryExtensions.cs new file mode 100644 index 00000000..62977c60 --- /dev/null +++ b/zero.Backoffice/Models/ListQuery/ListQueryExtensions.cs @@ -0,0 +1,65 @@ +using Newtonsoft.Json; +using Raven.Client.Documents.Linq; +using Raven.Client.Documents.Session; + +namespace zero.Backoffice.Models; + +public static class ListQueryExtensions +{ + public static ListQuery AsList(this string options) where TFilter : IListSpecificQuery + { + return JsonConvert.DeserializeObject>(options); + } + + public static ListQuery AsList(this string options) where T : IListSpecificQuery + { + return JsonConvert.DeserializeObject>(options); + } + + public static IQueryable Filter(this IRavenQueryable source, ListQuery listQuery) where T : ZeroIdEntity + { + Type collectionType = typeof(T); + Type zeroType = typeof(ZeroEntity); + bool isZeroType = zeroType.IsAssignableFrom(collectionType); + + IQueryable queryable = source; + + if (listQuery.Ids.Length > 0) + { + queryable = queryable.Where(x => x.Id.In(listQuery.Ids)); + } + + if (!listQuery.Search.IsNullOrEmpty() && listQuery.SearchSelectors.Length > 0) + { + foreach (var selector in listQuery.SearchSelectors) + { + queryable = queryable.SearchIf(selector, listQuery.Search, "*", "*", Raven.Client.Documents.Queries.SearchOperator.And); + } + } + else if (!listQuery.Search.IsNullOrEmpty() && listQuery.SearchSelector != null) + { + queryable = queryable.SearchIf(listQuery.SearchSelector, listQuery.Search, "*", "*", Raven.Client.Documents.Queries.SearchOperator.And); + } + + if (listQuery.OrderQuery != null) + { + queryable = listQuery.OrderQuery(queryable); + } + else if (!listQuery.OrderBy.IsNullOrEmpty()) + { + queryable = queryable.OrderBy(listQuery.OrderBy, listQuery.OrderIsDescending, listQuery.OrderType == ListQueryOrderType.String ? OrderingType.String : OrderingType.Double); + } + else if (isZeroType) + { + queryable = queryable.OrderByDescending(x => (x as ZeroEntity).CreatedDate); + } + + return queryable; + } + + + public static Paged Convert(this Paged result, ListQueryDisplayType displayType) where T : ZeroIdEntity + { + + } +} \ No newline at end of file diff --git a/zero.Backoffice/Models/ListQuery/ListQueryOrderType.cs b/zero.Backoffice/Models/ListQuery/ListQueryOrderType.cs new file mode 100644 index 00000000..58ecebb5 --- /dev/null +++ b/zero.Backoffice/Models/ListQuery/ListQueryOrderType.cs @@ -0,0 +1,7 @@ +namespace zero.Backoffice.Models; + +public enum ListQueryOrderType +{ + String, + Number +} \ No newline at end of file diff --git a/zero.Backoffice/Models/ListQuery/ListQueryRange.cs b/zero.Backoffice/Models/ListQuery/ListQueryRange.cs new file mode 100644 index 00000000..58e61570 --- /dev/null +++ b/zero.Backoffice/Models/ListQuery/ListQueryRange.cs @@ -0,0 +1,15 @@ +namespace zero.Backoffice.Models; + +public class ListQueryDateRange +{ + public DateTimeOffset? From { get; set; } + + public DateTimeOffset? To { get; set; } +} + +public class ListQueryRange +{ + public decimal? From { get; set; } + + public decimal? To { get; set; } +} \ No newline at end of file diff --git a/zero.Backoffice/Models/ListQuery/ListSpecificQuery.cs b/zero.Backoffice/Models/ListQuery/ListSpecificQuery.cs new file mode 100644 index 00000000..6ae45225 --- /dev/null +++ b/zero.Backoffice/Models/ListQuery/ListSpecificQuery.cs @@ -0,0 +1,5 @@ +namespace zero.Backoffice.Models; + +public interface IListSpecificQuery { } + +public class EmptyListSpecificQuery : IListSpecificQuery { } \ No newline at end of file diff --git a/zero.Backoffice/Models/ListResult.cs b/zero.Backoffice/Models/ListResult.cs deleted file mode 100644 index ec52b655..00000000 --- a/zero.Backoffice/Models/ListResult.cs +++ /dev/null @@ -1,67 +0,0 @@ -namespace zero.Backoffice.Models; - -/// -/// Represents a paged result for a model collection -/// -public class ListResult : ListResult -{ - public ListResult(long totalItems, long page, long pageSize) - { - TotalItems = totalItems; - Page = page; - PageSize = pageSize; - - if (pageSize > 0) - { - TotalPages = (long)Math.Ceiling(totalItems / (decimal)pageSize); - } - else - { - TotalPages = 1; - } - - HasMore = TotalPages > Page; - } - - public ListResult(IList items, long totalItems, long pageNumber, long pageSize) : this(totalItems, pageNumber, pageSize) - { - Items = items; - } - - public ListResult MapTo(Func convertItem) - { - return new ListResult(Items.Select(x => convertItem(x)).Where(x => x != null).ToList(), TotalItems, Page, PageSize); - } - - public IList Items { get; set; } = new List(); - - - /// - /// Calculates the skip size based on the paged parameters specified - /// - /// - /// Returns 0 if the page number or page size is zero - /// - public int GetSkipSize() - { - if (Page > 0 && PageSize > 0) - { - return Convert.ToInt32((Page - 1) * PageSize); - } - return 0; - } -} - - -public class ListResult -{ - public long Page { get; protected set; } - - public long PageSize { get; protected set; } - - public long TotalPages { get; protected set; } - - public long TotalItems { get; protected set; } - - public bool HasMore { get; protected set; } -} \ No newline at end of file diff --git a/zero.Backoffice/Models/SaveModel.cs b/zero.Backoffice/Models/SaveModel.cs new file mode 100644 index 00000000..c8238f53 --- /dev/null +++ b/zero.Backoffice/Models/SaveModel.cs @@ -0,0 +1,6 @@ +namespace zero.Backoffice.Models; + +public abstract class SaveModel : ZeroIdEntity where T : ZeroIdEntity +{ + +} \ No newline at end of file diff --git a/zero.Backoffice/Models/_legacy/ListModel.cs b/zero.Backoffice/Models/_legacy/ListModel.cs index 20e98f1e..1c17e271 100644 --- a/zero.Backoffice/Models/_legacy/ListModel.cs +++ b/zero.Backoffice/Models/_legacy/ListModel.cs @@ -1,6 +1,6 @@ namespace zero.Web.Models { - public abstract class ListModel + public abstract class ListModel where T : ZeroIdEntity { /// /// Id of the entity diff --git a/zero.Backoffice/Modules/Applications/ApplicationsController.cs b/zero.Backoffice/Modules/Applications/ApplicationsController.cs index 1bdf0ab1..64a3e2a5 100644 --- a/zero.Backoffice/Modules/Applications/ApplicationsController.cs +++ b/zero.Backoffice/Modules/Applications/ApplicationsController.cs @@ -29,7 +29,7 @@ namespace zero.Web.Controllers public async Task> GetAll() => await Api.GetAll(); - public async Task> GetByQuery([FromQuery] ListBackofficeQuery query) => await Api.GetByQuery(query); + public async Task> GetByQuery([FromQuery] ListQuery query) => await Api.GetByQuery(query); public IReadOnlyCollection GetAllFeatures() => Options.Features.GetAllItems(); @@ -37,11 +37,11 @@ namespace zero.Web.Controllers [HttpPost] [ZeroAuthorize(Permissions.Settings.Applications, PermissionsValue.Update)] - public async Task> Save([FromBody] Application model) => await Api.Save(model); + public async Task> Save([FromBody] Application model) => await Api.Save(model); [HttpDelete] [ZeroAuthorize(Permissions.Settings.Applications, PermissionsValue.Update)] - public async Task> Delete([FromQuery] string id) => await Api.Delete(id); + public async Task> Delete([FromQuery] string id) => await Api.Delete(id); } } diff --git a/zero.Backoffice/Modules/Countries/CountriesController.cs b/zero.Backoffice/Modules/Countries/CountriesController.cs index 8c4df0f1..47030bd3 100644 --- a/zero.Backoffice/Modules/Countries/CountriesController.cs +++ b/zero.Backoffice/Modules/Countries/CountriesController.cs @@ -1,66 +1,107 @@ using Microsoft.AspNetCore.Mvc; -namespace zero.Backoffice.Modules; +namespace zero.Backoffice.Modules.Countries; -/// -/// | GET /zero/api/countries/empty -/// | GET /zero/api/countries/{id} -/// | GET /zero/api/countries/{id}/revisions -/// | GET /zero/api/countries[type,query,filter,...] -/// | POST /zero/api/countries -/// | PUT /zero/api/countries/{id} -/// | DELETE /zero/api/countries/{id} -/// public class CountriesController : ZeroBackofficeApiController { - protected ICountriesStore Collection { get; set; } + protected ICountryStore Store { get; set; } - public CountriesController(ICountriesStore collection) + public CountriesController(ICountryStore store) { - Collection = collection; + Store = store; } [HttpGet("empty")] - public virtual async Task New() + public virtual async Task> Empty() { - return await Collection.Empty(); + Country model = await Store.Empty(); + + if (model == null) + { + return NotFound(); + } + + return Mapper.Map(model); } + [HttpGet("{id}")] - public virtual async Task Get(string id, string changeVector = null) + public virtual async Task> Get(string id, string changeVector = null) { - return await Collection.Load(id, changeVector); + Country model = await Store.Load(id, changeVector); + + if (model == null) + { + return NotFound(); + } + + return Mapper.Map(model); } + [HttpGet] - public virtual async Task> Get(ListBackofficeQuery query) + public virtual async Task> Get(ListQuery query) { - return await Collection.Load(query.Page, query.PageSize, q => q.OrderByDescending(x => x.CreatedDate)); + Paged result = await Store.Load(query.Page, query.PageSize, q => q.Filter(query)); + return Mapper.Map(result); } - //[HttpGet("{id}/revisions")] - //public virtual async Task>> GetRevisions(string id) - //{ - // return await Collection.GetRevisions(id); - //} - [HttpPost] - public virtual async Task> Create(Country country) + public virtual async Task> Create(CountrySave saveModel) { - return await Collection.Create(country); + Country model = Mapper.Map(saveModel); + Result result = await Store.Create(model); + Result mappedResult = Mapper.Map(result); + + if (result.IsSuccess) + { + return CreatedAtAction(nameof(CountriesController.Get), new { id = model.Id }, mappedResult); + } + + return mappedResult; } + [HttpPut("{id}")] - public virtual async Task> Update(string id, Country country) + public virtual async Task> Update(string id, CountrySave updateModel) { - return await Collection.Update(country); + if (id != updateModel.Id) + { + return BadRequest(BackofficeConstants.HttpErrors.NoIdMatchOnUpdate); + } + + Country model = Mapper.Map(updateModel); + model.Id = id; + Result result = await Store.Update(model); + + if (result.IsSuccess) + { + return NoContent(); + } + + return Mapper.Map(result); } + [HttpDelete("{id}")] - public virtual async Task> Delete(string id) + public virtual async Task> Delete(string id) { - return await Collection.Delete(id); + Country model = await Store.Load(id); + + if (model == null) + { + return NotFound(); + } + + Result result = await Store.Delete(model); + + if (result.IsSuccess) + { + return NoContent(); + } + + return result.WithoutModel(); } } \ No newline at end of file diff --git a/zero.Backoffice/Modules/Countries/CountryListModel.cs b/zero.Backoffice/Modules/Countries/CountryListModel.cs deleted file mode 100644 index 16fc74f5..00000000 --- a/zero.Backoffice/Modules/Countries/CountryListModel.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace zero.Backoffice.Modules; - -public class CountryListModel : ListModel -{ - public string Name { get; set; } - - public bool IsActive { get; set; } - - public bool IsPreferred { get; set; } - - public string Code { get; set; } -} diff --git a/zero.Backoffice/Modules/Countries/CountryPermissions.cs b/zero.Backoffice/Modules/Countries/CountryPermissions.cs index f2f04b99..a840144b 100644 --- a/zero.Backoffice/Modules/Countries/CountryPermissions.cs +++ b/zero.Backoffice/Modules/Countries/CountryPermissions.cs @@ -1,4 +1,4 @@ -namespace zero.Backoffice.Modules; +namespace zero.Backoffice.Modules.Countries; public class CountryPermissions : PermissionProvider { diff --git a/zero.Backoffice/Modules/Countries/zero_Backoffice_Countries_Listing.cs b/zero.Backoffice/Modules/Countries/Indexes/zero_Backoffice_Countries_Listing.cs similarity index 87% rename from zero.Backoffice/Modules/Countries/zero_Backoffice_Countries_Listing.cs rename to zero.Backoffice/Modules/Countries/Indexes/zero_Backoffice_Countries_Listing.cs index 45b3713d..d915cbfc 100644 --- a/zero.Backoffice/Modules/Countries/zero_Backoffice_Countries_Listing.cs +++ b/zero.Backoffice/Modules/Countries/Indexes/zero_Backoffice_Countries_Listing.cs @@ -1,6 +1,6 @@ using Raven.Client.Documents.Indexes; -namespace zero.Backoffice.Modules; +namespace zero.Backoffice.Modules.Countries; public class zero_Backoffice_Countries_Listing : ZeroIndex { diff --git a/zero.Backoffice/Modules/Countries/Maps/CountryBasic.cs b/zero.Backoffice/Modules/Countries/Maps/CountryBasic.cs new file mode 100644 index 00000000..0d5cbd1a --- /dev/null +++ b/zero.Backoffice/Modules/Countries/Maps/CountryBasic.cs @@ -0,0 +1,10 @@ +namespace zero.Backoffice.Modules.Countries; + +public class CountryBasic : BasicModel +{ + public bool IsActive { get; set; } + + public bool IsPreferred { get; set; } + + public string Code { get; set; } +} \ No newline at end of file diff --git a/zero.Backoffice/Modules/Countries/Maps/CountryDisplay.cs b/zero.Backoffice/Modules/Countries/Maps/CountryDisplay.cs new file mode 100644 index 00000000..f3883c80 --- /dev/null +++ b/zero.Backoffice/Modules/Countries/Maps/CountryDisplay.cs @@ -0,0 +1,12 @@ +namespace zero.Backoffice.Modules.Countries; + +public class CountryDisplay : DisplayModel +{ + public string Name { get; set; } + + public bool IsPreferred { get; set; } + + public string Code { get; set; } + + public string LanguageId { get; set; } +} \ No newline at end of file diff --git a/zero.Backoffice/Modules/Countries/Maps/CountryMapperProfile.cs b/zero.Backoffice/Modules/Countries/Maps/CountryMapperProfile.cs new file mode 100644 index 00000000..992019dd --- /dev/null +++ b/zero.Backoffice/Modules/Countries/Maps/CountryMapperProfile.cs @@ -0,0 +1,11 @@ +namespace zero.Backoffice.Modules.Countries; + +public class CountryMapperProfile : ZeroMapperProfile +{ + public CountryMapperProfile() + { + CreateMap(); + CreateMap(); + CreateMap(); + } +} diff --git a/zero.Backoffice/Modules/Countries/CountryEditModel.cs b/zero.Backoffice/Modules/Countries/Maps/CountrySave.cs similarity index 65% rename from zero.Backoffice/Modules/Countries/CountryEditModel.cs rename to zero.Backoffice/Modules/Countries/Maps/CountrySave.cs index d8f8bc3b..1e24752a 100644 --- a/zero.Backoffice/Modules/Countries/CountryEditModel.cs +++ b/zero.Backoffice/Modules/Countries/Maps/CountrySave.cs @@ -1,8 +1,8 @@ using System; -namespace zero.Backoffice.Modules; +namespace zero.Backoffice.Modules.Countries; -public class CountryEditModel : ObsoleteEditModel +public class CountrySave : SaveModel { public string Name { get; set; } diff --git a/zero.Backoffice/Modules/Countries/Module.cs b/zero.Backoffice/Modules/Countries/Module.cs deleted file mode 100644 index 4ca79c1a..00000000 --- a/zero.Backoffice/Modules/Countries/Module.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace zero.Backoffice.Modules; - -internal class CountriesModule : ZeroModule -{ - /// - public override void Register(IZeroModuleConfiguration config) - { - config.Services.AddScoped(); - } - - - /// - public override void Configure(IZeroOptions options) - { - options.For().Indexes.Add(); - } -} \ No newline at end of file diff --git a/zero.Backoffice/Modules/Integrations/IntegrationsController.cs b/zero.Backoffice/Modules/Integrations/IntegrationsController.cs index 3b580cdc..383dba9f 100644 --- a/zero.Backoffice/Modules/Integrations/IntegrationsController.cs +++ b/zero.Backoffice/Modules/Integrations/IntegrationsController.cs @@ -32,12 +32,12 @@ namespace zero.Web.Controllers [HttpPost] - public async Task> Save([FromBody] Integration model) => await Collection.Save(model); + public async Task> Save([FromBody] Integration model) => await Collection.Save(model); [HttpPost] - public async Task> SaveActiveState([FromBody] Integration model) => model.IsActive ? await Collection.Activate(model.Alias) : await Collection.Deactivate(model.Alias); + public async Task> SaveActiveState([FromBody] Integration model) => model.IsActive ? await Collection.Activate(model.Alias) : await Collection.Deactivate(model.Alias); [HttpDelete] - public async Task> Delete([FromQuery] string alias) => await Collection.DeleteByAlias(alias); + public async Task> Delete([FromQuery] string alias) => await Collection.DeleteByAlias(alias); } } \ No newline at end of file diff --git a/zero.Backoffice/Modules/Languages/LanguagesController.cs b/zero.Backoffice/Modules/Languages/LanguagesController.cs index 386a4c41..c6558ac1 100644 --- a/zero.Backoffice/Modules/Languages/LanguagesController.cs +++ b/zero.Backoffice/Modules/Languages/LanguagesController.cs @@ -31,7 +31,7 @@ namespace zero.Web.Controllers } - public override async Task> GetByQuery([FromQuery] ListBackofficeQuery query) + public override async Task> GetByQuery([FromQuery] ListQuery query) { query.OrderQuery = q => q.OrderByDescending(x => x.CreatedDate); return await Collection.Load(query); diff --git a/zero.Backoffice/Modules/Mails/MailTemplatesController.cs b/zero.Backoffice/Modules/Mails/MailTemplatesController.cs index b3b63d2f..88aea2a7 100644 --- a/zero.Backoffice/Modules/Mails/MailTemplatesController.cs +++ b/zero.Backoffice/Modules/Mails/MailTemplatesController.cs @@ -15,7 +15,7 @@ namespace zero.Web.Controllers PreviewTransform = (item, model) => model.Icon = "fth-mail"; } - public override async Task> GetByQuery([FromQuery] ListBackofficeQuery query) + public override async Task> GetByQuery([FromQuery] ListQuery query) { query.SearchFor(entity => entity.Name, entity => entity.Key, entity => entity.Subject); return await Collection.Load(query); diff --git a/zero.Backoffice/Modules/Media/MediaController.cs b/zero.Backoffice/Modules/Media/MediaController.cs index f70f198e..bbc43881 100644 --- a/zero.Backoffice/Modules/Media/MediaController.cs +++ b/zero.Backoffice/Modules/Media/MediaController.cs @@ -35,13 +35,13 @@ namespace zero.Web.Controllers [HttpPost] - public async Task> Upload(IFormFile file, [FromForm] string folderId) => await Collection.Save(await Collection.Upload(file, folderId)); + public async Task> Upload(IFormFile file, [FromForm] string folderId) => await Collection.Save(await Collection.Upload(file, folderId)); [HttpPost] public async Task UploadTemporary(IFormFile file, [FromForm] string folderId) => await Collection.Upload(file, folderId); [HttpPost] - public async Task> Move([FromBody] ActionCopyModel model) => await Collection.Move(model.Id, model.DestinationId); + public async Task> Move([FromBody] ActionCopyModel model) => await Collection.Move(model.Id, model.DestinationId); public async Task GetAll([FromQuery] MediaListQuery query) diff --git a/zero.Backoffice/Modules/Media/MediaFolderController.cs b/zero.Backoffice/Modules/Media/MediaFolderController.cs index 4590f9f4..94013fb6 100644 --- a/zero.Backoffice/Modules/Media/MediaFolderController.cs +++ b/zero.Backoffice/Modules/Media/MediaFolderController.cs @@ -21,6 +21,6 @@ namespace zero.Web.Controllers [HttpPost] - public async Task> Move([FromBody] ActionCopyModel model) => await Collection.Move(model.Id, model.DestinationId); + public async Task> Move([FromBody] ActionCopyModel model) => await Collection.Move(model.Id, model.DestinationId); } } diff --git a/zero.Backoffice/Modules/Pages/PagesController.cs b/zero.Backoffice/Modules/Pages/PagesController.cs index 31c2b91a..5a7a0d33 100644 --- a/zero.Backoffice/Modules/Pages/PagesController.cs +++ b/zero.Backoffice/Modules/Pages/PagesController.cs @@ -34,7 +34,7 @@ public class PagesController : ZeroBackofficeApiController } [HttpGet] - public virtual async Task> Get(ListBackofficeQuery query) + public virtual async Task> Get(ListQuery query) { return await Store.Load(query.Page, query.PageSize, q => q.OrderByDescending(x => x.CreatedDate)); } @@ -47,19 +47,19 @@ public class PagesController : ZeroBackofficeApiController [HttpPost] - public virtual async Task> Create(Country model) + public virtual async Task> Create(Country model) { return await Store.Create(model); } [HttpPut("{id}")] - public virtual async Task> Update(string id, Country model) + public virtual async Task> Update(string id, Country model) { return await Store.Update(model); } [HttpDelete("{id}")] - public virtual async Task> Delete(string id) + public virtual async Task> Delete(string id) { return await Store.Delete(id); } diff --git a/zero.Backoffice/Modules/Pages/ServiceCollectionExtensions.cs b/zero.Backoffice/Modules/Pages/ServiceCollectionExtensions.cs deleted file mode 100644 index 2df74e2b..00000000 --- a/zero.Backoffice/Modules/Pages/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace zero.Backoffice.Modules; - -public static class ServiceCollectionExtensions -{ - public static IServiceCollection AddZeroBackofficePages(this IServiceCollection services) - { - services.AddScoped(); - return services; - } -} \ No newline at end of file diff --git a/zero.Backoffice/Modules/Pages/_PagesController.cs b/zero.Backoffice/Modules/Pages/_PagesController.cs index 78a6ee79..567878ea 100644 --- a/zero.Backoffice/Modules/Pages/_PagesController.cs +++ b/zero.Backoffice/Modules/Pages/_PagesController.cs @@ -83,22 +83,22 @@ namespace zero.Web.Controllers [HttpPost] - public async Task>> SaveSorting([FromBody] string[] ids) => await Collection.SaveSorting(ids); + public async Task>> SaveSorting([FromBody] string[] ids) => await Collection.SaveSorting(ids); [HttpPost] - public async Task> Move([FromBody] ActionCopyModel model) => await Collection.Move(model.Id, model.DestinationId); + public async Task> Move([FromBody] ActionCopyModel model) => await Collection.Move(model.Id, model.DestinationId); [HttpPost] - public async Task> Copy([FromBody] ActionCopyModel model) => await Collection.Copy(model.Id, model.DestinationId, model.IncludeDescendants); + public async Task> Copy([FromBody] ActionCopyModel model) => await Collection.Copy(model.Id, model.DestinationId, model.IncludeDescendants); [HttpPost] - public async Task> Restore([FromBody] ActionCopyModel model) => await Collection.Restore(model.Id, model.IncludeDescendants); + public async Task> Restore([FromBody] ActionCopyModel model) => await Collection.Restore(model.Id, model.IncludeDescendants); [HttpDelete] - public async Task> DeleteRecursive([FromQuery] string id) => await Collection.Delete(id, recursive: true, moveToRecycleBin: true); + public async Task> DeleteRecursive([FromQuery] string id) => await Collection.Delete(id, recursive: true, moveToRecycleBin: true); } } diff --git a/zero.Backoffice/Modules/Previews/PreviewController.cs b/zero.Backoffice/Modules/Previews/PreviewController.cs index e1f25d1b..1811c983 100644 --- a/zero.Backoffice/Modules/Previews/PreviewController.cs +++ b/zero.Backoffice/Modules/Previews/PreviewController.cs @@ -19,17 +19,17 @@ namespace zero.Web.Controllers public async Task> GetById([FromQuery] string id) => Edit(await Api.GetById(id)); - public async Task> Add([FromBody] ZeroEntity model) + public async Task> Add([FromBody] ZeroEntity model) { - EntityResult preview = await Api.Add(model); - return EntityResult.From(preview, preview.Model?.Id); + Result preview = await Api.Add(model); + return Result.From(preview, preview.Model?.Id); } - public async Task> Update([FromQuery] string id, [FromBody] ZeroEntity model) + public async Task> Update([FromQuery] string id, [FromBody] ZeroEntity model) { - EntityResult preview = await Api.Update(id, model); - return EntityResult.From(preview, id); + Result preview = await Api.Update(id, model); + return Result.From(preview, id); } } } diff --git a/zero.Backoffice/Modules/RecycleBin/RecycleBinController.cs b/zero.Backoffice/Modules/RecycleBin/RecycleBinController.cs index a853becb..294666af 100644 --- a/zero.Backoffice/Modules/RecycleBin/RecycleBinController.cs +++ b/zero.Backoffice/Modules/RecycleBin/RecycleBinController.cs @@ -26,11 +26,11 @@ namespace zero.Web.Controllers [HttpDelete] - public async Task> Delete([FromQuery] string id) => await Api.Delete(id); + public async Task> Delete([FromQuery] string id) => await Api.Delete(id); [HttpDelete] - public async Task> DeleteByGroup([FromQuery] string group) => await Api.DeleteByGroup(group); + public async Task> DeleteByGroup([FromQuery] string group) => await Api.DeleteByGroup(group); } } diff --git a/zero.Backoffice/Modules/Security/AuthenticationController.cs b/zero.Backoffice/Modules/Security/AuthenticationController.cs index 702519c8..dc3221b6 100644 --- a/zero.Backoffice/Modules/Security/AuthenticationController.cs +++ b/zero.Backoffice/Modules/Security/AuthenticationController.cs @@ -22,25 +22,25 @@ namespace zero.Web.Controllers public async Task> GetUser() => Edit(await Api.GetUser()); - public EntityResult IsLoggedIn() => EntityResult.Maybe(Api.IsLoggedIn()); + public Result IsLoggedIn() => Result.Maybe(Api.IsLoggedIn()); [HttpPost] - public async Task LoginUser([FromBody] LoginModel model) => await Api.Login(model.Email, model.Password, model.IsPersistent); + public async Task LoginUser([FromBody] LoginModel model) => await Api.Login(model.Email, model.Password, model.IsPersistent); [HttpPost, ZeroAuthorize] - public async Task LogoutUser() + public async Task LogoutUser() { await Api.Logout(); - return EntityResult.Success(); + return Result.Success(); } [HttpPost, ZeroAuthorize] - public async Task SwitchApp(string appId) + public async Task SwitchApp(string appId) { - return EntityResult.Maybe(await Api.TrySwitchApp(appId)); + return Result.Maybe(await Api.TrySwitchApp(appId)); } } } diff --git a/zero.Backoffice/Modules/ServiceCollectionExtensions.cs b/zero.Backoffice/Modules/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..fa25d92e --- /dev/null +++ b/zero.Backoffice/Modules/ServiceCollectionExtensions.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using zero.Backoffice.Modules.Countries; + +namespace zero.Backoffice.Modules; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddZeroBackofficeModules(this IServiceCollection services, IConfiguration config) + { + services.AddScoped(); + + services.Configure(opts => + { + opts.Indexes.Add(); + }); + + return services; + } +} \ No newline at end of file diff --git a/zero.Backoffice/Modules/Spaces/SpacesController.cs b/zero.Backoffice/Modules/Spaces/SpacesController.cs index 7cd0005f..ad97d9d0 100644 --- a/zero.Backoffice/Modules/Spaces/SpacesController.cs +++ b/zero.Backoffice/Modules/Spaces/SpacesController.cs @@ -35,7 +35,7 @@ namespace zero.Web.Controllers public List GetAll() => Api.GetAll().Where(space => CanReadSpace(space.Alias)).ToList(); - public async Task GetList([FromQuery] string alias, [FromQuery] ListBackofficeQuery query = null) + public async Task GetList([FromQuery] string alias, [FromQuery] ListQuery query = null) { if (!CanReadSpace(alias)) { diff --git a/zero.Backoffice/Modules/Translations/TranslationsController.cs b/zero.Backoffice/Modules/Translations/TranslationsController.cs index e3a0fe69..234e7e3b 100644 --- a/zero.Backoffice/Modules/Translations/TranslationsController.cs +++ b/zero.Backoffice/Modules/Translations/TranslationsController.cs @@ -14,7 +14,7 @@ namespace zero.Web.Controllers { public TranslationsController(ITranslationsStore collection) : base(collection) { } - public override async Task> GetByQuery([FromQuery] ListBackofficeQuery query) + public override async Task> GetByQuery([FromQuery] ListQuery query) { query.SearchFor(entity => entity.Key, entity => entity.Value); query.OrderQuery = q => q.OrderByDescending(x => x.CreatedDate); diff --git a/zero.Backoffice/Modules/Users/UserRolesController.cs b/zero.Backoffice/Modules/Users/UserRolesController.cs index 429e9128..74c7e3f4 100644 --- a/zero.Backoffice/Modules/Users/UserRolesController.cs +++ b/zero.Backoffice/Modules/Users/UserRolesController.cs @@ -32,10 +32,10 @@ namespace zero.Web.Controllers [ZeroAuthorize(Permissions.Settings.Users, PermissionsValue.Update)] - public async Task> Save([FromBody] ZeroUserRole model) => await Api.Save(model); + public async Task> Save([FromBody] ZeroUserRole model) => await Api.Save(model); [ZeroAuthorize(Permissions.Settings.Users, PermissionsValue.Update)] - public async Task> Delete([FromQuery] string id) => await Api.Delete(id); + public async Task> Delete([FromQuery] string id) => await Api.Delete(id); } } diff --git a/zero.Backoffice/Modules/Users/UsersController.cs b/zero.Backoffice/Modules/Users/UsersController.cs index 3a68c8a3..e74a1a01 100644 --- a/zero.Backoffice/Modules/Users/UsersController.cs +++ b/zero.Backoffice/Modules/Users/UsersController.cs @@ -29,7 +29,7 @@ namespace zero.Web.Controllers public async Task> GetById([FromQuery] string id) => Edit(await Api.GetUserById(id)); - public async Task> GetAll([FromQuery] ListBackofficeQuery query) => await Api.GetByQuery(query); + public async Task> GetAll([FromQuery] ListQuery query) => await Api.GetByQuery(query); public IList GetAllPermissions() => PermissionsApi.GetAll(); @@ -55,13 +55,13 @@ namespace zero.Web.Controllers [ZeroAuthorize] - public async Task> UpdatePassword([FromBody] UserPasswordEditModel model) + public async Task> UpdatePassword([FromBody] UserPasswordEditModel model) { - EntityResult result; + Result result; if (model.NewPassword != model.ConfirmNewPassword) { - result = EntityResult.Fail(nameof(model.NewPassword), "@errors.changepassword.newpasswordsnotmatching"); + result = Result.Fail(nameof(model.NewPassword), "@errors.changepassword.newpasswordsnotmatching"); } else { @@ -79,7 +79,7 @@ namespace zero.Web.Controllers [ZeroAuthorize] - public async Task> HashPassword([FromBody] UserPasswordEditModel model) + public async Task> HashPassword([FromBody] UserPasswordEditModel model) { ZeroUser user = await Api.GetUserById(model.UserId); return await Api.HashPassword(user, model.CurrentPassword, model.NewPassword, model.ConfirmNewPassword); @@ -87,7 +87,7 @@ namespace zero.Web.Controllers [ZeroAuthorize(Permissions.Settings.Users, PermissionsValue.Update)] - public async Task> Disable([FromBody] ZeroUser model) + public async Task> Disable([FromBody] ZeroUser model) { ZeroUser entity = await Api.GetUserById(model.Id); return await Api.Disable(entity); @@ -95,7 +95,7 @@ namespace zero.Web.Controllers [ZeroAuthorize(Permissions.Settings.Users, PermissionsValue.Update)] - public async Task> Enable([FromBody] ZeroUser model) + public async Task> Enable([FromBody] ZeroUser model) { ZeroUser entity = await Api.GetUserById(model.Id); return await Api.Enable(entity); @@ -103,15 +103,15 @@ namespace zero.Web.Controllers [ZeroAuthorize(Permissions.Settings.Users, PermissionsValue.Update)] - public async Task> Save([FromBody] ZeroUser model) => await Api.Save(model); + public async Task> Save([FromBody] ZeroUser model) => await Api.Save(model); [ZeroAuthorize(Permissions.Settings.Users, PermissionsValue.Update)] // TODO do not need settings.users authorization for editing current user profiles - public async Task> SaveCurrent([FromBody] ZeroUser model) => await Api.Save(model); + public async Task> SaveCurrent([FromBody] ZeroUser model) => await Api.Save(model); [ZeroAuthorize(Permissions.Settings.Users, PermissionsValue.Update)] - public async Task> Delete([FromQuery] string id) => await Api.Delete(id); + public async Task> Delete([FromQuery] string id) => await Api.Delete(id); } } diff --git a/zero.Backoffice/Plugin.cs b/zero.Backoffice/Plugin.cs index f36d9053..3adec97f 100644 --- a/zero.Backoffice/Plugin.cs +++ b/zero.Backoffice/Plugin.cs @@ -27,6 +27,12 @@ public class ZeroBackofficePlugin : ZeroPlugin services.AddHostedService(); services.AddTransient(); + //Mvc.AddNewtonsoftJson(x => + //{ + // // TODO this shall only be configurated for backoffice controllers + // BackofficeJsonSerlializerSettings.Setup(x.SerializerSettings); + //}); + services.AddZeroBackofficeUIComposition(); //services.AddTransient(); diff --git a/zero.Backoffice/Registrations.cs b/zero.Backoffice/Registrations.cs deleted file mode 100644 index b03565f0..00000000 --- a/zero.Backoffice/Registrations.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace zero.Backoffice; - -internal class Registrations -{ - public static List Modules { get; } = new() - { - new CountriesModule(), - new SearchModule() - }; -} \ No newline at end of file diff --git a/zero.Backoffice/Usings.cs b/zero.Backoffice/Usings.cs index c355b1b8..9c2c0cc3 100644 --- a/zero.Backoffice/Usings.cs +++ b/zero.Backoffice/Usings.cs @@ -14,15 +14,16 @@ global using zero.Extensions; global using zero.Identity; global using zero.Localization; global using zero.Media; +global using zero.Models; global using zero.Pages; global using zero.Persistence; global using zero.Routing; global using zero.Utils; -global using zero.Models; global using zero.Backoffice.Configuration; global using zero.Backoffice.Controllers; global using zero.Backoffice.Models; global using zero.Backoffice.Modules; global using zero.Backoffice.UIComposition; -global using zero.Backoffice.DevServer; \ No newline at end of file +global using zero.Backoffice.DevServer; +global using zero.Backoffice.Mapper; \ No newline at end of file diff --git a/zero.Backoffice/zero.Backoffice.csproj b/zero.Backoffice/zero.Backoffice.csproj index 085120f1..1dfbad92 100644 --- a/zero.Backoffice/zero.Backoffice.csproj +++ b/zero.Backoffice/zero.Backoffice.csproj @@ -12,6 +12,10 @@ + + + + diff --git a/zero.Core/Architecture/Blueprints/BlueprintChildInterceptor.cs b/zero.Core/Architecture/Blueprints/BlueprintChildInterceptor.cs index 8fe58e46..9f4e2990 100644 --- a/zero.Core/Architecture/Blueprints/BlueprintChildInterceptor.cs +++ b/zero.Core/Architecture/Blueprints/BlueprintChildInterceptor.cs @@ -26,7 +26,7 @@ public class BlueprintChildInterceptor : Interceptor, IBlueprintInte } InterceptorResult result = new(); - result.Result = EntityResult.Fail("@blueprint.errors.cannotDeleteChild"); + result.Result = Result.Fail("@blueprint.errors.cannotDeleteChild"); return Task.FromResult(result); } } \ No newline at end of file diff --git a/zero.Core/Communication/Interceptors/Interceptor.cs b/zero.Core/Communication/Interceptors/Interceptor.cs index 48689418..635c99cd 100644 --- a/zero.Core/Communication/Interceptors/Interceptor.cs +++ b/zero.Core/Communication/Interceptors/Interceptor.cs @@ -66,7 +66,7 @@ public abstract partial class Interceptor : Interceptor, IInterceptor wher { Continue = result.Continue, InterceptorHash = result.InterceptorHash, - Result = result.Result != null ? EntityResult.From(result.Result, result.Result.Model) : null + Result = result.Result != null ? Result.From(result.Result, result.Result.Model) : null }; } } diff --git a/zero.Core/Communication/Interceptors/InterceptorInstruction.cs b/zero.Core/Communication/Interceptors/InterceptorInstruction.cs index ed3feac2..399f74d8 100644 --- a/zero.Core/Communication/Interceptors/InterceptorInstruction.cs +++ b/zero.Core/Communication/Interceptors/InterceptorInstruction.cs @@ -12,7 +12,7 @@ public class InterceptorInstruction where T : ZeroIdEntity, new() public Type ModelType { get; private set; } - public EntityResult Result { get; private set; } + public Result Result { get; private set; } protected IZeroContext Context { get; private set; } @@ -78,7 +78,7 @@ public class InterceptorInstruction where T : ZeroIdEntity, new() // we cancel all further interceptors if a result is available and return this instead if (result.Result != null) { - Result = EntityResult.From(result.Result, result.Result.Model as T); + Result = Result.From(result.Result, result.Result.Model as T); return false; } diff --git a/zero.Core/Communication/Interceptors/InterceptorResult.cs b/zero.Core/Communication/Interceptors/InterceptorResult.cs index 99a2b7b2..735ae3ba 100644 --- a/zero.Core/Communication/Interceptors/InterceptorResult.cs +++ b/zero.Core/Communication/Interceptors/InterceptorResult.cs @@ -15,5 +15,5 @@ public class InterceptorResult /// /// Set a result. This will prevent further execution of the operation and cancels all subsequent interceptors /// - public EntityResult Result { get; set; } + public Result Result { get; set; } } \ No newline at end of file diff --git a/zero.Core/Extensions/EnumerableExtensions.cs b/zero.Core/Extensions/EnumerableExtensions.cs index b527f53d..9dfd9d9f 100644 --- a/zero.Core/Extensions/EnumerableExtensions.cs +++ b/zero.Core/Extensions/EnumerableExtensions.cs @@ -2,54 +2,6 @@ public static class EnumerableExtensions { - /// - /// - /// - public static Paged ToQueriedList(this IEnumerable items, ListQuery query) where T : ZeroEntity - { - //queryable = queryable.Statistics(out QueryStatistics stats); - - if (query != null) - { - if (!query.IncludeInactive) - { - items = items.Where(x => x.IsActive); - } - - if (!query.Search.IsNullOrEmpty()) - { - items = items.Where(x => x.Name.Contains(query.Search, StringComparison.InvariantCultureIgnoreCase)); - } - //if (!query.Search.IsNullOrEmpty() && query.SearchSelector != null) - //{ - // items = items.SearchIf(query.SearchSelector, query.Search, "*", "*", Raven.Client.Documents.Queries.SearchOperator.And); - //} - //if (!query.Search.IsNullOrEmpty() && query.SearchSelectors.Length > 0) - //{ - // foreach (var selector in query.SearchSelectors) - // { - // items = items.SearchIf(selector, query.Search, "*", "*", Raven.Client.Documents.Queries.SearchOperator.And); - // } - //} - - //if (!query.OrderBy.IsNullOrEmpty()) - //{ - // items = items.OrderBy(query.OrderBy, query.OrderIsDescending); - //} - - if (query.PageSize > 0) - { - items = items.Paging(query.Page, query.PageSize); - } - } - - List result = items.ToList(); - - return new Paged(result, result.Count, query.Page, query.PageSize); - } - - - public static IEnumerable Paging(this IEnumerable source, int pageNumber, int pageSize) { pageNumber = pageNumber.Limit(1, 10_000_000); diff --git a/zero.Core/Extensions/ResultExtensions.cs b/zero.Core/Extensions/ResultExtensions.cs new file mode 100644 index 00000000..d726b0ab --- /dev/null +++ b/zero.Core/Extensions/ResultExtensions.cs @@ -0,0 +1,48 @@ +namespace zero.Extensions; + +public static class ResultExtensions +{ + public static Result WithoutModel(this Result origin) + { + Result result = new(); + result.IsSuccess = origin.IsSuccess; + result.Errors = origin.Errors; + return result; + } + + public static Result ConvertTo(this Result origin, TTarget model) + { + Result result = new(); + result.IsSuccess = origin.IsSuccess; + result.Errors = origin.Errors; + result.Model = model; + return result; + } + + + public static Result AddError(this Result origin, string property, string message) + { + origin.IsSuccess = false; + origin.Errors.Add(new(property, message)); + return origin; + } + + + public static Result AddError(this Result origin, string message) + { + origin.IsSuccess = false; + origin.Errors.Add(new(Constants.ErrorFieldNone, message)); + return origin; + } + + + public static Result AppendErrors(this Result origin, Result with) + { + foreach (ResultError error in with.Errors) + { + origin.Errors.Add(error); + } + origin.IsSuccess = origin.Errors.Any(); + return origin; + } +} \ No newline at end of file diff --git a/zero.Core/Identity/Services/AuthenticationService.cs b/zero.Core/Identity/Services/AuthenticationService.cs index 163b40f1..ae2c34ff 100644 --- a/zero.Core/Identity/Services/AuthenticationService.cs +++ b/zero.Core/Identity/Services/AuthenticationService.cs @@ -54,9 +54,9 @@ public class AuthenticationService : IAuthenticationService /// - public async Task Login(string email, string password, bool isPersistent) + public async Task Login(string email, string password, bool isPersistent) { - EntityResult result = new(); + Result result = new(); ZeroUser user = await SignInManager.UserManager.FindByNameAsync(email); @@ -97,7 +97,7 @@ public class AuthenticationService : IAuthenticationService return result; } - return EntityResult.Success(); + return Result.Success(); } @@ -141,7 +141,7 @@ public interface IAuthenticationService /// /// Logs a zero-user in and sets cookie /// - Task Login(string email, string password, bool isPersistent); + Task Login(string email, string password, bool isPersistent); /// /// Logs out the current user diff --git a/zero.Core/Identity/Services/UserRolesService.cs b/zero.Core/Identity/Services/UserRolesService.cs index 42349372..8d2454e7 100644 --- a/zero.Core/Identity/Services/UserRolesService.cs +++ b/zero.Core/Identity/Services/UserRolesService.cs @@ -45,7 +45,7 @@ public class UserRolesService : IUserRolesService /// - public async Task> Save(ZeroUserRole model) + public async Task> Save(ZeroUserRole model) { //ValidationResult validation = await new UserRoleValidator().ValidateAsync(model); @@ -72,25 +72,25 @@ public class UserRolesService : IUserRolesService model.Id = id; } - return EntityResult.Success(model); + return Result.Success(model); } /// - public async Task> Delete(string id) + public async Task> Delete(string id) { ZeroUserRole country = await Session.LoadAsync(id); if (country == null) { - return EntityResult.Fail("@errors.ondelete.idnotfound"); + return Result.Fail("@errors.ondelete.idnotfound"); } Session.Delete(country); await Session.SaveChangesAsync(); - return EntityResult.Success(); + return Result.Success(); } } @@ -110,10 +110,10 @@ public interface IUserRolesService /// /// Create or update a role /// - Task> Save(ZeroUserRole model); + Task> Save(ZeroUserRole model); /// /// Deletes a role /// - Task> Delete(string id); + Task> Delete(string id); } \ No newline at end of file diff --git a/zero.Core/Identity/Services/UserService.cs b/zero.Core/Identity/Services/UserService.cs index aef60371..8f46dbd0 100644 --- a/zero.Core/Identity/Services/UserService.cs +++ b/zero.Core/Identity/Services/UserService.cs @@ -51,7 +51,7 @@ public class UserService : IUserService /// - public async Task> Save(ZeroUser model) + public async Task> Save(ZeroUser model) { bool updateSecurityStamp = false; bool isUpdate = false; @@ -63,7 +63,7 @@ public class UserService : IUserService updateSecurityStamp = origin != null && model.PasswordHash != origin.PasswordHash; } - EntityResult result = isUpdate ? await Operations.Update(model) : await Operations.Create(model); + Result result = isUpdate ? await Operations.Update(model) : await Operations.Create(model); if (updateSecurityStamp) { @@ -75,33 +75,33 @@ public class UserService : IUserService /// - public async Task> Delete(string id) + public async Task> Delete(string id) { return await Operations.Delete(id); } /// - public async Task> HashPassword(ZeroUser user, string currentPassword, string newPassword, string confirmNewPassword) + public async Task> HashPassword(ZeroUser user, string currentPassword, string newPassword, string confirmNewPassword) { if (newPassword != confirmNewPassword) { - return EntityResult.Fail(nameof(newPassword), "@errors.changepassword.newpasswordsnotmatching"); + return Result.Fail(nameof(newPassword), "@errors.changepassword.newpasswordsnotmatching"); } if (currentPassword.IsNullOrWhiteSpace() || newPassword.IsNullOrWhiteSpace()) { - return EntityResult.Fail(nameof(currentPassword), "@errors.changepassword.emptyfields"); + return Result.Fail(nameof(currentPassword), "@errors.changepassword.emptyfields"); } if (user == null) { - return EntityResult.Fail("@errors.changepassword.nouser"); + return Result.Fail("@errors.changepassword.nouser"); } if (UserManager.PasswordHasher.VerifyHashedPassword(user, user.PasswordHash, currentPassword) != PasswordVerificationResult.Success) { - return EntityResult.Fail("@errors.changepassword.passwordincorrect"); + return Result.Fail("@errors.changepassword.passwordincorrect"); } // validate new password @@ -123,7 +123,7 @@ public class UserService : IUserService if (!isValid) { - EntityResult result = EntityResult.Fail(); + Result result = Result.Fail(); foreach (IdentityError error in errors) { result.AddError(error.Description); @@ -131,28 +131,28 @@ public class UserService : IUserService return result; } - return EntityResult.Success(UserManager.PasswordHasher.HashPassword(user, newPassword)); + return Result.Success(UserManager.PasswordHasher.HashPassword(user, newPassword)); } /// - public async Task> UpdatePassword(ZeroUser user, string currentPassword, string newPassword) + public async Task> UpdatePassword(ZeroUser user, string currentPassword, string newPassword) { if (currentPassword.IsNullOrWhiteSpace() || newPassword.IsNullOrWhiteSpace()) { - return EntityResult.Fail(nameof(currentPassword), "@errors.changepassword.emptyfields"); + return Result.Fail(nameof(currentPassword), "@errors.changepassword.emptyfields"); } if (user == null) { - return EntityResult.Fail("@errors.changepassword.nouser"); + return Result.Fail("@errors.changepassword.nouser"); } IdentityResult identityResult = await UserManager.ChangePasswordAsync(user as ZeroUser, currentPassword, newPassword); if (!identityResult.Succeeded) { - EntityResult result = EntityResult.Fail(); + Result result = Result.Fail(); foreach (IdentityError error in identityResult.Errors) { @@ -162,19 +162,19 @@ public class UserService : IUserService return result; } - return EntityResult.Success(user); + return Result.Success(user); } /// - public async Task> Enable(ZeroUser user) + public async Task> Enable(ZeroUser user) { return await UpdateActiveState(user, true); } /// - public async Task> Disable(ZeroUser user) + public async Task> Disable(ZeroUser user) { return await UpdateActiveState(user, false); } @@ -184,7 +184,7 @@ public class UserService : IUserService /// Updates the active state of user. /// If IsActive=false, the user cannot login anymore /// - async Task> UpdateActiveState(ZeroUser user, bool isActive) + async Task> UpdateActiveState(ZeroUser user, bool isActive) { user.IsActive = isActive; @@ -192,7 +192,7 @@ public class UserService : IUserService if (!identityResult.Succeeded) { - EntityResult result = EntityResult.Fail(); + Result result = Result.Fail(); foreach (IdentityError error in identityResult.Errors) { @@ -204,7 +204,7 @@ public class UserService : IUserService await UserManager.UpdateSecurityStampAsync(user as ZeroUser); - return EntityResult.Success(user); + return Result.Success(user); } @@ -268,33 +268,33 @@ public interface IUserService /// /// Creates or updates a user /// - Task> Save(ZeroUser model); + Task> Save(ZeroUser model); /// /// Deletes a user /// - Task> Delete(string id); + Task> Delete(string id); /// /// Changes the password of the current user. /// User is logged out if this operation succeeds. /// - Task> UpdatePassword(ZeroUser user, string currentPassword, string newPassword); + Task> UpdatePassword(ZeroUser user, string currentPassword, string newPassword); /// /// Tries to hash a new password /// - Task> HashPassword(ZeroUser user, string currentPassword, string newPassword, string confirmNewPassword); + Task> HashPassword(ZeroUser user, string currentPassword, string newPassword, string confirmNewPassword); /// /// Enables a user /// - Task> Enable(ZeroUser user); + Task> Enable(ZeroUser user); /// /// Disables a user /// - Task> Disable(ZeroUser user); + Task> Disable(ZeroUser user); /// /// Tries to switch the currently loaded backoffice application for the current user diff --git a/zero.Core/Media/MediaCreator.cs b/zero.Core/Media/MediaCreator.cs index 18a5d63d..9f8ce909 100644 --- a/zero.Core/Media/MediaCreator.cs +++ b/zero.Core/Media/MediaCreator.cs @@ -23,7 +23,7 @@ public class MediaCreator : IMediaCreator /// - public async Task> UploadFile(Stream fileStream, string filename, string folderId = null, CancellationToken cancellationToken = default) + public async Task> UploadFile(Stream fileStream, string filename, string folderId = null, CancellationToken cancellationToken = default) { string fileExtension = Path.GetExtension(filename); string normalizedFilename = Safenames.File(filename); @@ -34,7 +34,7 @@ public class MediaCreator : IMediaCreator if (!isImage && !isDocument) { // TODO error - return EntityResult.Fail("ERROR"); + return Result.Fail("ERROR"); } Media model = await Store.Empty(); @@ -67,7 +67,7 @@ public class MediaCreator : IMediaCreator // TODO save thumbnails } - return EntityResult.Success(model); + return Result.Success(model); } @@ -162,5 +162,5 @@ public interface IMediaCreator /// Uploads a file by using the attached file system /// /// A temporary media file which can be persisted in a store - Task> UploadFile(Stream fileStream, string filename, string folderId = null, CancellationToken cancellationToken = default); + Task> UploadFile(Stream fileStream, string filename, string folderId = null, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/zero.Core/Media/MediaManagement.cs b/zero.Core/Media/MediaManagement.cs index 3402207a..23cd88ee 100644 --- a/zero.Core/Media/MediaManagement.cs +++ b/zero.Core/Media/MediaManagement.cs @@ -48,7 +48,7 @@ public class MediaManagement : IMediaManagement /// - public virtual async Task> UpdateFile(Media file) + public virtual async Task> UpdateFile(Media file) { // TODO check new file/image/media return await Store.Update(file); @@ -56,7 +56,7 @@ public class MediaManagement : IMediaManagement /// - public virtual async Task> DeleteFile(Media file) + public virtual async Task> DeleteFile(Media file) { // TODO delete in file system return await Store.Delete(file); @@ -64,7 +64,7 @@ public class MediaManagement : IMediaManagement /// - public virtual async Task> UploadFile(Stream fileStream, string filename, string folderId = null, CancellationToken cancellationToken = default) + public virtual async Task> UploadFile(Stream fileStream, string filename, string folderId = null, CancellationToken cancellationToken = default) { return await Creator.UploadFile(fileStream, filename, folderId, cancellationToken); } @@ -79,7 +79,7 @@ public class MediaManagement : IMediaManagement /// - public virtual async Task> CreateFolder(Media folder) + public virtual async Task> CreateFolder(Media folder) { folder.IsActive = true; folder.Type = MediaType.Folder; @@ -88,7 +88,7 @@ public class MediaManagement : IMediaManagement /// - public virtual async Task> CreateFolder(string name, string parentId = null) + public virtual async Task> CreateFolder(string name, string parentId = null) { Media media = await Store.Empty(); media.Name = name; @@ -98,14 +98,14 @@ public class MediaManagement : IMediaManagement /// - public virtual async Task> UpdateFolder(Media folder) + public virtual async Task> UpdateFolder(Media folder) { return await Store.Update(folder); } /// - public virtual async Task> DeleteFolder(Media folder) + public virtual async Task> DeleteFolder(Media folder) { // TODO recursive return await Store.DeleteWithDescendants(folder); @@ -130,17 +130,17 @@ public interface IMediaManagement /// /// Update and store a media file /// - Task> UpdateFile(Media file); + Task> UpdateFile(Media file); /// /// Deletes a media file (collection entry as well as physical file) /// - Task> DeleteFile(Media file); + Task> DeleteFile(Media file); /// /// Uploads a file and persists it /// - Task> UploadFile(Stream fileStream, string filename, string folderId = null, CancellationToken cancellationToken = default); + Task> UploadFile(Stream fileStream, string filename, string folderId = null, CancellationToken cancellationToken = default); /// /// Get a media folder by id @@ -150,20 +150,20 @@ public interface IMediaManagement /// /// Creates a new media folder /// - Task> CreateFolder(Media folder); + Task> CreateFolder(Media folder); /// /// Creates a new media folder /// - Task> CreateFolder(string name, string parentId = null); + Task> CreateFolder(string name, string parentId = null); /// /// Rename and store a media folder /// - Task> UpdateFolder(Media folder); + Task> UpdateFolder(Media folder); /// /// Deletes a folder, as well as all descendant folders and files /// - Task> DeleteFolder(Media folder); + Task> DeleteFolder(Media folder); } diff --git a/zero.Core/Media/MediaManagementExtensions.cs b/zero.Core/Media/MediaManagementExtensions.cs index 1b08c4df..f42bccfd 100644 --- a/zero.Core/Media/MediaManagementExtensions.cs +++ b/zero.Core/Media/MediaManagementExtensions.cs @@ -23,7 +23,7 @@ namespace zero.Media /// /// Uploads a file and persists it /// - public static async Task> UploadFile(this IMediaManagement media, IFormFile formFile, string folderId = null, CancellationToken cancellationToken = default) + public static async Task> UploadFile(this IMediaManagement media, IFormFile formFile, string folderId = null, CancellationToken cancellationToken = default) { using Stream stream = formFile.OpenReadStream(); return await media.UploadFile(stream, formFile.FileName, folderId, cancellationToken); @@ -33,7 +33,7 @@ namespace zero.Media /// /// Uploads a file and persists it /// - public static async Task> UploadFile(this IMediaManagement media, byte[] fileBytes, string filename, string folderId = null, CancellationToken cancellationToken = default) + public static async Task> UploadFile(this IMediaManagement media, byte[] fileBytes, string filename, string folderId = null, CancellationToken cancellationToken = default) { using Stream stream = new MemoryStream(fileBytes); return await media.UploadFile(stream, filename, folderId, cancellationToken); @@ -43,7 +43,7 @@ namespace zero.Media /// /// Rename and store a media folder /// - public static async Task> RenameFolder(this IMediaManagement media, Media folder, string newName) + public static async Task> RenameFolder(this IMediaManagement media, Media folder, string newName) { folder.Name = newName; return await media.UpdateFolder(folder); @@ -53,12 +53,12 @@ namespace zero.Media /// /// Rename and store a media folder /// - public static async Task> RenameFolder(this IMediaManagement media, string folderId, string newName) + public static async Task> RenameFolder(this IMediaManagement media, string folderId, string newName) { Media folder = await media.GetFolder(folderId); if (folder == null) { - return EntityResult.Fail("@errors.idnotfound"); + return Result.Fail("@errors.idnotfound"); } return await RenameFolder(media, folder, newName); @@ -68,7 +68,7 @@ namespace zero.Media /// /// Move a media folder to a new parent /// - public static async Task> MoveFolder(this IMediaManagement media, Media folder, string newParentId) + public static async Task> MoveFolder(this IMediaManagement media, Media folder, string newParentId) { folder.ParentId = newParentId; return await media.UpdateFolder(folder); @@ -78,12 +78,12 @@ namespace zero.Media /// /// Move a media folder to a new parent /// - public static async Task> MoveFolder(this IMediaManagement media, string folderId, string newParentId) + public static async Task> MoveFolder(this IMediaManagement media, string folderId, string newParentId) { Media folder = await media.GetFolder(folderId); if (folder == null) { - return EntityResult.Fail("@errors.idnotfound"); + return Result.Fail("@errors.idnotfound"); } return await MoveFolder(media, folder, newParentId); @@ -93,12 +93,12 @@ namespace zero.Media /// /// Deletes a folder by id /// - public static async Task> DeleteFolder(this IMediaManagement media, string folderId) + public static async Task> DeleteFolder(this IMediaManagement media, string folderId) { Media folder = await media.GetFolder(folderId); if (folder == null) { - return EntityResult.Fail("@errors.idnotfound"); + return Result.Fail("@errors.idnotfound"); } return await media.DeleteFolder(folder); diff --git a/zero.Core/Models/Queries/ListQuery.cs b/zero.Core/Models/Queries/ListQuery.cs deleted file mode 100644 index c2511064..00000000 --- a/zero.Core/Models/Queries/ListQuery.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Newtonsoft.Json; -using Raven.Client.Documents.Session; -using System.Linq.Expressions; - -namespace zero.Models; - -public class ListQuery -{ - public string Search { get; set; } = null; - - public Expression> SearchSelector { get; set; } = null; - - public Expression>[] SearchSelectors { get; private set; } = Array.Empty>>(); - - public string OrderBy { get; set; } = "createdDate"; - - public ListQueryOrderType OrderType { get; set; } = ListQueryOrderType.String; - - public bool OrderIsDescending { get; set; } = true; - - public Func, IQueryable> OrderQuery = null; - - public int Page { get; set; } = 1; - - public int PageSize { get; set; } = 30; - - public bool IncludeInactive { get; set; } = false; - - public QueryStatistics Statistics { get; internal set; } - - public void SearchFor(params Expression>[] selectors) - { - SearchSelectors = selectors; - } -} - - -public class ListQuery : ListQuery where TFilter : IListSpecificQuery -{ - public TFilter Filter { get; set; } -} - - -public static class ListQueryExtensions -{ - public static ListQuery AsList(this string options) where TFilter : IListSpecificQuery - { - return JsonConvert.DeserializeObject>(options); - } - - public static ListQuery AsList(this string options) where T : IListSpecificQuery - { - return JsonConvert.DeserializeObject>(options); - } -} - - -public interface IListSpecificQuery { } - -public class EmptyListSpecificQuery : IListSpecificQuery { } - - -public class ListQueryDateRange -{ - public DateTimeOffset? From { get; set; } - - public DateTimeOffset? To { get; set; } -} - -public class ListQueryRange -{ - public decimal? From { get; set; } - - public decimal? To { get; set; } -} - -public enum ListQueryOrderType -{ - String, - Number -} \ No newline at end of file diff --git a/zero.Core/Models/Results/EntityResult.cs b/zero.Core/Models/Results/EntityResult.cs deleted file mode 100644 index 9e37b7fe..00000000 --- a/zero.Core/Models/Results/EntityResult.cs +++ /dev/null @@ -1,127 +0,0 @@ -using FluentValidation.Results; -using System.Runtime.Serialization; - -namespace zero.Models; - -[DataContract(Name = "result", Namespace = "")] -public class EntityResult -{ - [DataMember(Name = "model")] - public T Model { get; set; } - - [DataMember(Name = "success")] - public bool IsSuccess { get; set; } - - [DataMember(Name = "errors")] - public IList Errors { get; set; } = new List(); - - public EntityResult() { } - - public EntityResult(ValidationResult validation) - { - IsSuccess = validation.IsValid; - Errors = validation.Errors.Select(x => new EntityResultError() - { - Property = x.PropertyName, - Message = x.ErrorMessage - }).ToList(); - } - - public static EntityResult From(EntityResult with, T model = default) - { - EntityResult result = new EntityResult(); - - result.IsSuccess = with.IsSuccess; - result.Errors = with.Errors; - result.Model = model; - - return result; - } - - public void AddError(string property, string message) - { - IsSuccess = false; - Errors.Add(new EntityResultError() - { - Property = property, - Message = message - }); - } - - - public void AddError(string message) - { - IsSuccess = false; - Errors.Add(new EntityResultError() - { - Property = Constants.ErrorFieldNone, - Message = message - }); - } - - - public EntityResult Combine(EntityResult with) - { - if (IsSuccess && !with.IsSuccess) - { - IsSuccess = false; - } - foreach (EntityResultError error in with.Errors) - { - Errors.Add(error); - } - return this; - } - - - public static EntityResult Success() => new EntityResult() { IsSuccess = true }; - - public static EntityResult Success(T model) => new EntityResult() { IsSuccess = true, Model = model }; - - public static EntityResult Fail() => new EntityResult() { }; - - public static EntityResult Fail(string property, string message) - { - EntityResult result = new EntityResult(); - result.AddError(property, message); - return result; - } - - public static EntityResult Fail(string message) - { - EntityResult result = new EntityResult(); - result.AddError(message); - return result; - } - - public static EntityResult Fail(ValidationResult validation) => new EntityResult(validation); - - public static EntityResult Fail(EntityResultError error) => Fail(error.Property, error.Message); - - public static EntityResult Fail(IEnumerable errors) => new EntityResult() { IsSuccess = !errors.Any(), Errors = errors.ToList() }; -} - - -public class EntityResult : EntityResult -{ - public EntityResult() : base() { } - - public EntityResult(ValidationResult validation) : base(validation) { } - - public static EntityResult Maybe(bool isSuccess) => isSuccess ? Success() : Fail(); - - public new static EntityResult Success() => new EntityResult() { IsSuccess = true }; - - public new static EntityResult Fail() => new EntityResult() { }; -} - - -[DataContract(Name = "resultError", Namespace = "")] -public class EntityResultError -{ - [DataMember(Name = "property")] - public string Property { get; set; } - - [DataMember(Name = "message")] - public string Message { get; set; } -} diff --git a/zero.Core/Models/Results/Result.cs b/zero.Core/Models/Results/Result.cs new file mode 100644 index 00000000..1647066d --- /dev/null +++ b/zero.Core/Models/Results/Result.cs @@ -0,0 +1,90 @@ +using FluentValidation.Results; +using System.Runtime.Serialization; + +namespace zero.Models; + + +[DataContract(Name = "result", Namespace = "")] +public class Result +{ + [DataMember(Name = "success")] + public bool IsSuccess { get; set; } + + [DataMember(Name = "errors")] + public List Errors { get; set; } = new(); + + public Result() { } + + public Result(ValidationResult validation) + { + IsSuccess = validation.IsValid; + Errors = validation.Errors.Select(x => new ResultError() + { + Property = x.PropertyName, + Message = x.ErrorMessage + }).ToList(); + } + + public static Result Maybe(bool isSuccess) => isSuccess ? Success() : Fail(); + + public static Result Success() => new() { IsSuccess = true }; + + public static Result Fail() => new() { }; +} + + +public class Result : Result +{ + [DataMember(Name = "model")] + public T Model { get; set; } + + public Result() : base() { } + + public Result(ValidationResult validation) : base(validation) { } + + + public new static Result Success() => new() { IsSuccess = true }; + + public static Result Success(T model) => new() { IsSuccess = true, Model = model }; + + public new static Result Fail() => new() { }; + + public static Result Fail(string property, string message) + { + Result result = new(); + result.Errors.Add(new(property, message)); + return result; + } + + public static Result Fail(string message) + { + Result result = new(); + result.AddError(message); + return result; + } + + public static Result Fail(ValidationResult validation) => new(validation); + + public static Result Fail(ResultError error) => Fail(error.Property, error.Message); + + public static Result Fail(IEnumerable errors) => new() { IsSuccess = !errors.Any(), Errors = errors.ToList() }; +} + + +[DataContract(Name = "resultError", Namespace = "")] +public class ResultError +{ + [DataMember(Name = "property")] + public string Property { get; set; } + + [DataMember(Name = "message")] + public string Message { get; set; } + + public ResultError() { } + + public ResultError(string property, string message) + { + Property = property; + Message = message; + } +} diff --git a/zero.Core/Persistence/RavenQueryableExtensions.cs b/zero.Core/Persistence/RavenQueryableExtensions.cs index 8ef969d0..f0ce3ed5 100644 --- a/zero.Core/Persistence/RavenQueryableExtensions.cs +++ b/zero.Core/Persistence/RavenQueryableExtensions.cs @@ -8,78 +8,6 @@ namespace zero.Persistence; public static class RavenQueryableExtensions { - /// - /// - /// - public static async Task> FilterAsync(this IRavenQueryable source, ListQuery listQuery) - { - return await source.WithFilter(listQuery).ToListResultAsync(listQuery); - } - - - /// - /// - /// - public static IQueryable WithFilter(this IRavenQueryable source, ListQuery listQuery) - { - Type collectionType = typeof(T); - Type zeroType = typeof(ZeroEntity); - bool isZeroType = zeroType.IsAssignableFrom(collectionType); - - source.Statistics(out QueryStatistics stats); - listQuery.Statistics = stats; - - IQueryable queryable = source; - - if (!listQuery.IncludeInactive && isZeroType) - { - queryable = queryable.Where(x => (x as ZeroEntity).IsActive); - } - - if (!listQuery.Search.IsNullOrEmpty() && listQuery.SearchSelectors.Length > 0) - { - foreach (var selector in listQuery.SearchSelectors) - { - queryable = queryable.SearchIf(selector, listQuery.Search, "*", "*", Raven.Client.Documents.Queries.SearchOperator.And); - } - } - else if (!listQuery.Search.IsNullOrEmpty() && listQuery.SearchSelector != null) - { - queryable = queryable.SearchIf(listQuery.SearchSelector, listQuery.Search, "*", "*", Raven.Client.Documents.Queries.SearchOperator.And); - } - - if (listQuery.OrderQuery != null) - { - queryable = listQuery.OrderQuery(queryable); - } - else if (!listQuery.OrderBy.IsNullOrEmpty()) - { - queryable = queryable.OrderBy(listQuery.OrderBy, listQuery.OrderIsDescending, listQuery.OrderType == ListQueryOrderType.String ? OrderingType.String : OrderingType.Double); - } - else if (isZeroType) - { - queryable = queryable.OrderByDescending(x => (x as ZeroEntity).CreatedDate); - } - - if (listQuery.PageSize > 0) - { - queryable = queryable.Paging(listQuery.Page, listQuery.PageSize); - } - - return queryable; - } - - - /// - /// - /// - public static async Task> ToListResultAsync(this IQueryable source, ListQuery listQuery, CancellationToken token = default) - { - List results = await source.ToListAsync(token); - return new Paged(results, listQuery.Statistics.TotalResults, listQuery.Page, listQuery.PageSize); - } - - public static IOrderedQueryable OrderBy(this IQueryable source, string path, bool isDescending, OrderingType type = OrderingType.String) { if (!String.IsNullOrEmpty(path)) diff --git a/zero.Core/Stores/EntityStore.cs b/zero.Core/Stores/EntityStore.cs index d49750e9..60d40768 100644 --- a/zero.Core/Stores/EntityStore.cs +++ b/zero.Core/Stores/EntityStore.cs @@ -54,13 +54,13 @@ public abstract class EntityStore : IEntityStore where T : ZeroIdEntity, n public virtual IAsyncEnumerable Stream(Func, IQueryable> expression) => Operations.Stream(expression); /// - public virtual Task> Create(T model) => Operations.Create(model, async m => await Validate(m)); + public virtual Task> Create(T model) => Operations.Create(model, async m => await Validate(m)); /// - public virtual Task> Update(T model) => Operations.Update(model, async m => await Validate(m)); + public virtual Task> Update(T model) => Operations.Update(model, async m => await Validate(m)); /// - public virtual Task> Delete(T model) => Operations.Delete(model); + public virtual Task> Delete(T model) => Operations.Delete(model); /// public virtual async Task Validate(T model) @@ -141,15 +141,15 @@ public interface IEntityStore where T : ZeroIdEntity, new() /// /// Creates an entity with an optional validator /// - Task> Create(T model); + Task> Create(T model); /// /// Updates an entity with an optional validator /// - Task> Update(T model); + Task> Update(T model); /// /// Deletes an entity /// - Task> Delete(T model); + Task> Delete(T model); } \ No newline at end of file diff --git a/zero.Core/Stores/EntityStoreExtensions.cs b/zero.Core/Stores/EntityStoreExtensions.cs index 5414c52d..3b46e1d3 100644 --- a/zero.Core/Stores/EntityStoreExtensions.cs +++ b/zero.Core/Stores/EntityStoreExtensions.cs @@ -13,7 +13,7 @@ public static class EntityStoreExtensions /// /// Deletes an entity by Id /// - public static async Task> Delete(this IEntityStore store, string id) where T : ZeroIdEntity, new() => await store.Delete(await store.Load(id)); + public static async Task> Delete(this IEntityStore store, string id) where T : ZeroIdEntity, new() => await store.Delete(await store.Load(id)); /// @@ -31,7 +31,7 @@ public static class EntityStoreExtensions foreach (T model in models) { - EntityResult result = await store.Delete(model); + Result result = await store.Delete(model); successCount += result.IsSuccess ? 1 : 0; } @@ -42,5 +42,5 @@ public static class EntityStoreExtensions /// /// Deletes an entity by Id with all descendents /// - public static async Task> DeleteWithDescendants(this ITreeEntityStore store, string id) where T : ZeroIdEntity, IZeroTreeEntity, new() => await store.DeleteWithDescendants(await store.Load(id)); + public static async Task> DeleteWithDescendants(this ITreeEntityStore store, string id) where T : ZeroIdEntity, IZeroTreeEntity, new() => await store.DeleteWithDescendants(await store.Load(id)); } \ No newline at end of file diff --git a/zero.Core/Stores/StoreOperations.Delete.cs b/zero.Core/Stores/StoreOperations.Delete.cs index 8482c1a9..ce047c1a 100644 --- a/zero.Core/Stores/StoreOperations.Delete.cs +++ b/zero.Core/Stores/StoreOperations.Delete.cs @@ -3,11 +3,11 @@ public abstract partial class StoreOperations { /// - public virtual async Task> Delete(T model) where T : ZeroIdEntity, new() + public virtual async Task> Delete(T model) where T : ZeroIdEntity, new() { if (model == null) { - return EntityResult.Fail("@errors.ondelete.idnotfound"); + return Result.Fail("@errors.ondelete.idnotfound"); } InterceptorInstruction instruction = Interceptors.ForDelete(model); @@ -21,6 +21,6 @@ public abstract partial class StoreOperations await instruction.Complete(); await Session.SaveChangesAsync(); - return EntityResult.Success(); + return Result.Success(); } } \ No newline at end of file diff --git a/zero.Core/Stores/StoreOperations.Tree.cs b/zero.Core/Stores/StoreOperations.Tree.cs index e5654eea..879d1a3b 100644 --- a/zero.Core/Stores/StoreOperations.Tree.cs +++ b/zero.Core/Stores/StoreOperations.Tree.cs @@ -39,7 +39,7 @@ public abstract partial class StoreOperations /// - public async Task>> Sort(string[] sortedIds) where T : ZeroIdEntity, IZeroTreeEntity, new() + public async Task>> Sort(string[] sortedIds) where T : ZeroIdEntity, IZeroTreeEntity, new() { Dictionary items = await Load(sortedIds); uint index = 0; @@ -47,7 +47,7 @@ public abstract partial class StoreOperations // contains multiple parents, therefore fail if (items.Select(x => x.Value?.ParentId).Distinct().Count() > 1) { - return EntityResult>.Fail("@errors.treeentity.sortingmultipleparents"); + return Result>.Fail("@errors.treeentity.sortingmultipleparents"); } foreach (var item in items) @@ -57,24 +57,24 @@ public abstract partial class StoreOperations await Update(item.Value); } - return EntityResult>.Success(items.Select(x => x.Value).OrderByDescending(x => x.Sort)); + return Result>.Success(items.Select(x => x.Value).OrderByDescending(x => x.Sort)); } /// - public async Task> Move(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new() + public async Task> Move(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new() { T model = await Load(id); T parent = await Load(newParentId); if (model == null || (!newParentId.IsNullOrEmpty() && parent == null)) { - return EntityResult.Fail("@errors.idnotfound"); + return Result.Fail("@errors.idnotfound"); } if (isParentAllowed != null && !await isParentAllowed(model, newParentId)) { - return EntityResult.Fail("@errors.treeentity.parentnotallowed"); + return Result.Fail("@errors.treeentity.parentnotallowed"); } model.ParentId = parent?.Id; @@ -84,24 +84,24 @@ public abstract partial class StoreOperations /// - public Task> Copy(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new() => Copy(id, newParentId, false, isParentAllowed); + public Task> Copy(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new() => Copy(id, newParentId, false, isParentAllowed); /// - public Task> CopyWithDescendants(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new() => Copy(id, newParentId, true, isParentAllowed); + public Task> CopyWithDescendants(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new() => Copy(id, newParentId, true, isParentAllowed); /// /// Copies an entity (with optional descendants) to a new location /// - protected async Task> Copy(string id, string newParentId, bool includeDescendants, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new() + protected async Task> Copy(string id, string newParentId, bool includeDescendants, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new() { T model = await Load(id); T parent = await Load(newParentId); if (model == null || (!newParentId.IsNullOrEmpty() && parent == null)) { - return EntityResult.Fail("@errors.idnotfound"); + return Result.Fail("@errors.idnotfound"); } string baseId = model.Id; @@ -119,7 +119,7 @@ public abstract partial class StoreOperations // check if new parent is allowed if (isParentAllowed != null && !await isParentAllowed(model, newParentId)) { - return EntityResult.Fail("@errors.treeentity.parentnotallowed"); + return Result.Fail("@errors.treeentity.parentnotallowed"); } // recursive function to store descendants @@ -148,22 +148,22 @@ public abstract partial class StoreOperations await AddChildren(baseId, model.Id); } - return EntityResult.Success(model); + return Result.Success(model); } /// - public async Task> DeleteWithDescendants(T model) where T : ZeroIdEntity, IZeroTreeEntity, new() + public async Task> DeleteWithDescendants(T model) where T : ZeroIdEntity, IZeroTreeEntity, new() { List pages = await GetDescendantsAndSelf(model); if (pages.Count < 1) { - return EntityResult.Fail("@errors.ondelete.idnotfound"); + return Result.Fail("@errors.ondelete.idnotfound"); } await this.Delete(pages.ToArray()); - return EntityResult.Success(pages.Select(x => x.Id).ToArray()); + return Result.Success(pages.Select(x => x.Id).ToArray()); } diff --git a/zero.Core/Stores/StoreOperations.Write.cs b/zero.Core/Stores/StoreOperations.Write.cs index 4aebd8f8..cea2c3c0 100644 --- a/zero.Core/Stores/StoreOperations.Write.cs +++ b/zero.Core/Stores/StoreOperations.Write.cs @@ -5,17 +5,17 @@ namespace zero.Stores; public abstract partial class StoreOperations { /// - public virtual Task> Create(T model, Func> validate = null) where T : ZeroIdEntity, new() => Save(model, validate); + public virtual Task> Create(T model, Func> validate = null) where T : ZeroIdEntity, new() => Save(model, validate); /// - public virtual Task> Update(T model, Func> validate = null) where T : ZeroIdEntity, new() => Save(model, validate); + public virtual Task> Update(T model, Func> validate = null) where T : ZeroIdEntity, new() => Save(model, validate); /// - protected virtual async Task> Save(T model, Func> validate = null) where T : ZeroIdEntity, new() + protected virtual async Task> Save(T model, Func> validate = null) where T : ZeroIdEntity, new() { if (model == null) { - return EntityResult.Fail("@errors.onsave.empty"); + return Result.Fail("@errors.onsave.empty"); } bool isUpdate = !model.Id.IsNullOrEmpty() && await Session.Advanced.ExistsAsync(model.Id); @@ -29,7 +29,7 @@ public abstract partial class StoreOperations ValidationResult validation = await validate(model); if (!validation.IsValid) { - return EntityResult.Fail(validation); + return Result.Fail(validation); } } @@ -52,6 +52,6 @@ public abstract partial class StoreOperations await instruction.Complete(); await Session.SaveChangesAsync(); - return EntityResult.Success(model); + return Result.Success(model); } } \ No newline at end of file diff --git a/zero.Core/Stores/StoreOperations.cs b/zero.Core/Stores/StoreOperations.cs index 1177b4f4..8277225f 100644 --- a/zero.Core/Stores/StoreOperations.cs +++ b/zero.Core/Stores/StoreOperations.cs @@ -171,17 +171,17 @@ public interface IStoreOperations /// /// Creates an entity with an optional validator /// - Task> Create(T model, Func> validate = null) where T : ZeroIdEntity, new(); + Task> Create(T model, Func> validate = null) where T : ZeroIdEntity, new(); /// /// Updates an entity with an optional validator /// - Task> Update(T model, Func> validate = null) where T : ZeroIdEntity, new(); + Task> Update(T model, Func> validate = null) where T : ZeroIdEntity, new(); /// /// Deletes an entity /// - Task> Delete(T model) where T : ZeroIdEntity, new(); + Task> Delete(T model) where T : ZeroIdEntity, new(); /// /// Loads all children for an entity @@ -196,25 +196,25 @@ public interface IStoreOperations /// /// Update sorting of entities on a specific level /// - Task>> Sort(string[] sortedIds) where T : ZeroIdEntity, IZeroTreeEntity, new(); + Task>> Sort(string[] sortedIds) where T : ZeroIdEntity, IZeroTreeEntity, new(); /// /// Move an entity to a new parent /// - Task> Move(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new(); + Task> Move(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new(); /// /// Copies an entity to a new location /// - Task> Copy(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new(); + Task> Copy(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new(); /// /// Copies an entity with descendants to a new location /// - Task> CopyWithDescendants(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new(); + Task> CopyWithDescendants(string id, string newParentId, Func> isParentAllowed = null) where T : ZeroIdEntity, IZeroTreeEntity, new(); /// /// Deletes an entity with all descendents /// - Task> DeleteWithDescendants(T model) where T : ZeroIdEntity, IZeroTreeEntity, new(); + Task> DeleteWithDescendants(T model) where T : ZeroIdEntity, IZeroTreeEntity, new(); } \ No newline at end of file diff --git a/zero.Core/Stores/StoreOperationsExtensions.cs b/zero.Core/Stores/StoreOperationsExtensions.cs index 7b761c33..7e883617 100644 --- a/zero.Core/Stores/StoreOperationsExtensions.cs +++ b/zero.Core/Stores/StoreOperationsExtensions.cs @@ -13,7 +13,7 @@ public static class StoreOperationsExtensions /// /// Deletes an entity by Id /// - public static async Task> Delete(this IStoreOperations ops, string id) where T : ZeroIdEntity, new() => await ops.Delete(await ops.Load(id)); + public static async Task> Delete(this IStoreOperations ops, string id) where T : ZeroIdEntity, new() => await ops.Delete(await ops.Load(id)); /// @@ -31,7 +31,7 @@ public static class StoreOperationsExtensions foreach (T model in models) { - EntityResult result = await ops.Delete(model); + Result result = await ops.Delete(model); successCount += result.IsSuccess ? 1 : 0; } @@ -41,5 +41,5 @@ public static class StoreOperationsExtensions /// /// Deletes an entity by Id with all descendents /// - public static async Task> DeleteWithDescendants(this IStoreOperations ops, string id) where T : ZeroIdEntity, IZeroTreeEntity, new() => await ops.DeleteWithDescendants(await ops.Load(id)); + public static async Task> DeleteWithDescendants(this IStoreOperations ops, string id) where T : ZeroIdEntity, IZeroTreeEntity, new() => await ops.DeleteWithDescendants(await ops.Load(id)); } \ No newline at end of file diff --git a/zero.Core/Stores/TreeEntityStore.cs b/zero.Core/Stores/TreeEntityStore.cs index 33139cb6..cc68ef1b 100644 --- a/zero.Core/Stores/TreeEntityStore.cs +++ b/zero.Core/Stores/TreeEntityStore.cs @@ -9,21 +9,21 @@ public abstract class TreeEntityStore : EntityStore, ITreeEntityStore w /// - public override async Task> Create(T model) + public override async Task> Create(T model) { if (!await IsAllowedAsChild(model, model.ParentId)) { - return EntityResult.Fail("@errors.treeentity.parentnotallowed"); + return Result.Fail("@errors.treeentity.parentnotallowed"); } return await base.Create(model); } /// - public override async Task> Update(T model) + public override async Task> Update(T model) { if (!await IsAllowedAsChild(model, model.ParentId)) { - return EntityResult.Fail("@errors.treeentity.parentnotallowed"); + return Result.Fail("@errors.treeentity.parentnotallowed"); } return await base.Update(model); } @@ -32,22 +32,22 @@ public abstract class TreeEntityStore : EntityStore, ITreeEntityStore w public virtual Task IsAllowedAsChild(T model, string parentId) => Task.FromResult(true); /// - public virtual Task> Copy(string id, string newParentId) => Operations.Copy(id, newParentId, async (model, parentId) => await IsAllowedAsChild(model, parentId)); + public virtual Task> Copy(string id, string newParentId) => Operations.Copy(id, newParentId, async (model, parentId) => await IsAllowedAsChild(model, parentId)); /// - public virtual Task> CopyWithDescendants(string id, string newParentId) => Operations.CopyWithDescendants(id, newParentId, async (model, parentId) => await IsAllowedAsChild(model, parentId)); + public virtual Task> CopyWithDescendants(string id, string newParentId) => Operations.CopyWithDescendants(id, newParentId, async (model, parentId) => await IsAllowedAsChild(model, parentId)); /// - public virtual Task> Move(string id, string newParentId) => Operations.Move(id, newParentId, async (model, parentId) => await IsAllowedAsChild(model, parentId)); + public virtual Task> Move(string id, string newParentId) => Operations.Move(id, newParentId, async (model, parentId) => await IsAllowedAsChild(model, parentId)); /// - public virtual Task>> Sort(string[] sortedIds) => Operations.Sort(sortedIds); + public virtual Task>> Sort(string[] sortedIds) => Operations.Sort(sortedIds); /// - public virtual Task> DeleteWithDescendants(T model) => Operations.DeleteWithDescendants(model); + public virtual Task> DeleteWithDescendants(T model) => Operations.DeleteWithDescendants(model); /// - public virtual Task> DeleteWithDescendants(string id) => Operations.DeleteWithDescendants(id); + public virtual Task> DeleteWithDescendants(string id) => Operations.DeleteWithDescendants(id); /// public virtual Task> LoadChildren(string parentId, int pageNumber, int pageSize, Func, IQueryable> querySelector = null) @@ -81,30 +81,30 @@ public interface ITreeEntityStore : IEntityStore where T : ZeroIdEntity, I /// /// Update sorting of entities on a specific level /// - Task>> Sort(string[] sortedIds); + Task>> Sort(string[] sortedIds); /// /// Move an entity to a new parent /// - Task> Move(string id, string newParentId); + Task> Move(string id, string newParentId); /// /// Copies an entity to a new location /// - Task> Copy(string id, string newParentId); + Task> Copy(string id, string newParentId); /// /// Copies an entity with descendants to a new location /// - Task> CopyWithDescendants(string id, string newParentId); + Task> CopyWithDescendants(string id, string newParentId); /// /// Deletes an entity with all descendents /// - Task> DeleteWithDescendants(T model); + Task> DeleteWithDescendants(T model); /// /// Deletes an entity by Id with all descendents /// - Task> DeleteWithDescendants(string id); + Task> DeleteWithDescendants(string id); } \ No newline at end of file diff --git a/zero.Core/ZeroBuilder.cs b/zero.Core/ZeroBuilder.cs index 748538da..bb32b1d6 100644 --- a/zero.Core/ZeroBuilder.cs +++ b/zero.Core/ZeroBuilder.cs @@ -49,12 +49,6 @@ public class ZeroBuilder services.AddZeroRouting(Configuration); services.AddZeroStores(); - //Mvc.AddNewtonsoftJson(x => - //{ - // // TODO this shall only be configurated for backoffice controllers - // BackofficeJsonSerlializerSettings.Setup(x.SerializerSettings); - //}); - //if (Environment.GetEnvironmentVariable("DOTNET_WATCH") == "1") //{ // Mvc.AddRazorRuntimeCompilation(); diff --git a/zero.Core/zero.Core.csproj b/zero.Core/zero.Core.csproj index dac059fc..77ae83ea 100644 --- a/zero.Core/zero.Core.csproj +++ b/zero.Core/zero.Core.csproj @@ -23,7 +23,7 @@ - +