diff --git a/zero.Web/App/Components/permissions.vue b/zero.Web/App/Components/permissions.vue index 1200534f..a9d2b175 100644 --- a/zero.Web/App/Components/permissions.vue +++ b/zero.Web/App/Components/permissions.vue @@ -93,9 +93,9 @@ collection.items.forEach(permission => { if ( - (permission.valueType === 'boolean' && permission.value === true) || - (permission.valueType === 'readWrite' && permission.value !== 'none') || - (permission.valueType === 'string' && !!permission.value)) + (permission.valueType === 'boolean') || + (permission.valueType === 'readWrite') || + (permission.valueType === 'string')) { claims.push({ //$type: 'zero.Core.Entities.UserClaim, zero.Core', diff --git a/zero.Web/App/pages/settings/users.vue b/zero.Web/App/pages/settings/users.vue index 3e61018e..bb97d2fe 100644 --- a/zero.Web/App/pages/settings/users.vue +++ b/zero.Web/App/pages/settings/users.vue @@ -29,6 +29,7 @@ import AuthApi from 'zero/services/auth.js' import UserRolesApi from 'zero/resources/userRoles.js'; import UsersApi from 'zero/resources/users.js'; + import { filter as _filter, map as _map } from 'underscore'; export default { data: () => ({ @@ -38,7 +39,10 @@ created() { - this._user = AuthApi.user; + UserRolesApi.getAll().then(items => + { + this.roles = items; + }); this.usersConfig = { labelPrefix: '@user.fields.', @@ -58,7 +62,14 @@ link: this.getUserLink }, email: 'text', - roles: 'text', + roles: { + as: 'text', + render: item => + { + const roles = _filter(this.roles, role => item.roles.indexOf(role.alias) > -1); + return _map(roles, role => role.name).join(', '); + } + }, isActive: { as: 'bool', width: 200 @@ -66,11 +77,6 @@ }, items: UsersApi.getAll }; - - UserRolesApi.getAll().then(items => - { - this.roles = items; - }); }, methods: { diff --git a/zero.Web/Controllers/BackofficeController.cs b/zero.Web/Controllers/BackofficeController.cs index 08cefe34..39d3b8db 100644 --- a/zero.Web/Controllers/BackofficeController.cs +++ b/zero.Web/Controllers/BackofficeController.cs @@ -35,7 +35,7 @@ namespace zero.Web.Controllers } - protected IActionResult As(T model) where TTarget : class, new() where T : IZeroEntity + protected async Task As(T model) where TTarget : class, new() where T : IZeroEntity { if (model == null) { @@ -47,7 +47,7 @@ namespace zero.Web.Controllers // TODO show error with help on how to inject mapper in constructor + base constructor } - TTarget result = Mapper.Map(model); + TTarget result = await Mapper.Map(model); if (result is EditModel) { @@ -59,40 +59,40 @@ namespace zero.Web.Controllers } - protected IActionResult As(IEnumerable model) where TTarget : class, new() where T : IZeroEntity + protected async Task As(IEnumerable model) where TTarget : class, new() where T : IZeroEntity { if (model == null) { return new StatusCodeResult(404); } - return Json(Mapper.Map(model)); + return Json(await Mapper.Map(model)); } - protected IActionResult As(ListResult model) where TTarget : class, new() where T : IZeroEntity + protected async Task As(ListResult model) where TTarget : class, new() where T : IZeroEntity { if (model == null) { return new StatusCodeResult(404); } - return Json(Mapper.Map(model)); + return Json(await Mapper.Map(model)); } - protected IActionResult As(EntityResult model) where TTarget : class, new() where T : IZeroEntity + protected async Task As(EntityResult model) where TTarget : class, new() where T : IZeroEntity { if (model == null) { return new StatusCodeResult(404); } - return Json(Mapper.Map(model)); + return Json(await Mapper.Map(model)); } - protected TTarget Map(T model) where TTarget : class, new() + protected async Task Map(T model) where TTarget : class, new() { - return Mapper.Map(model); + return await Mapper.Map(model); } } } diff --git a/zero.Web/Controllers/CountriesController.cs b/zero.Web/Controllers/CountriesController.cs index 782182c3..b6ba55e6 100644 --- a/zero.Web/Controllers/CountriesController.cs +++ b/zero.Web/Controllers/CountriesController.cs @@ -25,7 +25,7 @@ namespace zero.Web.Controllers /// public async Task GetById([FromQuery] string id) { - return As(await Api.GetById(id)); + return await As(await Api.GetById(id)); } @@ -34,7 +34,7 @@ namespace zero.Web.Controllers /// public async Task GetAll([FromQuery] ListQuery query) { - return As(await Api.GetByQuery("en-US", query)); + return await As(await Api.GetByQuery("en-US", query)); } @@ -44,7 +44,7 @@ namespace zero.Web.Controllers [ZeroAuthorize(Permissions.Settings.Countries, PermissionsValue.Write)] public async Task Save([FromBody] CountryEditModel model) { - Country country = Mapper.Map(model, await Api.GetById(model.Id)); + Country country = await Mapper.Map(model, await Api.GetById(model.Id)); return Json(await Api.Save(country)); } diff --git a/zero.Web/Controllers/UserRolesController.cs b/zero.Web/Controllers/UserRolesController.cs index 228b0c2b..41729309 100644 --- a/zero.Web/Controllers/UserRolesController.cs +++ b/zero.Web/Controllers/UserRolesController.cs @@ -31,7 +31,7 @@ namespace zero.Web.Controllers /// public async Task GetById([FromQuery] string id) { - return As(await Api.GetById(id)); + return await As(await Api.GetById(id)); } @@ -40,7 +40,7 @@ namespace zero.Web.Controllers /// public async Task GetAll() { - return As(await Api.GetAll()); + return await As(await Api.GetAll()); } @@ -60,8 +60,8 @@ namespace zero.Web.Controllers public async Task Save([FromBody] UserRoleEditModel model) { var state = ModelState; - UserRole role = Mapper.Map(model, await Api.GetById(model.Id)); - return As(await Api.Save(role)); + UserRole role = await Mapper.Map(model, await Api.GetById(model.Id)); + return await As(await Api.Save(role)); } @@ -71,7 +71,7 @@ namespace zero.Web.Controllers [ZeroAuthorize(Permissions.Settings.Users, PermissionsValue.Write)] public async Task Delete([FromQuery] string id) { - return As(await Api.Delete(id)); + return await As(await Api.Delete(id)); } } } diff --git a/zero.Web/Controllers/UsersController.cs b/zero.Web/Controllers/UsersController.cs index 995323cd..8ca4d59b 100644 --- a/zero.Web/Controllers/UsersController.cs +++ b/zero.Web/Controllers/UsersController.cs @@ -13,13 +13,17 @@ namespace zero.Web.Controllers [ZeroAuthorize(Permissions.Settings.Users, PermissionsValue.Read)] public class UsersController : BackofficeController { - private IUserApi Api { get; set; } + IUserApi Api = null; - private ZeroOptions Options { get; set; } + IUserRolesApi RolesApi = null; - public UsersController(IZeroConfiguration config, IUserApi api, IMapper mapper, IToken token, IOptionsMonitor options) : base(config, mapper, token) + ZeroOptions Options = null; + + + public UsersController(IZeroConfiguration config, IUserApi api, IUserRolesApi rolesApi, IMapper mapper, IToken token, IOptionsMonitor options) : base(config, mapper, token) { Api = api; + RolesApi = rolesApi; Options = options.CurrentValue; } @@ -29,7 +33,7 @@ namespace zero.Web.Controllers /// public async Task GetById([FromQuery] string id) { - return As(await Api.GetUserById(id)); + return await As(await Api.GetUserById(id)); } @@ -38,7 +42,7 @@ namespace zero.Web.Controllers /// public async Task GetAll([FromQuery] ListQuery query) { - return As(await Api.GetByQuery(query, "zero.applications.1-A")); + return await As(await Api.GetByQuery(query, "zero.applications.1-A")); } diff --git a/zero.Web/Mapper/CountryMapperConfig.cs b/zero.Web/Mapper/CountryMapperConfig.cs index 2ddf6760..7fb7d1b4 100644 --- a/zero.Web/Mapper/CountryMapperConfig.cs +++ b/zero.Web/Mapper/CountryMapperConfig.cs @@ -1,4 +1,5 @@ -using zero.Core.Entities; +using Raven.Client.Documents; +using zero.Core.Entities; using zero.Web.Models; namespace zero.Web.Mapper diff --git a/zero.Web/Mapper/DefaultMapper.cs b/zero.Web/Mapper/DefaultMapper.cs index 821ddc5c..89576199 100644 --- a/zero.Web/Mapper/DefaultMapper.cs +++ b/zero.Web/Mapper/DefaultMapper.cs @@ -1,7 +1,10 @@ -using System; +using Raven.Client.Documents; +using Raven.Client.Documents.Session; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Threading.Tasks; using zero.Core.Entities; namespace zero.Web.Mapper @@ -10,6 +13,14 @@ namespace zero.Web.Mapper { MapCache Maps = new MapCache(); + IDocumentStore Raven = null; + + + public DefaultMapper(IDocumentStore raven) + { + Raven = raven; + } + /// public void Add() where T : IMapperConfig, new() @@ -34,39 +45,39 @@ namespace zero.Web.Mapper /// - public TTarget Map(TSource source) where TTarget : class, new() + public async Task Map(TSource source) where TTarget : class, new() { if (source == null) { return null; } - return Map(source, new TTarget()); + return await Map(source, new TTarget()); } /// - public TTarget Map(TSource source, TTarget target) where TTarget : class, new() + public async Task Map(TSource source, TTarget target) where TTarget : class, new() { if (source == null) { return target; } - Maps.Call(source, target); + await Maps.Call(source, target); return target; } /// - public IEnumerable Map(IEnumerable source) where TTarget : class, new() + public async Task> Map(IEnumerable source) where TTarget : class, new() { IList target = new List(); foreach (TSource item in source) { - target.Add(Map(item, new TTarget())); + target.Add(await Map(item, new TTarget())); } return target; @@ -74,13 +85,13 @@ namespace zero.Web.Mapper /// - public ListResult Map(ListResult source) where TTarget : class, new() + public async Task> Map(ListResult source) where TTarget : class, new() { IList target = new List(); foreach (TSource item in source.Items) { - target.Add(Map(item, new TTarget())); + target.Add(await Map(item, new TTarget())); } return new ListResult(target, source.TotalItems, source.Page, source.PageSize) @@ -91,13 +102,13 @@ namespace zero.Web.Mapper /// - public EntityResult Map(EntityResult source) where TTarget : class, new() + public async Task> Map(EntityResult source) where TTarget : class, new() { return new EntityResult() { IsSuccess = source.IsSuccess, Errors = source.Errors, - Model = Map(source.Model, new TTarget()) + Model = await Map(source.Model, new TTarget()) }; } @@ -105,14 +116,28 @@ namespace zero.Web.Mapper /// public void CreateMap(Action map) where TTarget : class, new() { - Maps.Add((source, target) => map((TSource)source, (TTarget)target)); + Maps.Add((source, target) => + { + map((TSource)source, (TTarget)target); + return Task.CompletedTask; + }); + } + + + /// + public void CreateMap(Func map) where TTarget : class, new() + { + Maps.Add(async (source, target) => + { + await map((TSource)source, (TTarget)target, null); + }); } /// /// Internal mappings cache /// - class MapCache : Dictionary>> + class MapCache : Dictionary>> { int Index = 0; @@ -122,14 +147,14 @@ namespace zero.Web.Mapper /// /// Adds a new action for the mapping /// - public void Add(Action map) + public void Add(Func map) { int sourceKey = GetKeyForType(typeof(TSource)); int targetKey = GetKeyForType(typeof(TTarget)); if (!ContainsKey(sourceKey)) { - Add(sourceKey, new Dictionary>()); + Add(sourceKey, new Dictionary>()); } if (!this[sourceKey].ContainsKey(targetKey)) @@ -142,7 +167,7 @@ namespace zero.Web.Mapper /// /// Get action from defined types /// - public void Call(TSource source, TTarget target) + public async Task Call(TSource source, TTarget target) { int sourceKey = GetKeyForType(typeof(TSource)); int targetKey = GetKeyForType(typeof(TTarget)); @@ -152,9 +177,9 @@ namespace zero.Web.Mapper return; } - Action result = this[sourceKey][targetKey]; + Func result = this[sourceKey][targetKey]; - result(source, target); + await result(source, target); } @@ -189,31 +214,34 @@ namespace zero.Web.Mapper /// /// Map an object to the target type /// - TTarget Map(TSource source) where TTarget : class, new(); + Task Map(TSource source) where TTarget : class, new(); /// /// Map an object to the target type given an already existing target instance /// - TTarget Map(TSource source, TTarget target) where TTarget : class, new(); + Task Map(TSource source, TTarget target) where TTarget : class, new(); /// /// Map a list of objects to the target type /// - IEnumerable Map(IEnumerable source) where TTarget : class, new(); + Task> Map(IEnumerable source) where TTarget : class, new(); /// /// Map a list result containing objects to the target type /// - ListResult Map(ListResult source) where TTarget : class, new(); + Task> Map(ListResult source) where TTarget : class, new(); /// /// Map an entity result to the target type /// - EntityResult Map(EntityResult source) where TTarget : class, new(); + Task> Map(EntityResult source) where TTarget : class, new(); /// /// Create a mapping from source to target object /// void CreateMap(Action map) where TTarget : class, new(); + + /// + void CreateMap(Func map) where TTarget : class, new(); } } \ No newline at end of file diff --git a/zero.Web/Mapper/IMapperConfig.cs b/zero.Web/Mapper/IMapperConfig.cs index 024c57ad..c4aa4f32 100644 --- a/zero.Web/Mapper/IMapperConfig.cs +++ b/zero.Web/Mapper/IMapperConfig.cs @@ -1,4 +1,6 @@ -namespace zero.Web.Mapper +using Raven.Client.Documents; + +namespace zero.Web.Mapper { public interface IMapperConfig { diff --git a/zero.Web/Mapper/MapperServiceCollectionExtensions.cs b/zero.Web/Mapper/MapperServiceCollectionExtensions.cs index 3843cdba..fccc02de 100644 --- a/zero.Web/Mapper/MapperServiceCollectionExtensions.cs +++ b/zero.Web/Mapper/MapperServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.DependencyInjection; +using Raven.Client.Documents; using System; using zero.Core; using zero.Web.Mapper; @@ -7,7 +8,7 @@ namespace zero.Web { public static class MapperServiceCollectionExtensions { - public static IServiceCollection AddMapper(this IServiceCollection services) where T : class, IMapper, new() + public static IServiceCollection AddMapper(this IServiceCollection services) where T : class, IMapper { return services.AddSingleton(); } @@ -24,6 +25,14 @@ namespace zero.Web public static IServiceCollection AddMapper(this IServiceCollection services) => services.AddMapper(); - public static IServiceCollection AddMapper(this IServiceCollection services, Action options) => services.AddMapper(options); + public static IServiceCollection AddMapper(this IServiceCollection services, Action options) + { + return services.AddSingleton(factory => + { + DefaultMapper mapper = new DefaultMapper(factory.GetService()); + options(mapper); + return mapper; + }); + } } } diff --git a/zero.Web/Mapper/UserMapperConfig.cs b/zero.Web/Mapper/UserMapperConfig.cs index 06732191..7402eb32 100644 --- a/zero.Web/Mapper/UserMapperConfig.cs +++ b/zero.Web/Mapper/UserMapperConfig.cs @@ -1,7 +1,10 @@ using System; using System.Linq; using zero.Core.Entities; +using zero.Core.Identity; +using zero.Core.Extensions; using zero.Web.Models; +using Raven.Client.Documents; namespace zero.Web.Mapper { @@ -73,7 +76,17 @@ namespace zero.Web.Mapper { target.Id = source.Id; target.Name = source.Name; - target.CountClaims = source.Claims.Count; + target.Alias = source.Alias; + target.CountClaims = source.Claims.Count(x => + { + string[] parts = x.Value.Split(':'); + + if (parts.Length < 2) + { + return true; + } + return parts[1] == PermissionsValue.True || parts[1] == PermissionsValue.Read || parts[1] == PermissionsValue.Write; + }); target.Icon = source.Icon; }); } diff --git a/zero.Web/Models/UserRoleListModel.cs b/zero.Web/Models/UserRoleListModel.cs index 20e11d3e..4a148721 100644 --- a/zero.Web/Models/UserRoleListModel.cs +++ b/zero.Web/Models/UserRoleListModel.cs @@ -7,5 +7,7 @@ public int CountClaims { get; set; } public string Icon { get; set; } + + public string Alias { get; set; } } } diff --git a/zero.Web/ZeroBuilder.cs b/zero.Web/ZeroBuilder.cs index 78c999ef..40f48c24 100644 --- a/zero.Web/ZeroBuilder.cs +++ b/zero.Web/ZeroBuilder.cs @@ -23,7 +23,7 @@ namespace zero.Web Services.AddOptions().Configure(opts => ConfigureDefaults(opts)); - Services.AddMapper(opts => + Services.AddMapper(opts => { opts.Add(); opts.Add();