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">
|
||||
<mat-form-field class="w40p">
|
||||
<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 matEndDate formControlName="end" placeholder="End date">
|
||||
</mat-date-range-input>
|
||||
@@ -17,6 +17,9 @@
|
||||
<mat-error>Ungültiges Enddatum</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<mat-slide-toggle [(ngModel)]="termless" class="w20p">
|
||||
Unbefristet
|
||||
</mat-slide-toggle>
|
||||
<button mat-fab extended (click)="create()" class="w20p">
|
||||
<mat-icon>playlist_add</mat-icon>
|
||||
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 { provideMomentDateAdapter } from '@angular/material-moment-adapter';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import 'moment/locale/de';
|
||||
|
||||
@Component({
|
||||
@@ -23,7 +24,7 @@ import 'moment/locale/de';
|
||||
{ provide: MAT_DATE_LOCALE, useValue: 'de-DE' },
|
||||
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',
|
||||
styleUrl: './rep-create-form.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
@@ -41,6 +42,7 @@ export class RepCreateFormComponent implements OnInit {
|
||||
private readonly _locale = signal(inject<unknown>(MAT_DATE_LOCALE));
|
||||
private readonly _adapter = inject<DateAdapter<unknown, unknown>>(DateAdapter);
|
||||
private readonly _intl = inject(MatDatepickerIntl);
|
||||
termless: boolean = false;
|
||||
|
||||
constructor() {
|
||||
const dialogData: { userRep: UserRep, afterCreation: (any: any) => any } = inject(MAT_DIALOG_DATA)
|
||||
@@ -68,19 +70,21 @@ export class RepCreateFormComponent implements OnInit {
|
||||
create() {
|
||||
const validFrom = this.range.value.start;
|
||||
const validTo = this.range.value.end;
|
||||
|
||||
if (!validFrom || !validTo) {
|
||||
|
||||
if ((!validFrom || !validTo) && !this.termless) {
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
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;
|
||||
}
|
||||
|
||||
this.userRep.validFrom = validFrom!;
|
||||
this.userRep.validTo = validTo!;
|
||||
if (!this.termless) {
|
||||
this.userRep.validFrom = validFrom!;
|
||||
this.userRep.validTo = validTo!;
|
||||
}
|
||||
|
||||
this.userRepService.create(this.userRep).subscribe({
|
||||
next: (res) => {
|
||||
|
||||
@@ -13,5 +13,7 @@
|
||||
[infoPanel]="infoPanel"
|
||||
[titlePanel]="titlePanel"
|
||||
[theme]="theme"
|
||||
[rowStyle] = "rowStyle"
|
||||
[rowClass] = "rowClass"
|
||||
(selectedRows)="onSelectedRows($event)">
|
||||
</gui-grid>
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, Inject, Input, OnDestroy, OnInit, ViewChild, input } from '@angular/core';
|
||||
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 { ColorModeService, Theme } from '../../../services/button/color-mode.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
@@ -8,7 +8,7 @@ import { FormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [CommonModule, FormsModule, GuiGridModule ],
|
||||
imports: [CommonModule, FormsModule, GuiGridModule],
|
||||
selector: 'app-base-table',
|
||||
templateUrl: './base-table.component.html',
|
||||
styleUrl: './base-table.component.css'
|
||||
@@ -111,6 +111,10 @@ export class BaseTableComponent<TModel, TApiService extends ApiService<TModel>>
|
||||
|
||||
@Input() columns: Array<GuiColumn> = [];
|
||||
|
||||
@Input() rowStyle: GuiRowStyle = {}
|
||||
|
||||
@Input() rowClass: GuiRowClass = {}
|
||||
|
||||
selected: boolean = false;
|
||||
safelyUnselectAll() {
|
||||
this.selected = true
|
||||
|
||||
@@ -46,9 +46,10 @@ export class UserRepresentationComponent extends BasePageComponent implements Af
|
||||
this.refreshService.removeAll();
|
||||
this.refreshService.add(() => {
|
||||
this.users.fetchData();
|
||||
this.groups.fetchData();
|
||||
this.repUsers.fetchData();
|
||||
this.repGroups.fetchData();
|
||||
this.groups.fetchData();
|
||||
this.userReps.fetchData();
|
||||
})
|
||||
this.transferService.add(() => {
|
||||
this.repUsers.safelyUnselectAll();
|
||||
@@ -103,9 +104,7 @@ export class UserRepresentationComponent extends BasePageComponent implements Af
|
||||
var newUserRep: UserRep = {
|
||||
userId: this.slUserId,
|
||||
groupId: this.slGroupId,
|
||||
repUserId: this.slRepUserId,
|
||||
validFrom: new Date(),
|
||||
validTo: new Date(new Date().setDate(new Date().getDate() + 7))
|
||||
repUserId: this.slRepUserId
|
||||
}
|
||||
|
||||
this.openCreateSheet(newUserRep, res => {
|
||||
|
||||
@@ -165,6 +165,14 @@ export const env = {
|
||||
header: "Repr. Benutzer",
|
||||
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",
|
||||
|
||||
@@ -167,11 +167,11 @@ export const env = {
|
||||
},
|
||||
{
|
||||
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",
|
||||
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" }
|
||||
]
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -67,6 +67,7 @@ code {
|
||||
|
||||
.input-row {
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.button-row {
|
||||
@@ -102,4 +103,4 @@ code {
|
||||
.w#{$i * 5}p {
|
||||
width: #{$i * 5 + "%"} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ try {
|
||||
.AndIf(c => !config.GetValue<bool>("UseEncryptor")));
|
||||
}).AddNewtonsoftJson(options =>
|
||||
{
|
||||
options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
|
||||
options.SerializerSettings.DateTimeZoneHandling = config.GetValue<DateTimeZoneHandling>("DateTimeZoneHandling");
|
||||
});
|
||||
|
||||
if (builder.Configuration.GetValue<bool>("UseSwagger"))
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
"IV": "gMuetIjlPvJnSzu+i7I3xg=="
|
||||
},
|
||||
"AllowedGroupName": "UM_ADMINS",
|
||||
"DateTimeZoneHandling": "Local",
|
||||
// Delete below in production
|
||||
"UseEncryptor": true,
|
||||
"UseSwagger": true
|
||||
|
||||
@@ -8,5 +8,7 @@
|
||||
public static readonly string UserAlreadyExists = "UserAlreadyExists";
|
||||
public static readonly string UserNotFound = "UserNotFound";
|
||||
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.Infrastructure.Contracts;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Services
|
||||
{
|
||||
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)
|
||||
{
|
||||
_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)
|
||||
@@ -20,5 +23,14 @@ namespace DigitalData.UserManager.Application.Services
|
||||
var urReadDTOs = _mapper.Map<IEnumerable<UserRepReadDto>>(urs);
|
||||
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")]
|
||||
public int? RepUserId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("VALID_FROM")]
|
||||
public required DateTime? ValidFrom { get; set; }
|
||||
public DateTime? ValidFrom { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("VALID_TO")]
|
||||
public required DateTime? ValidTo { get; set; }
|
||||
public DateTime? ValidTo { get; set; }
|
||||
|
||||
[ForeignKey("UserId")]
|
||||
public virtual User? User { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user