Compare commits

...

7 Commits

Author SHA1 Message Date
Developer 02
024aee1da8 chore: environment.prod.ts aktualisiert 2024-08-15 11:05:07 +02:00
Developer 02
c3001d1f52 feat: Löschbutton für Löschdienst hinzugefügt
- Einen Button hinzugefügt, um den Löschdienst auszulösen.
2024-08-15 11:00:00 +02:00
Developer 02
6299ac25e5 feat: Grundlegendes Gruppentabellenschema erstellt und als Standard festgelegt
- Schema für die grundlegende Gruppentabelle erstellt und als Standard festgelegt.
- Tabellenbreiten auf der Benutzerseite angepasst für ein verbessertes Layout.
2024-08-15 10:52:41 +02:00
Developer 02
08b9035083 feat: Automatische Aktualisierung nach Update und Fehlerbehandlung bei fehlgeschlagenen Updates
- Automatische Aktualisierung nach Update-Vorgängen implementiert.
- Fehlermeldungen für fehlgeschlagene Updates hinzugefügt.
2024-08-15 10:31:10 +02:00
Developer 02
3ed5ca0f00 refactor: Benutzer-DTOs und -Entitäten an die Datenbankstruktur angepasst 2024-08-15 09:42:36 +02:00
Developer 02
102c01b746 feat: add current user’s username as added_who in CreateAsync method 2024-08-14 20:53:38 +02:00
Developer 02
1375015275 refactor: Alle Controller außer Module und ModuleOfUser von BaseController vererbt
- Vererbung von BaseController auf alle Controller angewendet, mit Ausnahme von Module und ModuleOfUser.
2024-08-14 20:46:32 +02:00
21 changed files with 160 additions and 50 deletions

View File

