Disable Authentication & Login Page Rework (#619)
* Implemented the ability to disable authentication on a server instance. Admins will require authentication, but non-admin accounts can be setup without any password requirements. * WIP for new login page. * Reworked code to handle disabled auth better. First time user flow is moved into the user login component. * Removed debug code * Removed home component, shakeout testing is complete. * remove a file accidently committed * Fixed a code smell from last PR * Code smells
This commit is contained in:
parent
83d76982f4
commit
a5b6bf1b52
36 changed files with 376 additions and 174 deletions
|
@ -16,6 +16,10 @@ export class MemberService {
|
|||
return this.httpClient.get<Member[]>(this.baseUrl + 'users');
|
||||
}
|
||||
|
||||
getMemberNames() {
|
||||
return this.httpClient.get<string[]>(this.baseUrl + 'users/names');
|
||||
}
|
||||
|
||||
adminExists() {
|
||||
return this.httpClient.get<boolean>(this.baseUrl + 'admin/exists');
|
||||
}
|
||||
|
|
|
@ -131,7 +131,9 @@ export class MessageHubService {
|
|||
}
|
||||
|
||||
stopHubConnection() {
|
||||
this.hubConnection.stop().catch(err => console.error(err));
|
||||
if (this.hubConnection) {
|
||||
this.hubConnection.stop().catch(err => console.error(err));
|
||||
}
|
||||
}
|
||||
|
||||
sendMessage(methodName: string, body?: any) {
|
||||
|
|
|
@ -6,4 +6,5 @@ export interface ServerSettings {
|
|||
port: number;
|
||||
allowStatCollection: boolean;
|
||||
enableOpds: boolean;
|
||||
enableAuthentication: boolean;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,15 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="authentication" aria-describedby="authentication-info">Authentication</label>
|
||||
<p class="accent" id="authentication-info">By disabling authentication, all non-admin users will be able to login by just their username. No password will be required to authenticate.</p>
|
||||
<div class="form-check">
|
||||
<input id="authentication" type="checkbox" aria-label="User Authentication" class="form-check-input" formControlName="enableAuthentication">
|
||||
<label for="authentication" class="form-check-label">Enable Authentication</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4>Reoccuring Tasks</h4>
|
||||
<div class="form-group">
|
||||
<label for="settings-tasks-scan">Library Scan</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="taskScanTooltip" role="button" tabindex="0"></i>
|
||||
|
|
|
@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
|
|||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { ConfirmService } from 'src/app/shared/confirm.service';
|
||||
import { SettingsService } from '../settings.service';
|
||||
import { ServerSettings } from '../_models/server-settings';
|
||||
|
||||
|
@ -17,7 +18,7 @@ export class ManageSettingsComponent implements OnInit {
|
|||
taskFrequencies: Array<string> = [];
|
||||
logLevels: Array<string> = [];
|
||||
|
||||
constructor(private settingsService: SettingsService, private toastr: ToastrService) { }
|
||||
constructor(private settingsService: SettingsService, private toastr: ToastrService, private confirmService: ConfirmService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.settingsService.getTaskFrequencies().pipe(take(1)).subscribe(frequencies => {
|
||||
|
@ -35,6 +36,7 @@ export class ManageSettingsComponent implements OnInit {
|
|||
this.settingsForm.addControl('loggingLevel', new FormControl(this.serverSettings.loggingLevel, [Validators.required]));
|
||||
this.settingsForm.addControl('allowStatCollection', new FormControl(this.serverSettings.allowStatCollection, [Validators.required]));
|
||||
this.settingsForm.addControl('enableOpds', new FormControl(this.serverSettings.enableOpds, [Validators.required]));
|
||||
this.settingsForm.addControl('enableAuthentication', new FormControl(this.serverSettings.enableAuthentication, [Validators.required]));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -46,15 +48,28 @@ export class ManageSettingsComponent implements OnInit {
|
|||
this.settingsForm.get('loggingLevel')?.setValue(this.serverSettings.loggingLevel);
|
||||
this.settingsForm.get('allowStatCollection')?.setValue(this.serverSettings.allowStatCollection);
|
||||
this.settingsForm.get('enableOpds')?.setValue(this.serverSettings.enableOpds);
|
||||
this.settingsForm.get('enableAuthentication')?.setValue(this.serverSettings.enableAuthentication);
|
||||
}
|
||||
|
||||
saveSettings() {
|
||||
async saveSettings() {
|
||||
const modelSettings = this.settingsForm.value;
|
||||
|
||||
this.settingsService.updateServerSettings(modelSettings).pipe(take(1)).subscribe((settings: ServerSettings) => {
|
||||
if (this.settingsForm.get('enableAuthentication')?.value === false) {
|
||||
if (!await this.confirmService.confirm('Disabling Authentication opens your server up to unauthorized access and possible hacking. Are you sure you want to continue with this?')) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const informUserAfterAuthenticationEnabled = this.settingsForm.get('enableAuthentication')?.value && !this.serverSettings.enableAuthentication;
|
||||
|
||||
this.settingsService.updateServerSettings(modelSettings).pipe(take(1)).subscribe(async (settings: ServerSettings) => {
|
||||
this.serverSettings = settings;
|
||||
this.resetForm();
|
||||
this.toastr.success('Server settings updated');
|
||||
|
||||
if (informUserAfterAuthenticationEnabled) {
|
||||
await this.confirmService.alert('You have just re-enabled authentication. All non-admin users have been re-assigned a password of "[k.2@RZ!mxCQkJzE". This is a publicly known password. Please change their users passwords or request them to.');
|
||||
}
|
||||
}, (err: any) => {
|
||||
console.error('error: ', err);
|
||||
});
|
||||
|
|
|
@ -77,7 +77,7 @@ export class ManageUsersComponent implements OnInit, OnDestroy {
|
|||
this.createMemberToggle = true;
|
||||
}
|
||||
|
||||
onMemberCreated(success: boolean) {
|
||||
onMemberCreated(createdUser: User | null) {
|
||||
this.createMemberToggle = false;
|
||||
this.loadMembers();
|
||||
}
|
||||
|
|
|
@ -35,4 +35,8 @@ export class SettingsService {
|
|||
getOpdsEnabled() {
|
||||
return this.http.get<boolean>(this.baseUrl + 'settings/opds-enabled', {responseType: 'text' as 'json'});
|
||||
}
|
||||
|
||||
getAuthenticationEnabled() {
|
||||
return this.http.get<boolean>(this.baseUrl + 'settings/authentication-enabled', {responseType: 'text' as 'json'});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { LibraryDetailComponent } from './library-detail/library-detail.component';
|
||||
import { LibraryComponent } from './library/library.component';
|
||||
import { NotConnectedComponent } from './not-connected/not-connected.component';
|
||||
import { SeriesDetailComponent } from './series-detail/series-detail.component';
|
||||
import { RecentlyAddedComponent } from './recently-added/recently-added.component';
|
||||
|
@ -10,13 +8,12 @@ import { UserLoginComponent } from './user-login/user-login.component';
|
|||
import { AuthGuard } from './_guards/auth.guard';
|
||||
import { LibraryAccessGuard } from './_guards/library-access.guard';
|
||||
import { InProgressComponent } from './in-progress/in-progress.component';
|
||||
import { DashboardComponent as AdminDashboardComponent } from './admin/dashboard/dashboard.component';
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
|
||||
// TODO: Once we modularize the components, use this and measure performance impact: https://angular.io/guide/lazy-loading-ngmodules#preloading-modules
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '', component: HomeComponent},
|
||||
{path: '', component: UserLoginComponent},
|
||||
{
|
||||
path: 'admin',
|
||||
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
|
||||
|
@ -62,7 +59,7 @@ const routes: Routes = [
|
|||
},
|
||||
{path: 'login', component: UserLoginComponent},
|
||||
{path: 'no-connection', component: NotConnectedComponent},
|
||||
{path: '**', component: HomeComponent, pathMatch: 'full'}
|
||||
{path: '**', component: UserLoginComponent, pathMatch: 'full'}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -4,10 +4,9 @@ import { APP_INITIALIZER, ErrorHandler, NgModule } from '@angular/core';
|
|||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { NgbDropdownModule, NgbNavModule, NgbPaginationModule, NgbRatingModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { NgbCollapseModule, NgbDropdownModule, NgbNavModule, NgbPaginationModule, NgbRatingModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { NavHeaderComponent } from './nav-header/nav-header.component';
|
||||
import { JwtInterceptor } from './_interceptors/jwt.interceptor';
|
||||
import { UserLoginComponent } from './user-login/user-login.component';
|
||||
|
@ -87,7 +86,6 @@ if (environment.production) {
|
|||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
HomeComponent,
|
||||
NavHeaderComponent,
|
||||
UserLoginComponent,
|
||||
LibraryComponent,
|
||||
|
@ -114,6 +112,8 @@ if (environment.production) {
|
|||
NgbNavModule,
|
||||
NgbPaginationModule,
|
||||
|
||||
NgbCollapseModule, // Login
|
||||
|
||||
SharedModule,
|
||||
CarouselModule,
|
||||
TypeaheadModule,
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<div class="container">
|
||||
<ng-container *ngIf="firstTimeFlow">
|
||||
<p>Please create an admin account for yourself to start your reading journey.</p>
|
||||
<app-register-member (created)="onAdminCreated($event)" [firstTimeFlow]="firstTimeFlow"></app-register-member>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { MemberService } from '../_services/member.service';
|
||||
import { AccountService } from '../_services/account.service';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.scss']
|
||||
})
|
||||
export class HomeComponent implements OnInit {
|
||||
|
||||
firstTimeFlow = false;
|
||||
model: any = {};
|
||||
registerForm: FormGroup = new FormGroup({
|
||||
username: new FormControl('', [Validators.required]),
|
||||
password: new FormControl('', [Validators.required])
|
||||
});
|
||||
|
||||
constructor(public accountService: AccountService, private memberService: MemberService, private router: Router, private titleService: Title) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
this.memberService.adminExists().subscribe(adminExists => {
|
||||
this.firstTimeFlow = !adminExists;
|
||||
|
||||
if (this.firstTimeFlow) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.titleService.setTitle('Kavita');
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe(user => {
|
||||
if (user) {
|
||||
this.router.navigateByUrl('/library');
|
||||
} else {
|
||||
this.router.navigateByUrl('/login');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
onAdminCreated(success: boolean) {
|
||||
if (success) {
|
||||
this.router.navigateByUrl('/login');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -325,7 +325,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
});
|
||||
} else {
|
||||
// If no user, we can't render
|
||||
this.router.navigateByUrl('/home');
|
||||
this.router.navigateByUrl('/login');
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
<div class="text-danger" *ngIf="errors.length > 0">
|
||||
<p>Errors:</p>
|
||||
<ul>
|
||||
|
@ -10,7 +11,7 @@
|
|||
<input id="username" class="form-control" formControlName="username" type="text">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group" *ngIf="registerForm.get('isAdmin')?.value || !authDisabled">
|
||||
<label for="password">Password</label>
|
||||
<input id="password" class="form-control" formControlName="password" type="password">
|
||||
</div>
|
||||
|
@ -21,7 +22,7 @@
|
|||
</div>
|
||||
|
||||
<div class="float-right">
|
||||
<button class="btn btn-secondary mr-2" type="button" (click)="cancel()">Cancel</button>
|
||||
<button class="btn btn-primary" type="submit">Register</button>
|
||||
<button class="btn btn-secondary mr-2" type="button" (click)="cancel()" *ngIf="!firstTimeFlow">Cancel</button>
|
||||
<button class="btn btn-primary {{firstTimeFlow ? 'alt' : ''}}" type="submit">Register</button>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
.alt {
|
||||
background-color: #424c72;
|
||||
border-color: #444f75;
|
||||
}
|
||||
|
||||
.alt:hover {
|
||||
background-color: #3b4466;
|
||||
}
|
||||
|
||||
.alt:focus {
|
||||
background-color: #343c59;
|
||||
box-shadow: 0 0 0 0.2rem rgb(68 79 117 / 50%);
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { AccountService } from 'src/app/_services/account.service';
|
||||
import { SettingsService } from '../admin/settings.service';
|
||||
import { User } from '../_models/user';
|
||||
|
||||
@Component({
|
||||
selector: 'app-register-member',
|
||||
|
@ -10,35 +13,42 @@ import { AccountService } from 'src/app/_services/account.service';
|
|||
export class RegisterMemberComponent implements OnInit {
|
||||
|
||||
@Input() firstTimeFlow = false;
|
||||
@Output() created = new EventEmitter<boolean>();
|
||||
/**
|
||||
* Emits the new user created.
|
||||
*/
|
||||
@Output() created = new EventEmitter<User | null>();
|
||||
|
||||
adminExists = false;
|
||||
authDisabled: boolean = false;
|
||||
registerForm: FormGroup = new FormGroup({
|
||||
username: new FormControl('', [Validators.required]),
|
||||
password: new FormControl('', [Validators.required]),
|
||||
password: new FormControl('', []),
|
||||
isAdmin: new FormControl(false, [])
|
||||
});
|
||||
errors: string[] = [];
|
||||
|
||||
constructor(private accountService: AccountService) {
|
||||
constructor(private accountService: AccountService, private settingsService: SettingsService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.settingsService.getAuthenticationEnabled().pipe(take(1)).subscribe(authEnabled => {
|
||||
this.authDisabled = !authEnabled;
|
||||
});
|
||||
if (this.firstTimeFlow) {
|
||||
this.registerForm.get('isAdmin')?.setValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
register() {
|
||||
this.accountService.register(this.registerForm.value).subscribe(resp => {
|
||||
this.created.emit(true);
|
||||
this.accountService.register(this.registerForm.value).subscribe(user => {
|
||||
this.created.emit(user);
|
||||
}, err => {
|
||||
this.errors = err;
|
||||
});
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.created.emit(false);
|
||||
this.created.emit(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,28 +1,44 @@
|
|||
<div class="mx-auto login">
|
||||
<div class="card p-3" style="width: 18rem;">
|
||||
<div class="logo-container">
|
||||
<img class="logo" src="assets/images/kavita-book-cropped.png" alt="Kavita logo"/>
|
||||
<h3 class="card-title text-center">Kavita</h3>
|
||||
|
||||
<div class="display: inline-block" *ngIf="firstTimeFlow">
|
||||
<h3 class="card-title text-center">Create an Admin Account</h3>
|
||||
<div class="card p-3">
|
||||
<p>Please create an admin account for yourself to start your reading journey.</p>
|
||||
<app-register-member (created)="onAdminCreated($event)" [firstTimeFlow]="firstTimeFlow"></app-register-member>
|
||||
</div>
|
||||
|
||||
<div class="card-text">
|
||||
<form [formGroup]="loginForm" (ngSubmit)="login()">
|
||||
<div class="form-group">
|
||||
<label for="username">Username</label>
|
||||
<input class="form-control" formControlName="username" id="username" type="text" autofocus>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>
|
||||
<input class="form-control" formControlName="password" id="password" type="password">
|
||||
</div>
|
||||
|
||||
<div class="float-right">
|
||||
<button class="btn btn-primary alt" type="submit">Login</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<form [formGroup]="loginForm" (ngSubmit)="login()" novalidate class="needs-validation" *ngIf="!firstTimeFlow">
|
||||
<div class="row row-cols-4 row-cols-md-4 row-cols-sm-2 row-cols-xs-2">
|
||||
<ng-container *ngFor="let member of memberNames">
|
||||
<div class="col align-self-center card p-3 m-3" style="width: 12rem;">
|
||||
<span tabindex="0" (click)="select(member)" a11y-click="13,32">
|
||||
<div class="logo-container">
|
||||
<h3 class="card-title text-center">{{member | titlecase}}</h3>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<div class="card-text" #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed[member]" (keyup.enter)="$event.stopPropagation()">
|
||||
<div class="form-group" style="display: none;">
|
||||
<label for="username--{{member}}">Username</label>
|
||||
<input class="form-control" formControlName="username" id="username--{{member}}" type="text" [readonly]="true">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password--{{member}}">Password</label>
|
||||
<input class="form-control" formControlName="password" id="password--{{member}}" type="password" autofocus>
|
||||
<div *ngIf="authDisabled" class="invalid-feedback">
|
||||
Authentication is disabled. Only type password if this is an admin account.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="float-right">
|
||||
<button class="btn btn-primary alt" type="submit--{{member}}">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
|
@ -4,6 +4,7 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: -61px; // To offset the navbar
|
||||
height: calc(100vh);
|
||||
min-height: 289px;
|
||||
position: relative;
|
||||
|
@ -22,24 +23,34 @@
|
|||
}
|
||||
|
||||
.logo-container {
|
||||
margin: 0 auto 15px;
|
||||
|
||||
.logo {
|
||||
display:inline-block;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-top: 10vh;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: $primary-color;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
min-width: 300px;
|
||||
|
||||
&:focus {
|
||||
border: 2px solid white;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.card-title {
|
||||
font-family: 'Spartan', sans-serif;
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
vertical-align: middle;
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.card-text {
|
||||
|
@ -66,3 +77,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.invalid-feedback {
|
||||
display: inline-block;
|
||||
color: #343c59;
|
||||
}
|
|
@ -2,7 +2,9 @@ import { Component, OnInit } from '@angular/core';
|
|||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { first, take } from 'rxjs/operators';
|
||||
import { SettingsService } from '../admin/settings.service';
|
||||
import { User } from '../_models/user';
|
||||
import { AccountService } from '../_services/account.service';
|
||||
import { MemberService } from '../_services/member.service';
|
||||
import { NavService } from '../_services/nav.service';
|
||||
|
@ -17,27 +19,57 @@ export class UserLoginComponent implements OnInit {
|
|||
model: any = {username: '', password: ''};
|
||||
loginForm: FormGroup = new FormGroup({
|
||||
username: new FormControl('', [Validators.required]),
|
||||
password: new FormControl('', [Validators.required])
|
||||
password: new FormControl('', [Validators.required])
|
||||
});
|
||||
|
||||
constructor(private accountService: AccountService, private router: Router, private memberService: MemberService, private toastr: ToastrService, private navService: NavService) { }
|
||||
memberNames: Array<string> = [];
|
||||
isCollapsed: {[key: string]: boolean} = {};
|
||||
authDisabled: boolean = false;
|
||||
/**
|
||||
* If there are no admins on the server, this will enable the registration to kick in.
|
||||
*/
|
||||
firstTimeFlow: boolean = true;
|
||||
|
||||
constructor(private accountService: AccountService, private router: Router, private memberService: MemberService,
|
||||
private toastr: ToastrService, private navService: NavService, private settingsService: SettingsService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
// Validate that there are users so you can refresh to home. This is important for first installs
|
||||
this.validateAdmin();
|
||||
}
|
||||
|
||||
validateAdmin() {
|
||||
this.navService.hideNavBar();
|
||||
this.memberService.adminExists().subscribe(res => {
|
||||
if (!res) {
|
||||
this.router.navigateByUrl('/home');
|
||||
this.navService.showNavBar();
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe(user => {
|
||||
if (user) {
|
||||
this.router.navigateByUrl('/library');
|
||||
}
|
||||
});
|
||||
|
||||
this.settingsService.getAuthenticationEnabled().pipe(take(1)).subscribe((enabled: boolean) => {
|
||||
// There is a bug where this is coming back as a string not a boolean.
|
||||
this.authDisabled = enabled + '' === 'false';
|
||||
if (this.authDisabled) {
|
||||
this.loginForm.get('password')?.setValidators([]);
|
||||
}
|
||||
});
|
||||
|
||||
this.memberService.getMemberNames().pipe(take(1)).subscribe(members => {
|
||||
this.memberNames = members;
|
||||
const isOnlyOne = this.memberNames.length === 1;
|
||||
this.memberNames.forEach(name => this.isCollapsed[name] = !isOnlyOne);
|
||||
this.firstTimeFlow = members.length === 0;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
onAdminCreated(user: User | null) {
|
||||
if (user != null) {
|
||||
this.firstTimeFlow = false;
|
||||
this.isCollapsed[user.username] = true;
|
||||
this.select(user.username);
|
||||
this.memberNames.push(user.username);
|
||||
} else {
|
||||
this.toastr.error('There was an issue creating the new user. Please refresh and try again.');
|
||||
}
|
||||
}
|
||||
|
||||
login() {
|
||||
if (!this.loginForm.dirty || !this.loginForm.valid) { return; }
|
||||
this.model = {username: this.loginForm.get('username')?.value, password: this.loginForm.get('password')?.value};
|
||||
this.accountService.login(this.model).subscribe(() => {
|
||||
this.loginForm.reset();
|
||||
|
@ -45,7 +77,7 @@ export class UserLoginComponent implements OnInit {
|
|||
|
||||
// Check if user came here from another url, else send to library route
|
||||
const pageResume = localStorage.getItem('kavita--auth-intersection-url');
|
||||
if (pageResume && pageResume !== '/no-connection') {
|
||||
if (pageResume && pageResume !== '/no-connection' && pageResume !== '/login') {
|
||||
localStorage.setItem('kavita--auth-intersection-url', '');
|
||||
this.router.navigateByUrl(pageResume);
|
||||
} else {
|
||||
|
@ -62,4 +94,20 @@ export class UserLoginComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
select(member: string) {
|
||||
|
||||
this.loginForm.get('username')?.setValue(member);
|
||||
|
||||
this.isCollapsed[member] = !this.isCollapsed[member];
|
||||
this.collapseAllButName(member);
|
||||
// ?! Scroll to the newly opened element?
|
||||
}
|
||||
|
||||
collapseAllButName(name: string) {
|
||||
Object.keys(this.isCollapsed).forEach(key => {
|
||||
if (key !== name) {
|
||||
this.isCollapsed[key] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue