Merge pull request #5005 from GabrielInTheWorld/freshSpinner

Hotfix: Fresh login does not get the real user.
This commit is contained in:
Emanuel Schütze 2019-09-12 14:18:31 +02:00 committed by GitHub
commit 02c745ed75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 123 additions and 78 deletions

View File

@ -2,7 +2,7 @@ import { ApplicationRef, Component } from '@angular/core';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { auditTime, filter, take } from 'rxjs/operators';
import { filter, take } from 'rxjs/operators';
import { ConfigService } from './core/ui-services/config.service';
import { ConstantsService } from './core/core-services/constants.service';
@ -17,7 +17,6 @@ import { PrioritizeService } from './core/core-services/prioritize.service';
import { RoutingStateService } from './core/ui-services/routing-state.service';
import { ServertimeService } from './core/core-services/servertime.service';
import { ThemeService } from './core/ui-services/theme.service';
import { ViewUser } from './site/users/models/view-user';
declare global {
/**
@ -46,16 +45,6 @@ declare global {
styleUrls: ['./app.component.scss']
})
export class AppComponent {
/**
* Member to hold the state of `stable`.
*/
private isStable: boolean;
/**
* Member to hold the user.
*/
private user: ViewUser;
/**
* Master-component of all apps.
*
@ -79,11 +68,11 @@ export class AppComponent {
appRef: ApplicationRef,
servertimeService: ServertimeService,
router: Router,
private operator: OperatorService,
operator: OperatorService,
loginDataService: LoginDataService,
constantsService: ConstantsService, // Needs to be started, so it can register itself to the WebsocketService
themeService: ThemeService,
private overlayService: OverlayService,
overlayService: OverlayService,
countUsersService: CountUsersService, // Needed to register itself.
configService: ConfigService,
loadFontService: LoadFontService,
@ -115,31 +104,6 @@ export class AppComponent {
take(1)
)
.subscribe(() => servertimeService.startScheduler());
// Subscribe to hide the spinner if the application has changed.
appRef.isStable
.pipe(
filter(s => s),
auditTime(1000)
)
.subscribe(stable => {
// check the stable state only once.
if (!this.isStable && stable) {
this.isStable = true;
this.checkConnectionProgress();
}
});
// subscribe, to get the user.
operator.getViewUserObservable().subscribe(user => {
// check the user only once
if ((!this.user && user) || operator.isAnonymous) {
this.user = user;
this.checkConnectionProgress();
// if the user is logging out, remove this user.
} else if (user === null) {
this.user = user;
}
});
}
/**
@ -192,14 +156,4 @@ export class AppComponent {
return ((this % n) + n) % n;
};
}
/**
* Function to check if the user is existing and the app is already stable.
* If both conditions true, hide the spinner.
*/
private checkConnectionProgress(): void {
if ((this.user || this.operator.isAnonymous) && this.isStable) {
this.overlayService.setSpinner(false, null, false, true);
}
}
}

View File

@ -48,7 +48,9 @@ export class AuthService {
};
const response = await this.http.post<WhoAmI>(environment.urlPrefix + '/users/login/', user);
earlySuccessCallback();
await this.OpenSlides.shutdown();
await this.operator.setWhoAmI(response);
await this.OpenSlides.afterLoginBootup(response.user_id);
await this.redirectUser(response.user_id);
return response;
}

View File

