diff --git a/src/AbpDesk/Web_PlugIns/AbpDesk.MongoBlog.dll b/src/AbpDesk/Web_PlugIns/AbpDesk.MongoBlog.dll index 243e6fa82e..b7cc055fbd 100644 Binary files a/src/AbpDesk/Web_PlugIns/AbpDesk.MongoBlog.dll and b/src/AbpDesk/Web_PlugIns/AbpDesk.MongoBlog.dll differ diff --git a/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/GetIdentityUsersInput.cs b/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/GetIdentityUsersInput.cs new file mode 100644 index 0000000000..274800728a --- /dev/null +++ b/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/GetIdentityUsersInput.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Application.Dtos; +using Volo.Abp.Validation; + +namespace Volo.Abp.Identity +{ + public class GetIdentityUsersInput : PagedAndSortedResultRequestDto + { + public string Filter { get; set; } + } +} diff --git a/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityUserAppService.cs b/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityUserAppService.cs index 8738265374..c620ebd917 100644 --- a/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityUserAppService.cs +++ b/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityUserAppService.cs @@ -5,7 +5,7 @@ using Volo.Abp.Application.Services; namespace Volo.Abp.Identity { - public interface IIdentityUserAppService : IAsyncCrudAppService + public interface IIdentityUserAppService : IAsyncCrudAppService { Task> GetRolesAsync(Guid id); diff --git a/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateOutput.cs b/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateOutput.cs new file mode 100644 index 0000000000..e107db6b71 --- /dev/null +++ b/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateOutput.cs @@ -0,0 +1,11 @@ +using Volo.Abp.Application.Dtos; + +namespace Volo.Abp.Identity +{ + public class IdentityUserCreateOrUpdateOutput: EntityDto + { + public IdentityUserDto User { get; set; } + + public IdentityUserRoleDto[] Roles { get; set; } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserRoleDto.cs b/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserRoleDto.cs new file mode 100644 index 0000000000..eea833d957 --- /dev/null +++ b/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserRoleDto.cs @@ -0,0 +1,13 @@ +using System; + +namespace Volo.Abp.Identity +{ + public class IdentityUserRoleDto + { + public Guid Id { get; set; } + + public string Name { get; set; } + + public bool IsAssigned { get; set; } + } +} diff --git a/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserUpdateDto.cs b/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserUpdateDto.cs index cc551a7398..3117ff8003 100644 --- a/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserUpdateDto.cs +++ b/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserUpdateDto.cs @@ -2,6 +2,5 @@ { public class IdentityUserUpdateDto : IdentityUserCreateOrUpdateDtoBase { - } } \ No newline at end of file diff --git a/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/AbpDeskApplicationModuleAutoMapperProfile.cs b/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/AbpDeskApplicationModuleAutoMapperProfile.cs index e796a0a7ae..6f922c9707 100644 --- a/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/AbpDeskApplicationModuleAutoMapperProfile.cs +++ b/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/AbpDeskApplicationModuleAutoMapperProfile.cs @@ -8,6 +8,7 @@ namespace Volo.Abp.Identity { CreateMap(); CreateMap(); + CreateMap(); } } } \ No newline at end of file diff --git a/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs b/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs index fc264b4a60..68b92a04c5 100644 --- a/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs +++ b/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; @@ -12,11 +13,13 @@ namespace Volo.Abp.Identity { private readonly IdentityUserManager _userManager; private readonly IIdentityUserRepository _userRepository; + private readonly IIdentityRoleRepository _roleRepository; - public IdentityUserAppService(IdentityUserManager userManager, IIdentityUserRepository userRepository) + public IdentityUserAppService(IdentityUserManager userManager, IIdentityUserRepository userRepository, IIdentityRoleRepository roleRepository) { _userManager = userManager; _userRepository = userRepository; + _roleRepository = roleRepository; } public async Task GetAsync(Guid id) @@ -26,10 +29,30 @@ namespace Volo.Abp.Identity ); } - public async Task> GetListAsync(PagedAndSortedResultRequestDto input) + public async Task GetUserForCreateOrUpdateAsync(Guid id) + { + var userRoleDtos = ObjectMapper.Map, IdentityUserRoleDto[]>(await _roleRepository.GetListAsync()); + var output = new IdentityUserCreateOrUpdateOutput + { + Roles = userRoleDtos + }; + + var user = await _userManager.GetByIdAsync(id); + + output.User = ObjectMapper.Map(user); + + foreach (var userRoleDto in userRoleDtos) + { + userRoleDto.IsAssigned = await _userManager.IsInRoleAsync(user, userRoleDto.Name); + } + + return output; + } + + public async Task> GetListAsync(GetIdentityUsersInput input) { var count = (int)await _userRepository.GetCountAsync(); - var list = await _userRepository.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount); + var list = await _userRepository.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, input.Filter); return new PagedResultDto( count, diff --git a/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs b/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs index d583b83f46..39b1b649bb 100644 --- a/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs +++ b/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs @@ -24,7 +24,8 @@ namespace Volo.Abp.Identity //TODO: Why not return List instead of IList Task> GetListByNormalizedRoleNameAsync(string normalizedRoleName, CancellationToken cancellationToken); - Task> GetListAsync(string sorting, int maxResultCount, int skipCount); + //TODO: DTO can be used instead of parameters + Task> GetListAsync(string sorting, int maxResultCount, int skipCount, string filter); Task> GetRolesAsync(Guid userId); } diff --git a/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EfCoreIdentityUserRepository.cs b/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EfCoreIdentityUserRepository.cs index a845d8faf8..65ab54b5a6 100644 --- a/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EfCoreIdentityUserRepository.cs +++ b/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EfCoreIdentityUserRepository.cs @@ -78,6 +78,18 @@ namespace Volo.Abp.Identity return await query.ToListAsync(cancellationToken); } + public async Task> GetListAsync(string sorting, int maxResultCount, int skipCount, string filter) + { + return await this.WhereIf( + !filter.IsNullOrWhiteSpace(), + u => + u.UserName.Contains(filter) || + u.Email.Contains(filter) + ) + .OrderBy(sorting ?? nameof(IdentityUser.UserName)) + .PageBy(skipCount, maxResultCount).ToListAsync(); + } + public async Task> GetListAsync(string sorting, int maxResultCount, int skipCount) { return await this.OrderBy(sorting ?? nameof(IdentityUser.UserName)).PageBy(skipCount, maxResultCount).ToListAsync(); diff --git a/src/Volo.Abp.Identity.Web/Areas/Identity/Controllers/UsersController.cs b/src/Volo.Abp.Identity.Web/Areas/Identity/Controllers/UsersController.cs index 9450115d66..300395bf19 100644 --- a/src/Volo.Abp.Identity.Web/Areas/Identity/Controllers/UsersController.cs +++ b/src/Volo.Abp.Identity.Web/Areas/Identity/Controllers/UsersController.cs @@ -1,6 +1,6 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc; namespace Volo.Abp.Identity.Web.Areas.Identity.Controllers @@ -8,17 +8,28 @@ namespace Volo.Abp.Identity.Web.Areas.Identity.Controllers [Area("Identity")] public class UsersController : AbpController { - private readonly IIdentityUserAppService _userAppService; + private readonly IIdentityUserAppService _identityUserAppService; - public UsersController(IIdentityUserAppService userAppService) + public UsersController(IIdentityUserAppService identityUserAppService) { - _userAppService = userAppService; + _identityUserAppService = identityUserAppService; } public async Task Index() { - var result = await _userAppService.GetListAsync(new PagedAndSortedResultRequestDto()); - return View(result.Items); + return View(); + } + + public async Task _Create() + { + return PartialView(); + } + + public async Task _Update(Guid id) + { + var identityUser = await _identityUserAppService.GetUserForCreateOrUpdateAsync(id); + + return PartialView(identityUser); } } } diff --git a/src/Volo.Abp.Identity.Web/Areas/Identity/Views/Users/Index.cshtml b/src/Volo.Abp.Identity.Web/Areas/Identity/Views/Users/Index.cshtml index ed16546d72..7e498ddaa8 100644 --- a/src/Volo.Abp.Identity.Web/Areas/Identity/Views/Users/Index.cshtml +++ b/src/Volo.Abp.Identity.Web/Areas/Identity/Views/Users/Index.cshtml @@ -1,34 +1,37 @@ -@model IReadOnlyList - -@section styles { +@section styles { } @section scripts { - + }

Users

- + + + + + + +
- - - - - + + + + + + - - @foreach (var user in Model) - { - - - - - - } -
UsernameEmail AddressPhone Number
ActionsUsernameEmail AddressPhone Number
@user.UserName@user.Email@(user.PhoneNumber ?? "-")
\ No newline at end of file diff --git a/src/Volo.Abp.Identity.Web/Areas/Identity/Views/Users/_Create.cshtml b/src/Volo.Abp.Identity.Web/Areas/Identity/Views/Users/_Create.cshtml new file mode 100644 index 0000000000..623fae0570 --- /dev/null +++ b/src/Volo.Abp.Identity.Web/Areas/Identity/Views/Users/_Create.cshtml @@ -0,0 +1,63 @@ +@model Volo.Abp.Identity.IdentityUserDto + + + + \ No newline at end of file diff --git a/src/Volo.Abp.Identity.Web/Areas/Identity/Views/Users/_Update.cshtml b/src/Volo.Abp.Identity.Web/Areas/Identity/Views/Users/_Update.cshtml new file mode 100644 index 0000000000..0f1b7fedc2 --- /dev/null +++ b/src/Volo.Abp.Identity.Web/Areas/Identity/Views/Users/_Update.cshtml @@ -0,0 +1,30 @@ +@model Volo.Abp.Identity.IdentityUserDto + + + + \ No newline at end of file diff --git a/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj b/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj index 4cb0a66f59..efe55cc4a5 100644 --- a/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj +++ b/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj @@ -11,7 +11,16 @@ - + + + + + + + + + + diff --git a/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.css b/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.css index 00bc312198..ee22283b8e 100644 --- a/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.css +++ b/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.css @@ -1,3 +1,4 @@ -#IdentityUsersTable { - width: 100%; +.dataTable { + width: 100% !important; + border-spacing: 0 !important; } \ No newline at end of file diff --git a/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.js b/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.js index 7170f72224..393c59095c 100644 --- a/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.js +++ b/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.js @@ -1,3 +1,138 @@ -$(function() { - $('#IdentityUsersTable').DataTable(); -}); \ No newline at end of file +$(function () { + var identityUserAppService = volo.abp.identity.identityUser; + + var dataTable = $('#IdentityUsersTable').DataTable({ + processing: true, + serverSide: true, + ajax: function (requestData, callback, settings) { + var inputFilter = {}; + + //set paging filters + if (settings.oInit.paging) { + inputFilter = $.extend(inputFilter, { + maxResultCount: requestData.length, + skipCount: requestData.start + }); + } + + //set sorting filter + if (requestData.order && requestData.order.length > 0) { + var orderingField = requestData.order[0]; + if (requestData.columns[orderingField.column].data) { + inputFilter.sorting = requestData.columns[orderingField.column].data + " " + orderingField.dir; + } + } + + //set searching filter + if (requestData.search && requestData.search.value !== "") { + inputFilter.filter = requestData.search.value; + } + + if (callback) { + identityUserAppService.getList(inputFilter).done(function (result) { + callback({ + recordsTotal: result.totalCount, + recordsFiltered: result.totalCount, + data: result.items + }); + }); + } + }, + responsive: true, + columnDefs: [ + { + targets: 0, + data: null, + orderable: false, + autoWidth: false, + defaultContent: '', + render: function (list, type, record, meta) { + return ''; + } + }, + { + targets: 1, + data: "userName" + }, + { + targets: 2, + data: "email" + }, + { + targets: 3, + data: "phoneNumber" + } + ] + }); + + $(document).on('click', '.update-user', function () { + var id = $(this).data('id'); + + $('#createUpdateUserModal').modal('show') + .find('.modal-content') + .load(abp.appPath + 'Identity/Users/_Update', { id: id }); + }); + + $(document).on('click', '.delete-user', function () { + var id = $(this).data('id'); + + if (confirm('Are you sure you want to delete?')) { + identityUserAppService.delete(id).done(function () { + dataTable.ajax.reload(); + }); + } + }); + + $('.create-user').click(function () { + $('#createUpdateUserModal').modal('show') + .find('.modal-content') + .load(abp.appPath + 'Identity/Users/_Create'); + }); + + $(document).on('click', '#btnCreateUserSave', function () { + var $createUserForm = $('#createUserForm'); + var user = $createUserForm.serializeFormToObject(); + + identityUserAppService.create(user).done(function () { + $('#createUpdateUserModal').modal('hide'); + + dataTable.ajax.reload(); + }); + }); + + $(document).on('click', '#btnUpdateUserSave', function () { + var $updateUserForm = $('#updateUserForm'); + var user = $updateUserForm.serializeFormToObject(); + + identityUserAppService.update(user.Id, user).done(function () { + $('#createUpdateUserModal').modal('hide'); + + dataTable.ajax.reload(); + }); + }); +}); + +$.fn.serializeFormToObject = function () { + //serialize to array + var data = $(this).serializeArray(); + + //add also disabled items + $(':disabled[name]', this) + .each(function () { + data.push({ name: this.name, value: $(this).val() }); + }); + + //map to object + var obj = {}; + data.map(function (x) { obj[x.name] = x.value; }); + + return obj; +}; diff --git a/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.less b/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.less index f267dfefb8..b566f7d35c 100644 --- a/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.less +++ b/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.less @@ -1,3 +1,4 @@ -#IdentityUsersTable { - width: 100%; +.dataTable { + width: 100% !important; + border-spacing: 0 !important; } diff --git a/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.min.css b/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.min.css index 3690048700..557de2f607 100644 --- a/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.min.css +++ b/src/Volo.Abp.Identity.Web/wwwroot/modules/identity/views/users/index.min.css @@ -1 +1 @@ -#IdentityUsersTable{width:100%;} \ No newline at end of file +.dataTable{width:100% !important;border-spacing:0 !important;} \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Application/Services/IAsyncCrudAppService.cs b/src/Volo.Abp/Volo/Abp/Application/Services/IAsyncCrudAppService.cs index a94d0ce554..50f9314875 100644 --- a/src/Volo.Abp/Volo/Abp/Application/Services/IAsyncCrudAppService.cs +++ b/src/Volo.Abp/Volo/Abp/Application/Services/IAsyncCrudAppService.cs @@ -38,6 +38,8 @@ namespace Volo.Abp.Application.Services { Task GetAsync(TPrimaryKey id); + Task GetUserForCreateOrUpdateAsync(Guid id); + Task> GetListAsync(TGetListInput input); Task CreateAsync(TCreateInput input); diff --git a/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserAppService_Tests.cs b/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserAppService_Tests.cs index a4bbb9af11..4025713ae1 100644 --- a/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserAppService_Tests.cs +++ b/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserAppService_Tests.cs @@ -44,7 +44,7 @@ namespace Volo.Abp.Identity { //Act - var result = await _userAppService.GetListAsync(new PagedAndSortedResultRequestDto()); + var result = await _userAppService.GetListAsync(new GetIdentityUsersInput()); //Assert