diff --git a/zero.Api/Endpoints/Users/Indexes/zero_Api_Countries_Listing.cs b/zero.Api/Endpoints/Users/Indexes/zero_Api_Countries_Listing.cs new file mode 100644 index 00000000..c62900dc --- /dev/null +++ b/zero.Api/Endpoints/Users/Indexes/zero_Api_Countries_Listing.cs @@ -0,0 +1,17 @@ +using Raven.Client.Documents.Indexes; + +namespace zero.Api.Endpoints.Users; + +public class zero_Api_Users_Listing : ZeroIndex +{ + protected override void Create() + { + Map = items => items.Select(item => new + { + Name = item.Name, + CreatedDate = item.CreatedDate + }); + + Index(x => x.Name, FieldIndexing.Search); + } +} \ No newline at end of file diff --git a/zero.Api/Endpoints/Users/Maps/UserBasic.cs b/zero.Api/Endpoints/Users/Maps/UserBasic.cs new file mode 100644 index 00000000..7d8b330a --- /dev/null +++ b/zero.Api/Endpoints/Users/Maps/UserBasic.cs @@ -0,0 +1,12 @@ +namespace zero.Api.Endpoints.Users; + +public class UserBasic : ZeroIdEntity +{ + public string Name { get; set; } + + public bool IsActive { get; set; } + + public string Email { get; set; } + + public string AvatarId { get; set; } +} \ No newline at end of file diff --git a/zero.Api/Endpoints/Users/Maps/UserMapperProfile.cs b/zero.Api/Endpoints/Users/Maps/UserMapperProfile.cs new file mode 100644 index 00000000..74550423 --- /dev/null +++ b/zero.Api/Endpoints/Users/Maps/UserMapperProfile.cs @@ -0,0 +1,19 @@ +namespace zero.Api.Endpoints.Users; + +public class UserMapperProfile : ZeroMapperProfile +{ + public override void Configure(IZeroMapper mapper) + { + mapper.Define((source, ctx) => new(), Map); + } + + + protected virtual void Map(ZeroUser source, UserBasic target, IZeroMapperContext ctx) + { + target.Id = source.Id; + target.Name = source.Name; + target.Email = source.Email; + target.IsActive = source.IsActive; + target.AvatarId = source.AvatarId; + } +} \ No newline at end of file diff --git a/zero.Api/Endpoints/Users/UserModule.cs b/zero.Api/Endpoints/Users/UserModule.cs new file mode 100644 index 00000000..b0e546d6 --- /dev/null +++ b/zero.Api/Endpoints/Users/UserModule.cs @@ -0,0 +1,18 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace zero.Api.Endpoints.Users; + +public class UserModule : ZeroModule +{ + public override void ConfigureServices(IServiceCollection services, IConfiguration configuration) + { + services.AddSingleton(); + services.AddSingleton(); + + services.Configure(opts => + { + opts.Indexes.Add(); + }); + } +} \ No newline at end of file diff --git a/zero.Api/Endpoints/Users/UserPermissions.cs b/zero.Api/Endpoints/Users/UserPermissions.cs new file mode 100644 index 00000000..adf94058 --- /dev/null +++ b/zero.Api/Endpoints/Users/UserPermissions.cs @@ -0,0 +1,31 @@ +namespace zero.Api.Endpoints.Users; + +public class UserPermissions : PermissionProvider +{ + public const string Group = "zero.user"; + + public const string Create = "zero.user.create"; + public const string Read = "zero.user.read"; + public const string Update = "zero.user.update"; + public const string Delete = "zero.user.delete"; + + + public override Task Configure(IPermissionContext context) + { + PermissionGroup group = new(Group, "@user.list"); + group.Permissions.Add(new Permission("zero.user.defaults", "Default permissions") + { + Children = new() + { + new(Create, "@permission.states.create"), + new(Read, "@permission.states.read"), + new(Update, "@permission.states.update"), + new(Delete, "@permission.states.delete") + } + }); + + context.AddGroup(group); + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/zero.Api/Endpoints/Users/Users/UserListModel.cs b/zero.Api/Endpoints/Users/Users/UserListModel.cs deleted file mode 100644 index 0e370dbe..00000000 --- a/zero.Api/Endpoints/Users/Users/UserListModel.cs +++ /dev/null @@ -1,15 +0,0 @@ -//namespace zero.Web.Models -//{ -// public class UserListModel : ListModel -// { -// public string Name { get; set; } - -// public bool IsActive { get; set; } - -// public string Email { get; set; } - -// public string Roles { get; set; } - -// public string AvatarId { get; set; } -// } -//} diff --git a/zero.Api/Endpoints/Users/UsersController.cs b/zero.Api/Endpoints/Users/UsersController.cs new file mode 100644 index 00000000..14b30ff0 --- /dev/null +++ b/zero.Api/Endpoints/Users/UsersController.cs @@ -0,0 +1,64 @@ +using Microsoft.AspNetCore.Mvc; + +namespace zero.Api.Endpoints.Users; + +public class UsersController : ZeroApiController +{ + readonly IUserService Users; + + public UsersController(IUserService users) + { + Users = users; + } + + + [HttpGet("empty")] + [ZeroAuthorize(UserPermissions.Create)] + public virtual async Task> Empty(string flavor = null) + { + return new ZeroUser(); + } + + + [HttpGet("{id}")] + [ZeroAuthorize(UserPermissions.Read)] + public virtual async Task> Get(string id) + { + ZeroUser model = await Users.GetUserById(id); + + if (model == null) + { + return NotFound(); + } + + //HttpContext.Items[ApiConstants.ChangeToken] = Store.GetChangeToken(model); + + return model; + } + + + [HttpGet("")] + [ZeroAuthorize(UserPermissions.Read)] + public virtual async Task> Get([FromQuery] ListQuery query) + { + query.OrderQuery ??= q => q.OrderByDescending(x => x.CreatedDate); + query.SearchSelector ??= x => x.Name; + Paged result = await Users.GetAll(query.Page, query.PageSize); + return Mapper.Map(result); + } + + + //[HttpPost("")] + //[ZeroAuthorize(UserPermissions.Create)] + //public virtual Task> Create(ZeroUser saveModel) => CreateModel(saveModel); + + + //[HttpPut("{id}")] + //[ZeroAuthorize(UserPermissions.Update)] + //public virtual Task> Update(string id, ZeroUser updateModel, [FromQuery] string changeToken = null) => UpdateModel(id, updateModel, changeToken); + + + //[HttpDelete("{id}")] + //[ZeroAuthorize(UserPermissions.Delete)] + //public virtual Task> Delete(string id) => DeleteModel(id); +} \ No newline at end of file diff --git a/zero.Api/Plugin.cs b/zero.Api/Plugin.cs index 36c51f58..091cad18 100644 --- a/zero.Api/Plugin.cs +++ b/zero.Api/Plugin.cs @@ -38,6 +38,7 @@ public class ZeroApiPlugin : ZeroPlugin modules.Add(); modules.Add(); modules.Add(); + modules.Add(); modules.ConfigureServices(services, configuration); diff --git a/zero.Backoffice.UI/_notimplemented/helpers/overlay.js b/zero.Backoffice.UI/_notimplemented/helpers/overlay.js deleted file mode 100644 index b3c1e7a9..00000000 --- a/zero.Backoffice.UI/_notimplemented/helpers/overlay.js +++ /dev/null @@ -1,101 +0,0 @@ -import Vue from 'vue'; -import AppConfirm from 'zero/components/overlays/confirm.vue'; // TODO importing vue files in js/ts files causes a Rollup production build error -import AppMessage from 'zero/components/overlays/message.vue'; -import Strings from 'zero/helpers/strings.js'; -import { find as _find, extend as _extend } from 'underscore'; - -export default new Vue({ - - data: () => ({ - dropdownInstance: null, - instances: [] - }), - - methods: { - - - // opens an overlay - open(options) - { - const defaultWidth = options.display === 'editor' ? 560 : 460; - - options = _extend({ - id: Strings.guid(), - display: 'dialog', - width: defaultWidth, - hide: this.close, - autoclose: true, - softdismiss: options.display !== 'editor', - closeLabel: '@ui.close', - confirmLabel: '@ui.confirm', - confirmType: 'default', - alias: options.alias - }, options); - - if (typeof options.theme === 'undefined') - { - options.theme = 'default'; - } - - this.instances.push(options); - - return new Promise((resolve, reject) => - { - options.close = () => - { - this.close(options); - reject(options); - // TODO should we move to resolve here, so we don't trigger errors in case the implementation does not catch them? - // this will at least need some tests if the .then callback does not catch null values - }; - options.hide = options.close; - - options.confirm = data => - { - if (options.autoclose) - { - this.close(options); - } - resolve(data, options); - }; - }); - }, - - - // closes an overlay - close(instance) - { - if (this.instances.length < 1) - { - return; - } - - if (!instance) - { - this.instances.pop(); - return; - } - - if (typeof instance === 'string') - { - instance = _find(this.instances, item => item.id === instance); - } - - if (instance) - { - const index = this.instances.indexOf(instance); - this.instances.splice(index, 1); - } - }, - - // closes all overlays - closeAll() - { - this.instances.forEach(instance => - { - - }); - } - - } -}); \ No newline at end of file diff --git a/zero.Backoffice.UI/app/components/ui-add-button.vue b/zero.Backoffice.UI/app/components/ui-add-button.vue index c61c0eae..aa78ea41 100644 --- a/zero.Backoffice.UI/app/components/ui-add-button.vue +++ b/zero.Backoffice.UI/app/components/ui-add-button.vue @@ -5,7 +5,9 @@