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 { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; 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 { ConfigService } from './core/ui-services/config.service';
import { ConstantsService } from './core/core-services/constants.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 { RoutingStateService } from './core/ui-services/routing-state.service';
import { ServertimeService } from './core/core-services/servertime.service'; import { ServertimeService } from './core/core-services/servertime.service';
import { ThemeService } from './core/ui-services/theme.service'; import { ThemeService } from './core/ui-services/theme.service';
import { ViewUser } from './site/users/models/view-user';
declare global { declare global {
/** /**
@ -46,16 +45,6 @@ declare global {
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss']
}) })
export class AppComponent { 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. * Master-component of all apps.
* *
@ -79,11 +68,11 @@ export class AppComponent {
appRef: ApplicationRef, appRef: ApplicationRef,
servertimeService: ServertimeService, servertimeService: ServertimeService,
router: Router, router: Router,
private operator: OperatorService, operator: OperatorService,
loginDataService: LoginDataService, loginDataService: LoginDataService,
constantsService: ConstantsService, // Needs to be started, so it can register itself to the WebsocketService constantsService: ConstantsService, // Needs to be started, so it can register itself to the WebsocketService
themeService: ThemeService, themeService: ThemeService,
private overlayService: OverlayService, overlayService: OverlayService,
countUsersService: CountUsersService, // Needed to register itself. countUsersService: CountUsersService, // Needed to register itself.
configService: ConfigService, configService: ConfigService,
loadFontService: LoadFontService, loadFontService: LoadFontService,
@ -115,31 +104,6 @@ export class AppComponent {
take(1) take(1)
) )
.subscribe(() => servertimeService.startScheduler()); .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; 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); const response = await this.http.post<WhoAmI>(environment.urlPrefix + '/users/login/', user);
earlySuccessCallback(); earlySuccessCallback();
await this.OpenSlides.shutdown();
await this.operator.setWhoAmI(response); await this.operator.setWhoAmI(response);
await this.OpenSlides.afterLoginBootup(response.user_id);
await this.redirectUser(response.user_id); await this.redirectUser(response.user_id);
return response; return response;
} }

View File

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

View File

@ -1,6 +1,8 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { AutoupdateService } from './autoupdate.service'; import { AutoupdateService } from './autoupdate.service';
import { ConstantsService } from './constants.service'; import { ConstantsService } from './constants.service';
import { DataStoreService } from './data-store.service'; import { DataStoreService } from './data-store.service';
@ -20,14 +22,17 @@ export class OpenSlidesService {
*/ */
public redirectUrl: string; 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 * 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`. * (Anonymous is also a user in this case). This is the case after `afterLoginBootup`.
*/ */
private _booted = false; public get isBooted(): boolean {
return this.booted.value;
public get booted(): boolean {
return this._booted;
} }
/** /**
@ -113,7 +118,7 @@ export class OpenSlidesService {
} }
await this.setupDataStoreAndWebSocket(); await this.setupDataStoreAndWebSocket();
// Now finally booted. // Now finally booted.
this._booted = true; this.booted.next(true);
} }
/** /**
@ -139,7 +144,7 @@ export class OpenSlidesService {
*/ */
public async shutdown(): Promise<void> { public async shutdown(): Promise<void> {
await this.websocketService.close(); 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 { largeDialogSettings } from 'app/shared/utils/dialog-settings';
import { SuperSearchComponent } from 'app/site/common/components/super-search/super-search.component'; 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. * 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(); 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` * @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 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 { public showSpinner(text?: string, forceAppearing?: boolean): void {
if (!this.preventAppearingSpinner || forceAppearing) { if (!this.isConnectionStable() || forceAppearing) {
setTimeout(() => this.spinner.next({ isVisible, text })); 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. * Function to reset the properties for the spinner.
* *
@ -85,6 +145,8 @@ export class OverlayService {
* and still stays at the website. * and still stays at the website.
*/ */
public logout(): void { 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; 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 * Constructor for the login component
* *
@ -136,11 +141,12 @@ export class LoginMaskComponent extends BaseViewComponent implements OnInit, OnD
public async formLogin(): Promise<void> { public async formLogin(): Promise<void> {
this.loginErrorMsg = ''; this.loginErrorMsg = '';
try { try {
this.overlayService.showSpinner(this.translate.instant(this.loginMessage), true);
await this.authService.login(this.loginForm.value.username, this.loginForm.value.password, () => { 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. this.clearOperatorSubscription(); // We take control, not the subscription.
}); });
} catch (e) { } catch (e) {
this.overlayService.hideSpinner();
this.loginForm.setErrors({ this.loginForm.setErrors({
notFound: true notFound: true
}); });
@ -166,6 +172,7 @@ export class LoginMaskComponent extends BaseViewComponent implements OnInit, OnD
* Guests (if enabled) can navigate directly to the main page. * Guests (if enabled) can navigate directly to the main page.
*/ */
public guestLogin(): void { public guestLogin(): void {
this.overlayService.showSpinner(this.translate.instant(this.loginMessage));
this.authService.guestLogin(); this.authService.guestLogin();
} }
} }

View File

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

View File

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

View File

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