@ -1,5 +1,7 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { AutoupdateService } from './autoupdate.service';
import { ConstantsService } from './constants.service';
import { StorageService } from './storage.service';
@ -26,6 +28,11 @@ const SCHEMA_VERSION = 'SchemaVersion';
providedIn: 'root'
})
export class DataStoreUpgradeService {
/**
* Notify, when upgrade has checked.
*/
public readonly upgradeChecked = new BehaviorSubject(false);
/**
* @param autoupdateService
* @param constantsService
@ -48,6 +55,7 @@ export class DataStoreUpgradeService {
}
public async checkForUpgrade(serverVersion: SchemaVersion): Promise<boolean> {
this.upgradeChecked.next(false);
console.log('Server schema version:', serverVersion);
const clientVersion = await this.storageService.get<SchemaVersion>(SCHEMA_VERSION);
await this.storageService.set(SCHEMA_VERSION, serverVersion);
@ -77,6 +85,7 @@ export class DataStoreUpgradeService {
} else {
console.log('\t-> No upgrade needed.');
}
this.upgradeChecked.next(true);
return doUpgrade;
}
}

View File

@ -1,6 +1,8 @@
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { AutoupdateService } from './autoupdate.service';
import { ConstantsService } from './constants.service';
import { DataStoreService } from './data-store.service';
@ -20,14 +22,17 @@ export class OpenSlidesService {
*/
public redirectUrl: string;
/**
* Subject to hold the flag `booted`.
*/
public readonly booted = new BehaviorSubject(false);
/**
* Saves, if OpenSlides is fully booted. This means, that a user must be logged in
* (Anonymous is also a user in this case). This is the case after `afterLoginBootup`.
*/
private _booted = false;
public get booted(): boolean {
return this._booted;
public get isBooted(): boolean {
return this.booted.value;
}
/**
@ -113,7 +118,7 @@ export class OpenSlidesService {
}
await this.setupDataStoreAndWebSocket();
// Now finally booted.
this._booted = true;
this.booted.next(true);
}
/**
@ -139,7 +144,7 @@ export class OpenSlidesService {
*/
public async shutdown(): Promise<void> {
await this.websocketService.close();
this._booted = false;
this.booted.next(false);
}
/**

View File

@ -5,6 +5,9 @@ import { Observable, Subject } from 'rxjs';
import { largeDialogSettings } from 'app/shared/utils/dialog-settings';
import { SuperSearchComponent } from 'app/site/common/components/super-search/super-search.component';
import { DataStoreUpgradeService } from '../core-services/data-store-upgrade.service';
import { OpenSlidesService } from '../core-services/openslides.service';
import { OperatorService } from '../core-services/operator.service';
/**
* Component to control the visibility of components, that overlay the whole window.
@ -26,28 +29,66 @@ export class OverlayService {
private spinner: Subject<{ isVisible: boolean; text?: string }> = new Subject();
/**
* Boolean, whether appearing of the spinner should be prevented next time.
* Flag, that indicates, if the upgrade has checked.
*/
private preventAppearingSpinner = false;
private upgradeChecked = false;
/**
* The current user.
*/
private user = null;
/**
* Flag, whether the app has booted.
*/
private hasBooted = false;
/**
*
* @param dialogService Injects the `MatDialog` to show the `super-search.component`
*/
public constructor(private dialogService: MatDialog) {}
public constructor(
private dialogService: MatDialog,
private operator: OperatorService,
OpenSlides: OpenSlidesService,
upgradeService: DataStoreUpgradeService
) {
// Subscribe to the current user.
operator.getViewUserObservable().subscribe(user => {
if (user) {
this.user = user;
this.checkConnection();
}
});
// Subscribe to the booting-step.
OpenSlides.booted.subscribe(isBooted => {
this.hasBooted = isBooted;
this.checkConnection();
});
// Subscribe to the upgrade-mechanism.
upgradeService.upgradeChecked.subscribe(upgradeDone => {
this.upgradeChecked = upgradeDone;
this.checkConnection();
});
}
/**
* Function to change the visibility of the `global-spinner.component`.
* Function to show the `global-spinner.component`.
*
* @param isVisible flag, if the spinner should be shown.
* @param text optional. If the spinner should show a message.
* @param preventAppearing optional. Wether to prevent showing the spinner the next time.
* @param forceAppearing optional. If the spinner must be shown.
*/
public setSpinner(isVisible: boolean, text?: string, forceAppearing?: boolean, preventAppearing?: boolean): void {
if (!this.preventAppearingSpinner || forceAppearing) {
setTimeout(() => this.spinner.next({ isVisible, text }));
public showSpinner(text?: string, forceAppearing?: boolean): void {
if (!this.isConnectionStable() || forceAppearing) {
setTimeout(() => this.spinner.next({ isVisible: true, text }));
}
this.preventAppearingSpinner = preventAppearing;
}
/**
* Function to hide the `global-spinner.component`.
*/
public hideSpinner(): void {
setTimeout(() => this.spinner.next({ isVisible: false }));
}
/**
@ -78,6 +119,25 @@ export class OverlayService {
}
}
/**
* Checks, if the connection is stable.
* This relates to `appStable`, `booted` and `user || anonymous`.
*
* @returns True, if the three booleans are all true.
*/
public isConnectionStable(): boolean {
return this.upgradeChecked && this.hasBooted && (!!this.user || this.operator.isAnonymous);
}
/**
* Function to check, if the app is stable and, if true, hide the spinner.
*/
private checkConnection(): void {
if (this.isConnectionStable()) {
this.hideSpinner();
}
}
/**
* Function to reset the properties for the spinner.
*
@ -85,6 +145,8 @@ export class OverlayService {
* and still stays at the website.
*/
public logout(): void {
this.preventAppearingSpinner = false;
this.hasBooted = false;
this.user = null;
this.upgradeChecked = false;
}
}

View File

@ -52,6 +52,11 @@ export class LoginMaskComponent extends BaseViewComponent implements OnInit, OnD
public operatorSubscription: Subscription | null;
/**
* The message, that should appear, when the user logs in.
*/
private loginMessage = 'Loading data. Please wait...';
/**
* Constructor for the login component
*
@ -136,11 +141,12 @@ export class LoginMaskComponent extends BaseViewComponent implements OnInit, OnD
public async formLogin(): Promise<void> {
this.loginErrorMsg = '';
try {
this.overlayService.showSpinner(this.translate.instant(this.loginMessage), true);
await this.authService.login(this.loginForm.value.username, this.loginForm.value.password, () => {
this.overlayService.setSpinner(true, this.translate.instant('Loading data. Please wait...'));
this.clearOperatorSubscription(); // We take control, not the subscription.
});
} catch (e) {
this.overlayService.hideSpinner();
this.loginForm.setErrors({
notFound: true
});
@ -166,6 +172,7 @@ export class LoginMaskComponent extends BaseViewComponent implements OnInit, OnD
* Guests (if enabled) can navigate directly to the main page.
*/
public guestLogin(): void {
this.overlayService.showSpinner(this.translate.instant(this.loginMessage));
this.authService.guestLogin();
}
}

View File

@ -380,7 +380,7 @@ export class MotionListComponent extends BaseListViewComponent<ViewMotion> imple
} catch (e) {
this.raiseError(e);
} finally {
this.overlayService.setSpinner(false);
this.overlayService.hideSpinner();
}
}

