diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts index 22171a316..60260308c 100644 --- a/client/src/app/app-routing.module.ts +++ b/client/src/app/app-routing.module.ts @@ -7,7 +7,6 @@ import { LoginLegalNoticeComponent } from './site/login/components/login-legal-n import { LoginPrivacyPolicyComponent } from './site/login/components/login-privacy-policy/login-privacy-policy.component'; import { ResetPasswordComponent } from './site/login/components/reset-password/reset-password.component'; import { ResetPasswordConfirmComponent } from './site/login/components/reset-password-confirm/reset-password-confirm.component'; -import { AppPreloader } from './shared/utils/app-preloader'; /** * Global app routing @@ -30,8 +29,7 @@ const routes: Routes = [ ]; @NgModule({ - imports: [RouterModule.forRoot(routes, { preloadingStrategy: AppPreloader })], - exports: [RouterModule], - providers: [AppPreloader] + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] }) export class AppRoutingModule {} diff --git a/client/src/app/core/core-services/auth.service.ts b/client/src/app/core/core-services/auth.service.ts index 32262a09f..053e729ce 100644 --- a/client/src/app/core/core-services/auth.service.ts +++ b/client/src/app/core/core-services/auth.service.ts @@ -42,8 +42,7 @@ export class AuthService { /** * Try to log in a user. * - * Returns an observable 'user' with the correct login information or an error. - * The user will then be stored in the {@link OperatorService}, + * Returns an observable with the correct login information or an error. * errors will be forwarded to the parents error function. * * @param username @@ -56,18 +55,17 @@ export class AuthService { password: password }; const response = await this.http.post(environment.urlPrefix + '/users/login/', user); - this.operator.user = new User(response.user); return response; } /** * Logout function for both the client and the server. * - * Will clear the current {@link OperatorService} and - * send a `post`-request to `/apps/users/logout/'` + * Will clear the current operator and datastore and + * send a `post`-request to `/apps/users/logout/'`. Restarts OpenSlides. */ public async logout(): Promise { - this.operator.user = null; + await this.operator.setUser(null); try { await this.http.post(environment.urlPrefix + '/users/logout/', {}); } catch (e) { diff --git a/client/src/app/core/core-services/offline.service.ts b/client/src/app/core/core-services/offline.service.ts index d5a5b2da5..f13129e09 100644 --- a/client/src/app/core/core-services/offline.service.ts +++ b/client/src/app/core/core-services/offline.service.ts @@ -1,8 +1,5 @@ import { Injectable } from '@angular/core'; -import { DataStoreService } from './data-store.service'; -import { WhoAmIResponse } from './operator.service'; - /** * This service handles everything connected with being offline. * @@ -20,20 +17,15 @@ export class OfflineService { } /** - * Constructor to create the AutoupdateService. Calls the constructor of the parent class. - * @param DS */ - public constructor(private DS: DataStoreService) {} + public constructor() {} /** * Sets the offline flag. Restores the DataStoreService to the last known configuration. */ - public async goOfflineBecauseFailedWhoAmI(): Promise { + public goOfflineBecauseFailedWhoAmI(): void { this._offline = true; console.log('offline because whoami failed.'); - - // TODO: Init the DS from cache. - await this.DS.clear(); } /** @@ -50,16 +42,4 @@ export class OfflineService { public goOnline(): void { this._offline = false; } - - /** - * Returns the last cached WhoAmI response. - */ - public getLastWhoAmI(): WhoAmIResponse { - // TODO: use a cached WhoAmI response. - return { - user_id: null, - guest_enabled: false, - user: null - }; - } } diff --git a/client/src/app/core/core-services/openslides.service.ts b/client/src/app/core/core-services/openslides.service.ts index 82453e800..0c11e4251 100644 --- a/client/src/app/core/core-services/openslides.service.ts +++ b/client/src/app/core/core-services/openslides.service.ts @@ -2,10 +2,11 @@ import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { WebsocketService } from './websocket.service'; -import { OperatorService } from './operator.service'; +import { OperatorService, WhoAmIResponse } from './operator.service'; import { StorageService } from './storage.service'; import { AutoupdateService } from './autoupdate.service'; import { DataStoreService } from './data-store.service'; +import { take } from 'rxjs/operators'; /** * Handles the bootup/showdown of this application. @@ -51,8 +52,11 @@ export class OpenSlidesService { */ public async bootup(): Promise { // start autoupdate if the user is logged in: - const response = await this.operator.whoAmI(); - this.operator.guestsEnabled = response.guest_enabled; + const response = await this.operator.whoAmIFromStorage(); + await this.bootupWithWhoAmI(response); + } + + private async bootupWithWhoAmI(response: WhoAmIResponse): Promise { if (!response.user && !response.guest_enabled) { this.redirectUrl = location.pathname; @@ -66,8 +70,14 @@ export class OpenSlidesService { // Goto login, if the user isn't login and guests are not allowed this.router.navigate(['/login']); } + + this.checkOperator(false); } else { await this.afterLoginBootup(response.user_id); + + // Check for the operator via a async whoami (so no await here) + // to validate, that the cache was correct. + this.checkOperator(false); } } @@ -78,7 +88,7 @@ export class OpenSlidesService { * @param userId */ public async afterLoginBootup(userId: number): Promise { - // Else, check, which user was logged in last time + // Check, which user was logged in last time const lastUserId = await this.storageService.get('lastUserLoggedIn'); // if the user changed, reset the cache and save the new user. if (userId !== lastUserId) { @@ -96,33 +106,42 @@ export class OpenSlidesService { if (changeId > 0) { changeId += 1; } + // disconnect the WS connection, if there was one. This is needed + // to update the connection parameters, namely the cookies. If the user + // is changed, the WS needs to reconnect, so the new connection holds the new + // user information. + if (this.websocketService.isConnected) { + this.websocketService.close(); + // Wait for the disconnect. + await this.websocketService.closeEvent.pipe(take(1)).toPromise(); + } this.websocketService.connect({ changeId: changeId }); // Request changes after changeId. } /** * Shuts OpenSlides down. The websocket is closed and the operator is not set. */ - public shutdown(): void { + public async shutdown(): Promise { this.websocketService.close(); - this.operator.user = null; + await this.operator.setUser(null); } /** * Shutdown and bootup. */ public async reboot(): Promise { - this.shutdown(); + await this.shutdown(); await this.bootup(); } /** * Verify that the operator is the same as it was before. Should be alled on a reconnect. */ - private async checkOperator(): Promise { + private async checkOperator(requestChanges: boolean = true): Promise { const response = await this.operator.whoAmI(); // User logged off. if (!response.user && !response.guest_enabled) { - this.shutdown(); + await this.shutdown(); this.router.navigate(['/login']); } else { if ( @@ -130,8 +149,9 @@ export class OpenSlidesService { (!this.operator.user && response.user_id) ) { // user changed + await this.DS.clear(); await this.reboot(); - } else { + } else if (requestChanges) { // User is still the same, but check for missed autoupdates. this.autoupdateService.requestChanges(); } diff --git a/client/src/app/core/core-services/operator.service.ts b/client/src/app/core/core-services/operator.service.ts index f771327c3..ecd203d4f 100644 --- a/client/src/app/core/core-services/operator.service.ts +++ b/client/src/app/core/core-services/operator.service.ts @@ -1,5 +1,4 @@ import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; import { Observable, BehaviorSubject } from 'rxjs'; @@ -11,6 +10,9 @@ import { OfflineService } from './offline.service'; import { ViewUser } from 'app/site/users/models/view-user'; import { OnAfterAppsLoaded } from '../onAfterAppsLoaded'; import { UserRepositoryService } from '../repositories/users/user-repository.service'; +import { CollectionStringMapperService } from './collectionStringMapper.service'; +import { StorageService } from './storage.service'; +import { HttpService } from './http.service'; /** * Permissions on the client are just strings. This makes clear, that @@ -19,7 +21,7 @@ import { UserRepositoryService } from '../repositories/users/user-repository.ser export type Permission = string; /** - * Response format of the WHoAMI request. + * Response format of the WhoAmI request. */ export interface WhoAmIResponse { user_id: number; @@ -27,6 +29,16 @@ export interface WhoAmIResponse { user: User; } +function isWhoAmIResponse(obj: any): obj is WhoAmIResponse { + if (!obj) { + return false; + } + const whoAmI = obj as WhoAmIResponse; + return whoAmI.guest_enabled !== undefined && whoAmI.user !== undefined && whoAmI.user_id !== undefined; +} + +const WHOAMI_STORAGE_KEY = 'whoami'; + /** * The operator represents the user who is using OpenSlides. * @@ -42,6 +54,10 @@ export class OperatorService implements OnAfterAppsLoaded { */ private _user: User; + public get user(): User { + return this._user; + } + /** * The operator as a view user. We need a separation here, because * we need to acces the operators permissions, before we get data @@ -49,13 +65,6 @@ export class OperatorService implements OnAfterAppsLoaded { */ private _viewUser: ViewUser; - /** - * Get the user that corresponds to operator. - */ - public get user(): User { - return this._user; - } - /** * Get the user that corresponds to operator. */ @@ -63,23 +72,16 @@ export class OperatorService implements OnAfterAppsLoaded { return this._viewUser; } - /** - * Sets the current operator. - * - * The permissions are updated and the new user published. - */ - public set user(user: User) { - this.updateUser(user); - } - public get isAnonymous(): boolean { return !this.user || this.user.id === 0; } /** - * Save, if quests are enabled. + * Save, if guests are enabled. */ - public guestsEnabled: boolean; + public get guestsEnabled(): boolean { + return this.currentWhoAmIResponse ? this.currentWhoAmIResponse.guest_enabled : false; + } /** * The permissions of the operator. Updated via {@method updatePermissions}. @@ -99,21 +101,27 @@ export class OperatorService implements OnAfterAppsLoaded { /** * Do not access the repo before it wasn't loaded. Will be true after `onAfterAppsLoaded`. */ - private userRepoLoaded = false; + private userRepository: UserRepositoryService | null; + + /** + * The current WhoAmI response to extract the user (the operator) from. + */ + private currentWhoAmIResponse: WhoAmIResponse | null; /** * Sets up an observer for watching changes in the DS. If the operator user or groups are changed, * the operator's permissions are updated. * - * @param http HttpClient + * @param http * @param DS * @param offlineService */ public constructor( - private http: HttpClient, + private http: HttpService, private DS: DataStoreService, private offlineService: OfflineService, - private userRepository: UserRepositoryService + private collectionStringMapper: CollectionStringMapperService, + private storageService: StorageService ) { this.DS.changeObservable.subscribe(newModel => { if (this._user) { @@ -131,24 +139,60 @@ export class OperatorService implements OnAfterAppsLoaded { }); } + /** + * Gets the current WHoAmI response from the storage. + */ + public async whoAmIFromStorage(): Promise { + const defaultResponse = { + user_id: null, + guest_enabled: false, + user: null + }; + let response: WhoAmIResponse; + try { + response = await this.storageService.get(WHOAMI_STORAGE_KEY); + if (response) { + this.processWhoAmIResponse(response); + } else { + response = defaultResponse; + } + } catch (e) { + response = defaultResponse; + } + this.currentWhoAmIResponse = response; + return this.currentWhoAmIResponse; + } + /** * Load the repo to get a view user. */ public onAfterAppsLoaded(): void { - this.userRepoLoaded = true; + this.userRepository = this.collectionStringMapper.getRepository(ViewUser) as UserRepositoryService; if (this.user) { this._viewUser = this.userRepository.getViewModel(this.user.id); } } + /** + * Sets the operator user. Will be saved to storage + * @param user The new operator. + */ + public async setUser(user: User): Promise { + await this.updateUser(user, true); + } + /** * Updates the user and update the permissions. * * @param user The user to set. + * @param saveToStoare Whether to save the user to the storage WhoAmI. */ - private updateUser(user: User | null): void { + private async updateUser(user: User | null, saveToStorage: boolean = false): Promise { this._user = user; - if (user && this.userRepoLoaded) { + if (saveToStorage) { + await this.saveUserToStorate(); + } + if (user && this.userRepository) { this._viewUser = this.userRepository.getViewModel(user.id); } else { this._viewUser = null; @@ -158,33 +202,68 @@ export class OperatorService implements OnAfterAppsLoaded { /** * Calls `/apps/users/whoami` to find out the real operator. + * * @returns The response of the WhoAmI request. */ public async whoAmI(): Promise { try { - const response = await this.http.get(environment.urlPrefix + '/users/whoami/').toPromise(); - if (response && response.user) { - this.user = new User(response.user); + const response = await this.http.get(environment.urlPrefix + '/users/whoami/'); + if (isWhoAmIResponse(response)) { + this.processWhoAmIResponse(response); + await this.storageService.set(WHOAMI_STORAGE_KEY, response); + this.currentWhoAmIResponse = response; + } else { + this.offlineService.goOfflineBecauseFailedWhoAmI(); } - return response; } catch (e) { - // TODO: Implement the offline service. Currently a guest-whoami response is returned and - // the DS cleared. this.offlineService.goOfflineBecauseFailedWhoAmI(); - return this.offlineService.getLastWhoAmI(); } + return this.currentWhoAmIResponse; } /** - * Returns the operatorSubject as an observable. + * Saves the user to storage by wrapping it into a (maybe existing) + * WhoAMI response. + */ + private async saveUserToStorate(): Promise { + if (!this.currentWhoAmIResponse) { + this.currentWhoAmIResponse = { + user_id: null, + guest_enabled: false, + user: null + }; + } + if (this.user) { + this.currentWhoAmIResponse.user_id = this.user.id; + this.currentWhoAmIResponse.user = this.user; + } else { + this.currentWhoAmIResponse.user_id = null; + this.currentWhoAmIResponse.user = null; + } + await this.storageService.set(WHOAMI_STORAGE_KEY, this.currentWhoAmIResponse); + } + + /** + * Processes a WhoAmI response and set the user appropriately. * - * Services an components can use it to get informed when something changes in - * the operator + * @param response The WhoAMI response + */ + private processWhoAmIResponse(response: WhoAmIResponse): void { + this.updateUser(response.user ? new User(response.user) : null); + } + + /** + * @returns an observable for the operator as a user. */ public getUserObservable(): Observable { return this.operatorSubject.asObservable(); } + /** + * @returns an observable for the operator as a viewUser. Note, that + * the viewUser might not be there, so for reliable (and not display) information, + * use the `getUserObservable`. + */ public getViewUserObservable(): Observable { return this.viewOperatorSubject.asObservable(); } diff --git a/client/src/app/core/core-services/servertime.service.ts b/client/src/app/core/core-services/servertime.service.ts index ff6ac39b4..aaa7a7d0b 100644 --- a/client/src/app/core/core-services/servertime.service.ts +++ b/client/src/app/core/core-services/servertime.service.ts @@ -16,6 +16,8 @@ import { environment } from 'environments/environment.prod'; providedIn: 'root' }) export class ServertimeService { + // TODO: couple this with the offlineService: Just retry often, if we are online. + // When we are offline, this is not necessary. private static FAILURE_TIMEOUT = 30; private static NORMAL_TIMEOUT = 60 * 5; diff --git a/client/src/app/core/core-services/websocket.service.ts b/client/src/app/core/core-services/websocket.service.ts index 38f98cec6..b6429f412 100644 --- a/client/src/app/core/core-services/websocket.service.ts +++ b/client/src/app/core/core-services/websocket.service.ts @@ -46,10 +46,6 @@ export class WebsocketService { */ private _connectEvent: EventEmitter = new EventEmitter(); - private connectionOpen = false; - - private sendQueueWhileNotConnected: string[] = []; - /** * Getter for the connect event. */ @@ -57,6 +53,32 @@ export class WebsocketService { return this._connectEvent; } + /** + * Listeners will be nofitied, if the wesocket connection is closed. + */ + private _closeEvent: EventEmitter = new EventEmitter(); + + /** + * Getter for the close event. + */ + public get closeEvent(): EventEmitter { + return this._closeEvent; + } + + /** + * Saves, if the connection is open + */ + private _connectionOpen = false; + + /** + * Whether the WebSocket connection is established + */ + public get isConnected(): boolean { + return this._connectionOpen; + } + + private sendQueueWhileNotConnected: string[] = []; + /** * The websocket. */ @@ -134,7 +156,7 @@ export class WebsocketService { this._reconnectEvent.emit(); } this._connectEvent.emit(); - this.connectionOpen = true; + this._connectionOpen = true; this.sendQueueWhileNotConnected.forEach(entry => { this.websocket.send(entry); }); @@ -160,8 +182,9 @@ export class WebsocketService { this.websocket.onclose = (event: CloseEvent) => { this.zone.run(() => { this.websocket = null; - this.connectionOpen = false; + this._connectionOpen = false; if (event.code !== 1000) { + console.error(event); // Do not show the message snackbar on the projector // tests for /projector and /projector/ const onProjector = this.router.url.match(/^\/projector(\/[0-9]+\/?)?$/); @@ -182,6 +205,7 @@ export class WebsocketService { this.connect({ enableAutoupdates: true }); }, timeout); } + this._closeEvent.emit(); }); }; } @@ -235,7 +259,7 @@ export class WebsocketService { // Either send directly or add to queue, if not connected. const jsonMessage = JSON.stringify(message); - if (this.connectionOpen) { + if (this.isConnected) { this.websocket.send(jsonMessage); } else { this.sendQueueWhileNotConnected.push(jsonMessage); diff --git a/client/src/app/shared/utils/app-preloader.ts b/client/src/app/shared/utils/app-preloader.ts deleted file mode 100644 index 798a3d39e..000000000 --- a/client/src/app/shared/utils/app-preloader.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { PreloadingStrategy, Route } from '@angular/router'; -import { Observable, of } from 'rxjs'; - -/** - * Custom preload strategy class - * - * @example - * ``` - * { - * path: 'agenda', - * loadChildren: './agenda/agenda.module#AgendaModule', - * data: { preload: true } - * } - * ``` - */ -export class AppPreloader implements PreloadingStrategy { - /** - * Custom preload function. - * Can be add to routes as data argument. - * - * @param route The route to load - * @param load The load function - */ - public preload(route: Route, load: Function): Observable { - return route.data && route.data.preload ? load() : of(null); - } -} diff --git a/client/src/app/site/config/components/config-list/config-list.component.ts b/client/src/app/site/config/components/config-list/config-list.component.ts index b6f0b9b79..bbe9b69ff 100644 --- a/client/src/app/site/config/components/config-list/config-list.component.ts +++ b/client/src/app/site/config/components/config-list/config-list.component.ts @@ -1,8 +1,10 @@ import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; + import { TranslateService } from '@ngx-translate/core'; -import { ConfigRepositoryService, ConfigGroup } from '../../../../core/repositories/config/config-repository.service'; -import { BaseComponent } from '../../../../base.component'; + +import { ConfigRepositoryService, ConfigGroup } from 'app/core/repositories/config/config-repository.service'; +import { BaseComponent } from 'app/base.component'; /** * List view for the global settings diff --git a/client/src/app/site/config/components/custom-translation/custom-translation.component.ts b/client/src/app/site/config/components/custom-translation/custom-translation.component.ts index 9cbd8e661..e1889e23d 100644 --- a/client/src/app/site/config/components/custom-translation/custom-translation.component.ts +++ b/client/src/app/site/config/components/custom-translation/custom-translation.component.ts @@ -1,7 +1,7 @@ import { Component, forwardRef } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { CustomTranslation, CustomTranslations } from 'app/core/translate/translation-parser'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; /** * Custom translations as custom form component diff --git a/client/src/app/site/history/components/history-list/history-list.component.ts b/client/src/app/site/history/components/history-list/history-list.component.ts index 11427b8d9..f31d595ab 100644 --- a/client/src/app/site/history/components/history-list/history-list.component.ts +++ b/client/src/app/site/history/components/history-list/history-list.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit } from '@angular/core'; import { MatSnackBar } from '@angular/material'; import { Router } from '@angular/router'; -import { Subject } from 'rxjs'; import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; +import { Subject } from 'rxjs'; import { History } from 'app/shared/models/core/history'; import { HistoryRepositoryService } from 'app/core/repositories/history/history-repository.service'; diff --git a/client/src/app/site/login/components/login-mask/login-mask.component.ts b/client/src/app/site/login/components/login-mask/login-mask.component.ts index 310576eb6..e321117af 100644 --- a/client/src/app/site/login/components/login-mask/login-mask.component.ts +++ b/client/src/app/site/login/components/login-mask/login-mask.component.ts @@ -1,16 +1,19 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, OnDestroy } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; +import { FormGroup, Validators, FormBuilder } from '@angular/forms'; + +import { Subscription } from 'rxjs'; +import { TranslateService } from '@ngx-translate/core'; import { BaseComponent } from 'app/base.component'; import { AuthService } from 'app/core/core-services/auth.service'; import { OperatorService } from 'app/core/core-services/operator.service'; -import { FormGroup, Validators, FormBuilder } from '@angular/forms'; -import { TranslateService } from '@ngx-translate/core'; import { environment } from 'environments/environment'; import { OpenSlidesService } from 'app/core/core-services/openslides.service'; import { LoginDataService } from 'app/core/ui-services/login-data.service'; import { ParentErrorStateMatcher } from 'app/shared/parent-error-state-matcher'; import { HttpService } from 'app/core/core-services/http.service'; +import { User } from 'app/shared/models/users/user'; /** * Login mask component. @@ -22,7 +25,7 @@ import { HttpService } from 'app/core/core-services/http.service'; templateUrl: './login-mask.component.html', styleUrls: ['./login-mask.component.scss'] }) -export class LoginMaskComponent extends BaseComponent implements OnInit { +export class LoginMaskComponent extends BaseComponent implements OnInit, OnDestroy { /** * Show or hide password and change the indicator accordingly */ @@ -53,6 +56,8 @@ export class LoginMaskComponent extends BaseComponent implements OnInit { */ public inProcess = false; + public operatorSubscription: Subscription | null; + /** * Constructor for the login component * @@ -99,6 +104,32 @@ export class LoginMaskComponent extends BaseComponent implements OnInit { }, () => {} ); + + // Maybe the operator changes and the user is logged in. If so, redirect him and boot OpenSlides. + this.operatorSubscription = this.operator.getUserObservable().subscribe(user => { + if (user) { + this.clearOperatorSubscription(); + this.redirectUser(); + this.OpenSlides.afterLoginBootup(user.id); + } + }); + } + + /** + * Clear the subscription on destroy. + */ + public ngOnDestroy(): void { + this.clearOperatorSubscription(); + } + + /** + * Clears the subscription to the operator. + */ + private clearOperatorSubscription(): void { + if (this.operatorSubscription) { + this.operatorSubscription.unsubscribe(); + this.operatorSubscription = null; + } } /** @@ -120,14 +151,12 @@ export class LoginMaskComponent extends BaseComponent implements OnInit { this.loginErrorMsg = ''; this.inProcess = true; try { - const res = await this.authService.login(this.loginForm.value.username, this.loginForm.value.password); + const response = await this.authService.login(this.loginForm.value.username, this.loginForm.value.password); + this.clearOperatorSubscription(); // We take control, not the subscription. this.inProcess = false; - this.OpenSlides.afterLoginBootup(res.user_id); - let redirect = this.OpenSlides.redirectUrl ? this.OpenSlides.redirectUrl : '/'; - if (redirect.includes('login')) { - redirect = '/'; - } - this.router.navigate([redirect]); + await this.operator.setUser(new User(response.user)); + this.OpenSlides.afterLoginBootup(response.user_id); + this.redirectUser(); } catch (e) { this.loginForm.setErrors({ notFound: true @@ -137,6 +166,17 @@ export class LoginMaskComponent extends BaseComponent implements OnInit { } } + /** + * Redirects the user to the page where he came from. + */ + private redirectUser(): void { + let redirect = this.OpenSlides.redirectUrl ? this.OpenSlides.redirectUrl : '/'; + if (redirect.includes('login')) { + redirect = '/'; + } + this.router.navigate([redirect]); + } + /** * Go to the reset password view */ diff --git a/client/src/app/site/login/components/login-wrapper/login-wrapper.component.ts b/client/src/app/site/login/components/login-wrapper/login-wrapper.component.ts index 8108a3c20..180b69b94 100644 --- a/client/src/app/site/login/components/login-wrapper/login-wrapper.component.ts +++ b/client/src/app/site/login/components/login-wrapper/login-wrapper.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; + import { TranslateService } from '@ngx-translate/core'; import { BaseComponent } from '../../../../base.component'; diff --git a/client/src/app/site/login/components/reset-password-confirm/reset-password-confirm.component.ts b/client/src/app/site/login/components/reset-password-confirm/reset-password-confirm.component.ts index bb21644ed..56caafa5c 100644 --- a/client/src/app/site/login/components/reset-password-confirm/reset-password-confirm.component.ts +++ b/client/src/app/site/login/components/reset-password-confirm/reset-password-confirm.component.ts @@ -1,13 +1,14 @@ import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; +import { FormGroup, FormBuilder, Validators } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; +import { MatSnackBar } from '@angular/material'; + import { TranslateService } from '@ngx-translate/core'; import { BaseComponent } from '../../../../base.component'; -import { FormGroup, FormBuilder, Validators } from '@angular/forms'; -import { HttpClient } from '@angular/common/http'; import { environment } from 'environments/environment'; -import { ActivatedRoute, Router } from '@angular/router'; -import { MatSnackBar } from '@angular/material'; +import { HttpService } from 'app/core/core-services/http.service'; /** * Reset password component. @@ -40,7 +41,7 @@ export class ResetPasswordConfirmComponent extends BaseComponent implements OnIn public constructor( protected titleService: Title, protected translate: TranslateService, - private http: HttpClient, + private http: HttpService, formBuilder: FormBuilder, private activatedRoute: ActivatedRoute, private router: Router, @@ -88,13 +89,11 @@ export class ResetPasswordConfirmComponent extends BaseComponent implements OnIn } try { - await this.http - .post(environment.urlPrefix + '/users/reset-password-confirm/', { - user_id: this.user_id, - token: this.token, - password: this.newPasswordForm.get('password').value - }) - .toPromise(); + await this.http.post(environment.urlPrefix + '/users/reset-password-confirm/', { + user_id: this.user_id, + token: this.token, + password: this.newPasswordForm.get('password').value + }); // TODO: Does we get a response for displaying? this.matSnackBar.open( this.translate.instant('Your password was resetted successfully!'), diff --git a/client/src/app/site/login/components/reset-password/reset-password.component.ts b/client/src/app/site/login/components/reset-password/reset-password.component.ts index 1fb54cdef..d04ef0c44 100644 --- a/client/src/app/site/login/components/reset-password/reset-password.component.ts +++ b/client/src/app/site/login/components/reset-password/reset-password.component.ts @@ -1,14 +1,15 @@ import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; -import { TranslateService } from '@ngx-translate/core'; - -import { BaseComponent } from '../../../../base.component'; import { FormGroup, FormBuilder, Validators } from '@angular/forms'; -import { HttpClient } from '@angular/common/http'; -import { environment } from 'environments/environment'; import { MatSnackBar } from '@angular/material'; import { Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; + +import { environment } from 'environments/environment'; +import { BaseComponent } from '../../../../base.component'; +import { HttpService } from 'app/core/core-services/http.service'; + /** * Reset password component. * @@ -30,7 +31,7 @@ export class ResetPasswordComponent extends BaseComponent implements OnInit { public constructor( protected titleService: Title, protected translate: TranslateService, - private http: HttpClient, + private http: HttpService, formBuilder: FormBuilder, private matSnackBar: MatSnackBar, private router: Router @@ -57,11 +58,9 @@ export class ResetPasswordComponent extends BaseComponent implements OnInit { } try { - await this.http - .post(environment.urlPrefix + '/users/reset-password/', { - email: this.resetPasswordForm.get('email').value - }) - .toPromise(); + await this.http.post(environment.urlPrefix + '/users/reset-password/', { + email: this.resetPasswordForm.get('email').value + }); // TODO: Does we get a response for displaying? this.matSnackBar.open( this.translate.instant('An email with a password reset link was send!'), diff --git a/client/src/app/site/site-routing.module.ts b/client/src/app/site/site-routing.module.ts index 8643d3704..cb57a4ca0 100644 --- a/client/src/app/site/site-routing.module.ts +++ b/client/src/app/site/site-routing.module.ts @@ -16,53 +16,43 @@ const routes: Routes = [ children: [ { path: '', - loadChildren: './common/os-common.module#OsCommonModule', - data: { preload: true } + loadChildren: './common/os-common.module#OsCommonModule' }, { path: 'agenda', - loadChildren: './agenda/agenda.module#AgendaModule', - data: { preload: true } + loadChildren: './agenda/agenda.module#AgendaModule' }, { path: 'assignments', - loadChildren: './assignments/assignments.module#AssignmentsModule', - data: { preload: true } + loadChildren: './assignments/assignments.module#AssignmentsModule' }, { path: 'mediafiles', - loadChildren: './mediafiles/mediafiles.module#MediafilesModule', - data: { preload: true } + loadChildren: './mediafiles/mediafiles.module#MediafilesModule' }, { path: 'motions', - loadChildren: './motions/motions.module#MotionsModule', - data: { preload: true } + loadChildren: './motions/motions.module#MotionsModule' }, { path: 'settings', - loadChildren: './config/config.module#ConfigModule', - data: { preload: true } + loadChildren: './config/config.module#ConfigModule' }, { path: 'users', - loadChildren: './users/users.module#UsersModule', - data: { preload: true } + loadChildren: './users/users.module#UsersModule' }, { path: 'tags', - loadChildren: './tags/tag.module#TagModule', - data: { preload: true } + loadChildren: './tags/tag.module#TagModule' }, { path: 'history', - loadChildren: './history/history.module#HistoryModule', - data: { preload: true } + loadChildren: './history/history.module#HistoryModule' }, { path: 'projectors', - loadChildren: './projector/projector.module#ProjectorModule', - data: { preload: true } + loadChildren: './projector/projector.module#ProjectorModule' } ], canActivateChild: [AuthGuard] diff --git a/client/src/app/site/site.component.html b/client/src/app/site/site.component.html index 68ca496fe..2e759e3b3 100644 --- a/client/src/app/site/site.component.html +++ b/client/src/app/site/site.component.html @@ -36,7 +36,7 @@ {{ getLangName(this.translate.currentLang) }}
- + person Show profile diff --git a/client/src/app/site/site.component.ts b/client/src/app/site/site.component.ts index bb8d589d8..374d3bb2a 100644 --- a/client/src/app/site/site.component.ts +++ b/client/src/app/site/site.component.ts @@ -99,7 +99,9 @@ export class SiteComponent extends BaseComponent implements OnInit { // Scroll to top if accessing a page, not via browser history stack if (event instanceof NavigationEnd) { const contentContainer = document.querySelector('.mat-sidenav-content'); - contentContainer.scrollTo(0, 0); + if (contentContainer) { + contentContainer.scrollTo(0, 0); + } } }); }