Compare commits
9 Commits
c060cd9083
...
acfd9b4fb8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acfd9b4fb8 | ||
|
|
0f9ac0e637 | ||
|
|
0a8a5208a0 | ||
|
|
b1011c3ea2 | ||
|
|
11913ea667 | ||
|
|
ff6ebf300c | ||
|
|
7e05123fbf | ||
|
|
712932a0e2 | ||
|
|
a946ba871d |
@@ -2,7 +2,7 @@
|
|||||||
<div class="dd-row input-row">
|
<div class="dd-row input-row">
|
||||||
<mat-form-field class="w40p">
|
<mat-form-field class="w40p">
|
||||||
<mat-label>Geben Sie einen Datumsbereich ein</mat-label>
|
<mat-label>Geben Sie einen Datumsbereich ein</mat-label>
|
||||||
<mat-date-range-input [formGroup]="range" [rangePicker]="picker">
|
<mat-date-range-input [formGroup]="range" [rangePicker]="picker" [disabled]="termless">
|
||||||
<input matStartDate formControlName="start" placeholder="Start date">
|
<input matStartDate formControlName="start" placeholder="Start date">
|
||||||
<input matEndDate formControlName="end" placeholder="End date">
|
<input matEndDate formControlName="end" placeholder="End date">
|
||||||
</mat-date-range-input>
|
</mat-date-range-input>
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
<mat-error>Ungültiges Enddatum</mat-error>
|
<mat-error>Ungültiges Enddatum</mat-error>
|
||||||
}
|
}
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
<mat-slide-toggle [(ngModel)]="termless" class="w20p">
|
||||||
|
Unbefristet
|
||||||
|
</mat-slide-toggle>
|
||||||
<button mat-fab extended (click)="create()" class="w20p">
|
<button mat-fab extended (click)="create()" class="w20p">
|
||||||
<mat-icon>playlist_add</mat-icon>
|
<mat-icon>playlist_add</mat-icon>
|
||||||
Erstellen
|
Erstellen
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
.dd-row mat-form-field {
|
||||||
|
margin: 1rem 0rem 0rem 0rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dd-row mat-slide-toggle {
|
||||||
|
margin: 1rem 0rem 1rem 0rem;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { provideMomentDateAdapter } from '@angular/material-moment-adapter';
|
import { provideMomentDateAdapter } from '@angular/material-moment-adapter';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||||
import 'moment/locale/de';
|
import 'moment/locale/de';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -23,7 +24,7 @@ import 'moment/locale/de';
|
|||||||
{ provide: MAT_DATE_LOCALE, useValue: 'de-DE' },
|
{ provide: MAT_DATE_LOCALE, useValue: 'de-DE' },
|
||||||
provideMomentDateAdapter()
|
provideMomentDateAdapter()
|
||||||
],
|
],
|
||||||
imports: [MatFormFieldModule, MatDatepickerModule, FormsModule, ReactiveFormsModule, JsonPipe, MatButtonModule, MatIconModule, MatInputModule],
|
imports: [MatFormFieldModule, MatDatepickerModule, FormsModule, ReactiveFormsModule, JsonPipe, MatButtonModule, MatIconModule, MatInputModule, MatSlideToggleModule],
|
||||||
templateUrl: './rep-create-form.component.html',
|
templateUrl: './rep-create-form.component.html',
|
||||||
styleUrl: './rep-create-form.component.scss',
|
styleUrl: './rep-create-form.component.scss',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
@@ -41,6 +42,7 @@ export class RepCreateFormComponent implements OnInit {
|
|||||||
private readonly _locale = signal(inject<unknown>(MAT_DATE_LOCALE));
|
private readonly _locale = signal(inject<unknown>(MAT_DATE_LOCALE));
|
||||||
private readonly _adapter = inject<DateAdapter<unknown, unknown>>(DateAdapter);
|
private readonly _adapter = inject<DateAdapter<unknown, unknown>>(DateAdapter);
|
||||||
private readonly _intl = inject(MatDatepickerIntl);
|
private readonly _intl = inject(MatDatepickerIntl);
|
||||||
|
termless: boolean = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const dialogData: { userRep: UserRep, afterCreation: (any: any) => any } = inject(MAT_DIALOG_DATA)
|
const dialogData: { userRep: UserRep, afterCreation: (any: any) => any } = inject(MAT_DIALOG_DATA)
|
||||||
@@ -68,19 +70,21 @@ export class RepCreateFormComponent implements OnInit {
|
|||||||
create() {
|
create() {
|
||||||
const validFrom = this.range.value.start;
|
const validFrom = this.range.value.start;
|
||||||
const validTo = this.range.value.end;
|
const validTo = this.range.value.end;
|
||||||
|
|
||||||
if (!validFrom || !validTo) {
|
if ((!validFrom || !validTo) && !this.termless) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
icon: "error",
|
icon: "error",
|
||||||
title: "Oops...",
|
title: "Oops...",
|
||||||
text: "Bitte geben Sie einen gültigen Datumsbereich ein!",
|
text: "Bitte geben Sie einen gültigen Datumsbereich ein oder wählen Sie unbefristet!",
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.userRep.validFrom = validFrom!;
|
if (!this.termless) {
|
||||||
this.userRep.validTo = validTo!;
|
this.userRep.validFrom = validFrom!;
|
||||||
|
this.userRep.validTo = validTo!;
|
||||||
|
}
|
||||||
|
|
||||||
this.userRepService.create(this.userRep).subscribe({
|
this.userRepService.create(this.userRep).subscribe({
|
||||||
next: (res) => {
|
next: (res) => {
|
||||||
|
|||||||
@@ -13,5 +13,7 @@
|
|||||||
[infoPanel]="infoPanel"
|
[infoPanel]="infoPanel"
|
||||||
[titlePanel]="titlePanel"
|
[titlePanel]="titlePanel"
|
||||||
[theme]="theme"
|
[theme]="theme"
|
||||||
|
[rowStyle] = "rowStyle"
|
||||||
|
[rowClass] = "rowClass"
|
||||||
(selectedRows)="onSelectedRows($event)">
|
(selectedRows)="onSelectedRows($event)">
|
||||||
</gui-grid>
|
</gui-grid>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component, Inject, Input, OnDestroy, OnInit, ViewChild, input } from '@angular/core';
|
import { Component, Inject, Input, OnDestroy, OnInit, ViewChild, input } from '@angular/core';
|
||||||
import { ApiService } from '../../../services/api/user-management.api.service';
|
import { ApiService } from '../../../services/api/user-management.api.service';
|
||||||
import { GuiGridModule, GuiColumn, GuiColumnMenu, GuiSorting, GuiRowDetail, GuiPaging, GuiPagingDisplay, GuiSearching, GuiCellEdit, GuiInfoPanel, GuiTitlePanel, GuiRowSelection, GuiSelectedRow, GuiGridComponent, GuiGridApi, GuiTheme } from '@generic-ui/ngx-grid';
|
import { GuiGridModule, GuiColumn, GuiColumnMenu, GuiSorting, GuiRowDetail, GuiPaging, GuiPagingDisplay, GuiSearching, GuiCellEdit, GuiInfoPanel, GuiTitlePanel, GuiRowSelection, GuiSelectedRow, GuiGridComponent, GuiGridApi, GuiTheme, GuiRowStyle, GuiRowClass } from '@generic-ui/ngx-grid';
|
||||||
import { Subscription } from 'rxjs/internal/Subscription';
|
import { Subscription } from 'rxjs/internal/Subscription';
|
||||||
import { ColorModeService, Theme } from '../../../services/button/color-mode.service';
|
import { ColorModeService, Theme } from '../../../services/button/color-mode.service';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
@@ -8,7 +8,7 @@ import { FormsModule } from '@angular/forms';
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, FormsModule, GuiGridModule ],
|
imports: [CommonModule, FormsModule, GuiGridModule],
|
||||||
selector: 'app-base-table',
|
selector: 'app-base-table',
|
||||||
templateUrl: './base-table.component.html',
|
templateUrl: './base-table.component.html',
|
||||||
styleUrl: './base-table.component.css'
|
styleUrl: './base-table.component.css'
|
||||||
@@ -111,6 +111,10 @@ export class BaseTableComponent<TModel, TApiService extends ApiService<TModel>>
|
|||||||
|
|
||||||
@Input() columns: Array<GuiColumn> = [];
|
@Input() columns: Array<GuiColumn> = [];
|
||||||
|
|
||||||
|
@Input() rowStyle: GuiRowStyle = {}
|
||||||
|
|
||||||
|
@Input() rowClass: GuiRowClass = {}
|
||||||
|
|
||||||
selected: boolean = false;
|
selected: boolean = false;
|
||||||
safelyUnselectAll() {
|
safelyUnselectAll() {
|
||||||
this.selected = true
|
this.selected = true
|
||||||
|
|||||||
@@ -46,9 +46,10 @@ export class UserRepresentationComponent extends BasePageComponent implements Af
|
|||||||
this.refreshService.removeAll();
|
this.refreshService.removeAll();
|
||||||
this.refreshService.add(() => {
|
this.refreshService.add(() => {
|
||||||
this.users.fetchData();
|
this.users.fetchData();
|
||||||
|
this.groups.fetchData();
|
||||||
this.repUsers.fetchData();
|
this.repUsers.fetchData();
|
||||||
this.repGroups.fetchData();
|
this.repGroups.fetchData();
|
||||||
this.groups.fetchData();
|
this.userReps.fetchData();
|
||||||
})
|
})
|
||||||
this.transferService.add(() => {
|
this.transferService.add(() => {
|
||||||
this.repUsers.safelyUnselectAll();
|
this.repUsers.safelyUnselectAll();
|
||||||
@@ -103,9 +104,7 @@ export class UserRepresentationComponent extends BasePageComponent implements Af
|
|||||||
var newUserRep: UserRep = {
|
var newUserRep: UserRep = {
|
||||||
userId: this.slUserId,
|
userId: this.slUserId,
|
||||||
groupId: this.slGroupId,
|
groupId: this.slGroupId,
|
||||||
repUserId: this.slRepUserId,
|
repUserId: this.slRepUserId
|
||||||
validFrom: new Date(),
|
|
||||||
validTo: new Date(new Date().setDate(new Date().getDate() + 7))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.openCreateSheet(newUserRep, res => {
|
this.openCreateSheet(newUserRep, res => {
|
||||||
|
|||||||
@@ -165,6 +165,14 @@ export const env = {
|
|||||||
header: "Repr. Benutzer",
|
header: "Repr. Benutzer",
|
||||||
field: (ur: any) => ur.repUser?.username
|
field: (ur: any) => ur.repUser?.username
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
header: "Gültig von",
|
||||||
|
field: (ur: any) => ur.validFrom ? new Date(ur.validFrom).toLocaleDateString('de-DE') : ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "Gültig bis",
|
||||||
|
field: (ur: any) => ur.validTo ? new Date(ur.validTo).toLocaleDateString('de-DE') : ""
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
config_url: "/assets/config.json",
|
config_url: "/assets/config.json",
|
||||||
|
|||||||
@@ -167,11 +167,11 @@ export const env = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: "Gültig von",
|
header: "Gültig von",
|
||||||
field: (ur: any) => new Date(ur.validFrom).toLocaleDateString('de-DE')
|
field: (ur: any) => ur.validFrom ? new Date(ur.validFrom).toLocaleDateString('de-DE') : ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: "Gültig bis",
|
header: "Gültig bis",
|
||||||
field: (ur: any) => new Date(ur.validTo).toLocaleDateString('de-DE')
|
field: (ur: any) => ur.validTo ? new Date(ur.validTo).toLocaleDateString('de-DE') : ""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -196,4 +196,4 @@ export const env = {
|
|||||||
{ value: "en-US", name: "en-US" }
|
{ value: "en-US", name: "en-US" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -67,6 +67,7 @@ code {
|
|||||||
|
|
||||||
.input-row {
|
.input-row {
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-row {
|
.button-row {
|
||||||
@@ -102,4 +103,4 @@ code {
|
|||||||
.w#{$i * 5}p {
|
.w#{$i * 5}p {
|
||||||
width: #{$i * 5 + "%"} !important;
|
width: #{$i * 5 + "%"} !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ try {
|
|||||||
.AndIf(c => !config.GetValue<bool>("UseEncryptor")));
|
.AndIf(c => !config.GetValue<bool>("UseEncryptor")));
|
||||||
}).AddNewtonsoftJson(options =>
|
}).AddNewtonsoftJson(options =>
|
||||||
{
|
{
|
||||||
options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
|
options.SerializerSettings.DateTimeZoneHandling = config.GetValue<DateTimeZoneHandling>("DateTimeZoneHandling");
|
||||||
});
|
});
|
||||||
|
|
||||||
if (builder.Configuration.GetValue<bool>("UseSwagger"))
|
if (builder.Configuration.GetValue<bool>("UseSwagger"))
|
||||||
|
|||||||
@@ -72,6 +72,7 @@
|
|||||||
"IV": "gMuetIjlPvJnSzu+i7I3xg=="
|
"IV": "gMuetIjlPvJnSzu+i7I3xg=="
|
||||||
},
|
},
|
||||||
"AllowedGroupName": "UM_ADMINS",
|
"AllowedGroupName": "UM_ADMINS",
|
||||||
|
"DateTimeZoneHandling": "Local",
|
||||||
// Delete below in production
|
// Delete below in production
|
||||||
"UseEncryptor": true,
|
"UseEncryptor": true,
|
||||||
"UseSwagger": true
|
"UseSwagger": true
|
||||||
|
|||||||
@@ -8,5 +8,7 @@
|
|||||||
public static readonly string UserAlreadyExists = "UserAlreadyExists";
|
public static readonly string UserAlreadyExists = "UserAlreadyExists";
|
||||||
public static readonly string UserNotFound = "UserNotFound";
|
public static readonly string UserNotFound = "UserNotFound";
|
||||||
public static readonly string UnauthorizedUser = "UnauthorizedUser";
|
public static readonly string UnauthorizedUser = "UnauthorizedUser";
|
||||||
|
public static readonly string DateRangeNotXNOR = "DateRangeNotXNOR";
|
||||||
|
public static readonly string InvalidDateRange = "InvalidDateRange";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,13 +5,16 @@ using DigitalData.UserManager.Application.DTOs.UserRep;
|
|||||||
using DigitalData.UserManager.Domain.Entities;
|
using DigitalData.UserManager.Domain.Entities;
|
||||||
using DigitalData.UserManager.Infrastructure.Contracts;
|
using DigitalData.UserManager.Infrastructure.Contracts;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace DigitalData.UserManager.Application.Services
|
namespace DigitalData.UserManager.Application.Services
|
||||||
{
|
{
|
||||||
public class UserRepService : BaseService<IUserRepRepository, UserRepCreateDto, UserRepReadDto, UserRepUpdateDto, UserRep>, IUserRepService
|
public class UserRepService : BaseService<IUserRepRepository, UserRepCreateDto, UserRepReadDto, UserRepUpdateDto, UserRep>, IUserRepService
|
||||||
{
|
{
|
||||||
|
private readonly IStringLocalizer<Resource> _localizer;
|
||||||
public UserRepService(IUserRepRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper) : base(repository, mapper)
|
public UserRepService(IUserRepRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper) : base(repository, mapper)
|
||||||
{
|
{
|
||||||
|
_localizer = localizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<DataResult<IEnumerable<UserRepReadDto>>> ReadAllAsync(bool withUser = false, bool withRepGroup = false, bool withGroup = false, bool withRepUser = false, int? userId = null, int? groupId = null)
|
public async Task<DataResult<IEnumerable<UserRepReadDto>>> ReadAllAsync(bool withUser = false, bool withRepGroup = false, bool withGroup = false, bool withRepUser = false, int? userId = null, int? groupId = null)
|
||||||
@@ -20,5 +23,14 @@ namespace DigitalData.UserManager.Application.Services
|
|||||||
var urReadDTOs = _mapper.Map<IEnumerable<UserRepReadDto>>(urs);
|
var urReadDTOs = _mapper.Map<IEnumerable<UserRepReadDto>>(urs);
|
||||||
return Result.Success(urReadDTOs);
|
return Result.Success(urReadDTOs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task<DataResult<int>> CreateAsync(UserRepCreateDto createDto)
|
||||||
|
// XOR control
|
||||||
|
=> (createDto.ValidFrom is null && createDto.ValidTo is not null) || (createDto.ValidFrom is not null && createDto.ValidTo is null)
|
||||||
|
? Result.Fail<int>().Notice(LogLevel.None, Flag.DataIntegrityIssue, _localizer[Key.DateRangeNotXNOR])
|
||||||
|
//date range control
|
||||||
|
: (createDto.ValidFrom > createDto.ValidTo)
|
||||||
|
? Result.Fail<int>().Notice(LogLevel.None, Flag.DataIntegrityIssue, _localizer[Key.InvalidDateRange])
|
||||||
|
: await base.CreateAsync(createDto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,13 +18,11 @@ namespace DigitalData.UserManager.Domain.Entities
|
|||||||
[Column("REPR_USER")]
|
[Column("REPR_USER")]
|
||||||
public int? RepUserId { get; set; }
|
public int? RepUserId { get; set; }
|
||||||
|
|
||||||
[Required]
|
|
||||||
[Column("VALID_FROM")]
|
[Column("VALID_FROM")]
|
||||||
public required DateTime? ValidFrom { get; set; }
|
public DateTime? ValidFrom { get; set; }
|
||||||
|
|
||||||
[Required]
|
|
||||||
[Column("VALID_TO")]
|
[Column("VALID_TO")]
|
||||||
public required DateTime? ValidTo { get; set; }
|
public DateTime? ValidTo { get; set; }
|
||||||
|
|
||||||
[ForeignKey("UserId")]
|
[ForeignKey("UserId")]
|
||||||
public virtual User? User { get; set; }
|
public virtual User? User { get; set; }
|
||||||
|
|||||||
Reference in New Issue
Block a user