@@ -23,7 +23,7 @@ export class AppComponent {
@HostListener('window:keydown.control.s', ['$event'])
protected handleCtrlS(event: KeyboardEvent) {
event.preventDefault();
this.updateService.executeAll();
this.updateService.executeAllAsync().then(() => this.refreshService.executeAll());
}
@HostListener('window:keydown.control.r', ['$event'])

View File

@@ -36,9 +36,12 @@
<button *ngIf="isLogedIn()" class="btn" (click)="this.updateService.toggleEditability()" [ngStyle]="{ 'visibility': updateService.isVisible ? 'visible' : 'hidden' }" matTooltip="strg + L" matTooltipPosition="below" [matTooltipDisabled]="!updateService.isVisible">
<mat-icon class="scale-pulse">{{ updateService.isEditable ? 'lock_open' : 'lock' }}</mat-icon>
</button>
<button *ngIf="isLogedIn()" class="btn" (click)="updateService.executeAll()" [ngStyle]="{ 'visibility': updateService.isVisible ? 'visible' : 'hidden' }" matTooltip="strg + S" matTooltipPosition="below" matTooltipClass="pt-3" [matTooltipDisabled]="!updateService.isVisible">
<button *ngIf="isLogedIn()" class="btn" (click)="saveAsync()" [ngStyle]="{ 'visibility': updateService.isVisible ? 'visible' : 'hidden' }" matTooltip="strg + S" matTooltipPosition="below" matTooltipClass="pt-3" [matTooltipDisabled]="!updateService.isVisible">
<mat-icon class="scale-pulse" [matBadge]="updateActCount === 0 ? '' : updateActCount">save</mat-icon>
</button>
<button *ngIf="isLogedIn()" class="btn" (click)="deletionService.executeAll()" [ngStyle]="{ 'visibility': updateService.isVisible ? 'visible' : 'hidden' }" matTooltip="entf" matTooltipPosition="below" matTooltipClass="pt-3" [matTooltipDisabled]="!updateService.isVisible">
<mat-icon class="scale-pulse" [matBadge]="updateActCount === 0 ? '' : updateActCount">delete_forever</mat-icon>
</button>
<button *ngIf="isLogedIn()" class="btn" (click)="transferService.executeAll()" [ngStyle]="{ 'visibility': transferService.isVisible ? 'visible' : 'hidden' }" matTooltip="strg + ␣" matTooltipPosition="below" [matTooltipDisabled]="!transferService.isVisible">
<mat-icon class="move-left-right">swap_horiz</mat-icon>
</button>

View File

@@ -8,6 +8,7 @@ import { ColorModeBttnComponent } from '../common/color-mode-bttn/color-mode-btt
import { MatIconModule } from '@angular/material/icon';
import { RefreshService } from '../../services/button/refresh.service';
import { CreationService } from '../../services/button/creation.service';
import { DeletionService } from '../../services/button/deletion.service';
import { ButtonVisibilityService } from '../../services/button/button-visibility.service';
import { UpdateService, UpdateEvent } from '../../services/button/update.service';
import { TransferService } from '../../services/button/transfer.service';
@@ -35,7 +36,7 @@ export class NavMenuComponent {
isChecked = true;
constructor(private dialog: MatDialog, private authService: AuthenticationService, public refreshService: RefreshService, public creationService: CreationService, public updateService: UpdateService, public transferService: TransferService, public buttonVisibilityService: ButtonVisibilityService) {
constructor(private dialog: MatDialog, private authService: AuthenticationService, public refreshService: RefreshService, public creationService: CreationService, public updateService: UpdateService, public transferService: TransferService, public buttonVisibilityService: ButtonVisibilityService, public deletionService: DeletionService) {
this.authService.isAuthenticated().then().catch()
this.updateActCount = this.updateService.totalCount;
this.updateService.addChangeListener(UpdateEvent.CountChange, () => {
@@ -90,4 +91,8 @@ export class NavMenuComponent {
}, 3000);
}
}
async saveAsync() {
await this.updateService.executeAllAsync().then(() => this.refreshService.executeAll())
}
}

View File

@@ -18,7 +18,7 @@ import { GroupOfUserService } from '../../../services/api/group-of-user.service'
})
export class GroupTableComponent extends BaseTableComponent<Group, GroupService> {
constructor(service: GroupService, cModeService: ColorModeService, private gouService: GroupOfUserService) {
super(service, env.columnNames.group.complete, cModeService)
super(service, env.columnNames.group.basic, cModeService)
}
fetchDataByUsername(username: string) {

View File

@@ -26,7 +26,7 @@ export class BasePageComponent {
this.refreshService.removeAll()
this.creationService.disposeComponent();
if (this.updateService.any) {
this.updateService.executeAll().then()
this.updateService.executeAllAsync().then()
}
if(this.transferService.any)
this.transferService.removeAll()

View File

@@ -3,7 +3,7 @@
<div class="col-7">
<mat-tab-group>
<mat-tab label="Gruppen">
<app-group-table #groupTable [onSelectedRows]="groupsOnSelectedRows" [cellEditing]="cellEditing"></app-group-table>
<app-group-table #groupTable [onSelectedRows]="groupsOnSelectedRows" [cellEditing]="cellEditing" [columns]="complete_group_cols"></app-group-table>
</mat-tab>
</mat-tab-group>
</div>

View File

@@ -8,6 +8,7 @@ import { BasePageComponent } from '../base-page/base-page.component';
import { Group } from '../../models/user-management.api.models';
import { firstValueFrom, forkJoin } from 'rxjs';
import Swal from 'sweetalert2';
import { env } from '../../../environments/environment';
@Component({
standalone: true,
@@ -72,7 +73,7 @@ export class GroupComponent extends BasePageComponent implements AfterViewInit {
const deleteRequests = sRows.map(sRow => this.groupTable.service.delete(sRow.source.id!));
forkJoin(deleteRequests).subscribe({
next: () => {
this.updateService.executeAll().then(() => {
this.updateService.executeAllAsync().then(() => {
this.refreshService.executeAll();
})
@@ -90,4 +91,8 @@ export class GroupComponent extends BasePageComponent implements AfterViewInit {
}
});
}
get complete_group_cols() {
return env.columnNames.group.complete
}
}

View File

@@ -1,6 +1,6 @@
<div class="container-fluid text-center">
<div class="row m-0 p-0">
<div class="col-6">
<div class="col-8">
<mat-tab-group>
<mat-tab label="Benutzer">
<app-user-table #userTable [onSelectedRows]="usersOnSelectedRows"
@@ -8,14 +8,14 @@
</mat-tab>
</mat-tab-group>
</div>
<div class="col-3">
<div class="col-2">
<mat-tab-group>
<mat-tab label="Gruppen">
<app-group-table #groupTable [initData]="initWithoutData"></app-group-table>
</mat-tab>
</mat-tab-group>
</div>
<div class="col-3">
<div class="col-2">
<mat-tab-group>
<mat-tab label="Module">
<app-module-table #moduleTable [initData]="initWithoutData"></app-module-table>

View File

@@ -81,7 +81,7 @@ export class UserComponent extends BasePageComponent implements AfterViewInit {
const deleteRequests = sRows.map(sRow => this.userTable.service.delete(sRow.source.id!));
forkJoin(deleteRequests).subscribe({
next: () => {
this.updateService.executeAll().then(() => {
this.updateService.executeAllAsync().then(() => {
this.refreshService.executeAll();
})
Swal.fire({

View File

@@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { BaseButtonService } from './base-button.service';
import Swal from 'sweetalert2';
@Injectable({
providedIn: 'root'
@@ -48,8 +49,17 @@ export class UpdateService extends BaseButtonService {
}
}
async executeAll(): Promise<void> {
await Promise.all(Object.values(this.async_actions).map(action => action()));
async executeAllAsync(): Promise<void> {
const count = { err: 0, succ: 0, get all() { return this.err + this.succ } }
await Promise.all(Object.values(this.async_actions).map(action => action().then(() => count.succ += 1).catch(() => count.err += 1)))
.then(() => {
if (count.err > 0)
Swal.fire({
icon: "info",
title: "Verarbeitungsfehler",
text: `Von ${count.all} Aktualisierungen wurden ${count.succ} erfolgreich durchgeführt, ${count.err} jedoch nicht. Der Fehler könnte durch den Versuch entstanden sein, persönliche Daten zu aktualisieren. Bitte überprüfen Sie dies.`,
})
});
Object.values(this.actions).forEach(action => action());
this.removeAll();
}

View File

@@ -16,24 +16,79 @@ export const env = {
loginCheck: "/auth/check"
},
columnNames: {
user: [
{
header: 'Benutzername',
field: 'username'
},
{
header: 'Vorname',
field: 'prename'
},
{
header: 'Name',
field: 'name'
},
{
header: 'E-email',
field: 'email'
}],
user: {
basic: [
{
header: 'Benutzername',
field: 'username'
},
{
header: 'Vorname',
field: 'prename'
},
{
header: 'Name',
field: 'name'
},
{
header: 'E-email',
field: 'email'
}
],
detailed: [
{
header: 'Benutzername',
field: 'username'
},
{
header: 'Vorname',
field: 'prename'
},
{
header: 'Name',
field: 'name'
},
{
header: 'E-email',
field: 'email'
},
{
header:'Kommentar',
field: 'comment'
},
{
header: 'DatumsFormat',
field: 'dateFormat'
},
{
header: 'Kürzel',
field: 'shortname'
},
{
header: 'Hinzugefügt<br>wer',
field: 'addedWho'
},
{
header: 'Hinzugefügt<br>wann',
field: 'addedWhen'
},
{
header: 'Geändert<br>wer',
field: 'changedWho'
},
{
header: 'Geändert<br>wann',
field: 'changedWhen'
}
]
},
group: {
basic: [
{
header: "Gruppe",
field: "name"
}
],
complete: [
{
header: "Gruppe",
@@ -42,6 +97,34 @@ export const env = {
{
header: "Kommentar",
field: "comment"
},
{
header: "Active",
field: (group: any) => group.active ? "✓" : ""
},
{
header: "AD Sync",
field: (group: any) => group.adSync ? "✓" : ""
},
{
header: "Internal",
field: (group: any) => group.internal ? "✓" : ""
},
{
header: 'Hinzugefügt<br>wer',
field: (g: any) => g.addedWho
},
{
header: 'Hinzugefügt<br>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<br>wer',
field: 'changedWho'
},
{
header: 'Geändert<br>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: [
@@ -117,4 +200,4 @@ export const env = {
]
},
config_url: "/assets/config.json"
};
};

View File

@@ -83,6 +83,12 @@ export const env = {
]
},
group: {
basic: [
{
header: "Gruppe",
field: "name"
}
],
complete: [
{
header: "Gruppe",

View File

@@ -1,4 +1,3 @@
using DigitalData.Core.API;
using DigitalData.Core.DTO;
using DigitalData.UserManager.Application.Contracts;
using DigitalData.UserManager.Application.DTOs.GroupOfUser;
@@ -9,9 +8,9 @@ using Microsoft.AspNetCore.Mvc;
namespace DigitalData.UserManager.API.Controllers
{
[Authorize]
public class GroupOfUserController : CRUDControllerBaseWithErrorHandling<IGroupOfUserService, GroupOfUserCreateDto, GroupOfUserReadDto, GroupOfUserUpdateDto, GroupOfUser, int>
public class GroupOfUserController : BaseAuthController<IGroupOfUserService, GroupOfUserCreateDto, GroupOfUserReadDto, GroupOfUserUpdateDto, GroupOfUser>
{
public GroupOfUserController(ILogger<GroupOfUserController> logger, IGroupOfUserService service) : base(logger, service)
public GroupOfUserController(ILogger<GroupOfUserController> logger, IGroupOfUserService service, IUserService userService) : base(logger, service, userService)
{
}

View File

@@ -9,9 +9,9 @@ using Microsoft.AspNetCore.Mvc;
namespace DigitalData.UserManager.API.Controllers
{
[Authorize]
public class UserController : CRUDControllerBaseWithErrorHandling<IUserService, UserCreateDto, UserReadDto, UserUpdateDto, User, int>
public class UserController : BaseAuthController<IUserService, UserCreateDto, UserReadDto, UserUpdateDto, User>
{
public UserController(ILogger<UserController> logger, IUserService service) : base(logger, service)
public UserController(ILogger<UserController> logger, IUserService service) : base(logger, service, service)
{
}

View File

@@ -1,18 +1,16 @@
using DigitalData.Core.API;
using DigitalData.Core.DTO;
using DigitalData.Core.DTO;
using DigitalData.UserManager.Application.Contracts;
using DigitalData.UserManager.Application.DTOs.UserRep;
using DigitalData.UserManager.Domain.Entities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
namespace DigitalData.UserManager.API.Controllers
{
[Authorize]
public class UserRepController : CRUDControllerBaseWithErrorHandling<IUserRepService, UserRepCreateDto, UserRepReadDto, UserRepUpdateDto, UserRep, int>
public class UserRepController : BaseAuthController<IUserRepService, UserRepCreateDto, UserRepReadDto, UserRepUpdateDto, UserRep>
{
public UserRepController(ILogger<UserRepController> logger, IUserRepService service) : base(logger, service)
public UserRepController(ILogger<UserRepController> logger, IUserRepService service, IUserService userService) : base(logger, service, userService)
{
}

View File

@@ -1,8 +1,6 @@
using DigitalData.Core.Abstractions.Application;
using DigitalData.UserManager.Application.DTOs.GroupOfUser;
using DigitalData.UserManager.Application.DTOs.GroupOfUser;
using DigitalData.UserManager.Domain.Entities;
using DigitalData.Core.DTO;
using DigitalData.UserManager.Application.Services;
namespace DigitalData.UserManager.Application.Contracts
{

View File

@@ -1,8 +1,6 @@
using DigitalData.Core.Abstractions.Application;
using DigitalData.UserManager.Application.DTOs.UserRep;
using DigitalData.UserManager.Application.DTOs.UserRep;
using DigitalData.UserManager.Domain.Entities;
using DigitalData.Core.DTO;
using DigitalData.UserManager.Application.Services;
namespace DigitalData.UserManager.Application.Contracts
{

View File

@@ -3,5 +3,7 @@
public record BaseUpdateDto()
{
public string ChangedWho { get; set; } = "UNAUTHORIZED";
public DateTime ChangedWhen { get; set; } = DateTime.Now;
}
}

View File

@@ -13,7 +13,6 @@ namespace DigitalData.UserManager.Application.DTOs.User
public string? Comment { get; init; }
public bool? Deleted { get; init; }
public string DateFormat { get; init; } = "dd.MM.yyyy";
public string? ChangedWho { get; init; }
public bool Active { get; init; } = true;
}
}

View File

@@ -13,6 +13,7 @@ namespace DigitalData.UserManager.Application.DTOs.User
string? Comment,
bool? Deleted,
string? DateFormat,
bool? Active
bool? Active,
string AddedWho
) : BaseUpdateDto();
}

View File

@@ -1,5 +1,4 @@
using AutoMapper;
using DigitalData.Core.Application;
using DigitalData.Core.DTO;
using DigitalData.UserManager.Application.Contracts;
using DigitalData.UserManager.Application.DTOs.User;
@@ -52,6 +51,10 @@ namespace DigitalData.UserManager.Application.Services
if (await HasEntity(user.Id))
return Result.Fail<int>().Message(_localizer[Key.UserAlreadyExists]);
//set the user
var current_user = await GetUserAsync();
user.AddedWho = current_user?.Username ?? "UNAUTHORIZED";
var createdUser = await _repository.CreateAsync(user);
if (createdUser is null)
return Result.Fail<int>();