Fixes some UI issues corresponding to the theme
- Fixes white page at 'legalnotice' and 'privacypolicy' - Fixes the button to collapse the sidenav - Fixes a too long text in the headbar - Reworked the login data service: * make order of operations clear * prevent setting invalid data into the storage
This commit is contained in:
parent
20cbe37d74
commit
b5b3e60e81
@ -1,4 +1,4 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { PwaService } from './pwa.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
@ -6,12 +6,12 @@ import { E2EImportsModule } from 'e2e-imports.module';
|
||||
describe('PwaService', () => {
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
imports: [E2EImportsModule],
|
||||
providers: [PwaService]
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', () => {
|
||||
const service: PwaService = TestBed.get(PwaService);
|
||||
it('should be created', inject([PwaService], (service: PwaService) => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { StorageService } from './storage.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('StorageService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [StorageService]
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { DurationService } from './duration.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
@ -6,12 +6,12 @@ import { E2EImportsModule } from 'e2e-imports.module';
|
||||
describe('DurationService', () => {
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
imports: [E2EImportsModule],
|
||||
providers: [DurationService]
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', () => {
|
||||
const service: DurationService = TestBed.get(DurationService);
|
||||
it('should be created', inject([DurationService], (service: DurationService) => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -1,12 +1,17 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { HtmlToPdfService } from './html-to-pdf.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('HtmlToPdfService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [HtmlToPdfService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
const service: HtmlToPdfService = TestBed.get(HtmlToPdfService);
|
||||
it('should be created', inject([HtmlToPdfService], (service: HtmlToPdfService) => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -1,12 +1,17 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { LoadFontService } from './load-font.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('LoadFontService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [LoadFontService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
const service: LoadFontService = TestBed.get(LoadFontService);
|
||||
it('should be created', inject([LoadFontService], (service: LoadFontService) => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { LoginDataService } from './login-data.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('LoginDataService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [LoginDataService]
|
||||
});
|
||||
});
|
||||
|
@ -1,22 +1,35 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, EventEmitter } from '@angular/core';
|
||||
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
|
||||
import { ConfigService } from './config.service';
|
||||
import { StorageService } from '../core-services/storage.service';
|
||||
import { OpenSlidesStatusService } from '../core-services/openslides-status.service';
|
||||
import { HttpService } from '../core-services/http.service';
|
||||
import { environment } from 'environments/environment.prod';
|
||||
import { auditTime } from 'rxjs/operators';
|
||||
|
||||
/**
|
||||
* The login data send by the server.
|
||||
*/
|
||||
export interface LoginData {
|
||||
privacy_policy: string;
|
||||
legal_notice: string;
|
||||
privacy_policy?: string;
|
||||
legal_notice?: string;
|
||||
theme: string;
|
||||
logo_web_header: {
|
||||
path: string;
|
||||
display_name: string;
|
||||
};
|
||||
login_info_text?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks, if the given object holds valid LoginData.
|
||||
*
|
||||
* @param obj The object to check
|
||||
*/
|
||||
function isLoginData(obj: any): obj is LoginData {
|
||||
return !!obj && obj.theme && obj.logo_web_header;
|
||||
}
|
||||
|
||||
const LOGIN_DATA_STORAGE_KEY = 'LoginData';
|
||||
@ -29,28 +42,40 @@ const LOGIN_DATA_STORAGE_KEY = 'LoginData';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class LoginDataService {
|
||||
/**
|
||||
* Holds the installation notice.
|
||||
*/
|
||||
private readonly _loginInfoText = new BehaviorSubject<string>('');
|
||||
|
||||
/**
|
||||
* Returns the installation notice as observable.
|
||||
*/
|
||||
public get loginInfoText(): Observable<string> {
|
||||
return this._loginInfoText.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds the privacy policy
|
||||
*/
|
||||
private readonly _privacy_policy = new BehaviorSubject<string>('');
|
||||
private readonly _privacyPolicy = new BehaviorSubject<string>('');
|
||||
|
||||
/**
|
||||
* Returns an observable for the privacy policy
|
||||
*/
|
||||
public get privacy_policy(): Observable<string> {
|
||||
return this._privacy_policy.asObservable();
|
||||
public get privacyPolicy(): Observable<string> {
|
||||
return this._privacyPolicy.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds the legal notice
|
||||
*/
|
||||
private readonly _legal_notice = new BehaviorSubject<string>('');
|
||||
private readonly _legalNotice = new BehaviorSubject<string>('');
|
||||
|
||||
/**
|
||||
* Returns an observable for the legal notice
|
||||
*/
|
||||
public get legal_notice(): Observable<string> {
|
||||
return this._legal_notice.asObservable();
|
||||
public get legalNotice(): Observable<string> {
|
||||
return this._legalNotice.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,7 +93,7 @@ export class LoginDataService {
|
||||
/**
|
||||
* Holds the custom web header
|
||||
*/
|
||||
private readonly _logo_web_header = new BehaviorSubject<{ path: string; display_name: string }>({
|
||||
private readonly _logoWebHeader = new BehaviorSubject<{ path: string; display_name: string }>({
|
||||
path: '',
|
||||
display_name: ''
|
||||
});
|
||||
@ -76,10 +101,27 @@ export class LoginDataService {
|
||||
/**
|
||||
* Returns an observable for the web header
|
||||
*/
|
||||
public get logo_web_header(): Observable<{ path: string; display_name: string }> {
|
||||
return this._logo_web_header.asObservable();
|
||||
public get logoWebHeader(): Observable<{ path: string; display_name: string }> {
|
||||
return this._logoWebHeader.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit this event, if the current login data should be stored. This
|
||||
* is debounced to minimize requests to the storage service.
|
||||
*/
|
||||
private storeLoginDataRequests = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* Holds, if `_refresh` can be called. This will be true fter the setup.
|
||||
*/
|
||||
private canRefresh = false;
|
||||
|
||||
/**
|
||||
* Marks, if during the etup (with `canRefresh=false`) a refresh was requested.
|
||||
* After the setup, this variabel will be checked and a refresh triggered, if it is true.
|
||||
*/
|
||||
private markRefresh = false;
|
||||
|
||||
/**
|
||||
* Constructs this service. The config service is needed to update the privacy
|
||||
* policy and legal notice, when their config values change.
|
||||
@ -88,67 +130,112 @@ export class LoginDataService {
|
||||
public constructor(
|
||||
private configService: ConfigService,
|
||||
private storageService: StorageService,
|
||||
private OSStatus: OpenSlidesStatusService
|
||||
private OSStatus: OpenSlidesStatusService,
|
||||
private httpService: HttpService
|
||||
) {
|
||||
this.storeLoginDataRequests.pipe(auditTime(100)).subscribe(() => this.storeLoginData());
|
||||
this.setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the login data and *after* that the configs are subscribed. If a request for a refresh
|
||||
* was issued while the setup, the refresh will be executed afterwards.
|
||||
*/
|
||||
private async setup(): Promise<void> {
|
||||
await this.loadLoginData();
|
||||
this.configService.get<string>('general_event_privacy_policy').subscribe(value => {
|
||||
this._privacy_policy.next(value);
|
||||
this.storeLoginData();
|
||||
if (value !== undefined) {
|
||||
this._privacyPolicy.next(value);
|
||||
this.storeLoginDataRequests.next();
|
||||
}
|
||||
});
|
||||
this.configService.get<string>('general_event_legal_notice').subscribe(value => {
|
||||
this._legal_notice.next(value);
|
||||
this.storeLoginData();
|
||||
if (value !== undefined) {
|
||||
this._legalNotice.next(value);
|
||||
this.storeLoginDataRequests.next();
|
||||
}
|
||||
});
|
||||
configService.get<string>('openslides_theme').subscribe(value => {
|
||||
this.configService.get<string>('openslides_theme').subscribe(value => {
|
||||
if (value) {
|
||||
this._theme.next(value);
|
||||
this.storeLoginData();
|
||||
this.storeLoginDataRequests.next();
|
||||
}
|
||||
});
|
||||
configService.get<{ path: string; display_name: string }>('logo_web_header').subscribe(value => {
|
||||
this._logo_web_header.next(value);
|
||||
this.storeLoginData();
|
||||
this.configService.get<{ path: string; display_name: string }>('logo_web_header').subscribe(value => {
|
||||
if (value) {
|
||||
this._logoWebHeader.next(value);
|
||||
this.storeLoginDataRequests.next();
|
||||
}
|
||||
});
|
||||
this.canRefresh = true;
|
||||
if (this.markRefresh) {
|
||||
this._refresh();
|
||||
}
|
||||
}
|
||||
|
||||
this.loadLoginData();
|
||||
/**
|
||||
* Explicit refresh the ata from the server.
|
||||
*/
|
||||
public refresh(): void {
|
||||
if (this.canRefresh && !this.markRefresh) {
|
||||
this._refresh();
|
||||
} else if (!this.canRefresh) {
|
||||
this.markRefresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual refresh implementation.
|
||||
*/
|
||||
private async _refresh(): Promise<void> {
|
||||
try {
|
||||
const loginData = await this.httpService.get<LoginData>(environment.urlPrefix + '/users/login/');
|
||||
this.setLoginData(loginData);
|
||||
this.storeLoginDataRequests.next();
|
||||
} catch (e) {
|
||||
console.log('Could not refresh login data', e);
|
||||
}
|
||||
this.markRefresh = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the login data from the storage. If it there, set it.
|
||||
*/
|
||||
private async loadLoginData(): Promise<void> {
|
||||
const loginData = await this.storageService.get<LoginData | null>(LOGIN_DATA_STORAGE_KEY);
|
||||
if (loginData) {
|
||||
const loginData = await this.storageService.get<any>(LOGIN_DATA_STORAGE_KEY);
|
||||
if (isLoginData(loginData)) {
|
||||
this.setLoginData(loginData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the login data
|
||||
* Triggers all subjects with the given data.
|
||||
*
|
||||
* @param loginData the login data
|
||||
* @param loginData The data
|
||||
*/
|
||||
public setLoginData(loginData: LoginData): void {
|
||||
this._privacy_policy.next(loginData.privacy_policy);
|
||||
this._legal_notice.next(loginData.legal_notice);
|
||||
private setLoginData(loginData: LoginData): void {
|
||||
this._privacyPolicy.next(loginData.privacy_policy);
|
||||
this._legalNotice.next(loginData.legal_notice);
|
||||
this._theme.next(loginData.theme);
|
||||
this.storeLoginData(loginData);
|
||||
this._logoWebHeader.next(loginData.logo_web_header);
|
||||
this._loginInfoText.next(loginData.login_info_text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Saves the login data to the storeage. Do not call this method and
|
||||
* use `storeLoginDataRequests` instead. The data to store will be
|
||||
* taken form all subjects.
|
||||
*/
|
||||
private storeLoginData(loginData?: LoginData): void {
|
||||
if (!loginData) {
|
||||
loginData = {
|
||||
privacy_policy: this._privacy_policy.getValue(),
|
||||
legal_notice: this._legal_notice.getValue(),
|
||||
theme: this._theme.getValue(),
|
||||
logo_web_header: this._logo_web_header.getValue()
|
||||
};
|
||||
private storeLoginData(): void {
|
||||
if (this.OSStatus.isInHistoryMode) {
|
||||
return;
|
||||
}
|
||||
if (!this.OSStatus.isInHistoryMode) {
|
||||
const loginData = {
|
||||
privacy_policy: this._privacyPolicy.getValue(),
|
||||
legal_notice: this._legalNotice.getValue(),
|
||||
theme: this._theme.getValue(),
|
||||
logo_web_header: this._logoWebHeader.getValue()
|
||||
};
|
||||
this.storageService.set(LOGIN_DATA_STORAGE_KEY, loginData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,17 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { MediaManageService } from './media-manage.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('MediaManageService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({ imports: [E2EImportsModule] }));
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [MediaManageService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
const service: MediaManageService = TestBed.get(MediaManageService);
|
||||
it('should be created', inject([MediaManageService], (service: MediaManageService) => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -1,17 +1,17 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { PdfDocumentService } from '../ui-services/pdf-document.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('PdfDocumentService', () => {
|
||||
beforeEach(() =>
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
})
|
||||
);
|
||||
imports: [E2EImportsModule],
|
||||
providers: [PdfDocumentService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
const service: PdfDocumentService = TestBed.get(PdfDocumentService);
|
||||
it('should be created', inject([PdfDocumentService], (service: PdfDocumentService) => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -1,12 +1,17 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { PollService } from './poll.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('PollService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [PollService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
const service: PollService = TestBed.get(PollService);
|
||||
it('should be created', inject([PollService], (service: PollService) => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -1,17 +1,17 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { RoutingStateService } from './routing-state.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('RoutingStateService', () => {
|
||||
beforeEach(() =>
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
})
|
||||
);
|
||||
imports: [E2EImportsModule],
|
||||
providers: [RoutingStateService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
const service: RoutingStateService = TestBed.get(RoutingStateService);
|
||||
it('should be created', inject([RoutingStateService], (service: RoutingStateService) => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -1,12 +1,17 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { SpinnerService } from './spinner.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('SpinnerService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [SpinnerService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
const service: SpinnerService = TestBed.get(SpinnerService);
|
||||
it('should be created', inject([SpinnerService], (service: SpinnerService) => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -1,12 +1,17 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { ThemeService } from './theme.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('ThemeService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [ThemeService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
const service: ThemeService = TestBed.get(ThemeService);
|
||||
it('should be created', inject([ThemeService], (service: ThemeService) => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -77,17 +77,4 @@ export class ThemeService {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to ensure, that there is at least one theme set to define
|
||||
* the colors of the components.
|
||||
*
|
||||
* If a theme is already set, nothing happens, otherwise the
|
||||
* `DEFAULT_THEME` will be set.
|
||||
*/
|
||||
public checkTheme(): void {
|
||||
if (!this.currentTheme || this.currentTheme === '') {
|
||||
this.changeTheme(ThemeService.DEFAULT_THEME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { UpdateService } from './update.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
@ -11,8 +11,7 @@ describe('UpdateService', () => {
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', () => {
|
||||
const service: UpdateService = TestBed.get(UpdateService);
|
||||
it('should be created', inject([UpdateService], (service: UpdateService) => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { ViewportService } from './viewport.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('ViewportService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [ViewportService]
|
||||
});
|
||||
});
|
||||
|
@ -1,12 +1,17 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { XlsxExportServiceService } from './xlsx-export-service.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('XlsxExportServiceService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [XlsxExportServiceService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
const service: XlsxExportServiceService = TestBed.get(XlsxExportServiceService);
|
||||
it('should be created', inject([XlsxExportServiceService], (service: XlsxExportServiceService) => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
.toolbar-left {
|
||||
display: flex;
|
||||
max-width: calc(100% - 100px);
|
||||
button {
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
<mat-card class="os-card">
|
||||
<div>
|
||||
<div class="legal-notice-text" [innerHtml]="legalNotice"></div>
|
||||
<div *ngIf="legalNotice" class="legal-notice-text" [innerHtml]="legalNotice"></div>
|
||||
<div *ngIf="!legalNotice" translate>
|
||||
The event manager hasn't set up a legal notice yet.
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<div *ngIf="versionInfo" class="version-text">
|
||||
<a [attr.href]="versionInfo.openslides_url" target="_blank">
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { LoginDataService } from 'app/core/ui-services/login-data.service';
|
||||
import { environment } from 'environments/environment';
|
||||
import { HttpService } from 'app/core/core-services/http.service';
|
||||
@ -82,20 +80,14 @@ export class LegalNoticeContentComponent implements OnInit {
|
||||
* @param translate
|
||||
* @param http
|
||||
*/
|
||||
public constructor(
|
||||
private loginDataService: LoginDataService,
|
||||
private translate: TranslateService,
|
||||
private http: HttpService
|
||||
) {}
|
||||
public constructor(private loginDataService: LoginDataService, private http: HttpService) {}
|
||||
|
||||
/**
|
||||
* Subscribes for the legal notice text.
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
this.loginDataService.legal_notice.subscribe(legalNotice => {
|
||||
if (legalNotice) {
|
||||
this.legalNotice = this.translate.instant(legalNotice);
|
||||
}
|
||||
this.loginDataService.legalNotice.subscribe(legalNotice => {
|
||||
this.legalNotice = legalNotice;
|
||||
});
|
||||
|
||||
// Query the version info.
|
||||
|
@ -42,7 +42,7 @@ export class LogoComponent implements OnInit, OnDestroy {
|
||||
* On init method
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
this.logoSubscription = this.loginDataService.logo_web_header.subscribe(nextLogo => {
|
||||
this.logoSubscription = this.loginDataService.logoWebHeader.subscribe(nextLogo => {
|
||||
if (nextLogo) {
|
||||
this.logoPath = nextLogo.path;
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { LoginDataService } from 'app/core/ui-services/login-data.service';
|
||||
|
||||
/**
|
||||
@ -24,16 +22,14 @@ export class PrivacyPolicyContentComponent implements OnInit {
|
||||
* @param loginDataService Login Data
|
||||
* @param translate for the translation
|
||||
*/
|
||||
public constructor(private loginDataService: LoginDataService, private translate: TranslateService) {}
|
||||
public constructor(private loginDataService: LoginDataService) {}
|
||||
|
||||
/**
|
||||
* Subscribes for the privacy policy text
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
this.loginDataService.privacy_policy.subscribe(privacyPolicy => {
|
||||
if (privacyPolicy) {
|
||||
this.privacyPolicy = this.translate.instant(privacyPolicy);
|
||||
}
|
||||
this.loginDataService.privacyPolicy.subscribe(privacyPolicy => {
|
||||
this.privacyPolicy = privacyPolicy;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -6,18 +6,13 @@ import { Title } from '@angular/platform-browser';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseComponent } from 'app/base.component';
|
||||
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||
import { AuthService } from 'app/core/core-services/auth.service';
|
||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||
import { environment } from 'environments/environment';
|
||||
import { LoginDataService, LoginData } from 'app/core/ui-services/login-data.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 { SpinnerService } from 'app/core/ui-services/spinner.service';
|
||||
|
||||
interface LoginDataWithInfoText extends LoginData {
|
||||
info_text?: string;
|
||||
}
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
|
||||
/**
|
||||
* Login mask component.
|
||||
@ -29,7 +24,7 @@ interface LoginDataWithInfoText extends LoginData {
|
||||
templateUrl: './login-mask.component.html',
|
||||
styleUrls: ['./login-mask.component.scss']
|
||||
})
|
||||
export class LoginMaskComponent extends BaseComponent implements OnInit, OnDestroy {
|
||||
export class LoginMaskComponent extends BaseViewComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* Show or hide password and change the indicator accordingly
|
||||
*/
|
||||
@ -72,16 +67,16 @@ export class LoginMaskComponent extends BaseComponent implements OnInit, OnDestr
|
||||
public constructor(
|
||||
title: Title,
|
||||
translate: TranslateService,
|
||||
matSnackBar: MatSnackBar,
|
||||
private authService: AuthService,
|
||||
private operator: OperatorService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private formBuilder: FormBuilder,
|
||||
private httpService: HttpService,
|
||||
private loginDataService: LoginDataService,
|
||||
private spinnerService: SpinnerService
|
||||
) {
|
||||
super(title, translate);
|
||||
super(title, translate, matSnackBar);
|
||||
// Hide the spinner if the user is at `login-mask`
|
||||
spinnerService.setVisibility(false);
|
||||
this.createForm();
|
||||
@ -94,17 +89,8 @@ export class LoginMaskComponent extends BaseComponent implements OnInit, OnDestr
|
||||
* Observes the operator, if a user was already logged in, recreate to user and skip the login
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
// 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<LoginDataWithInfoText>(environment.urlPrefix + '/users/login/').then(
|
||||
response => {
|
||||
if (response.info_text) {
|
||||
this.installationNotice = response.info_text;
|
||||
}
|
||||
this.loginDataService.setLoginData(response);
|
||||
},
|
||||
() => {}
|
||||
this.subscriptions.push(
|
||||
this.loginDataService.loginInfoText.subscribe(notice => (this.installationNotice = notice))
|
||||
);
|
||||
|
||||
// Maybe the operator changes and the user is logged in. If so, redirect him and boot OpenSlides.
|
||||
|
@ -4,6 +4,7 @@ import { Title } from '@angular/platform-browser';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseComponent } from '../../../../base.component';
|
||||
import { LoginDataService } from 'app/core/ui-services/login-data.service';
|
||||
|
||||
/**
|
||||
* Login component.
|
||||
@ -22,7 +23,11 @@ export class LoginWrapperComponent extends BaseComponent implements OnInit {
|
||||
* @param titleService to set the title
|
||||
* @param translate just needed because super.setTitle depends in the `translator.instant` function
|
||||
*/
|
||||
public constructor(protected titleService: Title, protected translate: TranslateService) {
|
||||
public constructor(
|
||||
protected titleService: Title,
|
||||
protected translate: TranslateService,
|
||||
private loginDataService: LoginDataService
|
||||
) {
|
||||
super(titleService, translate);
|
||||
}
|
||||
|
||||
@ -31,5 +36,6 @@ export class LoginWrapperComponent extends BaseComponent implements OnInit {
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
super.setTitle('Login');
|
||||
this.loginDataService.refresh();
|
||||
}
|
||||
}
|
||||
|
@ -21,10 +21,12 @@
|
||||
color="primary"
|
||||
class="submit-button"
|
||||
[disabled]="newPasswordForm.invalid"
|
||||
translate
|
||||
>
|
||||
Reset password
|
||||
{{ 'Reset password' | translate }}
|
||||
</button>
|
||||
|
||||
<button type="button" mat-button routerLink="/login">
|
||||
{{ 'Back to login' | translate }}
|
||||
</button>
|
||||
<button type="button" class="back-button" routerLink="/login" translate>Back to login</button>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -2,7 +2,14 @@
|
||||
<form [formGroup]="resetPasswordForm" (ngSubmit)="resetPassword()" autocomplete="off">
|
||||
<h3 translate>Enter your email to send the password reset link</h3>
|
||||
<mat-form-field>
|
||||
<input matInput required placeholder="{{ 'Email' | translate }}" formControlName="email" type="email" autocomplete="off" />
|
||||
<input
|
||||
matInput
|
||||
required
|
||||
placeholder="{{ 'Email' | translate }}"
|
||||
formControlName="email"
|
||||
type="email"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<mat-error *ngIf="resetPasswordForm.get('email').invalid" translate>
|
||||
Please enter a valid email address!
|
||||
</mat-error>
|
||||
|
@ -8,7 +8,6 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { environment } from 'environments/environment';
|
||||
import { HttpService } from 'app/core/core-services/http.service';
|
||||
import { ThemeService } from 'app/core/ui-services/theme.service';
|
||||
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||
|
||||
/**
|
||||
@ -35,8 +34,7 @@ export class ResetPasswordComponent extends BaseViewComponent implements OnInit
|
||||
matSnackBar: MatSnackBar,
|
||||
private http: HttpService,
|
||||
formBuilder: FormBuilder,
|
||||
private router: Router,
|
||||
private themeService: ThemeService
|
||||
private router: Router
|
||||
) {
|
||||
super(titleService, translate, matSnackBar);
|
||||
this.resetPasswordForm = formBuilder.group({
|
||||
@ -49,7 +47,6 @@ export class ResetPasswordComponent extends BaseViewComponent implements OnInit
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
super.setTitle('Reset password');
|
||||
this.themeService.checkTheme();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,6 +86,7 @@ mat-sidenav-container {
|
||||
height: $size;
|
||||
width: $size;
|
||||
font-size: $size;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -697,20 +697,17 @@ class UserLoginView(WhoAmIDataView):
|
||||
"""
|
||||
if self.request.method == "GET":
|
||||
if config["general_login_info_text"]:
|
||||
context["info_text"] = config["general_login_info_text"]
|
||||
context["login_info_text"] = config["general_login_info_text"]
|
||||
else:
|
||||
try:
|
||||
user = User.objects.get(username="admin")
|
||||
except User.DoesNotExist:
|
||||
context["info_text"] = ""
|
||||
else:
|
||||
if user.check_password("admin"):
|
||||
context["info_text"] = (
|
||||
context["login_info_text"] = (
|
||||
f"Use <strong>admin</strong> and <strong>admin</strong> for your first login.<br>"
|
||||
"Please change your password to hide this message!"
|
||||
)
|
||||
else:
|
||||
context["info_text"] = ""
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
# Add the privacy policy and legal notice, so the client can display it
|
||||
# even, it is not logged in.
|
||||
context["privacy_policy"] = config["general_event_privacy_policy"]
|
||||
|
@ -72,7 +72,7 @@ class TestUserLoginView(TestCase):
|
||||
response = self.client.get(self.url)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTrue(json.loads(response.content.decode()).get("info_text"))
|
||||
self.assertTrue(json.loads(response.content.decode()).get("login_info_text"))
|
||||
|
||||
def test_post_no_data(self):
|
||||
response = self.client.post(self.url)
|
||||
|
Loading…
Reference in New Issue
Block a user