diff --git a/client/src/app/core/ui-services/login-data.service.ts b/client/src/app/core/ui-services/login-data.service.ts index 2b4940199..ac34c5319 100644 --- a/client/src/app/core/ui-services/login-data.service.ts +++ b/client/src/app/core/ui-services/login-data.service.ts @@ -3,10 +3,22 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; import { ConfigService } from './config.service'; +import { StorageService } from '../core-services/storage.service'; /** - * This service holds the privacy policy and the legal notice, so they are available - * even if the user is not logged in. + * The login data send by the server. + */ +export interface LoginData { + privacy_policy: string; + legal_notice: string; + theme: string; +} + +const LOGIN_DATA_STORAGE_KEY = 'LoginData'; + +/** + * This service holds the privacy policy, the legal notice and the OpenSlides theme, so + * they are available even if the user is not logged in. */ @Injectable({ providedIn: 'root' @@ -15,7 +27,7 @@ export class LoginDataService { /** * Holds the privacy policy */ - private _privacy_policy = new BehaviorSubject(''); + private readonly _privacy_policy = new BehaviorSubject(''); /** * Returns an observable for the privacy policy @@ -27,7 +39,7 @@ export class LoginDataService { /** * Holds the legal notice */ - private _legal_notice = new BehaviorSubject(''); + private readonly _legal_notice = new BehaviorSubject(''); /** * Returns an observable for the legal notice @@ -36,33 +48,76 @@ export class LoginDataService { return this._legal_notice.asObservable(); } + /** + * Holds the theme + */ + private readonly _theme = new BehaviorSubject(''); + + /** + * Returns an observable for the theme + */ + public get theme(): Observable { + return this._theme.asObservable(); + } + /** * Constructs this service. The config service is needed to update the privacy * policy and legal notice, when their config values change. * @param configService */ - public constructor(private configService: ConfigService) { + public constructor(private configService: ConfigService, private storageService: StorageService) { this.configService.get('general_event_privacy_policy').subscribe(value => { - this.setPrivacyPolicy(value); + this._privacy_policy.next(value); + this.storeLoginData(); }); this.configService.get('general_event_legal_notice').subscribe(value => { - this.setLegalNotice(value); + this._legal_notice.next(value); + this.storeLoginData(); }); + configService.get('openslides_theme').subscribe(value => { + this._theme.next(value); + this.storeLoginData(); + }); + + this.loadLoginData(); } /** - * Setter for the privacy policy - * @param privacyPolicy The new privacy policy to set + * Load the login data from the storage. If it there, set it. */ - public setPrivacyPolicy(privacyPolicy: string): void { - this._privacy_policy.next(privacyPolicy); + private async loadLoginData(): Promise { + const loginData = await this.storageService.get(LOGIN_DATA_STORAGE_KEY); + if (loginData) { + this.setLoginData(loginData); + } } /** - * Setter for the legal notice - * @param legalNotice The new legal notice to set + * Setter for the login data + * + * @param loginData the login data */ - public setLegalNotice(legalNotice: string): void { - this._legal_notice.next(legalNotice); + public setLoginData(loginData: LoginData): void { + this._privacy_policy.next(loginData.privacy_policy); + this._legal_notice.next(loginData.legal_notice); + this._theme.next(loginData.theme); + this.storeLoginData(loginData); + } + + /** + * Saves the login data in the storage. + * + * @param loginData If given, this data is used. If it's null, the current values + * from the behaviour subject are taken. + */ + private storeLoginData(loginData?: LoginData): void { + if (!loginData) { + loginData = { + privacy_policy: this._privacy_policy.getValue(), + legal_notice: this._legal_notice.getValue(), + theme: this._theme.getValue() + }; + } + this.storageService.set(LOGIN_DATA_STORAGE_KEY, loginData); } } diff --git a/client/src/app/core/ui-services/theme.service.ts b/client/src/app/core/ui-services/theme.service.ts index 350851b89..c5e363085 100644 --- a/client/src/app/core/ui-services/theme.service.ts +++ b/client/src/app/core/ui-services/theme.service.ts @@ -1,31 +1,33 @@ import { Injectable } from '@angular/core'; -import { ConfigService } from './config.service'; + +import { LoginDataService } from './login-data.service'; /** - * Service to set the theme for the OpenSlides. - * Reads related data from server, - * the server sends the value of the new theme --> the new theme has only to be added to the body. + * Service to set the theme for OpenSlides. */ @Injectable({ providedIn: 'root' }) export class ThemeService { /** - * Here it will subscribe to the observer from config-service to read data. + * Here it will subscribe to the observer from login data service. The stheme is part of + * the login data, so get it from there and not from the config. This service will + * also cache the theme and provide the right theme on login. * - * @param configService must be injected to get the data from server. + * @param loginDataService must be injected to get the theme. */ - public constructor(configService: ConfigService) { - configService.get('openslides_theme').subscribe(newTheme => { - // Listen to the related event. - const classList = document.getElementsByTagName('body')[0].classList; // Get the classlist of the body. - if (newTheme) { - const toRemove = Array.from(classList).filter((item: string) => item.includes('theme')); - if (toRemove.length) { - classList.remove(...toRemove); // Remove all old themes. - } - classList.add(newTheme); // Add the new theme. + public constructor(loginDataService: LoginDataService) { + loginDataService.theme.subscribe(newTheme => { + if (!newTheme) { + return; } + + const classList = document.getElementsByTagName('body')[0].classList; // Get the classlist of the body. + const toRemove = Array.from(classList).filter((item: string) => item.includes('theme')); + if (toRemove.length) { + classList.remove(...toRemove); // Remove all old themes. + } + classList.add(newTheme); // Add the new theme. }); } } 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 e321117af..76c9a4d4b 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 @@ -10,11 +10,15 @@ import { AuthService } from 'app/core/core-services/auth.service'; import { OperatorService } from 'app/core/core-services/operator.service'; 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 { LoginDataService, LoginData } 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'; +interface LoginDataWithInfoText extends LoginData { + info_text?: string; +} + /** * Login mask component. * @@ -94,13 +98,12 @@ export class LoginMaskComponent extends BaseComponent implements OnInit, OnDestr // Get the login data. Save information to the login data service. If there is an // error, ignore it. // TODO: This has to be caught by the offline service - this.httpService.get(environment.urlPrefix + '/users/login/').then( + this.httpService.get(environment.urlPrefix + '/users/login/').then( response => { if (response.info_text) { this.installationNotice = response.info_text; } - this.loginDataService.setPrivacyPolicy(response.privacy_policy); - this.loginDataService.setLegalNotice(response.legal_notice); + this.loginDataService.setLoginData(response); }, () => {} ); diff --git a/openslides/users/views.py b/openslides/users/views.py index 277b05308..516fe7546 100644 --- a/openslides/users/views.py +++ b/openslides/users/views.py @@ -521,6 +521,8 @@ class UserLoginView(APIView): # even, it is not logged in. context["privacy_policy"] = config["general_event_privacy_policy"] context["legal_notice"] = config["general_event_legal_notice"] + # Add the theme, so the loginpage is themed correctly + context["theme"] = config["openslides_theme"] else: # self.request.method == 'POST' context["user_id"] = self.user.pk