Compare commits
108 Commits
ae14f5842e
...
feat/authF
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1155cb406 | ||
|
|
9ae3345859 | ||
|
|
a4e4883d6b | ||
|
|
9f6acfb8d3 | ||
|
|
be78947b48 | ||
|
|
b2e64e794c | ||
|
|
d6b82cf085 | ||
|
|
6cd72fe755 | ||
|
|
8d0beab709 | ||
|
|
52871f006d | ||
|
|
ac064f4671 | ||
|
|
2d792c8544 | ||
|
|
239a5708a7 | ||
|
|
23283a6846 | ||
|
|
7d317308d5 | ||
|
|
2aab942563 | ||
|
|
054c91609e | ||
|
|
5c097eda80 | ||
|
|
d228a3cd50 | ||
|
|
0786013bd0 | ||
|
|
beabc3f4e0 | ||
|
|
44560e7057 | ||
|
|
2098a7d48d | ||
|
|
140f172369 | ||
|
|
b3e7c1aa99 | ||
|
|
0d4436b061 | ||
|
|
b88fd78367 | ||
|
|
7670f2119e | ||
|
|
a142196d87 | ||
|
|
59e8c6c0c6 | ||
|
|
3cf1215a1c | ||
|
|
81c00401b7 | ||
|
|
e86b42d955 | ||
|
|
80d28e12b9 | ||
|
|
7fc71f427b | ||
|
|
bd7d521c1e | ||
|
|
33326866f9 | ||
|
|
fbf9bbeba0 | ||
|
|
b7f8ea1e8e | ||
|
|
6fc8bdc964 | ||
|
|
b3d46aaf30 | ||
|
|
2870f0e18e | ||
|
|
337a0b892e | ||
|
|
2e1bf69889 | ||
|
|
0657bbe2c4 | ||
|
|
acfd9b4fb8 | ||
|
|
0f9ac0e637 | ||
|
|
0a8a5208a0 | ||
|
|
b1011c3ea2 | ||
|
|
11913ea667 | ||
|
|
ff6ebf300c | ||
|
|
7e05123fbf | ||
|
|
712932a0e2 | ||
|
|
a946ba871d | ||
|
|
c060cd9083 | ||
|
|
371967380b | ||
|
|
7316343658 | ||
|
|
31c8249516 | ||
|
|
114995d274 | ||
|
|
e8376ccd21 | ||
|
|
52e6eac71d | ||
|
|
36c55b6382 | ||
|
|
c73b299e3e | ||
|
|
968ff8349f | ||
|
|
770921011a | ||
|
|
a9bc4f90ac | ||
|
|
6e5ba82869 | ||
|
|
fb3dedadc5 | ||
|
|
8cf2183cd6 | ||
|
|
881d2ccac8 | ||
|
|
deacd1a8c6 | ||
|
|
616862391e | ||
|
|
296f29cf82 | ||
|
|
5df5cc555a | ||
|
|
b3131637ab | ||
|
|
4d9a766864 | ||
|
|
01bc5a4425 | ||
|
|
be07f16d63 | ||
|
|
671500b3a5 | ||
|
|
1be71a42e5 | ||
|
|
6319d22ba9 | ||
|
|
5551610dff | ||
|
|
b997ea4cce | ||
|
|
1b5fa1f52c | ||
|
|
5f4a8e373c | ||
|
|
91b78f4b59 | ||
|
|
3749b5ee97 | ||
|
|
ab6c843248 | ||
|
|
b6bc97df07 | ||
|
|
44a017ad9e | ||
|
|
faac31b3bb | ||
|
|
2800392be3 | ||
|
|
b7f4ed7597 | ||
|
|
16cc729373 | ||
|
|
4d38cce459 | ||
|
|
80a3f96404 | ||
|
|
2a4358a7c7 | ||
|
|
978d8aaa55 | ||
|
|
ae729198b9 | ||
|
|
76f57676b1 | ||
|
|
97cefb3fea | ||
|
|
1273b7ac46 | ||
|
|
4c02607409 | ||
|
|
9f99bb0bc9 | ||
|
|
e80ec2cf8d | ||
|
|
25995e8d48 | ||
|
|
9e11463ef2 | ||
|
|
622cb1f702 |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
12
DigitalData.UserManager.API/.config/dotnet-tools.json
Normal file
12
DigitalData.UserManager.API/.config/dotnet-tools.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "9.0.3",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
"@angular/core": "^17.3.0",
|
||||
"@angular/forms": "^17.3.0",
|
||||
"@angular/material": "^17.3.10",
|
||||
"@angular/material-moment-adapter": "^17.3.10",
|
||||
"@angular/platform-browser": "^17.3.0",
|
||||
"@angular/platform-browser-dynamic": "^17.3.0",
|
||||
"@angular/platform-server": "^17.3.0",
|
||||
@@ -542,6 +543,19 @@
|
||||
"rxjs": "^6.5.3 || ^7.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/material-moment-adapter": {
|
||||
"version": "17.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-17.3.10.tgz",
|
||||
"integrity": "sha512-R68ssdGMSmVIfpOGaB9vjW5lBh6zH9GboBuaIAqizC/ZAzdEgpmT7qdr3PBCmRPTLTx8Yx9K3rhgRekO79ympw==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/core": "^17.0.0 || ^18.0.0",
|
||||
"@angular/material": "17.3.10",
|
||||
"moment": "^2.18.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/platform-browser": {
|
||||
"version": "17.3.11",
|
||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.3.11.tgz",
|
||||
@@ -9453,6 +9467,15 @@
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/mrmime": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "user-manager-ui",
|
||||
"version": "0.0.0",
|
||||
"version": "4.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --ssl -o",
|
||||
"build": "ng build",
|
||||
"build": "ng build --configuration production",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"serve:ssr:user_manager_ui": "node dist/user_manager_ui/server/server.mjs"
|
||||
@@ -18,6 +18,7 @@
|
||||
"@angular/core": "^17.3.0",
|
||||
"@angular/forms": "^17.3.0",
|
||||
"@angular/material": "^17.3.10",
|
||||
"@angular/material-moment-adapter": "^17.3.10",
|
||||
"@angular/platform-browser": "^17.3.0",
|
||||
"@angular/platform-browser-dynamic": "^17.3.0",
|
||||
"@angular/platform-server": "^17.3.0",
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<div class="dd-container">
|
||||
<!-- id, name -->
|
||||
<div class="dd-row input-row">
|
||||
<mat-form-field class="w20p">
|
||||
<mat-label>Id</mat-label>
|
||||
<input matInput readonly [value]="group.id" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w80p">
|
||||
<mat-label>Gruppe</mat-label>
|
||||
<input matInput [formControl]="name" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<!-- comment -->
|
||||
<div class="dd-row input-row">
|
||||
<mat-form-field>
|
||||
<mat-label>Kommentar</mat-label>
|
||||
<textarea matInput [formControl]="comment"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<!-- active, internal, async -->
|
||||
<div class="dd-row input-row">
|
||||
<mat-slide-toggle [(ngModel)]="group.active">
|
||||
Aktiv
|
||||
</mat-slide-toggle>
|
||||
<mat-slide-toggle [(ngModel)]="group.internal" disabled>
|
||||
Interne Gruppe
|
||||
</mat-slide-toggle>
|
||||
<mat-slide-toggle [(ngModel)]="group.adSync" disabled>
|
||||
Mit Active Directory
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
<!-- addedWho, addedWhen, changedWho and changedWhen -->
|
||||
<div class="dd-row input-row">
|
||||
<mat-form-field>
|
||||
<mat-label>Hinzugefügt wer</mat-label>
|
||||
<input matInput readonly [value]="group.addedWho" />
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Hinzugefügt wann</mat-label>
|
||||
<input matInput readonly [value]="group.addedWhen | date:'dd.MM.yyyy'" />
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Geändert wer</mat-label>
|
||||
<input matInput readonly [value]="group.changedWho" />
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Geändert wann</mat-label>
|
||||
<input matInput readonly [value]="group.changedWhen | date:'dd.MM.yyyy'" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<!-- save-button, delete-button -->
|
||||
<div class="dd-row button-row">
|
||||
<button mat-fab extended (click)="update()">
|
||||
<mat-icon>save</mat-icon>
|
||||
Speichern
|
||||
</button>
|
||||
<button mat-fab extended (click)="delete()">
|
||||
<mat-icon>delete</mat-icon>
|
||||
Löschen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GroupUpdateFormComponent } from './group-update-form.component';
|
||||
|
||||
describe('GroupUpdateFormComponent', () => {
|
||||
let component: GroupUpdateFormComponent;
|
||||
let fixture: ComponentFixture<GroupUpdateFormComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [GroupUpdateFormComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GroupUpdateFormComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,103 @@
|
||||
import { Component, inject, signal } from '@angular/core';
|
||||
import { Group } from '../../../models/user-management.api.models';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { GroupService } from '../../../services/api/group.service';
|
||||
import { RefreshService } from '../../../services/button/refresh.service';
|
||||
import Swal from 'sweetalert2';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { env } from '../../../../environments/environment'
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
|
||||
@Component({
|
||||
selector: 'app-group-update-form',
|
||||
standalone: true,
|
||||
imports: [MatFormFieldModule, MatInputModule, FormsModule, ReactiveFormsModule, MatIconModule, MatButtonModule, CommonModule, MatTabsModule, MatSelectModule, MatDividerModule, MatCheckboxModule, MatSlideToggleModule],
|
||||
templateUrl: './group-update-form.component.html',
|
||||
styleUrl: './group-update-form.component.scss'
|
||||
})
|
||||
export class GroupUpdateFormComponent {
|
||||
|
||||
readonly dialogRef: MatDialogRef<GroupUpdateFormComponent> = inject(MatDialogRef<GroupUpdateFormComponent>);
|
||||
|
||||
readonly group: Group = inject(MAT_DIALOG_DATA);
|
||||
|
||||
get allowedDateFormats(): Array<{ value: string, name: string }> {
|
||||
return env.constants.date_formats;
|
||||
}
|
||||
|
||||
get allowedLanguages(): Array<{ value: string, name: string }> {
|
||||
return env.constants.languages;
|
||||
}
|
||||
|
||||
readonly name = new FormControl(this.group.name);
|
||||
readonly comment = new FormControl(this.group.comment);
|
||||
|
||||
mailErrorMessage = signal('');
|
||||
errorMessage = signal('');
|
||||
|
||||
constructor(private uService: GroupService, private rService: RefreshService) {
|
||||
}
|
||||
|
||||
update() {
|
||||
|
||||
this.group.name = this.name.value!;
|
||||
this.group.comment = this.comment.value!;
|
||||
|
||||
this.uService.update(this.group).subscribe({
|
||||
next: () => {
|
||||
this.rService.executeAll();
|
||||
},
|
||||
error: err => {
|
||||
console.error(err)
|
||||
Swal.fire({
|
||||
title: "Interner Dienstfehler",
|
||||
text: "Bitte wenden Sie sich an das IT-Team, um den Fehler zu beheben.",
|
||||
icon: "error"
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
delete() {
|
||||
Swal.fire({
|
||||
text: "Sind Sie sicher, dass Sie diesen Datensatz löschen wollen?",
|
||||
icon: "question",
|
||||
showDenyButton: true,
|
||||
confirmButtonText: "Ja",
|
||||
denyButtonText: `Nein`
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
if (this.group.id) {
|
||||
this.uService.delete(this.group.id).subscribe({
|
||||
next: () => {
|
||||
this.rService.executeAll();
|
||||
this.dialogRef.close();
|
||||
},
|
||||
error: err => {
|
||||
Swal.fire({
|
||||
title: "Interner Dienstfehler",
|
||||
text: "Bitte wenden Sie sich an das IT-Team, um den Fehler zu beheben.",
|
||||
icon: "error"
|
||||
});
|
||||
},
|
||||
})
|
||||
}
|
||||
else
|
||||
Swal.fire({
|
||||
title: "Ein unerwarteter Fehler",
|
||||
text: "Die Benutzer-ID existiert nicht (Nullwert).",
|
||||
icon: "error"
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<div class="dd-container">
|
||||
<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" [disabled]="termless">
|
||||
<input matStartDate formControlName="start" placeholder="Start date">
|
||||
<input matEndDate formControlName="end" placeholder="End date">
|
||||
</mat-date-range-input>
|
||||
<mat-hint>{{dateFormatString()}}</mat-hint>
|
||||
<mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle>
|
||||
<mat-date-range-picker #picker></mat-date-range-picker>
|
||||
|
||||
@if (range.controls.start.hasError('matStartDateInvalid')) {
|
||||
<mat-error>Ungültiges Startdatum</mat-error>
|
||||
}
|
||||
@if (range.controls.end.hasError('matEndDateInvalid')) {
|
||||
<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
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RepCreateFormComponent } from './rep-create-form.component';
|
||||
|
||||
describe('RepCreateFormComponent', () => {
|
||||
let component: RepCreateFormComponent;
|
||||
let fixture: ComponentFixture<RepCreateFormComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [RepCreateFormComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(RepCreateFormComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,99 @@
|
||||
import { Component, inject, ChangeDetectionStrategy, signal, OnInit, computed } from '@angular/core';
|
||||
import { UserRep } from '../../../models/user-management.api.models';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { UserRepService } from '../../../services/api/user-representation.service';
|
||||
import { GroupUpdateFormComponent } from '../group-update-form/group-update-form.component';
|
||||
import { JsonPipe } from '@angular/common';
|
||||
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { DateAdapter, MAT_DATE_LOCALE, provideNativeDateAdapter } from '@angular/material/core';
|
||||
import { MatDatepickerIntl, MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import Swal from 'sweetalert2';
|
||||
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({
|
||||
selector: 'app-rep-create-form',
|
||||
standalone: true,
|
||||
providers: [
|
||||
provideNativeDateAdapter(),
|
||||
{ provide: MAT_DATE_LOCALE, useValue: 'de-DE' },
|
||||
provideMomentDateAdapter()
|
||||
],
|
||||
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,
|
||||
})
|
||||
export class RepCreateFormComponent implements OnInit {
|
||||
|
||||
readonly userRep: UserRep;
|
||||
readonly afterCreation: (any: any) => any;
|
||||
readonly userRepService: UserRepService = inject(UserRepService);
|
||||
readonly dialogRef: MatDialogRef<GroupUpdateFormComponent> = inject(MatDialogRef<GroupUpdateFormComponent>);
|
||||
readonly range = new FormGroup({
|
||||
start: new FormControl<Date | null>(null),
|
||||
end: new FormControl<Date | null>(null),
|
||||
});
|
||||
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)
|
||||
this.userRep = dialogData.userRep;
|
||||
this.afterCreation = dialogData.afterCreation;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
//update close button label
|
||||
this._intl.closeCalendarLabel = 'Kalender schließen';
|
||||
this._intl.changes.next();
|
||||
|
||||
//set local
|
||||
this._locale.set('de');
|
||||
this._adapter.setLocale(this._locale());
|
||||
}
|
||||
|
||||
readonly dateFormatString = computed(() => {
|
||||
if (this._locale() === 'de-DE') {
|
||||
return 'dd.mm.yyyy';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
create() {
|
||||
const validFrom = this.range.value.start;
|
||||
const validTo = this.range.value.end;
|
||||
|
||||
if ((!validFrom || !validTo) && !this.termless) {
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Oops...",
|
||||
text: "Bitte geben Sie einen gültigen Datumsbereich ein oder wählen Sie unbefristet!",
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.termless) {
|
||||
this.userRep.validFrom = validFrom!;
|
||||
this.userRep.validTo = validTo!;
|
||||
}
|
||||
|
||||
this.userRepService.create(this.userRep).subscribe({
|
||||
next: (res) => {
|
||||
this.afterCreation({ successful: res });
|
||||
this.dialogRef.close();
|
||||
},
|
||||
error: (error) => {
|
||||
this.afterCreation({ error: error });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,72 +1,103 @@
|
||||
<div class="container my-3">
|
||||
<div class="row">
|
||||
<div [ngClass]="formFieldBSClass">
|
||||
<mat-form-field>
|
||||
<mat-label>Benutzername</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[formControl]="username"
|
||||
(blur)="updateErrorMessage()"
|
||||
<div class="dd-container">
|
||||
<!-- id, username, e-mail -->
|
||||
<div class="dd-row input-row">
|
||||
<mat-form-field class="w10p">
|
||||
<mat-label>Id</mat-label>
|
||||
<input matInput readonly [value]="user.id" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w30p">
|
||||
<mat-label>Benutzername</mat-label>
|
||||
<input matInput [formControl]="username" (blur)="updateErrorMessage()" required />
|
||||
@if (email.invalid) {
|
||||
<mat-error>{{errorMessage()}}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w60p">
|
||||
<mat-label>E-Mail</mat-label>
|
||||
<input matInput placeholder="user@example.com" [formControl]="email" (blur)="updateMailErrorMessage()"
|
||||
required />
|
||||
@if (email.invalid) {
|
||||
<mat-error>{{errorMessage()}}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div [ngClass]="formFieldBSClass">
|
||||
<mat-form-field>
|
||||
<mat-label>E-Mail</mat-label>
|
||||
<input
|
||||
matInput placeholder="user@example.com"
|
||||
[formControl]="email"
|
||||
(blur)="updateMailErrorMessage()"
|
||||
required />
|
||||
@if (email.invalid) {
|
||||
<mat-error>{{mailErrorMessage()}}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div [ngClass]="formFieldBSClass">
|
||||
<div [ngClass]="buttonBSClass">
|
||||
<button mat-fab extended (click)="update()">
|
||||
<mat-icon>save</mat-icon>
|
||||
Speichern
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@if (email.invalid) {
|
||||
<mat-error>{{mailErrorMessage()}}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div [ngClass]="formFieldBSClass">
|
||||
<mat-form-field>
|
||||
<mat-label>Vorname</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[formControl]="name"
|
||||
(blur)="updateErrorMessage()"
|
||||
required />
|
||||
@if (email.invalid) {
|
||||
<mat-error>{{errorMessage()}}</mat-error>
|
||||
<!-- firstname, surname -->
|
||||
<div class="dd-row input-row">
|
||||
<mat-form-field>
|
||||
<mat-label>Vorname</mat-label>
|
||||
<input matInput [formControl]="name" (blur)="updateErrorMessage()" required />
|
||||
@if (email.invalid) {
|
||||
<mat-error>{{errorMessage()}}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Nachname</mat-label>
|
||||
<input matInput [formControl]="surname" (blur)="updateErrorMessage()" required />
|
||||
@if (email.invalid) {
|
||||
<mat-error>{{errorMessage()}}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<!-- shortname -->
|
||||
<div class="dd-row input-row">
|
||||
<mat-form-field>
|
||||
<mat-label>Kürzel</mat-label>
|
||||
<input matInput [formControl]="shortname" />
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Datumsformat</mat-label>
|
||||
<mat-select [(value)]="user.dateFormat" [(ngModel)]="user.dateFormat">
|
||||
@for (format of allowedDateFormats; track format) {
|
||||
<mat-option [value]="format.value">{{format.name}}</mat-option>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div [ngClass]="formFieldBSClass">
|
||||
<mat-form-field>
|
||||
<mat-label>Nachname</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[formControl]="surname"
|
||||
(blur)="updateErrorMessage()"
|
||||
required />
|
||||
@if (email.invalid) {
|
||||
<mat-error>{{errorMessage()}}</mat-error>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Sprache</mat-label>
|
||||
<mat-select [(value)]="user.language" [(ngModel)]="user.language">
|
||||
@for (language of allowedLanguages; track language) {
|
||||
<mat-option [value]="language.value">{{language.name}}</mat-option>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div [ngClass]="formFieldBSClass">
|
||||
<button mat-fab extended (click)="delete()">
|
||||
<mat-icon>delete</mat-icon>
|
||||
Löschen
|
||||
</button>
|
||||
</div>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<!-- comment -->
|
||||
<div class="dd-row input-row">
|
||||
<mat-form-field>
|
||||
<mat-label>Kommentar</mat-label>
|
||||
<textarea matInput [formControl]="comment"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<!-- addedWho, addedWhen, changedWho and changedWhen -->
|
||||
<div class="dd-row input-row">
|
||||
<mat-form-field>
|
||||
<mat-label>Hinzugefügt wer</mat-label>
|
||||
<input matInput readonly [value]="user.addedWho" />
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Hinzugefügt wann</mat-label>
|
||||
<input matInput readonly [value]="user.addedWhen | date:'dd.MM.yyyy'" />
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Geändert wer</mat-label>
|
||||
<input matInput readonly [value]="user.changedWho" />
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Geändert wann</mat-label>
|
||||
<input matInput readonly [value]="user.changedWhen | date:'dd.MM.yyyy'" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<!-- save-button, delete-button -->
|
||||
<div class="dd-row button-row">
|
||||
<button mat-fab extended (click)="update()">
|
||||
<mat-icon>save</mat-icon>
|
||||
Speichern
|
||||
</button>
|
||||
<button mat-fab extended (click)="delete()">
|
||||
<mat-icon>delete</mat-icon>
|
||||
Löschen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -10,15 +10,17 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { UserGroupDirImportComponent } from "../../user-group-dir-import/user-group-dir-import.component";
|
||||
import { UserService } from '../../../services/api/user.service';
|
||||
import { RefreshService } from '../../../services/button/refresh.service';
|
||||
import Swal from 'sweetalert2';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { env } from '../../../../environments/environment'
|
||||
import {MatDividerModule} from '@angular/material/divider';
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-update-form',
|
||||
standalone: true,
|
||||
imports: [MatFormFieldModule, MatInputModule, FormsModule, ReactiveFormsModule, MatIconModule, MatButtonModule, CommonModule, MatTabsModule, UserGroupDirImportComponent],
|
||||
imports: [MatFormFieldModule, MatInputModule, FormsModule, ReactiveFormsModule, MatIconModule, MatButtonModule, CommonModule, MatTabsModule, MatSelectModule, MatDividerModule],
|
||||
templateUrl: './user-update-form.component.html',
|
||||
styleUrl: './user-update-form.component.scss'
|
||||
})
|
||||
@@ -28,17 +30,24 @@ export class UserUpdateFormComponent {
|
||||
|
||||
readonly user: User = inject(MAT_DIALOG_DATA);
|
||||
|
||||
get allowedDateFormats(): Array<{ value: string, name: string }> {
|
||||
return env.constants.date_formats;
|
||||
}
|
||||
|
||||
get allowedLanguages(): Array<{ value: string, name: string }> {
|
||||
return env.constants.languages;
|
||||
}
|
||||
|
||||
readonly username = new FormControl(this.user.username, [Validators.required]);
|
||||
readonly email = new FormControl(this.user.email, [Validators.required, Validators.email]);
|
||||
readonly name = new FormControl(this.user.prename, [Validators.required]);
|
||||
readonly surname = new FormControl(this.user.name, [Validators.required]);
|
||||
readonly email = new FormControl(this.user.email, [Validators.required, Validators.email]);
|
||||
readonly shortname = new FormControl(this.user.shortname);
|
||||
readonly comment = new FormControl(this.user.comment);
|
||||
|
||||
mailErrorMessage = signal('');
|
||||
errorMessage = signal('');
|
||||
|
||||
public readonly formFieldBSClass: string = "col d-flex justify-content-center mx-1 my-2"
|
||||
public readonly buttonBSClass: string = "d-flex justify-content-center mx-1 my-2"
|
||||
|
||||
constructor(private uService: UserService, private rService: RefreshService) {
|
||||
merge(
|
||||
this.email.statusChanges, this.email.valueChanges)
|
||||
@@ -77,6 +86,8 @@ export class UserUpdateFormComponent {
|
||||
this.user.prename = this.name.value!;
|
||||
this.user.username = this.username.value!;
|
||||
this.user.name = this.surname.value!;
|
||||
this.user.shortname = this.shortname.value!;
|
||||
this.user.comment = this.comment.value!;
|
||||
|
||||
this.uService.update(this.user).subscribe({
|
||||
next: () => {
|
||||
|
||||
@@ -13,5 +13,8 @@
|
||||
[infoPanel]="infoPanel"
|
||||
[titlePanel]="titlePanel"
|
||||
[theme]="theme"
|
||||
(selectedRows)="onSelectedRows($event)">
|
||||
[rowStyle] = "rowStyle"
|
||||
[rowClass] = "rowClass"
|
||||
(selectedRows)="onSelectedRows($event)"
|
||||
(click)="click && click(this)">
|
||||
</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'
|
||||
@@ -69,6 +69,10 @@ export class BaseTableComponent<TModel, TApiService extends ApiService<TModel>>
|
||||
|
||||
private themeSubscription: Subscription = new Subscription();
|
||||
|
||||
private static count: number = 0;
|
||||
|
||||
public readonly id: number = (BaseTableComponent.count++)
|
||||
|
||||
constructor(@Inject(ApiService<TModel>) service: TApiService, columns: Array<GuiColumn>, private cModeService: ColorModeService) {
|
||||
this.service = service;
|
||||
if (this.columns.length == 0)
|
||||
@@ -111,6 +115,12 @@ export class BaseTableComponent<TModel, TApiService extends ApiService<TModel>>
|
||||
|
||||
@Input() columns: Array<GuiColumn> = [];
|
||||
|
||||
@Input() rowStyle: GuiRowStyle = {}
|
||||
|
||||
@Input() rowClass: GuiRowClass = {}
|
||||
|
||||
@Input() click: ((table: BaseTableComponent<TModel, TApiService>) => void) | undefined;
|
||||
|
||||
selected: boolean = false;
|
||||
safelyUnselectAll() {
|
||||
this.selected = true
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { UserRep } from '../../../models/user-management.api.models';
|
||||
import { UserRepService } from '../../../services/api/user-representation.service';
|
||||
import { BaseTableComponent } from '../base-table/base-table.component';
|
||||
import { GuiGridModule, GuiColumn } from '@generic-ui/ngx-grid';
|
||||
import { GuiGridModule } from '@generic-ui/ngx-grid';
|
||||
import { ColorModeService } from '../../../services/button/color-mode.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
@@ -31,4 +31,12 @@ export class UserRepTableComponent extends BaseTableComponent<UserRep, UserRepSe
|
||||
error: (error: any) => { }
|
||||
});
|
||||
}
|
||||
|
||||
public fetchByUser(id: number): void {
|
||||
this.fetchData(id, undefined);
|
||||
}
|
||||
|
||||
public fetchByGroup(id: number): void {
|
||||
this.fetchData(undefined, id);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,9 @@ export interface User {
|
||||
deleted?: boolean;
|
||||
dateFormat?: string;
|
||||
addedWho?: string;
|
||||
addedWhen?: Date;
|
||||
changedWho?: string;
|
||||
changedWhen?: Date;
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
@@ -23,7 +25,9 @@ export interface Group {
|
||||
active?: boolean;
|
||||
comment?: string;
|
||||
addedWho?: string;
|
||||
addedWhen?: Date;
|
||||
changedWho?: string;
|
||||
changedWhen?: Date;
|
||||
}
|
||||
|
||||
export interface Module {
|
||||
@@ -56,15 +60,17 @@ export interface GroupOfUser {
|
||||
|
||||
export interface UserRep {
|
||||
id?: number,
|
||||
userId: number,
|
||||
repUserId?: number,
|
||||
userId?: number,
|
||||
repGroupId?: number,
|
||||
groupId?: number,
|
||||
addedWho: string,
|
||||
repUserId?: number,
|
||||
validFrom?: Date,
|
||||
validTo?: Date,
|
||||
addedWho?: string,
|
||||
repUser?: User
|
||||
user?: User,
|
||||
repGroup?: Group,
|
||||
group?: Group,
|
||||
repUser?: User
|
||||
group?: Group,
|
||||
}
|
||||
|
||||
export interface DirGroup {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="col-7">
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Gruppen">
|
||||
<app-group-table #groupTable [onSelectedRows]="groupsOnSelectedRows" [cellEditing]="cellEditing" [columns]="complete_group_cols"></app-group-table>
|
||||
<app-group-table #groupTable [onSelectedRows]="groupsOnSelectedRows" [cellEditing]="cellEditing" [columns]="detailed_group_cols"></app-group-table>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ViewChild } from '@angular/core';
|
||||
import { AfterViewInit, Component, ViewChild, inject } from '@angular/core';
|
||||
import { GroupTableComponent } from '../../components/tables/group-table/group-table.component';
|
||||
import { UserTableComponent } from '../../components/tables/user-table/user-table.component';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
@@ -9,6 +9,8 @@ import { Group } from '../../models/user-management.api.models';
|
||||
import { firstValueFrom, forkJoin } from 'rxjs';
|
||||
import Swal from 'sweetalert2';
|
||||
import { env } from '../../../environments/environment';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { GroupUpdateFormComponent } from '../../components/forms/group-update-form/group-update-form.component';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
@@ -33,15 +35,17 @@ export class GroupComponent extends BasePageComponent implements AfterViewInit {
|
||||
}
|
||||
}
|
||||
|
||||
private sGroupId = null;
|
||||
private sGroup: Group | null = null;
|
||||
|
||||
private readonly dialog: MatDialog = inject(MatDialog);
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.buttonVisibilityService.setVisibleOnly(this.refreshService, this.creationService, this.updateService)
|
||||
this.refreshService.removeAll()
|
||||
this.refreshService.add(() => {
|
||||
this.groupTable.fetchData();
|
||||
if (this.sGroupId)
|
||||
this.userTable.fetchDataByGroupId(this.sGroupId);
|
||||
if (this.sGroup)
|
||||
this.userTable.fetchDataByGroupId(this.sGroup.id!);
|
||||
});
|
||||
this.creationService.component = GroupFormComponent
|
||||
|
||||
@@ -53,9 +57,12 @@ export class GroupComponent extends BasePageComponent implements AfterViewInit {
|
||||
|
||||
groupsOnSelectedRows = (rows: GuiSelectedRow[]) => {
|
||||
if (rows.length > 0) {
|
||||
this.sGroupId = rows[0].source.id;
|
||||
if (this.sGroupId)
|
||||
this.userTable.fetchDataByGroupId(this.sGroupId);
|
||||
this.sGroup = rows[0].source;
|
||||
if (this.sGroup)
|
||||
this.userTable.fetchDataByGroupId(this.sGroup.id!);
|
||||
}
|
||||
else if (rows.length == 0 && this.sGroup?.name != null) {
|
||||
this.openUpdateSheet(this.sGroup);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +99,14 @@ export class GroupComponent extends BasePageComponent implements AfterViewInit {
|
||||
});
|
||||
}
|
||||
|
||||
get complete_group_cols() {
|
||||
return env.columnNames.group.complete
|
||||
get detailed_group_cols() {
|
||||
return env.columnNames.group.detailed
|
||||
}
|
||||
|
||||
openUpdateSheet(group: Group): void {
|
||||
this.dialog.open(GroupUpdateFormComponent, {
|
||||
width: "50rem",
|
||||
data: group
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,10 @@
|
||||
<div class="col-5">
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Benutzer">
|
||||
<app-user-table #users [onSelectedRows]="userOnSelectedRows"></app-user-table>
|
||||
<app-user-table #users [click]="userOnClick"></app-user-table>
|
||||
</mat-tab>
|
||||
<mat-tab label="Gruppe">
|
||||
<app-group-table #rightGroups [columns]="groupColumns" [onSelectedRows]="groupOnSelectedRows"></app-group-table>
|
||||
<app-group-table #groups [columns]="groupColumns" [click]="groupOnClick"></app-group-table>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
@@ -16,10 +16,10 @@
|
||||
<div class="col-4">
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Rep. Benutzer">
|
||||
<app-user-table #repUsers [onSelectedRows]="repUserOnSelectedRows"></app-user-table>
|
||||
<app-user-table #repUsers [click]="repUserOnClick"></app-user-table>
|
||||
</mat-tab>
|
||||
<mat-tab label="Rep. Gruppen">
|
||||
<app-group-table #repGroups [columns]="groupRepCols" [onSelectedRows]="repGroupOnSelectedRows"></app-group-table>
|
||||
<app-group-table #repGroups [columns]="groupRepCols" [click]="repGroupOnClick"></app-group-table>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
@@ -27,7 +27,7 @@
|
||||
<div class="col-3">
|
||||
<mat-tab-group>
|
||||
<mat-tab label="{{useRepLabel}}">
|
||||
<app-user-rep-table #userReps [initData]="initWithoutData" [onSelectedRows]="userRepOnSelectedRows"></app-user-rep-table>
|
||||
<app-user-rep-table #userReps [initData]="initWithoutData" [rowClass]="rep_row_class" [click]="repOnClick"></app-user-rep-table>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AfterViewInit, Component, Inject, ViewChild } from '@angular/core';
|
||||
import { GuiColumn, GuiSelectedRow } from '@generic-ui/ngx-grid/gui/grid/src/core/api/gui.grid.public-api';
|
||||
import { AfterViewInit, Component, ViewChild, inject } from '@angular/core';
|
||||
import { GuiColumn, GuiRowClass, GuiRowStyle, GuiSelectedRow } from '@generic-ui/ngx-grid/gui/grid/src/core/api/gui.grid.public-api';
|
||||
import { UserTableComponent } from '../../components/tables/user-table/user-table.component';
|
||||
import { UserRepTableComponent } from '../../components/tables/user-rep-table/user-rep-table.component';
|
||||
import { GroupTableComponent } from '../../components/tables/group-table/group-table.component';
|
||||
@@ -8,7 +8,12 @@ import Swal from 'sweetalert2';
|
||||
import { MatTabsModule, MatTabGroup } from '@angular/material/tabs';
|
||||
import { env } from '../../../environments/environment';
|
||||
import { BasePageComponent } from '../base-page/base-page.component';
|
||||
import { UserRep } from '../../models/user-management.api.models';
|
||||
import { Group, User, UserRep } from '../../models/user-management.api.models';
|
||||
import { RepCreateFormComponent } from '../../components/forms/rep-create-form/rep-create-form.component';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { BaseTableComponent } from '../../components/tables/base-table/base-table.component';
|
||||
import { GroupService } from '../../services/api/group.service';
|
||||
import { UserService } from '../../services/api/user.service';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
@@ -22,11 +27,27 @@ export class UserRepresentationComponent extends BasePageComponent implements Af
|
||||
useRepLabel: string = "";
|
||||
groupColumns: Array<GuiColumn>;
|
||||
groupRepCols: Array<GuiColumn>;
|
||||
slUserId: null | number = null;
|
||||
slRepUserId: null | number = null;
|
||||
slRepGroupId: null | number = null;
|
||||
slRightGroupId: null | number = null;
|
||||
slUserRepId: null | number = null;
|
||||
slUserId?: number;
|
||||
slGroupId?: number;
|
||||
slRepUserId?: number;
|
||||
slRepGroupId?: number;
|
||||
slRepId?: number;
|
||||
|
||||
private readonly dialog: MatDialog = inject(MatDialog);
|
||||
|
||||
rep_row_class: GuiRowClass = {
|
||||
classFunction(source, index) {
|
||||
const now = new Date()
|
||||
|
||||
return (!source.validFrom && !source.validTo)
|
||||
? "current-period-row"
|
||||
: (new Date(source.validFrom) > now)
|
||||
? "future-period-row"
|
||||
: (new Date(source.validTo) < now)
|
||||
? "past-period-row"
|
||||
: "current-period-row";
|
||||
}
|
||||
}
|
||||
|
||||
initWithoutData = () => { }
|
||||
|
||||
@@ -42,9 +63,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();
|
||||
@@ -59,38 +81,44 @@ export class UserRepresentationComponent extends BasePageComponent implements Af
|
||||
@ViewChild("repGroups") repGroups!: GroupTableComponent;
|
||||
@ViewChild("userReps") userReps!: UserRepTableComponent;
|
||||
|
||||
userGroupOnSelectedRows = (rows: GuiSelectedRow[], isUser: boolean = true) => {
|
||||
// user
|
||||
userOnSelectedRows = (rows: GuiSelectedRow[]) => {
|
||||
if (rows.length > 0) {
|
||||
this.users.safelyUnselectAll();
|
||||
|
||||
if (isUser) {
|
||||
this.useRepLabel = `Vertretungen von ${rows[0].source?.username}`
|
||||
this.userReps.fetchData(rows[0].source?.id)
|
||||
this.slUserId = rows[0].source?.id
|
||||
}
|
||||
else {
|
||||
this.useRepLabel = `Vertretungen von ${rows[0].source?.name}`
|
||||
this.userReps.fetchData(undefined, rows[0].source?.id)
|
||||
this.slUserId = rows[0].source?.id
|
||||
}
|
||||
this.useRepLabel = `Vertretungen von ${rows[0].source?.username}`
|
||||
//this.users.safelyUnselectAll();
|
||||
this.userReps.fetchByUser(rows[0].source?.id);
|
||||
this.slGroupId = undefined;
|
||||
this.slUserId = rows[0].source?.id
|
||||
}
|
||||
}
|
||||
|
||||
userOnSelectedRows = (rows: GuiSelectedRow[]) => {
|
||||
this.userGroupOnSelectedRows(rows, true);
|
||||
userOnClick = (table: BaseTableComponent<User, UserService>) => {
|
||||
this.userOnSelectedRows(table.selectedRows);
|
||||
}
|
||||
|
||||
// group
|
||||
groupOnSelectedRows = (rows: GuiSelectedRow[]) => {
|
||||
this.userGroupOnSelectedRows(rows, false);
|
||||
if (rows.length > 0) {
|
||||
this.useRepLabel = `Vertretungen von ${rows[0].source?.name}`
|
||||
this.groups.safelyUnselectAll();
|
||||
this.userReps.fetchByGroup(rows[0].source?.id);
|
||||
this.slUserId = undefined;
|
||||
this.slGroupId = rows[0].source?.id
|
||||
}
|
||||
}
|
||||
|
||||
groupOnClick = (table: BaseTableComponent<Group, GroupService>) => {
|
||||
this.groupOnSelectedRows(table.selectedRows);
|
||||
}
|
||||
|
||||
//repUser
|
||||
repUserOnSelectedRows = (rows: GuiSelectedRow[]) => {
|
||||
if (rows.length == 0 && this.slRepUserId) {
|
||||
if (!this.slUserId) {
|
||||
if (!this.slUserId && !this.slGroupId) {
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Oops...",
|
||||
text: "Bitte wählen Sie den Benutzer!",
|
||||
text: "Bitte wählen Sie den Benutzer oder die Gruppe!",
|
||||
});
|
||||
}
|
||||
else if (!this.slRepUserId) {
|
||||
@@ -103,17 +131,22 @@ export class UserRepresentationComponent extends BasePageComponent implements Af
|
||||
else {
|
||||
var newUserRep: UserRep = {
|
||||
userId: this.slUserId,
|
||||
repUserId: this.slRepUserId,
|
||||
addedWho: 'DEFAULT'
|
||||
groupId: this.slGroupId,
|
||||
repUserId: this.slRepUserId
|
||||
}
|
||||
this.userRepService.create(newUserRep).subscribe({
|
||||
next: (response) => {
|
||||
this.slRepUserId = null;
|
||||
|
||||
this.openCreateSheet(newUserRep, res => {
|
||||
if (res.successful) {
|
||||
this.slRepUserId = undefined;
|
||||
|
||||
this.repUsers.safelyUnselectAll()
|
||||
if (this.slUserId != null)
|
||||
this.userReps.fetchData(this.slUserId)
|
||||
},
|
||||
error: (error) => {
|
||||
this.repGroups.safelyUnselectAll()
|
||||
if (this.slUserId)
|
||||
this.userReps.fetchByUser(this.slUserId)
|
||||
if (this.slGroupId)
|
||||
this.userReps.fetchByGroup(this.slGroupId)
|
||||
}
|
||||
else if (res.error) {
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Oops...",
|
||||
@@ -123,20 +156,25 @@ export class UserRepresentationComponent extends BasePageComponent implements Af
|
||||
});
|
||||
}
|
||||
|
||||
this.slRepUserId = null;
|
||||
this.slRepUserId = undefined;
|
||||
}
|
||||
else if (rows.length > 0) {
|
||||
this.slRepUserId = rows[0].source?.id;
|
||||
}
|
||||
}
|
||||
|
||||
repUserOnClick = (table: BaseTableComponent<User, UserService>) => {
|
||||
this.repUserOnSelectedRows(table.selectedRows);
|
||||
}
|
||||
|
||||
// repGroup
|
||||
repGroupOnSelectedRows = (rows: GuiSelectedRow[]) => {
|
||||
if (rows.length == 0 && this.slRepGroupId) {
|
||||
if (!this.slUserId) {
|
||||
if (!this.slUserId && !this.slGroupId) {
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Oops...",
|
||||
text: "Bitte wählen Sie den Benutzer!",
|
||||
text: "Bitte wählen Sie den Benutzer oder die Gruppe!",
|
||||
});
|
||||
}
|
||||
else if (!this.slRepGroupId) {
|
||||
@@ -149,17 +187,21 @@ export class UserRepresentationComponent extends BasePageComponent implements Af
|
||||
else {
|
||||
var newUserRep = {
|
||||
userId: this.slUserId,
|
||||
groupId: this.slGroupId,
|
||||
repGroupId: this.slRepGroupId,
|
||||
addedWho: 'DEFAULT'
|
||||
}
|
||||
this.userRepService.create(newUserRep).subscribe({
|
||||
next: (res) => {
|
||||
this.slRepGroupId = null;
|
||||
|
||||
this.openCreateSheet(newUserRep, res => {
|
||||
if (res.successful) {
|
||||
this.slRepGroupId = undefined;
|
||||
this.repUsers.safelyUnselectAll()
|
||||
if (this.slUserId != null)
|
||||
this.userReps.fetchData(this.slUserId)
|
||||
},
|
||||
error: (error) => {
|
||||
this.groups.safelyUnselectAll()
|
||||
if (this.slUserId)
|
||||
this.userReps.fetchByUser(this.slUserId)
|
||||
if (this.slGroupId)
|
||||
this.userReps.fetchByGroup(this.slGroupId)
|
||||
}
|
||||
else if (res.error) {
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Oops...",
|
||||
@@ -169,24 +211,31 @@ export class UserRepresentationComponent extends BasePageComponent implements Af
|
||||
});
|
||||
}
|
||||
|
||||
this.slRepGroupId = null;
|
||||
this.slRepGroupId = undefined;
|
||||
}
|
||||
else if (rows.length > 0) {
|
||||
this.slRepGroupId = rows[0].source?.id;
|
||||
}
|
||||
}
|
||||
|
||||
userRepOnSelectedRows = (rows: GuiSelectedRow[]) => {
|
||||
if (rows.length == 0 && this.slUserRepId) {
|
||||
this.userRepService.delete(this.slUserRepId).subscribe({
|
||||
repGroupOnClick = (table: BaseTableComponent<Group, GroupService>) => {
|
||||
this.repGroupOnSelectedRows(table.selectedRows);
|
||||
}
|
||||
|
||||
// rep events
|
||||
repOnSelectedRows = (rows: GuiSelectedRow[]) => {
|
||||
if (rows.length == 0 && this.slRepId) {
|
||||
this.userRepService.delete(this.slRepId).subscribe({
|
||||
next: (res) => {
|
||||
this.slUserRepId = null;
|
||||
this.slRepId = undefined;
|
||||
this.userReps.safelyUnselectAll();
|
||||
if (this.slUserId != null)
|
||||
if (this.slUserId != undefined)
|
||||
this.userReps.fetchData(this.slUserId)
|
||||
if (this.slGroupId != undefined)
|
||||
this.userReps.fetchData(undefined, this.slGroupId)
|
||||
},
|
||||
error: (err) => {
|
||||
this.slUserRepId = null;
|
||||
this.slRepId = undefined;
|
||||
this.repUsers.safelyUnselectAll()
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
@@ -197,7 +246,19 @@ export class UserRepresentationComponent extends BasePageComponent implements Af
|
||||
})
|
||||
}
|
||||
else if (rows.length > 0) {
|
||||
this.slUserRepId = rows[0].source?.id;
|
||||
this.slRepId = rows[0].source?.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repOnClick = (table: BaseTableComponent<UserRep, UserRepService>) => {
|
||||
this.repOnSelectedRows(table.selectedRows);
|
||||
}
|
||||
|
||||
openCreateSheet(userRep: UserRep, afterCreation: (any: any) => any): void {
|
||||
|
||||
this.dialog.open(RepCreateFormComponent, {
|
||||
width: "50rem",
|
||||
data: { userRep: userRep, afterCreation: afterCreation }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Benutzer">
|
||||
<app-user-table #userTable [onSelectedRows]="usersOnSelectedRows"
|
||||
[cellEditing]="cellEditing" [columns]="detailed_user_columns"></app-user-table>
|
||||
[cellEditing]="cellEditing" [columns]="basic_user_columns"></app-user-table>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { User } from '../../models/user-management.api.models';
|
||||
import { firstValueFrom, forkJoin } from 'rxjs';
|
||||
import Swal from 'sweetalert2';
|
||||
import { env } from '../../../environments/environment'
|
||||
import { MatBottomSheet, MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
||||
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { UserUpdateFormComponent } from '../../components/forms/user-update-form/user-update-form.component';
|
||||
@@ -40,8 +40,6 @@ export class UserComponent extends BasePageComponent implements AfterViewInit {
|
||||
|
||||
private sUser: any = null;
|
||||
|
||||
private _bottomSheet = inject(MatBottomSheet);
|
||||
|
||||
private readonly dialog: MatDialog = inject(MatDialog);
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
@@ -107,8 +105,8 @@ export class UserComponent extends BasePageComponent implements AfterViewInit {
|
||||
});
|
||||
}
|
||||
|
||||
public get detailed_user_columns() {
|
||||
return env.columnNames.user.detailed
|
||||
public get basic_user_columns() {
|
||||
return env.columnNames.user.basic
|
||||
}
|
||||
|
||||
openUpdateSheet(user: User): void {
|
||||
|
||||
@@ -53,7 +53,7 @@ export const env = {
|
||||
field: 'email'
|
||||
},
|
||||
{
|
||||
header:'Kommentar',
|
||||
header: 'Kommentar',
|
||||
field: 'comment'
|
||||
},
|
||||
{
|
||||
@@ -89,7 +89,7 @@ export const env = {
|
||||
field: "name"
|
||||
}
|
||||
],
|
||||
complete: [
|
||||
detailed: [
|
||||
{
|
||||
header: "Gruppe",
|
||||
field: "name"
|
||||
@@ -97,34 +97,6 @@ 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: [
|
||||
@@ -189,15 +161,39 @@ export const env = {
|
||||
header: "Repr. Gruppen",
|
||||
field: (ur: any) => ur.repGroup?.name
|
||||
},
|
||||
{
|
||||
header: "Rechte Gruppen",
|
||||
field: (ur: any) => ur.rightGroup?.name
|
||||
},
|
||||
{
|
||||
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"
|
||||
};
|
||||
config_url: "/assets/config.json",
|
||||
constants: {
|
||||
date_formats: [
|
||||
{
|
||||
value: "dd.MM.yyyy",
|
||||
name: "dd.MM.yyyy",
|
||||
},
|
||||
{
|
||||
value: "MM.dd.yyyy",
|
||||
name: "MM.dd.yyyy",
|
||||
},
|
||||
{
|
||||
value: "yyyy-MM-dd",
|
||||
name: "yyyy-MM-dd",
|
||||
}
|
||||
],
|
||||
languages: [
|
||||
{ value: "de-DE", name: "de-DE" },
|
||||
{ value: "en-US", name: "en-US" }
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -53,7 +53,7 @@ export const env = {
|
||||
field: 'email'
|
||||
},
|
||||
{
|
||||
header:'Kommentar',
|
||||
header: 'Kommentar',
|
||||
field: 'comment'
|
||||
},
|
||||
{
|
||||
@@ -89,7 +89,7 @@ export const env = {
|
||||
field: "name"
|
||||
}
|
||||
],
|
||||
complete: [
|
||||
detailed: [
|
||||
{
|
||||
header: "Gruppe",
|
||||
field: "name"
|
||||
@@ -97,34 +97,6 @@ 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: [
|
||||
@@ -193,7 +165,35 @@ 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"
|
||||
};
|
||||
config_url: "/assets/config.json",
|
||||
constants: {
|
||||
date_formats: [
|
||||
{
|
||||
value: "dd.MM.yyyy",
|
||||
name: "dd.MM.yyyy",
|
||||
},
|
||||
{
|
||||
value: "MM.dd.yyyy",
|
||||
name: "MM.dd.yyyy",
|
||||
},
|
||||
{
|
||||
value: "yyyy-MM-dd",
|
||||
name: "yyyy-MM-dd",
|
||||
}
|
||||
],
|
||||
languages: [
|
||||
{ value: "de-DE", name: "de-DE" },
|
||||
{ value: "en-US", name: "en-US" }
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -45,6 +45,74 @@ code {
|
||||
color: rgb(100, 95, 95) !important;
|
||||
}
|
||||
|
||||
.mdc-tab__text-label{
|
||||
.mdc-tab__text-label {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
//Layout
|
||||
.dd-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
margin: 1rem 0 1rem 0;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.dd-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input-row {
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.button-row {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.dd-row mat-form-field {
|
||||
width: 100%;
|
||||
margin: 0 1rem 0 1rem;
|
||||
}
|
||||
|
||||
.dd-row mat-checkbox {
|
||||
width: 100%;
|
||||
margin: 0 1rem 1rem 1rem;
|
||||
}
|
||||
|
||||
.dd-row mat-slide-toggle {
|
||||
width: 100%;
|
||||
margin: 0 1rem 1rem 1rem;
|
||||
}
|
||||
|
||||
.dd-row button {
|
||||
margin: 0 1rem 0 1rem;
|
||||
}
|
||||
|
||||
.dd-container mat-divider {
|
||||
margin: 0 0 1rem 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@for $i from 1 through 20 {
|
||||
.w#{$i * 5}p {
|
||||
width: #{$i * 5 + "%"} !important;
|
||||
}
|
||||
}
|
||||
|
||||
.future-period-row {
|
||||
background: rgba(76, 110, 140, .4) !important;
|
||||
}
|
||||
|
||||
.current-period-row {
|
||||
background: rgba(76, 110, 76, .4) !important;
|
||||
}
|
||||
|
||||
.past-period-row {
|
||||
background: rgba(110, 76, 76, .4) !important;
|
||||
}
|
||||
@@ -1,154 +1,72 @@
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using DigitalData.UserManager.Application;
|
||||
using DigitalData.UserManager.Application.DTOs.Auth;
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using DigitalData.Core.DTO;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using DigitalData.UserManager.Application;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace DigitalData.UserManager.API.Controllers
|
||||
namespace DigitalData.UserManager.API.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class AuthController : ControllerBase
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
public class AuthController : ControllerBase
|
||||
private readonly ILogger<UserController> _logger;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IStringLocalizer<Resource> _localizer;
|
||||
|
||||
public AuthController(ILogger<UserController> logger, IUserService userService, IStringLocalizer<Resource> localizer)
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IGroupOfUserService _gouService;
|
||||
private readonly IDirectorySearchService _dirSearchService;
|
||||
private readonly IStringLocalizer<Resource> _localizer;
|
||||
private readonly ILogger<AuthController> _logger;
|
||||
_logger = logger;
|
||||
_userService = userService;
|
||||
_localizer = localizer;
|
||||
}
|
||||
|
||||
public AuthController(IUserService userService, IGroupOfUserService gouService, IDirectorySearchService directorySearchService, IStringLocalizer<Resource> localizer, ILogger<AuthController> logger)
|
||||
[Authorize]
|
||||
[HttpGet("check")]
|
||||
public IActionResult CheckAuthentication() => Ok();
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("login")]
|
||||
public Task<IActionResult> Login([FromBody] LogInDto login) => throw new NotImplementedException();
|
||||
|
||||
[Authorize]
|
||||
[HttpGet("user")]
|
||||
public async Task<IActionResult> GetUserWithClaims()
|
||||
{
|
||||
try
|
||||
{
|
||||
_userService = userService;
|
||||
_gouService = gouService;
|
||||
_dirSearchService = directorySearchService;
|
||||
_localizer = localizer;
|
||||
_logger = logger;
|
||||
}
|
||||
// Extract the username from the Name claim.
|
||||
string? username = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("check")]
|
||||
public IActionResult CheckAuthentication()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Ok(User.Identity?.IsAuthenticated ?? false);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(username))
|
||||
return Unauthorized();
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("login")]
|
||||
public async Task<IActionResult> Login([FromBody] LogInDto login)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool isValid = _dirSearchService.ValidateCredentials(login.Username, login.Password);
|
||||
|
||||
if (!isValid)
|
||||
return Unauthorized(Result.Fail().Message(_localizer[Key.UserNotFound]));
|
||||
|
||||
var gouMsg = await _gouService.HasGroup(login.Username, "PM_USER", caseSensitive: false);
|
||||
if (!gouMsg.IsSuccess)
|
||||
return Unauthorized(Result.Fail().Message(_localizer[Key.UnauthorizedUser]));
|
||||
|
||||
//find the user
|
||||
var uRes = await _userService.ReadByUsernameAsync(login.Username);
|
||||
if (!uRes.IsSuccess || uRes.Data is null)
|
||||
return await _userService.ReadByUsernameAsync(username)
|
||||
.ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
return Unauthorized(uRes);
|
||||
}
|
||||
|
||||
UserReadDto user = uRes.Data;
|
||||
|
||||
// Create claims
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new (ClaimTypes.NameIdentifier, user.Id.ToString()),
|
||||
new (ClaimTypes.Name, user.Username),
|
||||
new (ClaimTypes.Surname, user.Name ?? ""),
|
||||
new (ClaimTypes.GivenName, user.Prename ?? ""),
|
||||
new (ClaimTypes.Email, user.Email ?? ""),
|
||||
new (ClaimTypes.Role, "PM_USER")
|
||||
};
|
||||
|
||||
// Create claimsIdentity
|
||||
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
|
||||
// Create authProperties
|
||||
var authProperties = new AuthenticationProperties
|
||||
{
|
||||
IsPersistent = true,
|
||||
AllowRefresh = true,
|
||||
ExpiresUtc = DateTime.UtcNow.AddMinutes(60)
|
||||
};
|
||||
|
||||
// Sign in
|
||||
await HttpContext.SignInAsync(
|
||||
CookieAuthenticationDefaults.AuthenticationScheme,
|
||||
new ClaimsPrincipal(claimsIdentity),
|
||||
authProperties);
|
||||
|
||||
_dirSearchService.SetSearchRootCache(user.Username, login.Password);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
_logger.LogNotice(n);
|
||||
return NotFound(Result.Fail().Message(_localizer[Key.UserNotFound]));
|
||||
});
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
[HttpGet("user")]
|
||||
public async Task<IActionResult> GetUserWithClaims()
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Extract the username from the Name claim.
|
||||
string? username = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
|
||||
|
||||
if (string.IsNullOrEmpty(username))
|
||||
return Unauthorized();
|
||||
|
||||
return await _userService.ReadByUsernameAsync(username)
|
||||
.ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return NotFound(Result.Fail().Message(_localizer[Key.UserNotFound]));
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
[HttpPost("logout")]
|
||||
public async Task<IActionResult> Logout()
|
||||
{
|
||||
try
|
||||
{
|
||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
return Ok();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
[HttpPost("logout")]
|
||||
public IActionResult Logout()
|
||||
{
|
||||
Response.Cookies.Delete("AuthToken", new()
|
||||
{
|
||||
Path = "/"
|
||||
});
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
@@ -7,41 +7,40 @@ using DigitalData.UserManager.Domain.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace DigitalData.UserManager.API.Controllers
|
||||
namespace DigitalData.UserManager.API.Controllers;
|
||||
|
||||
[Authorize]
|
||||
public class BaseAuthController<TCRUDService, TCreateDto, TReadDto, TUpdateDto, TBaseEntity> : CRUDControllerBaseWithErrorHandling<TCRUDService, TCreateDto, TReadDto, TUpdateDto, TBaseEntity, int>
|
||||
where TCRUDService : IBaseService<TCreateDto, TReadDto, TBaseEntity>
|
||||
where TCreateDto : BaseCreateDto
|
||||
where TReadDto : class
|
||||
where TUpdateDto : BaseUpdateDto
|
||||
where TBaseEntity : BaseEntity
|
||||
{
|
||||
[Authorize]
|
||||
public class BaseAuthController<TCRUDService, TCreateDto, TReadDto, TUpdateDto, TBaseEntity> : CRUDControllerBaseWithErrorHandling<TCRUDService, TCreateDto, TReadDto, TUpdateDto, TBaseEntity, int>
|
||||
where TCRUDService : IBaseService<TCreateDto, TReadDto, TUpdateDto, TBaseEntity>
|
||||
where TCreateDto : BaseCreateDto
|
||||
where TReadDto : class
|
||||
where TUpdateDto : BaseUpdateDto
|
||||
where TBaseEntity : BaseEntity
|
||||
private readonly Lazy<int?> _lUserId;
|
||||
|
||||
public BaseAuthController(ILogger logger, TCRUDService service, IUserService userService) : base(logger, service)
|
||||
{
|
||||
private readonly Lazy<int?> _lUserId;
|
||||
|
||||
public BaseAuthController(ILogger logger, TCRUDService service, IUserService userService) : base(logger, service)
|
||||
_lUserId = new(() =>
|
||||
{
|
||||
_lUserId = new(() =>
|
||||
{
|
||||
var idSt = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
bool hasId = int.TryParse(idSt, out int id);
|
||||
return hasId ? id : null;
|
||||
});
|
||||
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;
|
||||
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;
|
||||
};
|
||||
}
|
||||
return id is int intId
|
||||
? await userService.ReadByIdAsync(intId).ThenAsync(
|
||||
Success: res => res,
|
||||
Fail: UserReadDto? (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return null;
|
||||
})
|
||||
: null;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using DigitalData.UserManager.API.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace DigitalData.UserManager.API.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class ConstantsController : ControllerBase
|
||||
{
|
||||
private readonly Constants _constants;
|
||||
public ConstantsController(IOptions<Constants> constantsOptions)
|
||||
{
|
||||
_constants = constantsOptions.Value;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult GetConstant(string? name = null)
|
||||
{
|
||||
if(name is null)
|
||||
return Ok(_constants);
|
||||
|
||||
|
||||
return Ok(_constants[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,226 +10,225 @@ using Microsoft.Extensions.Localization;
|
||||
using DigitalData.Core.DTO;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace DigitalData.UserManager.API.Controllers
|
||||
namespace DigitalData.UserManager.API.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>")]
|
||||
[Authorize]
|
||||
public class DirectoryController : ControllerBase
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>")]
|
||||
[Authorize]
|
||||
public class DirectoryController : ControllerBase
|
||||
private readonly IUserService _userService;
|
||||
private readonly IDirectorySearchService _dirSearchService;
|
||||
private readonly Dictionary<string, string> _customSearchFilters;
|
||||
private readonly IStringLocalizer<Resource> _localizer;
|
||||
private readonly ILogger<DirectoryController> _logger;
|
||||
|
||||
public DirectoryController(IConfiguration configuration, IStringLocalizer<Resource> localizer, IUserService userService, IDirectorySearchService directorySearchService, ILogger<DirectoryController> logger)
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IDirectorySearchService _dirSearchService;
|
||||
private readonly Dictionary<string, string> _customSearchFilters;
|
||||
private readonly IStringLocalizer<Resource> _localizer;
|
||||
private readonly ILogger<DirectoryController> _logger;
|
||||
_localizer = localizer;
|
||||
_userService = userService;
|
||||
_dirSearchService = directorySearchService;
|
||||
|
||||
public DirectoryController(IConfiguration configuration, IStringLocalizer<Resource> localizer, IUserService userService, IDirectorySearchService directorySearchService, ILogger<DirectoryController> logger)
|
||||
var customSearchFiltersSection = configuration.GetSection("DirectorySearch:CustomSearchFilters");
|
||||
_customSearchFilters = customSearchFiltersSection.Get<Dictionary<string, string>>() ?? new();
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet("Root/{username}")]
|
||||
public IActionResult GetRootOf(string username)
|
||||
{
|
||||
try
|
||||
{
|
||||
_localizer = localizer;
|
||||
_userService = userService;
|
||||
_dirSearchService = directorySearchService;
|
||||
var root = _dirSearchService.GetSearchRootCache(username);
|
||||
|
||||
var customSearchFiltersSection = configuration.GetSection("DirectorySearch:CustomSearchFilters");
|
||||
_customSearchFilters = customSearchFiltersSection.Get<Dictionary<string, string>>() ?? new();
|
||||
_logger = logger;
|
||||
return root is null ? NotFound() : Ok(new
|
||||
{
|
||||
guid = root.Guid,
|
||||
nativeGuid = root.NativeGuid,
|
||||
name = root.Name,
|
||||
path = root.Path,
|
||||
parentPath = root.Parent?.Path,
|
||||
username = root.Username,
|
||||
schemaClassName = root.SchemaClassName
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet("Root/{username}")]
|
||||
public IActionResult GetRootOf(string username)
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
var root = _dirSearchService.GetSearchRootCache(username);
|
||||
|
||||
return root is null ? NotFound() : Ok(new
|
||||
{
|
||||
guid = root.Guid,
|
||||
nativeGuid = root.NativeGuid,
|
||||
name = root.Name,
|
||||
path = root.Path,
|
||||
parentPath = root.Parent?.Path,
|
||||
username = root.Username,
|
||||
schemaClassName = root.SchemaClassName
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("CustomSearchFilter")]
|
||||
public IActionResult GetAllCustomFilters(string? filtername)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (filtername is null)
|
||||
{
|
||||
return Ok(_customSearchFilters);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dirSearchService.CustomSearchFilters.TryGetValue(filtername, out string? filter);
|
||||
return filter is null ? NotFound() : Ok(filter);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("CreateSearchRoot")]
|
||||
public async Task<IActionResult> CreateSearchRoot([FromBody] SearchRootCreateDto searchRootCreateDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dirEntryUsername = searchRootCreateDto.DirEntryUsername ?? CurrentUser;
|
||||
if (dirEntryUsername is null)
|
||||
return Unauthorized();
|
||||
|
||||
bool isValid = _dirSearchService.ValidateCredentials(dirEntryUsername, searchRootCreateDto.DirEntryPassword);
|
||||
|
||||
if (!isValid)
|
||||
return Unauthorized(Result.Fail().Message(_localizer[Key.UserNotFound]));
|
||||
|
||||
var userResult = await _userService.ReadByUsernameAsync(dirEntryUsername);
|
||||
if (!userResult.IsSuccess || userResult.Data is null)
|
||||
return Unauthorized(Result.Fail().Message(_localizer[Key.UserNotFoundInLocalDB]));
|
||||
|
||||
_dirSearchService.SetSearchRootCache(userResult.Data.Username, searchRootCreateDto.DirEntryPassword);
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("SearchByFilter/{filter}")]
|
||||
public IActionResult SearchByFilter([FromRoute] string filter, string? dirEntryUsername, params string[] propName)
|
||||
{
|
||||
try
|
||||
{
|
||||
dirEntryUsername ??= CurrentUser;
|
||||
|
||||
if (dirEntryUsername is null)
|
||||
return Unauthorized();
|
||||
|
||||
return _dirSearchService.FindAllByUserCache(dirEntryUsername, filter, properties: propName).Then(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status424FailedDependency);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("SearchByFilterName/{filterName}")]
|
||||
public IActionResult SearchByFilterName([FromRoute] string filterName, string? dirEntryUsername, params string[] propName)
|
||||
{
|
||||
try
|
||||
{
|
||||
dirEntryUsername ??= CurrentUser;
|
||||
|
||||
if (dirEntryUsername is null)
|
||||
return Unauthorized();
|
||||
|
||||
_dirSearchService.CustomSearchFilters.TryGetValue(filterName, out string? filter);
|
||||
|
||||
if (filter is null)
|
||||
return NotFound($"The filter named {filterName} does not exist.");
|
||||
|
||||
return _dirSearchService.FindAllByUserCache(dirEntryUsername, filter, properties: propName).Then(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status424FailedDependency);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("Group")]
|
||||
public IActionResult GetGroups(string? dirEntryUsername, params string[] propName)
|
||||
{
|
||||
try
|
||||
{
|
||||
dirEntryUsername ??= CurrentUser;
|
||||
|
||||
if (dirEntryUsername is null)
|
||||
return Unauthorized();
|
||||
|
||||
_dirSearchService.CustomSearchFilters.TryGetValue("Group", out string? filter);
|
||||
|
||||
if (filter is null)
|
||||
throw new InvalidOperationException("The LDAP Group Search filter configuration is missing in your appsettings. Please ensure it's added under DirectorySearch:CustomSearchFilters:Group to enable group searches.");
|
||||
|
||||
return _dirSearchService.FindAllByUserCache(username: dirEntryUsername, filter, properties: propName).Then(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status424FailedDependency);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("User")]
|
||||
public IActionResult GetUsersByGroupName(string? dirEntryUsername, [FromQuery] string? groupName = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] propName = { "memberof", "samaccountname", "givenname", "sn", "mail" };
|
||||
dirEntryUsername ??= CurrentUser;
|
||||
|
||||
if (dirEntryUsername is null)
|
||||
return Unauthorized();
|
||||
|
||||
_dirSearchService.CustomSearchFilters.TryGetValue("User", out string? filter);
|
||||
|
||||
if (filter is null)
|
||||
throw new InvalidOperationException("The LDAP User Search filter configuration is missing in your appsettings. Please ensure it's added under DirectorySearch:CustomSearchFilters:User to enable group searches.");
|
||||
|
||||
return _dirSearchService.FindAllByUserCache(username: dirEntryUsername, filter, properties: propName).Then(
|
||||
Success: data =>
|
||||
{
|
||||
if (groupName is not null)
|
||||
data = data
|
||||
.Where(rp => rp.PropertyNames.Cast<string>().Contains("memberof") &&
|
||||
rp["memberof"].Cast<string>().Any(ldapDir => ldapDir.Contains(groupName)))
|
||||
.ToList();
|
||||
return Ok(data);
|
||||
},
|
||||
Fail: IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status424FailedDependency);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
private string? CurrentUser
|
||||
{
|
||||
get => (HttpContext.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value);
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("CustomSearchFilter")]
|
||||
public IActionResult GetAllCustomFilters(string? filtername)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (filtername is null)
|
||||
{
|
||||
return Ok(_customSearchFilters);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dirSearchService.CustomSearchFilters.TryGetValue(filtername, out string? filter);
|
||||
return filter is null ? NotFound() : Ok(filter);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("CreateSearchRoot")]
|
||||
public async Task<IActionResult> CreateSearchRoot([FromBody] SearchRootCreateDto searchRootCreateDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dirEntryUsername = searchRootCreateDto.DirEntryUsername ?? CurrentUser;
|
||||
if (dirEntryUsername is null)
|
||||
return Unauthorized();
|
||||
|
||||
bool isValid = _dirSearchService.ValidateCredentials(dirEntryUsername, searchRootCreateDto.DirEntryPassword);
|
||||
|
||||
if (!isValid)
|
||||
return Unauthorized(Result.Fail().Message(_localizer[Key.UserNotFound]));
|
||||
|
||||
var userResult = await _userService.ReadByUsernameAsync(dirEntryUsername);
|
||||
if (!userResult.IsSuccess || userResult.Data is null)
|
||||
return Unauthorized(Result.Fail().Message(_localizer[Key.UserNotFoundInLocalDB]));
|
||||
|
||||
_dirSearchService.SetSearchRootCache(userResult.Data.Username, searchRootCreateDto.DirEntryPassword);
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("SearchByFilter/{filter}")]
|
||||
public IActionResult SearchByFilter([FromRoute] string filter, string? dirEntryUsername, params string[] propName)
|
||||
{
|
||||
try
|
||||
{
|
||||
dirEntryUsername ??= CurrentUser;
|
||||
|
||||
if (dirEntryUsername is null)
|
||||
return Unauthorized();
|
||||
|
||||
return _dirSearchService.FindAllByUserCache(dirEntryUsername, filter, properties: propName).Then(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status424FailedDependency);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("SearchByFilterName/{filterName}")]
|
||||
public IActionResult SearchByFilterName([FromRoute] string filterName, string? dirEntryUsername, params string[] propName)
|
||||
{
|
||||
try
|
||||
{
|
||||
dirEntryUsername ??= CurrentUser;
|
||||
|
||||
if (dirEntryUsername is null)
|
||||
return Unauthorized();
|
||||
|
||||
_dirSearchService.CustomSearchFilters.TryGetValue(filterName, out string? filter);
|
||||
|
||||
if (filter is null)
|
||||
return NotFound($"The filter named {filterName} does not exist.");
|
||||
|
||||
return _dirSearchService.FindAllByUserCache(dirEntryUsername, filter, properties: propName).Then(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status424FailedDependency);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("Group")]
|
||||
public IActionResult GetGroups(string? dirEntryUsername, params string[] propName)
|
||||
{
|
||||
try
|
||||
{
|
||||
dirEntryUsername ??= CurrentUser;
|
||||
|
||||
if (dirEntryUsername is null)
|
||||
return Unauthorized();
|
||||
|
||||
_dirSearchService.CustomSearchFilters.TryGetValue("Group", out string? filter);
|
||||
|
||||
if (filter is null)
|
||||
throw new InvalidOperationException("The LDAP Group Search filter configuration is missing in your appsettings. Please ensure it's added under DirectorySearch:CustomSearchFilters:Group to enable group searches.");
|
||||
|
||||
return _dirSearchService.FindAllByUserCache(username: dirEntryUsername, filter, properties: propName).Then(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status424FailedDependency);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("User")]
|
||||
public IActionResult GetUsersByGroupName(string? dirEntryUsername, [FromQuery] string? groupName = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] propName = { "memberof", "samaccountname", "givenname", "sn", "mail" };
|
||||
dirEntryUsername ??= CurrentUser;
|
||||
|
||||
if (dirEntryUsername is null)
|
||||
return Unauthorized();
|
||||
|
||||
_dirSearchService.CustomSearchFilters.TryGetValue("User", out string? filter);
|
||||
|
||||
if (filter is null)
|
||||
throw new InvalidOperationException("The LDAP User Search filter configuration is missing in your appsettings. Please ensure it's added under DirectorySearch:CustomSearchFilters:User to enable group searches.");
|
||||
|
||||
return _dirSearchService.FindAllByUserCache(username: dirEntryUsername, filter, properties: propName).Then(
|
||||
Success: data =>
|
||||
{
|
||||
if (groupName is not null)
|
||||
data = data
|
||||
.Where(rp => rp.PropertyNames.Cast<string>().Contains("memberof") &&
|
||||
rp["memberof"].Cast<string>().Any(ldapDir => ldapDir.Contains(groupName)))
|
||||
.ToList();
|
||||
return Ok(data);
|
||||
},
|
||||
Fail: IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status424FailedDependency);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
private string? CurrentUser
|
||||
{
|
||||
get => (HttpContext.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,44 @@
|
||||
using DigitalData.UserManager.Application.Services;
|
||||
using DigitalData.UserManager.Application.Services.Options;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace DigitalData.UserManager.API.Controllers
|
||||
namespace DigitalData.UserManager.API.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class EncryptionController : ControllerBase
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class EncryptionController : ControllerBase
|
||||
private readonly Encryptor _encryptor;
|
||||
|
||||
public EncryptionController(Encryptor encryptor)
|
||||
{
|
||||
private readonly Encryptor _encryptor;
|
||||
_encryptor = encryptor;
|
||||
}
|
||||
|
||||
public EncryptionController(Encryptor encryptor)
|
||||
{
|
||||
_encryptor = encryptor;
|
||||
}
|
||||
[HttpPost("encrypt")]
|
||||
public IActionResult Encrypt([FromQuery] string plainText, [FromBody] EncryptionParameters? options = null)
|
||||
{
|
||||
string cipherText = options is null
|
||||
? _encryptor.Encrypt(plainText)
|
||||
: Encryptor.Encrypt(plainText, options.Key, options.IV);
|
||||
|
||||
[HttpPost("encrypt")]
|
||||
public IActionResult Encrypt([FromQuery] string plainText, [FromBody] EncryptionParameters? options = null)
|
||||
{
|
||||
string cipherText = options is null
|
||||
? _encryptor.Encrypt(plainText)
|
||||
: Encryptor.Encrypt(plainText, options.Key, options.IV);
|
||||
return Ok(cipherText);
|
||||
}
|
||||
|
||||
return Ok(cipherText);
|
||||
}
|
||||
[HttpPost("decrypt")]
|
||||
public IActionResult Decrypt([FromQuery] string cipherText, [FromBody] EncryptionParameters? options = null)
|
||||
{
|
||||
var plainText = options is null
|
||||
? _encryptor.Decrypt(cipherText)
|
||||
: Encryptor.Decrypt(cipherText, options.Key, options.IV);
|
||||
|
||||
[HttpPost("decrypt")]
|
||||
public IActionResult Decrypt([FromQuery] string cipherText, [FromBody] EncryptionParameters? options = null)
|
||||
{
|
||||
var plainText = options is null
|
||||
? _encryptor.Decrypt(cipherText)
|
||||
: Encryptor.Decrypt(cipherText, options.Key, options.IV);
|
||||
return Ok(plainText);
|
||||
}
|
||||
|
||||
return Ok(plainText);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Generate()
|
||||
{
|
||||
var param = Encryptor.GenerateParameters();
|
||||
return Ok(param);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult Generate()
|
||||
{
|
||||
var param = Encryptor.GenerateParameters();
|
||||
return Ok(param);
|
||||
}
|
||||
}
|
||||
@@ -5,39 +5,38 @@ using DigitalData.UserManager.Domain.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace DigitalData.UserManager.API.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
public class GroupController : BaseAuthController<IGroupService, GroupCreateDto, GroupReadDto, GroupUpdateDto, Group>
|
||||
{
|
||||
public GroupController(ILogger<GroupController> logger, IGroupService service, IUserService userService) : base(logger, service, userService)
|
||||
{
|
||||
}
|
||||
namespace DigitalData.UserManager.API.Controllers;
|
||||
|
||||
[HttpPost("ByDir")]
|
||||
public async Task<IActionResult> CreateByDir(DirectoryGroupDto adGroup)
|
||||
[Authorize]
|
||||
public class GroupController : BaseAuthController<IGroupService, GroupCreateDto, GroupReadDto, GroupUpdateDto, Group>
|
||||
{
|
||||
public GroupController(ILogger<GroupController> logger, IGroupService service, IUserService userService) : base(logger, service, userService)
|
||||
{
|
||||
}
|
||||
|
||||
[HttpPost("ByDir")]
|
||||
public async Task<IActionResult> CreateByDir(DirectoryGroupDto adGroup)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _service.CreateAsync(adGroup).ThenAsync(
|
||||
Success: id =>
|
||||
{
|
||||
var createdResource = new { Id = id };
|
||||
var actionName = nameof(GetById);
|
||||
var routeValues = new { id = createdResource.Id };
|
||||
return CreatedAtAction(actionName, routeValues, createdResource);
|
||||
},
|
||||
Fail: IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return BadRequest();
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
return await _service.CreateAsync(adGroup).ThenAsync(
|
||||
Success: id =>
|
||||
{
|
||||
var createdResource = new { Id = id };
|
||||
var actionName = nameof(GetById);
|
||||
var routeValues = new { id = createdResource.Id };
|
||||
return CreatedAtAction(actionName, routeValues, createdResource);
|
||||
},
|
||||
Fail: IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return BadRequest();
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,77 +5,76 @@ using DigitalData.UserManager.Domain.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace DigitalData.UserManager.API.Controllers
|
||||
namespace DigitalData.UserManager.API.Controllers;
|
||||
|
||||
[Authorize]
|
||||
public class GroupOfUserController : BaseAuthController<IGroupOfUserService, GroupOfUserCreateDto, GroupOfUserReadDto, GroupOfUserUpdateDto, GroupOfUser>
|
||||
{
|
||||
[Authorize]
|
||||
public class GroupOfUserController : BaseAuthController<IGroupOfUserService, GroupOfUserCreateDto, GroupOfUserReadDto, GroupOfUserUpdateDto, GroupOfUser>
|
||||
public GroupOfUserController(ILogger<GroupOfUserController> logger, IGroupOfUserService service, IUserService userService) : base(logger, service, userService)
|
||||
{
|
||||
public GroupOfUserController(ILogger<GroupOfUserController> logger, IGroupOfUserService service, IUserService userService) : base(logger, service, userService)
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
public async Task<IActionResult> Delete([FromQuery] int groupId, [FromQuery] int userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
public async Task<IActionResult> Delete([FromQuery] int groupId, [FromQuery] int userId)
|
||||
{
|
||||
try
|
||||
return await _service.DeleteAsyncByGroupUserId(groupId, userId).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
return await _service.DeleteAsyncByGroupUserId(groupId, userId).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> GetAll() => base.GetAll();
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll([FromQuery]bool withUser = false, [FromQuery]bool withGroup = false, [FromQuery] string? username = null)
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (username is not null)
|
||||
return await _service.ReadByUsernameAsync(username).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return NotFound();
|
||||
});
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
return await _service.ReadAllAsyncWith(withUser, withGroup).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
[NonAction]
|
||||
public override Task<IActionResult> GetAll() => base.GetAll();
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll([FromQuery]bool withUser = false, [FromQuery]bool withGroup = false, [FromQuery] string? username = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (username is not null)
|
||||
return await _service.ReadByUsernameAsync(username).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return NotFound();
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("Has")]
|
||||
public async Task<IActionResult> HasGroup([FromQuery] string username, [FromQuery] string groupname)
|
||||
return await _service.ReadAllAsyncWith(withUser, withGroup).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return NotFound();
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
try
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("Has")]
|
||||
public async Task<IActionResult> HasGroup([FromQuery] string username, [FromQuery] string groupname)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _service.HasGroup(username, groupname).ThenAsync(Ok, (m, n) =>
|
||||
{
|
||||
return await _service.HasGroup(username, groupname).ThenAsync(Ok, (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,12 @@ using DigitalData.UserManager.Application.DTOs.Module;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace DigitalData.UserManager.API.Controllers
|
||||
namespace DigitalData.UserManager.API.Controllers;
|
||||
|
||||
[Authorize]
|
||||
public class ModuleController : ReadControllerBaseWithErrorHandling<IModuleService, ModuleDto, Module, int>
|
||||
{
|
||||
[Authorize]
|
||||
public class ModuleController : ReadControllerBaseWithErrorHandling<IModuleService, ModuleDto, Module, int>
|
||||
public ModuleController(ILogger<ModuleController> logger, IModuleService service) : base(logger, service)
|
||||
{
|
||||
public ModuleController(ILogger<ModuleController> logger, IModuleService service) : base(logger, service)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,48 +6,47 @@ using DigitalData.UserManager.Domain.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace DigitalData.UserManager.API.Controllers
|
||||
namespace DigitalData.UserManager.API.Controllers;
|
||||
|
||||
[Authorize]
|
||||
public class ModuleOfUserController : CRUDControllerBaseWithErrorHandling<IModuleOfUserService, ModuleOfUserCreateDto, ModuleOfUserReadDto, ModuleOfUserUpdateDto, ModuleOfUser, int>
|
||||
{
|
||||
[Authorize]
|
||||
public class ModuleOfUserController : CRUDControllerBaseWithErrorHandling<IModuleOfUserService, ModuleOfUserCreateDto, ModuleOfUserReadDto, ModuleOfUserUpdateDto, ModuleOfUser, int>
|
||||
public ModuleOfUserController(ILogger<ModuleOfUserController> logger, IModuleOfUserService service) : base(logger, service)
|
||||
{
|
||||
public ModuleOfUserController(ILogger<ModuleOfUserController> logger, IModuleOfUserService service) : base(logger, service)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> GetAll() => base.GetAll();
|
||||
[NonAction]
|
||||
public override Task<IActionResult> GetAll() => base.GetAll();
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll(string? username = null)
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll(string? username = null)
|
||||
{
|
||||
|
||||
if (username is not null)
|
||||
return await _service.ReadByUserAsync(username).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
|
||||
return await base.GetAll();
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
public async Task<IActionResult> Delete([FromQuery] int moduleId, [FromQuery]int userId)
|
||||
{
|
||||
try
|
||||
if (username is not null)
|
||||
return await _service.ReadByUserAsync(username).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
return await _service.DeleteAsyncByModuleUserId(moduleId, userId).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return BadRequest();
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
});
|
||||
|
||||
return await base.GetAll();
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
public async Task<IActionResult> Delete([FromQuery] int moduleId, [FromQuery]int userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _service.DeleteAsyncByModuleUserId(moduleId, userId).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return BadRequest();
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using DigitalData.Core.API;
|
||||
using DigitalData.Core.DTO;
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
@@ -6,95 +5,94 @@ using DigitalData.UserManager.Domain.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace DigitalData.UserManager.API.Controllers
|
||||
namespace DigitalData.UserManager.API.Controllers;
|
||||
|
||||
[Authorize]
|
||||
public class UserController : BaseAuthController<IUserService, UserCreateDto, UserReadDto, UserUpdateDto, User>
|
||||
{
|
||||
[Authorize]
|
||||
public class UserController : BaseAuthController<IUserService, UserCreateDto, UserReadDto, UserUpdateDto, User>
|
||||
public UserController(ILogger<UserController> logger, IUserService service) : base(logger, service, service)
|
||||
{
|
||||
public UserController(ILogger<UserController> logger, IUserService service) : base(logger, service, service)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("ByModuleId/{moduleId}")]
|
||||
public async Task<IActionResult> GetByModuleId([FromRoute] int moduleId, [FromQuery]bool assigned = true)
|
||||
[HttpGet("ByModuleId/{moduleId}")]
|
||||
public async Task<IActionResult> GetByModuleId([FromRoute] int moduleId, [FromQuery]bool assigned = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
return await (assigned ? _service.ReadByModuleIdAsync(moduleId) : _service.ReadUnassignedByModuleIdAsync(moduleId))
|
||||
.ThenAsync(Ok, IActionResult(m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("ByGroupId/{groupId}")]
|
||||
public async Task<IActionResult> GetByGroupId([FromRoute] int groupId, [FromQuery] bool assigned = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await (assigned ? _service.ReadByGroupIdAsync(groupId) : _service.ReadUnassignedByGroupIdAsync(groupId))
|
||||
.ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("ByDir")]
|
||||
public async Task<IActionResult> CreateByDir(UserPrincipalDto upDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _service.CreateAsync(upDto).ThenAsync(
|
||||
Success: id =>
|
||||
{
|
||||
var createdResource = new { Id = id };
|
||||
var actionName = nameof(GetById);
|
||||
var routeValues = new { id = createdResource.Id };
|
||||
return CreatedAtAction(actionName, routeValues, createdResource);
|
||||
},
|
||||
Fail: IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return BadRequest();
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("ByUsername/{username}")]
|
||||
public virtual async Task<IActionResult> GetByUsername([FromRoute] string username)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _service.ReadByUsernameAsync(username).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
return await (assigned ? _service.ReadByModuleIdAsync(moduleId) : _service.ReadUnassignedByModuleIdAsync(moduleId))
|
||||
.ThenAsync(Ok, IActionResult(m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return NotFound();
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("ByGroupId/{groupId}")]
|
||||
public async Task<IActionResult> GetByGroupId([FromRoute] int groupId, [FromQuery] bool assigned = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await (assigned ? _service.ReadByGroupIdAsync(groupId) : _service.ReadUnassignedByGroupIdAsync(groupId))
|
||||
.ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("ByDir")]
|
||||
public async Task<IActionResult> CreateByDir(UserPrincipalDto upDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _service.CreateAsync(upDto).ThenAsync(
|
||||
Success: id =>
|
||||
{
|
||||
var createdResource = new { Id = id };
|
||||
var actionName = nameof(GetById);
|
||||
var routeValues = new { id = createdResource.Id };
|
||||
return CreatedAtAction(actionName, routeValues, createdResource);
|
||||
},
|
||||
Fail: IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return BadRequest();
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("ByUsername/{username}")]
|
||||
public virtual async Task<IActionResult> GetByUsername([FromRoute] string username)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _service.ReadByUsernameAsync(username).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
_logger.LogNotice(n);
|
||||
return NotFound();
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,38 +5,37 @@ using DigitalData.UserManager.Domain.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace DigitalData.UserManager.API.Controllers
|
||||
namespace DigitalData.UserManager.API.Controllers;
|
||||
|
||||
[Authorize]
|
||||
public class UserRepController : BaseAuthController<IUserRepService, UserRepCreateDto, UserRepReadDto, UserRepUpdateDto, UserRep>
|
||||
{
|
||||
[Authorize]
|
||||
public class UserRepController : BaseAuthController<IUserRepService, UserRepCreateDto, UserRepReadDto, UserRepUpdateDto, UserRep>
|
||||
public UserRepController(ILogger<UserRepController> logger, IUserRepService service, IUserService userService) : base(logger, service, userService)
|
||||
{
|
||||
public UserRepController(ILogger<UserRepController> logger, IUserRepService service, IUserService userService) : base(logger, service, userService)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public override Task<IActionResult> GetAll()
|
||||
[NonAction]
|
||||
public override Task<IActionResult> GetAll()
|
||||
{
|
||||
return base.GetAll();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll(bool withUser = false, bool withRepGroup = false, bool withGroup = false, bool withRepUser = false, int? userId = null, int? groupId = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return base.GetAll();
|
||||
return await _service.ReadAllAsync(withUser: withUser, withRepGroup: withRepGroup, withGroup: withGroup, withRepUser: withRepUser,
|
||||
userId: userId, groupId: groupId).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return NotFound();
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll(bool withUser = false, bool withRepGroup = false, bool withGroup = false, bool withRepUser = false, int? userId = null, int? groupId = null)
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _service.ReadAllAsync(withUser, withRepGroup, withGroup, withRepUser, userId, groupId).ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return NotFound();
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +1,40 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>2.0.0.0</Version>
|
||||
<Version>6.0.1</Version>
|
||||
<AssemblyVersion>6.0.1</AssemblyVersion>
|
||||
<FileVersion>6.0.1</FileVersion>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="wwwroot\assets\img\DD_white.svg" />
|
||||
<Content Remove="wwwroot\assets\img\digital_data.svg" />
|
||||
<Content Remove="wwwroot\assets\img\digital_data_red_BG.svg" />
|
||||
<Content Remove="wwwroot\assets\img\group.svg" />
|
||||
<Content Remove="wwwroot\assets\img\Huhn_andersrum.webp" />
|
||||
<Content Remove="wwwroot\assets\img\login_logo.svg" />
|
||||
<Content Remove="wwwroot\assets\img\mode_logo.svg" />
|
||||
<Content Remove="wwwroot\assets\img\thema_bttn.svg" />
|
||||
<Content Remove="wwwroot\assets\img\user-plus-svgrepo-com.svg" />
|
||||
<Content Remove="wwwroot\assets\img\user.svg" />
|
||||
<Content Remove="wwwroot\chunk-A2L6DXQH.js" />
|
||||
<Content Remove="wwwroot\chunk-ZC35XWOR.js" />
|
||||
<Content Remove="wwwroot\favicon.ico" />
|
||||
<Content Remove="wwwroot\group-table\index.html" />
|
||||
<Content Remove="wwwroot\index.html" />
|
||||
<Content Remove="wwwroot\main-QF3MRK45.js" />
|
||||
<Content Remove="wwwroot\media\bootstrap-icons-OCU552PF.woff" />
|
||||
<Content Remove="wwwroot\media\bootstrap-icons-X6UQXWUS.woff2" />
|
||||
<Content Remove="wwwroot\module-table\index.html" />
|
||||
<Content Remove="wwwroot\polyfills-6EAL64PA.js" />
|
||||
<Content Remove="wwwroot\scripts-EEEIPNC3.js" />
|
||||
<Content Remove="wwwroot\styles-ZC4KW2NT.css" />
|
||||
<Content Remove="wwwroot\user-assignment\index.html" />
|
||||
<Content Remove="wwwroot\user-representation\index.html" />
|
||||
<Content Remove="wwwroot\user-table\index.html" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DigitalData.Core.API" Version="2.0.0" />
|
||||
<Content Include="wwwroot\assets\img\.vscode\settings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DigitalData.Auth.Client" Version="1.3.5" />
|
||||
<PackageReference Include="DigitalData.Core.API" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.14" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.20" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.16" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.15">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.15" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="NLog" Version="5.3.2" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.11" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="System.DirectoryServices" Version="7.0.1" />
|
||||
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="7.0.1" />
|
||||
<PackageReference Include="System.DirectoryServices.Protocols" Version="7.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DigitalData.UserManager.Application\DigitalData.UserManager.Application.csproj" />
|
||||
<ProjectReference Include="..\DigitalData.UserManager.Domain\DigitalData.UserManager.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -64,6 +42,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\Assets\icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
<None Include="wwwroot\assets\img\DD_white.svg" />
|
||||
<None Include="wwwroot\assets\img\digital_data.svg" />
|
||||
<None Include="wwwroot\assets\img\digital_data_red_BG.svg" />
|
||||
@@ -74,24 +56,11 @@
|
||||
<None Include="wwwroot\assets\img\thema_bttn.svg" />
|
||||
<None Include="wwwroot\assets\img\user-plus-svgrepo-com.svg" />
|
||||
<None Include="wwwroot\assets\img\user.svg" />
|
||||
<None Include="wwwroot\favicon.ico" />
|
||||
<None Include="wwwroot\group-table\index.html" />
|
||||
<None Include="wwwroot\index.html" />
|
||||
<None Include="wwwroot\media\bootstrap-icons-OCU552PF.woff" />
|
||||
<None Include="wwwroot\media\bootstrap-icons-X6UQXWUS.woff2" />
|
||||
<None Include="wwwroot\module-table\index.html" />
|
||||
<None Include="wwwroot\polyfills-6EAL64PA.js" />
|
||||
<None Include="wwwroot\scripts-EEEIPNC3.js" />
|
||||
<None Include="wwwroot\styles-ZC4KW2NT.css" />
|
||||
<None Include="wwwroot\user-assignment\index.html" />
|
||||
<None Include="wwwroot\user-representation\index.html" />
|
||||
<None Include="wwwroot\user-table\index.html" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="wwwroot\assets\config.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<ProjectReference Include="..\DigitalData.UserManager.DependencyInjection\DigitalData.UserManager.DependencyInjection.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
18
DigitalData.UserManager.API/LazyServiceProvider.cs
Normal file
18
DigitalData.UserManager.API/LazyServiceProvider.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace DigitalData.UserManager.API;
|
||||
|
||||
public class LazyServiceProvider : IServiceProvider
|
||||
{
|
||||
private Lazy<IServiceProvider>? _serviceProvider;
|
||||
|
||||
public Func<IServiceProvider> Factory
|
||||
{
|
||||
set => _serviceProvider = new(value);
|
||||
}
|
||||
|
||||
public object? GetService(Type serviceType)
|
||||
{
|
||||
if (_serviceProvider is null)
|
||||
throw new InvalidOperationException("GetService cannot be called before _serviceProvider is set.");
|
||||
return _serviceProvider.Value.GetService(serviceType);
|
||||
}
|
||||
}
|
||||
12
DigitalData.UserManager.API/Models/AuthTokenKeys.cs
Normal file
12
DigitalData.UserManager.API/Models/AuthTokenKeys.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace DigitalData.UserManager.API.Models;
|
||||
|
||||
public class AuthTokenKeys
|
||||
{
|
||||
public string Cookie { get; init; } = "AuthToken";
|
||||
|
||||
public string QueryString { get; init; } = "AuthToken";
|
||||
|
||||
public string Issuer { get; init; } = "auth.digitaldata.works";
|
||||
|
||||
public string Audience { get; init; } = "user-manager.digitaldata.works";
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace DigitalData.UserManager.API.Models
|
||||
{
|
||||
public class Constants
|
||||
{
|
||||
public IEnumerable<string> UserLanguages { get; init; } = Array.Empty<string>();
|
||||
|
||||
public object? this[string propertyName] => GetType()
|
||||
.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance)?
|
||||
.GetValue(this, null);
|
||||
}
|
||||
}
|
||||
18
DigitalData.UserManager.API/Models/ModelExtensions.cs
Normal file
18
DigitalData.UserManager.API/Models/ModelExtensions.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace DigitalData.UserManager.API.Models;
|
||||
|
||||
public static class ModelExtensions
|
||||
{
|
||||
public static List<Claim> ToClaimList(this UserReadDto user) => new()
|
||||
{
|
||||
new (ClaimTypes.NameIdentifier, user.Id.ToString()),
|
||||
new (ClaimTypes.Name, user.Username),
|
||||
new (ClaimTypes.Surname, user.Name ?? ""),
|
||||
new (ClaimTypes.GivenName, user.Prename ?? ""),
|
||||
new (ClaimTypes.Email, user.Email ?? "")
|
||||
};
|
||||
|
||||
public static Dictionary<string, object> ToClaimDictionary(this UserReadDto user) => user.ToClaimList().ToDictionary(claim => claim.Type, claim => (object)claim.Value);
|
||||
}
|
||||
@@ -9,26 +9,40 @@ using DigitalData.Core.API;
|
||||
using DigitalData.UserManager.API.Controllers;
|
||||
using DigitalData.UserManager.Application.Services;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Reflection.Metadata;
|
||||
using Newtonsoft.Json;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using DigitalData.UserManager.API.Models;
|
||||
using DigitalData.Auth.Client;
|
||||
using DigitalData.UserManager.API;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.Extensions.Options;
|
||||
using DigitalData.Core.Abstractions.Security.Extensions;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using DigitalData.UserManager.DependencyInjection;
|
||||
|
||||
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
||||
logger.Debug("init main");
|
||||
|
||||
try {
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
|
||||
var config = builder.Configuration;
|
||||
|
||||
builder.Services.AddEncryptor(builder.Configuration.GetSection("EncryptionParameters"));
|
||||
|
||||
if (builder.Configuration.GetValue<bool>("RunAsWindowsService"))
|
||||
builder.Host.UseWindowsService();
|
||||
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Host.UseNLog();
|
||||
|
||||
builder.Services.AddControllers();
|
||||
|
||||
builder.Services.AddControllers(opt =>
|
||||
{
|
||||
opt.Conventions.Add(new RemoveIfControllerConvention()
|
||||
.AndIf(c => c.ControllerName == nameof(EncryptionController).Replace("Controller", ""))
|
||||
.AndIf(c => !config.GetValue<bool>("UseEncryptor")));
|
||||
}).AddNewtonsoftJson(options =>
|
||||
{
|
||||
options.SerializerSettings.DateTimeZoneHandling = config.GetValue<DateTimeZoneHandling>("DateTimeZoneHandling");
|
||||
});
|
||||
|
||||
if (builder.Configuration.GetValue<bool>("UseSwagger"))
|
||||
{
|
||||
@@ -56,7 +70,7 @@ try {
|
||||
// Once the app is built, the password will be decrypted with Encryptor. lazy loading also acts as a call back method.
|
||||
Lazy<string>? cnn_str = null;
|
||||
|
||||
builder.Services.AddDbContext<UserManagerDbContext>(options => options.UseSqlServer(cnn_str!.Value).EnableDetailedErrors());
|
||||
builder.Services.AddUserManager(options => options.UseSqlServer(cnn_str!.Value).EnableSensitiveDataLogging());
|
||||
|
||||
var allowedOrigins = builder.Configuration.GetSection("AllowedOrigins").Get<string[]>() ?? throw new InvalidOperationException("In appsettings there is no allowed origin.");
|
||||
|
||||
@@ -71,19 +85,93 @@ try {
|
||||
.AllowCredentials();
|
||||
});
|
||||
});
|
||||
|
||||
//builder.Services.AddAutoMapper(typeof(DirectoryMappingProfile).Assembly);
|
||||
builder.Services.AddUserManager<UserManagerDbContext>();
|
||||
|
||||
|
||||
builder.ConfigureBySection<DirectorySearchOptions>();
|
||||
builder.Services.AddDirectorySearchService();
|
||||
builder.Services.AddDirectorySearchService(config.GetSection("DirectorySearchOptions"));
|
||||
builder.Services.AddJWTService<UserReadDto>(user => new SecurityTokenDescriptor()
|
||||
{
|
||||
Claims = user.ToClaimList().ToDictionary(claim => claim.Type, claim => claim.Value as object)
|
||||
});
|
||||
|
||||
var lazyProvider = new LazyServiceProvider();
|
||||
|
||||
builder.Services.AddAuthHubClient(config.GetSection("AuthClientParams"));
|
||||
|
||||
var authTokenKeys = config.GetSection(nameof(AuthTokenKeys)).Get<AuthTokenKeys>() ?? new();
|
||||
|
||||
builder.Services
|
||||
.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddJwtBearer(opt =>
|
||||
{
|
||||
opt.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) =>
|
||||
{
|
||||
var clientParams = lazyProvider.GetRequiredService<IOptions<ClientParams>>()?.Value;
|
||||
var publicKey = clientParams!.PublicKeys.Get(authTokenKeys.Issuer, authTokenKeys.Audience);
|
||||
return new List<SecurityKey>() { publicKey.SecurityKey };
|
||||
},
|
||||
ValidateIssuer = true,
|
||||
ValidIssuer = authTokenKeys.Issuer,
|
||||
ValidateAudience = true,
|
||||
ValidAudience = authTokenKeys.Audience,
|
||||
};
|
||||
|
||||
opt.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
// if there is no token read related cookie or query string
|
||||
if (context.Token is null) // if there is no token
|
||||
{
|
||||
if (context.Request.Cookies.TryGetValue(authTokenKeys.Cookie, out var cookieToken) && cookieToken is not null)
|
||||
context.Token = cookieToken;
|
||||
else if (context.Request.Query.TryGetValue(authTokenKeys.QueryString, out var queryStrToken))
|
||||
context.Token = queryStrToken;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
builder.Services.AddSwaggerGen(setupAct =>
|
||||
{
|
||||
setupAct.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.Http,
|
||||
Scheme = "Bearer"
|
||||
});
|
||||
|
||||
setupAct.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
Array.Empty<string>()
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
builder.Services.AddCookieBasedLocalizer();
|
||||
|
||||
builder.ConfigureBySection<Constants>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
lazyProvider.Factory = () => app.Services;
|
||||
|
||||
cnn_str = new(() =>
|
||||
{
|
||||
var encryptor = app.Services.GetRequiredService<Encryptor>();
|
||||
|
||||
@@ -11,9 +11,12 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||
<ProjectGuid>07ccd651-647c-49f7-9715-30cebc13710d</ProjectGuid>
|
||||
<DesktopBuildPackageLocation>E:\TekH\Visual Studio\src\DigitalData.UserManager.API.zip</DesktopBuildPackageLocation>
|
||||
<DesktopBuildPackageLocation>P:\Install .Net\0 DD - Smart UP\DD-UserManager\Web\$(Version)\$(Version).zip</DesktopBuildPackageLocation>
|
||||
<PackageAsSingleFile>true</PackageAsSingleFile>
|
||||
<DeployIisAppPath>UserManager</DeployIisAppPath>
|
||||
<DeployIisAppPath>UserManager.API</DeployIisAppPath>
|
||||
<_TargetId>IISWebDeployPackage</_TargetId>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<SelfContained>true</SelfContained>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -22,7 +22,7 @@
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchBrowser": false,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:7103;http://localhost:5137",
|
||||
"environmentVariables": {
|
||||
|
||||
@@ -71,13 +71,20 @@
|
||||
"Key": "JGPwHVD0BQmC7upi5OV11PzzIk47ugTJoqBV/et5w40=",
|
||||
"IV": "gMuetIjlPvJnSzu+i7I3xg=="
|
||||
},
|
||||
"AllowedGroupName": "UM_ADMINS",
|
||||
"DateTimeZoneHandling": "Local",
|
||||
// Delete below in production
|
||||
"UseEncryptor": true,
|
||||
"UseSwagger": true,
|
||||
"Constants": {
|
||||
"UserLanguages": [
|
||||
"de-DE",
|
||||
"en-US"
|
||||
]
|
||||
"AuthClientParams": {
|
||||
"Url": "https://localhost:7192/auth-hub",
|
||||
"PublicKeys": [
|
||||
{
|
||||
"Issuer": "auth.digitaldata.works",
|
||||
"Audience": "user-manager.digitaldata.works",
|
||||
"Content": "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3QCd7dH/xOUITFZbitMa/xnh8a0LyL6ZBvSRAwkI9ceplTRSHJXoM1oB+xtjWE1kOuHVLe941Tm03szS4+/rHIm0Ejva/KKlv7sPFAHE/pWuoPS303vOHgI4HAFcuwywA8CghUWzaaK5LU/Hl8srWwxBHv5hKIUjJFJygeAIENvFOZ1gFbB3MPEC99PiPOwAmfl4tMQUmSsFyspl/RWVi7bTv26ZE+m3KPcWppmvmYjXlSitxRaySxnfFvpca/qWfd/uUUg2KWKtpAwWVkqr0qD9v3TyKSgHoGDsrFpwSx8qufUJSinmZ1u/0iKl6TXeHubYS4C4SUSVjOWXymI2ZQIDAQAB-----END PUBLIC KEY-----"
|
||||
}
|
||||
],
|
||||
"RetryDelay": "00:00:05"
|
||||
}
|
||||
}
|
||||
7
DigitalData.UserManager.API/wwwroot/chunk-BERTLP66.js
Normal file
7
DigitalData.UserManager.API/wwwroot/chunk-BERTLP66.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
164
DigitalData.UserManager.API/wwwroot/main-UKQG27PC.js
Normal file
164
DigitalData.UserManager.API/wwwroot/main-UKQG27PC.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,10 +5,9 @@ using DigitalData.UserManager.Application.DTOs.Base;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts
|
||||
{
|
||||
public interface IBaseService<TCreateDto, TReadDto, TUpdateDto, TBaseEntity> : ICRUDService<TCreateDto, TReadDto, TUpdateDto, TBaseEntity, int>
|
||||
public interface IBaseService<TCreateDto, TReadDto, TBaseEntity> : ICRUDService<TCreateDto, TReadDto, TBaseEntity, int>
|
||||
where TCreateDto : BaseCreateDto
|
||||
where TReadDto : class
|
||||
where TUpdateDto : BaseUpdateDto
|
||||
where TBaseEntity : BaseEntity
|
||||
{
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using DigitalData.Core.DTO;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts
|
||||
{
|
||||
public interface IGroupOfUserService : IBaseService<GroupOfUserCreateDto, GroupOfUserReadDto, GroupOfUserUpdateDto, GroupOfUser>
|
||||
public interface IGroupOfUserService : IBaseService<GroupOfUserCreateDto, GroupOfUserReadDto, GroupOfUser>
|
||||
{
|
||||
Task<Result> DeleteAsyncByGroupUserId(int groupId, int userId);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using DigitalData.Core.DTO;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts
|
||||
{
|
||||
public interface IGroupService : IBaseService<GroupCreateDto, GroupReadDto, GroupUpdateDto, Group>
|
||||
public interface IGroupService : IBaseService<GroupCreateDto, GroupReadDto, Group>
|
||||
{
|
||||
Task<DataResult<int>> CreateAsync(DirectoryGroupDto dirGroup);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts
|
||||
{
|
||||
public interface IModuleOfUserService : ICRUDService<ModuleOfUserCreateDto, ModuleOfUserReadDto, ModuleOfUserUpdateDto, ModuleOfUser, int>
|
||||
public interface IModuleOfUserService : ICRUDService<ModuleOfUserCreateDto, ModuleOfUserReadDto, ModuleOfUser, int>
|
||||
{
|
||||
Task<Result> DeleteAsyncByModuleUserId(int moduleId, int userId);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using DigitalData.Core.DTO;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts
|
||||
{
|
||||
public interface IUserRepService : IBaseService<UserRepCreateDto, UserRepReadDto, UserRepUpdateDto, UserRep>
|
||||
public interface IUserRepService : IBaseService<UserRepCreateDto, UserRepReadDto, UserRep>
|
||||
{
|
||||
Task<DataResult<IEnumerable<UserRepReadDto>>> ReadAllAsync(bool withUser = false, bool withRepGroup = false, bool withGroup = false, bool withRepUser = false, int? userId = null, int? groupId = null);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using DigitalData.Core.DTO;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts
|
||||
{
|
||||
public interface IUserService : IBaseService<UserCreateDto, UserReadDto, UserUpdateDto, User>
|
||||
public interface IUserService : IBaseService<UserCreateDto, UserReadDto, User>
|
||||
{
|
||||
Task<DataResult<IEnumerable<UserReadDto>>> ReadByModuleIdAsync(int moduleId);
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
|
||||
public interface IClientUserRepository : ICRUDRepository<ClientUser, int>
|
||||
{
|
||||
Task<IEnumerable<ClientUser>> ReadAsync(bool readOnly = true, int? userId = null);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
|
||||
public interface IGroupOfUserRepository : ICRUDRepository<GroupOfUser, int>
|
||||
{
|
||||
IQueryable<GroupOfUser> ReadByGroupId(int groupId);
|
||||
|
||||
Task<IEnumerable<GroupOfUser>> ReadByGroupUserIdAsync(int groupId, int userId);
|
||||
|
||||
Task<IEnumerable<GroupOfUser>> ReadAllAsyncWithGroup();
|
||||
|
||||
Task<IEnumerable<GroupOfUser>> ReadAllAsyncWithUser();
|
||||
|
||||
Task<IEnumerable<GroupOfUser>> ReadAllAsyncWithGroupAndUser();
|
||||
|
||||
Task<IEnumerable<GroupOfUser>> ReadByUsernameAsync(string username);
|
||||
|
||||
Task<IEnumerable<GroupOfUser>> ReadByUserIdAsync(int userId);
|
||||
|
||||
// merge all GroupOfUserRepository-methods conditionally under this method
|
||||
Task<IEnumerable<GroupOfUser>> ReadAsync(
|
||||
bool readOnly = true,
|
||||
bool withGroup = true, bool withUser = true,
|
||||
int? id = null, int? groupId = null, int? userId = null, string? username = null);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
|
||||
public interface IGroupRepository : ICRUDRepository<Group, int>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
|
||||
public interface IModuleOfUserRepository : ICRUDRepository<ModuleOfUser, int>
|
||||
{
|
||||
IQueryable<ModuleOfUser> ReadByModuleId(int moduleId);
|
||||
|
||||
Task<IEnumerable<ModuleOfUser>> ReadByModelUserIdAsync(int moduleId, int userId);
|
||||
|
||||
Task<IEnumerable<ModuleOfUser>> ReadByUserAsync(string username);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
|
||||
public interface IModuleRepository : ICRUDRepository<Module, int>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
|
||||
public interface IUserRepRepository : ICRUDRepository<UserRep, int>
|
||||
{
|
||||
Task<IEnumerable<UserRep>> ReadAllAsync(
|
||||
bool withUser = false, bool withRepGroup = false, bool withGroup = false, bool withRepUser = false,
|
||||
int? userId = null, int? repUserId = null, int? groupId = null, int? repGroupId = null, bool readOnly = true);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
|
||||
public interface IUserRepository : ICRUDRepository<User, int>
|
||||
{
|
||||
Task<IEnumerable<User>> ReadByModuleIdAsync(int moduleId);
|
||||
|
||||
Task<IEnumerable<User>> ReadUnassignedByModuleIdAsync(int moduleId);
|
||||
|
||||
Task<IEnumerable<User>> ReadByGroupIdAsync(int groupId);
|
||||
|
||||
Task<IEnumerable<User>> ReadUnassignedByGroupIdAsync(int groupId);
|
||||
|
||||
Task<User?> ReadByUsernameAsync(string username);
|
||||
}
|
||||
@@ -2,9 +2,6 @@
|
||||
using DigitalData.UserManager.Application.MappingProfiles;
|
||||
using DigitalData.UserManager.Application.Services;
|
||||
using DigitalData.UserManager.Application.Services.Options;
|
||||
using DigitalData.UserManager.Infrastructure.Contracts;
|
||||
using DigitalData.UserManager.Infrastructure.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
@@ -19,8 +16,7 @@ namespace DigitalData.UserManager.Application
|
||||
/// <typeparam name="TDbContext">The type of the DbContext to use for the repositories.</typeparam>
|
||||
/// <param name="services">The IServiceCollection to which the services will be added.</param>
|
||||
/// <returns>The updated IServiceCollection.</returns>
|
||||
public static IServiceCollection AddUserManager<TDbContext>(this IServiceCollection services)
|
||||
where TDbContext : DbContext, IUserManagerDbContext
|
||||
public static IServiceCollection AddUserManagerApplication(this IServiceCollection services)
|
||||
=> services
|
||||
.AddAutoMapper(typeof(UserMappingProfile).Assembly)
|
||||
.AddAutoMapper(typeof(GroupMappingProfile).Assembly)
|
||||
@@ -29,20 +25,13 @@ namespace DigitalData.UserManager.Application
|
||||
.AddAutoMapper(typeof(ModuleOfUserMappingProfile).Assembly)
|
||||
.AddAutoMapper(typeof(UserRepMappingProfile).Assembly)
|
||||
|
||||
.AddScoped<IUserRepository, UserRepository<TDbContext>>()
|
||||
.AddScoped<IGroupRepository, GroupRepository<TDbContext>>()
|
||||
.AddScoped<IGroupOfUserRepository, GroupOfUserRepository<TDbContext>>()
|
||||
.AddScoped<IModuleRepository, ModuleRepository<TDbContext>>()
|
||||
.AddScoped<IModuleOfUserRepository, ModuleOfUserRepository<TDbContext>>()
|
||||
.AddScoped<IUserRepRepository, UserRepRepository<TDbContext>>()
|
||||
|
||||
.AddScoped<IUserService, UserService>()
|
||||
.AddScoped<IGroupService, GroupService>()
|
||||
.AddScoped<IGroupOfUserService, GroupOfUserService>()
|
||||
.AddScoped<IModuleService, ModuleService>()
|
||||
.AddScoped<IModuleOfUserService, ModuleOfUserService>()
|
||||
.AddScoped<IUserRepService, UserRepService>();
|
||||
|
||||
|
||||
public static IServiceCollection AddEncryptor(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddSingleton<Encryptor>();
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
|
||||
namespace DigitalData.UserManager.Application.DTOs.Base
|
||||
{
|
||||
// TODO: use getter - setter methods for a simple inheritance.
|
||||
public record BaseReadDto(int Id, string? AddedWho, DateTime? AddedWhen, string? ChangedWho, DateTime? ChangedWhen) : BaseDTO<int>(Id);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
|
||||
|
||||
namespace DigitalData.UserManager.Application.DTOs.User
|
||||
{
|
||||
//TODO: inherit from base read dto
|
||||
public record UserReadDto()
|
||||
{
|
||||
public int Id { get; set; }
|
||||
@@ -12,23 +13,29 @@ namespace DigitalData.UserManager.Application.DTOs.User
|
||||
|
||||
public string? Name { get; set; }
|
||||
|
||||
public string Username { get; set; }
|
||||
public required string Username { get; set; }
|
||||
|
||||
public string? Shortname { get; set; }
|
||||
|
||||
public string? Email { get; set; }
|
||||
|
||||
public string Language { get; set; }
|
||||
public required string Language { get; set; }
|
||||
|
||||
public string? Comment { get; set; }
|
||||
|
||||
public bool Deleted { get; set; }
|
||||
|
||||
public string DateFormat { get; set; }
|
||||
public required string DateFormat { get; set; }
|
||||
|
||||
public string AddedWho { get; set; }
|
||||
public string? ChangedWho { get; set; }
|
||||
|
||||
public bool Active { get; set; }
|
||||
public required DateTime? ChangedWhen { get; set; }
|
||||
|
||||
public string? AddedWho { get; init; }
|
||||
|
||||
public required DateTime AddedWhen { get; init; }
|
||||
|
||||
public bool Active { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[NotMapped]
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
namespace DigitalData.UserManager.Application.DTOs.UserRep
|
||||
{
|
||||
public record UserRepCreateDto(
|
||||
int UserId,
|
||||
int? UserId,
|
||||
int? RepGroupId,
|
||||
int? GroupId,
|
||||
int RepUserId
|
||||
int? RepUserId,
|
||||
DateTime? ValidFrom,
|
||||
DateTime? ValidTo
|
||||
) : BaseCreateDto();
|
||||
}
|
||||
@@ -6,12 +6,14 @@ namespace DigitalData.UserManager.Application.DTOs.UserRep
|
||||
{
|
||||
public record UserRepReadDto(
|
||||
int Id,
|
||||
int UserId,
|
||||
int? RepGroupId,
|
||||
int? UserId,
|
||||
int? GroupId,
|
||||
string AddedWho,
|
||||
string ChangedWho,
|
||||
int? RepUserId,
|
||||
int? RepGroupId,
|
||||
DateTime? ValidFrom,
|
||||
DateTime? ValidTo,
|
||||
string AddedWho,
|
||||
string? ChangedWho,
|
||||
UserReadDto? User,
|
||||
GroupReadDto? RepGroup,
|
||||
GroupReadDto? Group,
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
namespace DigitalData.UserManager.Application.DTOs.UserRep
|
||||
{
|
||||
public record UserRepUpdateDto(
|
||||
int UserId,
|
||||
int? UserId,
|
||||
int? RepGroupId,
|
||||
int? GroupId,
|
||||
int RepUserId
|
||||
int? RepUserId,
|
||||
DateTime? ValidFrom,
|
||||
DateTime? ValidTo
|
||||
) : BaseUpdateDto();
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PackageId>UserManager.Application</PackageId>
|
||||
<Version>2.0.0.0</Version>
|
||||
<Version>3.1.3</Version>
|
||||
<Authors>Digital Data GmbH</Authors>
|
||||
<Company>Digital Data GmbH</Company>
|
||||
<Product>UserManager.Application</Product>
|
||||
@@ -14,19 +14,26 @@
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
<RepositoryUrl>http://git.dd:3000/AppStd/WebUserManager.git</RepositoryUrl>
|
||||
<PackageTags>digital data application user maanger</PackageTags>
|
||||
<AssemblyVersion>3.1.3</AssemblyVersion>
|
||||
<FileVersion>3.1.3</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\DigitalData.UserManager.Domain\Assets\icon.png">
|
||||
<None Include="..\Assets\icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||
<PackageReference Include="DigitalData.Core.Application" Version="2.0.0" />
|
||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher.Abstraction" Version="2.0.0" />
|
||||
<PackageReference Include="DigitalData.Core.Abstractions" Version="3.4.1" />
|
||||
<PackageReference Include="DigitalData.Core.Application" Version="3.2.1" />
|
||||
<PackageReference Include="DigitalData.Core.DTO" Version="2.0.1" />
|
||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher.Abstraction" Version="3.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
|
||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="7.0.16" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="7.0.0" />
|
||||
<PackageReference Include="System.DirectoryServices" Version="7.0.1" />
|
||||
@@ -34,16 +41,26 @@
|
||||
<PackageReference Include="System.DirectoryServices.Protocols" Version="7.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DigitalData.UserManager.Domain\DigitalData.UserManager.Domain.csproj" />
|
||||
<ProjectReference Include="..\DigitalData.UserManager.Infrastructure\DigitalData.UserManager.Infrastructure.csproj" />
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
|
||||
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="7.0.16" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
|
||||
<PackageReference Include="System.DirectoryServices" Version="8.0.0" />
|
||||
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="8.0.1" />
|
||||
<PackageReference Include="System.DirectoryServices.Protocols" Version="8.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
|
||||
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="7.0.16" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.4" />
|
||||
<PackageReference Include="System.DirectoryServices" Version="9.0.4" />
|
||||
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.4" />
|
||||
<PackageReference Include="System.DirectoryServices.Protocols" Version="9.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Assets\icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
<ProjectReference Include="..\DigitalData.UserManager.Domain\DigitalData.UserManager.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,10 @@ using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Services
|
||||
{
|
||||
public class BaseService<TCRUDRepository, TCreateDto, TReadDto, TUpdateDto, TBaseEntity> : CRUDService<TCRUDRepository, TCreateDto, TReadDto, TUpdateDto, TBaseEntity, int>, IBaseService<TCreateDto, TReadDto, TUpdateDto, TBaseEntity>
|
||||
public class BaseService<TCRUDRepository, TCreateDto, TReadDto, TBaseEntity> : CRUDService<TCRUDRepository, TCreateDto, TReadDto, TBaseEntity, int>, IBaseService<TCreateDto, TReadDto, TBaseEntity>
|
||||
where TCRUDRepository : ICRUDRepository<TBaseEntity, int>
|
||||
where TCreateDto : BaseCreateDto
|
||||
where TReadDto : class
|
||||
where TUpdateDto : BaseUpdateDto
|
||||
where TBaseEntity : BaseEntity
|
||||
{
|
||||
public BaseService(TCRUDRepository repository, IMapper mapper) : base(repository, mapper)
|
||||
@@ -37,12 +36,13 @@ namespace DigitalData.UserManager.Application.Services
|
||||
return await base.CreateAsync(createDto);
|
||||
}
|
||||
|
||||
public override async Task<Result> UpdateAsync(TUpdateDto updateDto)
|
||||
// made without generic type
|
||||
public override async Task<Result> UpdateAsync<TUpdateDto>(TUpdateDto updateDto)
|
||||
{
|
||||
var user = await GetUserAsync();
|
||||
if (user is not null)
|
||||
if (user is not null && updateDto is BaseUpdateDto baseUpdateDto)
|
||||
{
|
||||
updateDto.ChangedWho = user.Username;
|
||||
baseUpdateDto.ChangedWho = user.Username;
|
||||
}
|
||||
|
||||
return await base.UpdateAsync(updateDto);
|
||||
|
||||
@@ -3,11 +3,11 @@ using DigitalData.Core.DTO;
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using DigitalData.UserManager.Application.DTOs.GroupOfUser;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using DigitalData.UserManager.Infrastructure.Contracts;
|
||||
using DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Services
|
||||
{
|
||||
public class GroupOfUserService : BaseService<IGroupOfUserRepository, GroupOfUserCreateDto, GroupOfUserReadDto, GroupOfUserUpdateDto, GroupOfUser>, IGroupOfUserService
|
||||
public class GroupOfUserService : BaseService<IGroupOfUserRepository, GroupOfUserCreateDto, GroupOfUserReadDto, GroupOfUser>, IGroupOfUserService
|
||||
{
|
||||
public GroupOfUserService(IGroupOfUserRepository repository, IMapper mapper) : base(repository, mapper)
|
||||
{
|
||||
|
||||
@@ -3,15 +3,15 @@ using DigitalData.Core.DTO;
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using DigitalData.UserManager.Application.DTOs.Group;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using DigitalData.UserManager.Infrastructure.Contracts;
|
||||
using DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Services
|
||||
{
|
||||
public class GroupService : BaseService<IGroupRepository, GroupCreateDto, GroupReadDto, GroupUpdateDto, Group>, IGroupService
|
||||
public class GroupService : BaseService<IGroupRepository, GroupCreateDto, GroupReadDto, Group>, IGroupService
|
||||
{
|
||||
private readonly IStringLocalizer<Resource> _localizer;
|
||||
public GroupService(IGroupRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper) : base(repository, mapper)
|
||||
private readonly IStringLocalizer<Resource>? _localizer;
|
||||
public GroupService(IGroupRepository repository, IMapper mapper, IStringLocalizer<Resource>? localizer = null) : base(repository, mapper)
|
||||
{
|
||||
_localizer = localizer;
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace DigitalData.UserManager.Application.Services
|
||||
group.AddedWho = user?.AddedWho ?? "UNAUTHORIZED";
|
||||
|
||||
if (await HasEntity(group.Id))
|
||||
return Result.Fail<int>().Message(_localizer[Key.GroupAlreadyExists.ToString()]);
|
||||
return Result.Fail<int>().Message(_localizer?[Key.GroupAlreadyExists].Value);
|
||||
|
||||
var createdGroup = await _repository.CreateAsync(group);
|
||||
if (createdGroup is null)
|
||||
|
||||
@@ -4,11 +4,11 @@ using DigitalData.Core.DTO;
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using DigitalData.UserManager.Application.DTOs.ModuleOfUser;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using DigitalData.UserManager.Infrastructure.Contracts;
|
||||
using DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Services
|
||||
{
|
||||
public class ModuleOfUserService : CRUDService<IModuleOfUserRepository, ModuleOfUserCreateDto, ModuleOfUserReadDto, ModuleOfUserUpdateDto, ModuleOfUser, int>, IModuleOfUserService
|
||||
public class ModuleOfUserService : CRUDService<IModuleOfUserRepository, ModuleOfUserCreateDto, ModuleOfUserReadDto, ModuleOfUser, int>, IModuleOfUserService
|
||||
{
|
||||
public ModuleOfUserService(IModuleOfUserRepository repository, IMapper mapper) : base(repository, mapper)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using DigitalData.Core.Application;
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using DigitalData.UserManager.Application.DTOs.Module;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using DigitalData.UserManager.Infrastructure.Contracts;
|
||||
using DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Services
|
||||
{
|
||||
|
||||
@@ -1,25 +1,36 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using DigitalData.UserManager.Application.DTOs.UserRep;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using DigitalData.UserManager.Infrastructure.Contracts;
|
||||
using DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Services
|
||||
{
|
||||
public class UserRepService : BaseService<IUserRepRepository, UserRepCreateDto, UserRepReadDto, UserRepUpdateDto, UserRep>, IUserRepService
|
||||
public class UserRepService : BaseService<IUserRepRepository, UserRepCreateDto, UserRepReadDto, UserRep>, IUserRepService
|
||||
{
|
||||
public UserRepService(IUserRepRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper) : base(repository, mapper)
|
||||
private readonly IStringLocalizer<Resource>? _localizer;
|
||||
public UserRepService(IUserRepRepository repository, IMapper mapper, IStringLocalizer<Resource>? localizer = null) : 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)
|
||||
{
|
||||
var urs = await _repository.ReadAllAsync(withUser, withRepGroup, withGroup, withRepUser, userId, groupId);
|
||||
var urs = await _repository.ReadAllAsync(withUser: withUser, withRepGroup: withRepGroup, withGroup: withGroup, withRepUser: withRepUser, userId: userId, groupId: groupId);
|
||||
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].Value)
|
||||
//date range control
|
||||
: (createDto.ValidFrom > createDto.ValidTo)
|
||||
? Result.Fail<int>().Notice(LogLevel.None, Flag.DataIntegrityIssue, _localizer?[Key.InvalidDateRange].Value)
|
||||
: await base.CreateAsync(createDto);
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,15 @@ using DigitalData.Core.DTO;
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using DigitalData.UserManager.Infrastructure.Contracts;
|
||||
using DigitalData.UserManager.Application.Contracts.Repositories;
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace DigitalData.UserManager.Application.Services
|
||||
{
|
||||
public class UserService : BaseService<IUserRepository, UserCreateDto, UserReadDto, UserUpdateDto, User>, IUserService
|
||||
public class UserService : BaseService<IUserRepository, UserCreateDto, UserReadDto, User>, IUserService
|
||||
{
|
||||
private readonly IStringLocalizer<Resource> _localizer;
|
||||
public UserService(IUserRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper) : base(repository, mapper)
|
||||
private readonly IStringLocalizer<Resource>? _localizer;
|
||||
public UserService(IUserRepository repository, IMapper mapper, IStringLocalizer<Resource>? localizer = null) : base(repository, mapper)
|
||||
{
|
||||
_localizer = localizer;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ namespace DigitalData.UserManager.Application.Services
|
||||
var user = _mapper.Map<User>(upDto);
|
||||
|
||||
if (await HasEntity(user.Id))
|
||||
return Result.Fail<int>().Message(_localizer[Key.UserAlreadyExists]);
|
||||
return Result.Fail<int>().Message(_localizer?[Key.UserAlreadyExists].Value);
|
||||
|
||||
//set the user
|
||||
var current_user = await GetUserAsync();
|
||||
@@ -66,7 +66,7 @@ namespace DigitalData.UserManager.Application.Services
|
||||
{
|
||||
var user = await _repository.ReadByUsernameAsync(username);
|
||||
if (user is null)
|
||||
return Result.Fail<UserReadDto>().Message(_localizer[Key.UserNotFoundInLocalDB]);
|
||||
return Result.Fail<UserReadDto>().Message(_localizer?[Key.UserNotFoundInLocalDB].Value);
|
||||
|
||||
var userDto = _mapper.Map<UserReadDto>(user);
|
||||
return Result.Success(userDto);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PackageId>UserManager</PackageId>
|
||||
<Version>1.0.0</Version>
|
||||
<Authors>Digital Data GmbH</Authors>
|
||||
<Company>Digital Data GmbH</Company>
|
||||
<Product>UserManager</Product>
|
||||
<Description>Die Hauptbibliothek, die Benutzer-, Gruppen- und Modulzuweisungen über Active Directory mit Entity Framework durchführt.</Description>
|
||||
<Copyright>Copyright 2024</Copyright>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
<RepositoryUrl>http://git.dd:3000/AppStd/WebUserManager.git</RepositoryUrl>
|
||||
<PackageTags>digital data user maanger</PackageTags>
|
||||
<AssemblyVersion>1.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\Assets\icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DigitalData.UserManager.Application\DigitalData.UserManager.Application.csproj" />
|
||||
<ProjectReference Include="..\DigitalData.UserManager.Domain\DigitalData.UserManager.Domain.csproj" />
|
||||
<ProjectReference Include="..\DigitalData.UserManager.Infrastructure\DigitalData.UserManager.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
25
DigitalData.UserManager.DependencyInjection/Extensions.cs
Normal file
25
DigitalData.UserManager.DependencyInjection/Extensions.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using DigitalData.UserManager.Application;
|
||||
using DigitalData.UserManager.Infrastructure;
|
||||
using DigitalData.UserManager.Infrastructure.Contracts;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace DigitalData.UserManager.DependencyInjection;
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static IServiceCollection AddUserManager<TDbContext>(this IServiceCollection services)
|
||||
where TDbContext : DbContext, IUserManagerDbContext
|
||||
{
|
||||
services.AddUserManagerInfrastructure<TDbContext>();
|
||||
services.AddUserManagerApplication();
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddUserManager(this IServiceCollection services, Action<DbContextOptionsBuilder> optionsAction)
|
||||
{
|
||||
services.AddUserManagerInfrastructure(optionsAction);
|
||||
services.AddUserManagerApplication();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.1 KiB |
@@ -1,11 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PackageId>UserManager.Domain</PackageId>
|
||||
<Version>2.0.0.0</Version>
|
||||
<Version>3.0.2</Version>
|
||||
<Authors>Digital Data GmbH</Authors>
|
||||
<Company>Digital Data GmbH</Company>
|
||||
<Product>UserManager.Domain</Product>
|
||||
@@ -14,24 +14,19 @@
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
<RepositoryUrl>http://git.dd:3000/AppStd/WebUserManager.git</RepositoryUrl>
|
||||
<PackageTags>digital data domain user maanger</PackageTags>
|
||||
<AssemblyVersion>3.0.2</AssemblyVersion>
|
||||
<FileVersion>3.0.2</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\DigitalData.UserManager.Application\Assets\icon.png">
|
||||
<None Include="..\Assets\icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DigitalData.Core.Abstractions" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Assets\icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
<PackageReference Include="DigitalData.Core.Abstractions" Version="3.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace DigitalData.UserManager.Domain.Entities
|
||||
[Column("CHANGED_WHO")]
|
||||
public string? ChangedWho { get; set; }
|
||||
|
||||
//TODO: assign it to default value in create dto, not here!
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
[DefaultValue("GETDATE()")]
|
||||
public DateTime AddedWhen { get; set; } = DateTime.Now;
|
||||
|
||||
35
DigitalData.UserManager.Domain/Entities/ClientUser.cs
Normal file
35
DigitalData.UserManager.Domain/Entities/ClientUser.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace DigitalData.UserManager.Domain.Entities
|
||||
{
|
||||
[Table("TBDD_CLIENT_USER", Schema = "dbo")]
|
||||
public class ClientUser : IUnique<int>
|
||||
{
|
||||
[Column("GUID")]
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("USER_ID")]
|
||||
public int UserId { get; init; }
|
||||
|
||||
[Required]
|
||||
[Column("CLIENT_ID")]
|
||||
public int ClientId { get; init; }
|
||||
|
||||
[Column("COMMENT")]
|
||||
public string? Comment { get; init; }
|
||||
|
||||
[StringLength(50)]
|
||||
[Column("ADDED_WHO")]
|
||||
public string? AddedWho { get; set; }
|
||||
|
||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||
[DefaultValue("GETDATE()")]
|
||||
public DateTime AddedWhen { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace DigitalData.UserManager.Domain.Entities
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace DigitalData.UserManager.Domain.Entities
|
||||
{
|
||||
[Table("TBDD_USER_REPRESENTATION", Schema = "dbo")]
|
||||
public class UserRep : BaseEntity
|
||||
{
|
||||
[Required]
|
||||
[Column("USER_ID")]
|
||||
public int UserId { get; set; }
|
||||
public int? UserId { get; set; }
|
||||
|
||||
[Column("REPR_GROUP")]
|
||||
public int? RepGroupId { get; set; }
|
||||
@@ -20,6 +18,12 @@ namespace DigitalData.UserManager.Domain.Entities
|
||||
[Column("REPR_USER")]
|
||||
public int? RepUserId { get; set; }
|
||||
|
||||
[Column("VALID_FROM")]
|
||||
public DateTime? ValidFrom { get; set; }
|
||||
|
||||
[Column("VALID_TO")]
|
||||
public DateTime? ValidTo { get; set; }
|
||||
|
||||
[ForeignKey("UserId")]
|
||||
public virtual User? User { get; set; }
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.1 KiB |
@@ -1,22 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Infrastructure.Contracts
|
||||
{
|
||||
public interface IGroupOfUserRepository : ICRUDRepository<GroupOfUser, int>
|
||||
{
|
||||
IQueryable<GroupOfUser> ReadByGroupId(int groupId);
|
||||
|
||||
Task<IEnumerable<GroupOfUser>> ReadByGroupUserIdAsync(int groupId, int userId);
|
||||
|
||||
Task<IEnumerable<GroupOfUser>> ReadAllAsyncWithGroup();
|
||||
|
||||
Task<IEnumerable<GroupOfUser>> ReadAllAsyncWithUser();
|
||||
|
||||
Task<IEnumerable<GroupOfUser>> ReadAllAsyncWithGroupAndUser();
|
||||
|
||||
Task<IEnumerable<GroupOfUser>> ReadByUsernameAsync(string username);
|
||||
|
||||
Task<IEnumerable<GroupOfUser>> ReadByUserIdAsync(int userId);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Infrastructure.Contracts
|
||||
{
|
||||
public interface IGroupRepository : ICRUDRepository<Group, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Infrastructure.Contracts
|
||||
{
|
||||
public interface IModuleOfUserRepository : ICRUDRepository<ModuleOfUser, int>
|
||||
{
|
||||
IQueryable<ModuleOfUser> ReadByModuleId(int moduleId);
|
||||
|
||||
Task<IEnumerable<ModuleOfUser>> ReadByModelUserIdAsync(int moduleId, int userId);
|
||||
|
||||
Task<IEnumerable<ModuleOfUser>> ReadByUserAsync(string username);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using DigitalData.Core.Abstractions.Infrastructure;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
|
||||
namespace DigitalData.UserManager.Infrastructure.Contracts
|
||||
{
|
||||
public interface IModuleRepository : ICRUDRepository<Module, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user