Add default values for when Sync is off
This commit is contained in:
parent
9fb29dec20
commit
a122ae07a9
12 changed files with 203 additions and 42 deletions
|
|
@ -12,13 +12,17 @@ export class AgeRatingPipe implements PipeTransform {
|
|||
|
||||
private readonly translocoService = inject(TranslocoService);
|
||||
|
||||
transform(value: AgeRating | AgeRatingDto | undefined): string {
|
||||
transform(value: AgeRating | AgeRatingDto | undefined | string): string {
|
||||
if (value === undefined || value === null) return this.translocoService.translate('age-rating-pipe.unknown');
|
||||
|
||||
if (value.hasOwnProperty('title')) {
|
||||
return (value as AgeRatingDto).title;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
value = parseInt(value, 10) as AgeRating;
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
case AgeRating.Unknown:
|
||||
return this.translocoService.translate('age-rating-pipe.unknown');
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {UserOwner} from "../_models/user";
|
|||
import {translate} from "@jsverse/transloco";
|
||||
|
||||
@Pipe({
|
||||
name: 'creationSourcePipe'
|
||||
name: 'userOwnerPipe'
|
||||
})
|
||||
export class UserOwnerPipe implements PipeTransform {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import {AgeRating} from "../../_models/metadata/age-rating";
|
||||
|
||||
export interface OidcConfig {
|
||||
authority: string;
|
||||
|
|
@ -8,6 +9,10 @@ export interface OidcConfig {
|
|||
autoLogin: boolean;
|
||||
disablePasswordAuthentication: boolean;
|
||||
providerName: string;
|
||||
defaultRoles: string[];
|
||||
defaultLibraries: number[];
|
||||
defaultAgeRating: AgeRating;
|
||||
defaultIncludeUnknowns: boolean;
|
||||
}
|
||||
|
||||
export interface OidcPublicConfig {
|
||||
|
|
|
|||
|
|
@ -78,12 +78,12 @@
|
|||
@if (userForm.get('owner'); as formControl) {
|
||||
<app-setting-item [title]="t('owner')" [subtitle]="t('owner-tooltip')">
|
||||
<ng-template #view>
|
||||
<div>{{member().owner | UserOwnerPipe}}</div>
|
||||
<div>{{member().owner | userOwnerPipe}}</div>
|
||||
</ng-template>
|
||||
<ng-template #edit>
|
||||
<select class="form-select" id="creationSource" formControlName="creationSource">
|
||||
@for (source of UserOwners; track source) {
|
||||
<option [value]="source">{{source | UserOwnerPipe}}</option>
|
||||
<option [value]="source">{{source | userOwnerPipe}}</option>
|
||||
}
|
||||
</select>
|
||||
</ng-template>
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export class EditUserComponent implements OnInit {
|
|||
ngOnInit(): void {
|
||||
this.userForm.addControl('email', new FormControl(this.member().email, [Validators.required]));
|
||||
this.userForm.addControl('username', new FormControl(this.member().username, [Validators.required, Validators.pattern(AllowedUsernameCharacters)]));
|
||||
this.userForm.addControl('creationSource', new FormControl(this.member().owner, [Validators.required]));
|
||||
this.userForm.addControl('owner', new FormControl(this.member().owner, [Validators.required]));
|
||||
|
||||
// TODO: Rework, bad hack
|
||||
// Work around isLocked so we're able to downgrade users
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
ChangeDetectorRef,
|
||||
Component,
|
||||
EventEmitter,
|
||||
inject,
|
||||
inject, input,
|
||||
Input,
|
||||
OnInit,
|
||||
Output
|
||||
|
|
@ -29,6 +29,7 @@ export class LibrarySelectorComponent implements OnInit {
|
|||
private readonly cdRef = inject(ChangeDetectorRef);
|
||||
|
||||
@Input() member: Member | undefined;
|
||||
preselectedLibraries = input<number[]>([]);
|
||||
@Output() selected: EventEmitter<Array<Library>> = new EventEmitter<Array<Library>>();
|
||||
|
||||
allLibraries: Library[] = [];
|
||||
|
|
@ -61,6 +62,14 @@ export class LibrarySelectorComponent implements OnInit {
|
|||
});
|
||||
this.selectAll = this.selections.selected().length === this.allLibraries.length;
|
||||
this.selected.emit(this.selections.selected());
|
||||
} else if (this.preselectedLibraries().length > 0) {
|
||||
this.preselectedLibraries().forEach((id) => {
|
||||
const foundLib = this.allLibraries.find(lib => lib.id === id);
|
||||
if (foundLib) {
|
||||
this.selections.toggle(foundLib, true, (a, b) => a.name === b.name);
|
||||
}
|
||||
});
|
||||
this.selectAll = this.selections.selected().length === this.allLibraries.length;
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,6 +141,55 @@
|
|||
|
||||
</ng-container>
|
||||
|
||||
<div class="setting-section-break"></div>
|
||||
<h4>{{t('defaults')}}</h4>
|
||||
<div class="text-muted">{{t('defaults-requirement')}}</div>
|
||||
<ng-container>
|
||||
|
||||
<div class="row g-0 mt-4 mb-4">
|
||||
@if(settingsForm.get('defaultAgeRating'); as formControl) {
|
||||
<app-setting-item [title]="t('defaultAgeRating')" [subtitle]="t('defaultAgeRating-tooltip')">
|
||||
<ng-template #view>
|
||||
<div>{{formControl.value | ageRating}}</div>
|
||||
</ng-template>
|
||||
<ng-template #edit>
|
||||
<select class="form-select" formControlName="defaultAgeRating">
|
||||
<option value="-1">{{t('no-restriction')}}</option>
|
||||
@for (ageRating of ageRatings(); track ageRating.value) {
|
||||
<option [value]="ageRating.value">{{ageRating.title}}</option>
|
||||
}
|
||||
</select>
|
||||
</ng-template>
|
||||
</app-setting-item>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="row g-0 mt-4 mb-4">
|
||||
@if(settingsForm.get('defaultIncludeUnknowns'); as formControl) {
|
||||
<app-setting-switch [title]="t('defaultIncludeUnknowns')" [subtitle]="t('defaultIncludeUnknowns-tooltip')">
|
||||
<ng-template #switch>
|
||||
<div class="form-check form-switch float-end">
|
||||
<input id="defaultIncludeUnknowns" type="checkbox" class="form-check-input" formControlName="defaultIncludeUnknowns">
|
||||
</div>
|
||||
</ng-template>
|
||||
</app-setting-switch>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (this.oidcSettings()) {
|
||||
<div class="row g-0 mb-3">
|
||||
<div class="col-md-6 pe-4">
|
||||
<app-role-selector (selected)="updateRoles($event)" [allowAdmin]="true" [preSelectedRoles]="selectedRoles()"></app-role-selector>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<app-library-selector (selected)="updateLibraries($event)" [preselectedLibraries]="selectedLibraries()"></app-library-selector>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
</ng-container>
|
||||
|
||||
</form>
|
||||
|
||||
</ng-container>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {ChangeDetectorRef, Component, DestroyRef, OnInit} from '@angular/core';
|
||||
import {ChangeDetectorRef, Component, DestroyRef, effect, OnInit, signal} from '@angular/core';
|
||||
import {TranslocoDirective} from "@jsverse/transloco";
|
||||
import {ServerSettings} from "../_models/server-settings";
|
||||
import {
|
||||
|
|
@ -16,6 +16,16 @@ import {SettingItemComponent} from "../../settings/_components/setting-item/sett
|
|||
import {SettingSwitchComponent} from "../../settings/_components/setting-switch/setting-switch.component";
|
||||
import {debounceTime, distinctUntilChanged, filter, map, of, switchMap, tap} from "rxjs";
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
import {RestrictionSelectorComponent} from "../../user-settings/restriction-selector/restriction-selector.component";
|
||||
import {AgeRatingPipe} from "../../_pipes/age-rating.pipe";
|
||||
import {MetadataService} from "../../_services/metadata.service";
|
||||
import {AgeRating} from "../../_models/metadata/age-rating";
|
||||
import {AgeRatingDto} from "../../_models/metadata/age-rating-dto";
|
||||
import {allRoles, Role} from "../../_services/account.service";
|
||||
import {Library} from "../../_models/library/library";
|
||||
import {LibraryService} from "../../_services/library.service";
|
||||
import {LibrarySelectorComponent} from "../library-selector/library-selector.component";
|
||||
import {RoleSelectorComponent} from "../role-selector/role-selector.component";
|
||||
|
||||
@Component({
|
||||
selector: 'app-manage-open-idconnect',
|
||||
|
|
@ -23,7 +33,10 @@ import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
|||
TranslocoDirective,
|
||||
ReactiveFormsModule,
|
||||
SettingItemComponent,
|
||||
SettingSwitchComponent
|
||||
SettingSwitchComponent,
|
||||
AgeRatingPipe,
|
||||
LibrarySelectorComponent,
|
||||
RoleSelectorComponent
|
||||
],
|
||||
templateUrl: './manage-open-idconnect.component.html',
|
||||
styleUrl: './manage-open-idconnect.component.scss'
|
||||
|
|
@ -31,30 +44,43 @@ import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
|||
export class ManageOpenIDConnectComponent implements OnInit {
|
||||
|
||||
serverSettings!: ServerSettings;
|
||||
oidcSettings!: OidcConfig;
|
||||
oidcSettings = signal<OidcConfig | undefined>(undefined);
|
||||
settingsForm: FormGroup = new FormGroup({});
|
||||
|
||||
ageRatings = signal<AgeRatingDto[]>([]);
|
||||
selectedLibraries = signal<number[]>([]);
|
||||
selectedRoles = signal<string[]>([]);
|
||||
|
||||
constructor(
|
||||
private settingsService: SettingsService,
|
||||
private cdRef: ChangeDetectorRef,
|
||||
private destroyRef: DestroyRef,
|
||||
private metadataService: MetadataService,
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.metadataService.getAllAgeRatings().subscribe(ratings => {
|
||||
this.ageRatings.set(ratings);
|
||||
});
|
||||
|
||||
this.settingsService.getServerSettings().subscribe({
|
||||
next: data => {
|
||||
this.serverSettings = data;
|
||||
this.oidcSettings = this.serverSettings.oidcConfig;
|
||||
this.oidcSettings.set(this.serverSettings.oidcConfig);
|
||||
this.selectedRoles.set(this.serverSettings.oidcConfig.defaultRoles);
|
||||
this.selectedLibraries.set(this.serverSettings.oidcConfig.defaultLibraries);
|
||||
|
||||
this.settingsForm.addControl('authority', new FormControl(this.oidcSettings.authority, [], [this.authorityValidator()]));
|
||||
this.settingsForm.addControl('clientId', new FormControl(this.oidcSettings.clientId, [this.requiredIf('authority')]));
|
||||
this.settingsForm.addControl('provisionAccounts', new FormControl(this.oidcSettings.provisionAccounts, []));
|
||||
this.settingsForm.addControl('requireVerifiedEmail', new FormControl(this.oidcSettings.requireVerifiedEmail, []));
|
||||
this.settingsForm.addControl('syncUserSettings', new FormControl(this.oidcSettings.syncUserSettings, []));
|
||||
this.settingsForm.addControl('autoLogin', new FormControl(this.oidcSettings.autoLogin, []));
|
||||
this.settingsForm.addControl('disablePasswordAuthentication', new FormControl(this.oidcSettings.disablePasswordAuthentication, []));
|
||||
this.settingsForm.addControl('providerName', new FormControl(this.oidcSettings.providerName, []));
|
||||
this.settingsForm.addControl('authority', new FormControl(this.serverSettings.oidcConfig.authority, [], [this.authorityValidator()]));
|
||||
this.settingsForm.addControl('clientId', new FormControl(this.serverSettings.oidcConfig.clientId, [this.requiredIf('authority')]));
|
||||
this.settingsForm.addControl('provisionAccounts', new FormControl(this.serverSettings.oidcConfig.provisionAccounts, []));
|
||||
this.settingsForm.addControl('requireVerifiedEmail', new FormControl(this.serverSettings.oidcConfig.requireVerifiedEmail, []));
|
||||
this.settingsForm.addControl('syncUserSettings', new FormControl(this.serverSettings.oidcConfig.syncUserSettings, []));
|
||||
this.settingsForm.addControl('autoLogin', new FormControl(this.serverSettings.oidcConfig.autoLogin, []));
|
||||
this.settingsForm.addControl('disablePasswordAuthentication', new FormControl(this.serverSettings.oidcConfig.disablePasswordAuthentication, []));
|
||||
this.settingsForm.addControl('providerName', new FormControl(this.serverSettings.oidcConfig.providerName, []));
|
||||
this.settingsForm.addControl("defaultAgeRating", new FormControl(this.serverSettings.oidcConfig.defaultAgeRating, []));
|
||||
this.settingsForm.addControl('defaultIncludeUnknowns', new FormControl(this.serverSettings.oidcConfig.defaultIncludeUnknowns, []));
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.settingsForm.valueChanges.pipe(
|
||||
|
|
@ -64,7 +90,7 @@ export class ManageOpenIDConnectComponent implements OnInit {
|
|||
filter(() => {
|
||||
// Do not auto save when provider settings have changed
|
||||
const settings: OidcConfig = this.settingsForm.getRawValue();
|
||||
return settings.authority == this.oidcSettings.authority && settings.clientId == this.oidcSettings.clientId;
|
||||
return settings.authority == this.oidcSettings()?.authority && settings.clientId == this.oidcSettings()?.clientId;
|
||||
}),
|
||||
tap(() => this.save())
|
||||
).subscribe();
|
||||
|
|
@ -72,17 +98,30 @@ export class ManageOpenIDConnectComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
updateRoles(roles: string[]) {
|
||||
this.selectedRoles.set(roles);
|
||||
this.save();
|
||||
}
|
||||
|
||||
updateLibraries(libraries: Library[]) {
|
||||
this.selectedLibraries.set(libraries.map(l => l.id));
|
||||
this.save();
|
||||
}
|
||||
|
||||
save() {
|
||||
if (!this.settingsForm.valid) return;
|
||||
if (!this.settingsForm.valid || !this.serverSettings || !this.oidcSettings) return;
|
||||
|
||||
const data = this.settingsForm.getRawValue();
|
||||
const newSettings = Object.assign({}, this.serverSettings);
|
||||
newSettings.oidcConfig = data as OidcConfig;
|
||||
newSettings.oidcConfig.defaultAgeRating = parseInt(newSettings.oidcConfig.defaultAgeRating as unknown as string, 10) as AgeRating;
|
||||
newSettings.oidcConfig.defaultRoles = this.selectedRoles();
|
||||
newSettings.oidcConfig.defaultLibraries = this.selectedLibraries();
|
||||
|
||||
this.settingsService.updateServerSettings(newSettings).subscribe({
|
||||
next: data => {
|
||||
this.serverSettings = data;
|
||||
this.oidcSettings = data.oidcConfig;
|
||||
this.oidcSettings.set(data.oidcConfig);
|
||||
this.cdRef.markForCheck();
|
||||
},
|
||||
error: error => {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
ChangeDetectorRef,
|
||||
Component,
|
||||
EventEmitter,
|
||||
inject,
|
||||
inject, input,
|
||||
Input,
|
||||
OnInit,
|
||||
Output
|
||||
|
|
@ -33,6 +33,7 @@ export class RoleSelectorComponent implements OnInit {
|
|||
* This must have roles
|
||||
*/
|
||||
@Input() member: Member | undefined | User;
|
||||
preSelectedRoles = input<string[]>([]);
|
||||
/**
|
||||
* Allows the selection of Admin role
|
||||
*/
|
||||
|
|
@ -77,6 +78,13 @@ export class RoleSelectorComponent implements OnInit {
|
|||
foundRole[0].selected = true;
|
||||
}
|
||||
});
|
||||
} else if (this.preSelectedRoles().length > 0) {
|
||||
this.preSelectedRoles().forEach((role) => {
|
||||
const foundRole = this.selectedRoles.filter(item => item.data === role);
|
||||
if (foundRole.length > 0) {
|
||||
foundRole[0].selected = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// For new users, preselect LoginRole
|
||||
this.selectedRoles.forEach(role => {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,15 @@
|
|||
"disablePasswordAuthentication": "Disable password authentication",
|
||||
"disablePasswordAuthentication-tooltip": "Users with the admin role can bypass this restriction",
|
||||
"providerName": "Provider name",
|
||||
"providerName-tooltip": "Name show on the login screen"
|
||||
"providerName-tooltip": "Name show on the login screen",
|
||||
|
||||
"defaults": "Defaults",
|
||||
"defaults-requirement": "The following settings are used when a user is registered via OIDC while SyncUserSettings is turned off",
|
||||
"defaultIncludeUnknowns": "Include unknowns",
|
||||
"defaultIncludeUnknowns-tooltip": "Include unknown age ratings",
|
||||
"defaultAgeRating": "Age rating",
|
||||
"defaultAgeRating-tooltip": "Maximum age rating shown to new users",
|
||||
"no-restriction": "{{restriction-selector.no-restriction}}"
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue