diff --git a/DigitalData.UserManager.API/ClientApp/user_manager_ui/src/app/pages/group/group.component.html b/DigitalData.UserManager.API/ClientApp/user_manager_ui/src/app/pages/group/group.component.html index 488fce0..d5627b1 100644 --- a/DigitalData.UserManager.API/ClientApp/user_manager_ui/src/app/pages/group/group.component.html +++ b/DigitalData.UserManager.API/ClientApp/user_manager_ui/src/app/pages/group/group.component.html @@ -1,13 +1,13 @@
-
+
-
+
diff --git a/DigitalData.UserManager.API/ClientApp/user_manager_ui/src/environments/environment.ts b/DigitalData.UserManager.API/ClientApp/user_manager_ui/src/environments/environment.ts index f010d50..3309549 100644 --- a/DigitalData.UserManager.API/ClientApp/user_manager_ui/src/environments/environment.ts +++ b/DigitalData.UserManager.API/ClientApp/user_manager_ui/src/environments/environment.ts @@ -51,6 +51,34 @@ export const env = { { header: 'E-email', field: 'email' + }, + { + header:'Kommentar', + field: 'comment' + }, + { + header: 'DatumsFormat', + field: 'dateFormat' + }, + { + header: 'Kürzel', + field: 'shortname' + }, + { + header: 'Hinzugefügt
wer', + field: 'addedWho' + }, + { + header: 'Hinzugefügt
wann', + field: 'addedWhen' + }, + { + header: 'Geändert
wer', + field: 'changedWho' + }, + { + header: 'Geändert
wann', + field: 'changedWhen' } ] }, @@ -65,8 +93,8 @@ export const env = { field: "comment" }, { - header: "Kommentar", - field: "comment" + header: "Active", + field: (group: any) => group.active ? "✓" : "" }, { header: "AD Sync", @@ -75,6 +103,22 @@ export const env = { { header: "Internal", field: (group: any) => group.internal ? "✓" : "" + }, + { + header: 'Hinzugefügt
wer', + field: (g: any) => g.addedWho + }, + { + header: 'Hinzugefügt
wann', + field: (g: any) => new Date(g.addedWhen).toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: '2-digit', hour: '2-digit', minute: '2-digit' }).replace(',', '') + }, + { + header: 'Geändert
wer', + field: 'changedWho' + }, + { + header: 'Geändert
wann', + field: (g: any) => new Date(g.changedWhen).toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: '2-digit', hour: '2-digit', minute: '2-digit' }).replace(',', '') } ], representative: [ diff --git a/DigitalData.UserManager.API/Controllers/BaseAuthController.cs b/DigitalData.UserManager.API/Controllers/BaseAuthController.cs new file mode 100644 index 0000000..6d36161 --- /dev/null +++ b/DigitalData.UserManager.API/Controllers/BaseAuthController.cs @@ -0,0 +1,47 @@ +using DigitalData.Core.API; +using DigitalData.Core.DTO; +using DigitalData.UserManager.Application.Contracts; +using DigitalData.UserManager.Application.DTOs.Base; +using DigitalData.UserManager.Application.DTOs.User; +using DigitalData.UserManager.Domain.Entities; +using Microsoft.AspNetCore.Authorization; +using System.Security.Claims; + +namespace DigitalData.UserManager.API.Controllers +{ + [Authorize] + public class BaseAuthController : CRUDControllerBaseWithErrorHandling + where TCRUDService : IBaseService + where TCreateDto : BaseCreateDto + where TReadDto : class + where TUpdateDto : BaseUpdateDto + where TBaseEntity : BaseEntity + { + private readonly Lazy _lUserId; + + public BaseAuthController(ILogger logger, TCRUDService service, IUserService userService) : base(logger, service) + { + _lUserId = new(() => + { + var idSt = User.FindFirstValue(ClaimTypes.NameIdentifier); + bool hasId = int.TryParse(idSt, out int id); + return hasId ? id : null; + }); + + service.UserFactoryAsync = async () => + { + var id = _lUserId.Value; + + return id is int intId + ? await userService.ReadByIdAsync(intId).ThenAsync( + Success: res => res, + Fail: UserReadDto? (m, n) => + { + _logger.LogNotice(n); + return null; + }) + : null; + }; + } + } +} \ No newline at end of file diff --git a/DigitalData.UserManager.API/Controllers/GroupController.cs b/DigitalData.UserManager.API/Controllers/GroupController.cs index a5ba919..5ac4611 100644 --- a/DigitalData.UserManager.API/Controllers/GroupController.cs +++ b/DigitalData.UserManager.API/Controllers/GroupController.cs @@ -1,4 +1,3 @@ -using DigitalData.Core.API; using DigitalData.Core.DTO; using DigitalData.UserManager.Application.Contracts; using DigitalData.UserManager.Application.DTOs.Group; @@ -9,9 +8,9 @@ using Microsoft.AspNetCore.Mvc; namespace DigitalData.UserManager.API.Controllers { [Authorize] - public class GroupController : CRUDControllerBaseWithErrorHandling + public class GroupController : BaseAuthController { - public GroupController(ILogger logger, IGroupService service) : base(logger, service) + public GroupController(ILogger logger, IGroupService service, IUserService userService) : base(logger, service, userService) { } diff --git a/DigitalData.UserManager.Application/Contracts/IBaseService.cs b/DigitalData.UserManager.Application/Contracts/IBaseService.cs new file mode 100644 index 0000000..6438e94 --- /dev/null +++ b/DigitalData.UserManager.Application/Contracts/IBaseService.cs @@ -0,0 +1,19 @@ +using DigitalData.UserManager.Domain.Entities; +using DigitalData.Core.Abstractions.Application; +using DigitalData.UserManager.Application.DTOs.User; +using DigitalData.UserManager.Application.DTOs.Base; + +namespace DigitalData.UserManager.Application.Contracts +{ + public interface IBaseService : ICRUDService + where TCreateDto : BaseCreateDto + where TReadDto : class + where TUpdateDto : BaseUpdateDto + where TBaseEntity : BaseEntity + { + + public Func> UserFactoryAsync { set; } + + public Task GetUserAsync(); + } +} \ No newline at end of file diff --git a/DigitalData.UserManager.Application/Contracts/IGroupService.cs b/DigitalData.UserManager.Application/Contracts/IGroupService.cs index ffc342d..5dae49d 100644 --- a/DigitalData.UserManager.Application/Contracts/IGroupService.cs +++ b/DigitalData.UserManager.Application/Contracts/IGroupService.cs @@ -1,11 +1,10 @@ -using DigitalData.Core.Abstractions.Application; -using DigitalData.UserManager.Application.DTOs.Group; +using DigitalData.UserManager.Application.DTOs.Group; using DigitalData.UserManager.Domain.Entities; using DigitalData.Core.DTO; namespace DigitalData.UserManager.Application.Contracts { - public interface IGroupService : ICRUDService + public interface IGroupService : IBaseService { Task> CreateAsync(DirectoryGroupDto dirGroup); } diff --git a/DigitalData.UserManager.Application/DTOs/Base/BaseCreateDto.cs b/DigitalData.UserManager.Application/DTOs/Base/BaseCreateDto.cs new file mode 100644 index 0000000..97759cc --- /dev/null +++ b/DigitalData.UserManager.Application/DTOs/Base/BaseCreateDto.cs @@ -0,0 +1,7 @@ +namespace DigitalData.UserManager.Application.DTOs.Base +{ + public record BaseCreateDto() + { + public string AddedWho { get; set; } = "UNAUTHORIZED"; + } +} \ No newline at end of file diff --git a/DigitalData.UserManager.Application/DTOs/Base/BaseReadDto.cs b/DigitalData.UserManager.Application/DTOs/Base/BaseReadDto.cs new file mode 100644 index 0000000..1a37358 --- /dev/null +++ b/DigitalData.UserManager.Application/DTOs/Base/BaseReadDto.cs @@ -0,0 +1,6 @@ +using DigitalData.Core.DTO; + +namespace DigitalData.UserManager.Application.DTOs.Base +{ + public record BaseReadDto(int Id, string? AddedWho, DateTime? AddedWhen, string? ChangedWho, DateTime? ChangedWhen) : BaseDTO(Id); +} \ No newline at end of file diff --git a/DigitalData.UserManager.Application/DTOs/Base/BaseUpdateDto.cs b/DigitalData.UserManager.Application/DTOs/Base/BaseUpdateDto.cs new file mode 100644 index 0000000..5b784ae --- /dev/null +++ b/DigitalData.UserManager.Application/DTOs/Base/BaseUpdateDto.cs @@ -0,0 +1,7 @@ +namespace DigitalData.UserManager.Application.DTOs.Base +{ + public record BaseUpdateDto() + { + public string ChangedWho { get; set; } = "UNAUTHORIZED"; + } +} \ No newline at end of file diff --git a/DigitalData.UserManager.Application/DTOs/Group/GroupCreateDto.cs b/DigitalData.UserManager.Application/DTOs/Group/GroupCreateDto.cs index 07fd172..d1b2da4 100644 --- a/DigitalData.UserManager.Application/DTOs/Group/GroupCreateDto.cs +++ b/DigitalData.UserManager.Application/DTOs/Group/GroupCreateDto.cs @@ -1,4 +1,6 @@ -namespace DigitalData.UserManager.Application.DTOs.Group +using DigitalData.UserManager.Application.DTOs.Base; + +namespace DigitalData.UserManager.Application.DTOs.Group { public record GroupCreateDto ( @@ -7,8 +9,6 @@ bool? Internal, bool? Active, string? Comment, - string? AddedWho, - string? ChangedWho, int EcmFkId - ); + ) : BaseCreateDto(); } \ No newline at end of file diff --git a/DigitalData.UserManager.Application/DTOs/Group/GroupReadDto.cs b/DigitalData.UserManager.Application/DTOs/Group/GroupReadDto.cs index cdd7b91..1e338c2 100644 --- a/DigitalData.UserManager.Application/DTOs/Group/GroupReadDto.cs +++ b/DigitalData.UserManager.Application/DTOs/Group/GroupReadDto.cs @@ -1,4 +1,6 @@ -namespace DigitalData.UserManager.Application.DTOs.Group +using DigitalData.UserManager.Application.DTOs.Base; + +namespace DigitalData.UserManager.Application.DTOs.Group { public record GroupReadDto ( @@ -9,6 +11,8 @@ bool? Active, string? Comment, string? AddedWho, - string? ChangedWho - ); + DateTime? AddedWhen, + string? ChangedWho, + DateTime? ChangedWhen + ) : BaseReadDto(Id, AddedWho, AddedWhen, ChangedWho, ChangedWhen); } \ No newline at end of file diff --git a/DigitalData.UserManager.Application/DTOs/Group/GroupUpdateDto.cs b/DigitalData.UserManager.Application/DTOs/Group/GroupUpdateDto.cs index fbc6358..dd99e4c 100644 --- a/DigitalData.UserManager.Application/DTOs/Group/GroupUpdateDto.cs +++ b/DigitalData.UserManager.Application/DTOs/Group/GroupUpdateDto.cs @@ -1,4 +1,6 @@ -namespace DigitalData.UserManager.Application.DTOs.Group +using DigitalData.UserManager.Application.DTOs.Base; + +namespace DigitalData.UserManager.Application.DTOs.Group { public record GroupUpdateDto ( @@ -9,5 +11,5 @@ bool? Active, string? Comment, string? ChangedWho - ); + ) : BaseUpdateDto(); } \ No newline at end of file diff --git a/DigitalData.UserManager.Application/Services/BaseService.cs b/DigitalData.UserManager.Application/Services/BaseService.cs new file mode 100644 index 0000000..ca36cc6 --- /dev/null +++ b/DigitalData.UserManager.Application/Services/BaseService.cs @@ -0,0 +1,51 @@ +using AutoMapper; +using DigitalData.Core.Abstractions.Infrastructure; +using DigitalData.Core.Application; +using DigitalData.Core.DTO; +using DigitalData.UserManager.Application.Contracts; +using DigitalData.UserManager.Application.DTOs.Base; +using DigitalData.UserManager.Application.DTOs.User; +using DigitalData.UserManager.Domain.Entities; + +namespace DigitalData.UserManager.Application.Services +{ + public class BaseService : CRUDService, IBaseService + where TCRUDRepository : ICRUDRepository + where TCreateDto : BaseCreateDto + where TReadDto : class + where TUpdateDto : BaseUpdateDto + where TBaseEntity : BaseEntity + { + public BaseService(TCRUDRepository repository, IMapper mapper) : base(repository, mapper) + { + } + + private Lazy>? _lazyUserAsync = null; + + public Func> UserFactoryAsync { set => _lazyUserAsync = new Lazy>(value); } + + public async Task GetUserAsync() => _lazyUserAsync is null ? null : await _lazyUserAsync.Value; + + public override async Task> CreateAsync(TCreateDto createDto) + { + var user = await GetUserAsync(); + if(user is not null) + { + createDto.AddedWho = user.Username; + } + + return await base.CreateAsync(createDto); + } + + public override async Task UpdateAsync(TUpdateDto updateDto) + { + var user = await GetUserAsync(); + if (user is not null) + { + updateDto.ChangedWho = user.Username; + } + + return await base.UpdateAsync(updateDto); + } + } +} \ No newline at end of file diff --git a/DigitalData.UserManager.Application/Services/GroupService.cs b/DigitalData.UserManager.Application/Services/GroupService.cs index 3eb7c6a..d6be011 100644 --- a/DigitalData.UserManager.Application/Services/GroupService.cs +++ b/DigitalData.UserManager.Application/Services/GroupService.cs @@ -1,5 +1,4 @@ using AutoMapper; -using DigitalData.Core.Application; using DigitalData.Core.DTO; using DigitalData.UserManager.Application.Contracts; using DigitalData.UserManager.Application.DTOs.Group; @@ -9,7 +8,7 @@ using Microsoft.Extensions.Localization; namespace DigitalData.UserManager.Application.Services { - public class GroupService : CRUDService, IGroupService + public class GroupService : BaseService, IGroupService { private readonly IStringLocalizer _localizer; public GroupService(IGroupRepository repository, IStringLocalizer localizer, IMapper mapper) : base(repository, mapper) @@ -17,15 +16,14 @@ namespace DigitalData.UserManager.Application.Services _localizer = localizer; } - public override Task> CreateAsync(GroupCreateDto createDto) - { - return base.CreateAsync(createDto); - } - public async Task> CreateAsync(DirectoryGroupDto adGroup) { var group = _mapper.MapOrThrow(adGroup); + //set the user + var user = await GetUserAsync(); + group.AddedWho = user?.AddedWho ?? "UNAUTHORIZED"; + if (await HasEntity(group.Id)) return Result.Fail().Message(_localizer[Key.GroupAlreadyExists.ToString()]); diff --git a/DigitalData.UserManager.Domain/Entities/BaseEntity.cs b/DigitalData.UserManager.Domain/Entities/BaseEntity.cs new file mode 100644 index 0000000..90a55bd --- /dev/null +++ b/DigitalData.UserManager.Domain/Entities/BaseEntity.cs @@ -0,0 +1,30 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DigitalData.UserManager.Domain.Entities +{ + public class BaseEntity + { + [Column("GUID")] + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + + [StringLength(50)] + [DefaultValue("DEFAULT")] + [Column("ADDED_WHO")] + public string? AddedWho { get; set; } + + [StringLength(50)] + [Column("CHANGED_WHO")] + public string? ChangedWho { get; set; } + + [Column("ADDED_WHEN", TypeName = "datetime")] + [DefaultValue("GETDATE()")] + public DateTime AddedWhen { get; set; } = DateTime.Now; + + [Column("CHANGED_WHEN", TypeName = "datetime")] + public DateTime? ChangedWhen { get; set; } + } +} \ No newline at end of file diff --git a/DigitalData.UserManager.Domain/Entities/Group.cs b/DigitalData.UserManager.Domain/Entities/Group.cs index bb09e28..8a37d37 100644 --- a/DigitalData.UserManager.Domain/Entities/Group.cs +++ b/DigitalData.UserManager.Domain/Entities/Group.cs @@ -5,13 +5,8 @@ using System.ComponentModel.DataAnnotations.Schema; namespace DigitalData.UserManager.Domain.Entities { [Table("TBDD_GROUPS", Schema = "dbo")] - public class Group + public class Group : BaseEntity { - [Column("GUID")] - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; set; } - [StringLength(50)] public string? Name { get; set; } @@ -31,27 +26,9 @@ namespace DigitalData.UserManager.Domain.Entities [StringLength(200)] public string? Comment { get; set; } - [StringLength(50)] - [DefaultValue("DEFAULT")] - [Column("ADDED_WHO")] - public string? AddedWho { get; set; } - - [StringLength(50)] - [Column("CHANGED_WHO")] - public string? ChangedWho { get; set; } - [Required] [Column("ECM_FK_ID")] [DefaultValue(0)] public int EcmFkId { get; set; } - - #region IGNORED COLUMNS - //[Column(TypeName = "datetime")] - //[DefaultValue("GETDATE()")] - //public DateTime? AddedWhen { get; set; } - - //[Column(TypeName = "datetime")] - //public DateTime? ChangedWhen { get; set; } - #endregion } } \ No newline at end of file