View File

@ -81,10 +81,10 @@ export class MotionMultiselectService {
`\n${i} ` +
this.translate.instant('of') +
` ${motions.length}`;
this.overlayService.setSpinner(true, message, true);
this.overlayService.showSpinner(message, true);
await this.repo.delete(motion);
}
this.overlayService.setSpinner(false);
this.overlayService.hideSpinner();
}
}
@ -119,7 +119,7 @@ export class MotionMultiselectService {
const selectedChoice = await this.choiceService.open(title, choices);
if (selectedChoice) {
const message = `${motions.length} ` + this.translate.instant(this.messageForSpinner);
this.overlayService.setSpinner(true, message, true);
this.overlayService.showSpinner(message, true);
await this.repo.setMultiState(motions, selectedChoice.items as number);
}
} else {
@ -152,7 +152,7 @@ export class MotionMultiselectService {
recommendation: selectedChoice.action ? 0 : (selectedChoice.items as number)
}));
const message = `${motions.length} ` + this.translate.instant(this.messageForSpinner);
this.overlayService.setSpinner(true, message, true);
this.overlayService.showSpinner(message, true);
await this.httpService.post('/rest/motions/motion/manage_multiple_recommendation/', {
motions: requestData
});
@ -181,7 +181,7 @@ export class MotionMultiselectService {
);
if (selectedChoice) {
const message = this.translate.instant(this.messageForSpinner);
this.overlayService.setSpinner(true, message, true);
this.overlayService.showSpinner(message, true);
await this.repo.setMultiCategory(motions, selectedChoice.items as number);
}
}
@ -220,7 +220,7 @@ export class MotionMultiselectService {
}
const message = `${motions.length} ` + this.translate.instant(this.messageForSpinner);
this.overlayService.setSpinner(true, message, true);
this.overlayService.showSpinner(message, true);
await this.httpService.post('/rest/motions/motion/manage_multiple_submitters/', { motions: requestData });
}
}
@ -268,7 +268,7 @@ export class MotionMultiselectService {
}
const message = `${motions.length} ` + this.translate.instant(this.messageForSpinner);
this.overlayService.setSpinner(true, message, true);
this.overlayService.showSpinner(message, true);
await this.httpService.post('/rest/motions/motion/manage_multiple_tags/', { motions: requestData });
}
}
@ -290,7 +290,7 @@ export class MotionMultiselectService {
);
if (selectedChoice) {
const message = this.translate.instant(this.messageForSpinner);
this.overlayService.setSpinner(true, message, true);
this.overlayService.showSpinner(message, true);
const blockId = selectedChoice.action ? null : (selectedChoice.items as number);
await this.repo.setMultiMotionBlock(motions, blockId);
}
@ -355,7 +355,7 @@ export class MotionMultiselectService {
if (selectedChoice && motions.length) {
const message = this.translate.instant(`I have ${motions.length} favorite motions. Please wait ...`);
const star = (selectedChoice.items as number) === choices[0].id;
this.overlayService.setSpinner(true, message, true);
this.overlayService.showSpinner(message, true);
await this.personalNoteService.bulkSetStar(motions, star);
}
}

View File

@ -103,7 +103,10 @@ export class SiteComponent extends BaseComponent implements OnInit {
private overlayService: OverlayService
) {
super(title, translate);
overlayService.setSpinner(true, translate.instant('Loading data. Please wait...'));
overlayService.showSpinner(
translate.instant('Loading data. Please wait...'),
!(operator.guestsEnabled && operator.isAnonymous)
);
this.operator.getViewUserObservable().subscribe(user => {
if (!operator.isAnonymous) {
@ -253,6 +256,9 @@ export class SiteComponent extends BaseComponent implements OnInit {
* Function to log out the current user
*/
public logout(): void {
if (this.operator.guestsEnabled) {
this.overlayService.showSpinner(null, true);
}
this.authService.logout();
this.overlayService.logout();
}