Changes the storage engine from window storage to the indexeddb storage

parent fc3e41cc
Pipeline #16929 failed with stage
in 39 seconds
......@@ -3008,6 +3008,12 @@
"qrcode": "^0.8.2"
}
},
"@types/intro.js": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/@types/intro.js/-/intro.js-2.4.3.tgz",
"integrity": "sha512-PLjhcHEPDzpfNRMX0JlpCatAnck30UH7Q4q8yaCglS6t62vHGLpQlXCuLak2jew6BEVPOxqn24g+qABxDi1mLQ==",
"dev": true
},
"@types/jasmine": {
"version": "2.8.7",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.7.tgz",
......
......@@ -28,7 +28,7 @@ const JOBS_FOLDER = path.join(DIST_FOLDER, 'browser', 'assets', 'jobs');
const corsOptions = require('./cors.config.ts');
const cache = { 'arsnova-click-v2-frontend': {} };
const availableLangs = ['en', 'de', 'fr', 'es', 'it'];
const availableLangs = ['en', 'DE', 'FR', 'ES', 'it'];
const projectGitLocation = {
'arsnova-click-v2-frontend': path.join(DIST_FOLDER, 'browser'),
};
......
......@@ -16,7 +16,7 @@
top: 0;
color: #fff;
font-size: 3rem;
z-index: 1050;
z-index: 1040;
}
#footer-move-left {
......
......@@ -21,6 +21,7 @@ import { TrackingMockService } from '../../service/tracking/tracking.mock.servic
import { TrackingService } from '../../service/tracking/tracking.service';
import { WebsocketMockService } from '../../service/websocket/websocket.mock.service';
import { WebsocketService } from '../../service/websocket/websocket.service';
import { SharedModule } from '../../shared/shared.module';
import { FooterBarComponent } from './footer-bar.component';
......@@ -31,14 +32,12 @@ describe('FooterBarComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
HttpClientModule,
HttpClientTestingModule,
NgbModule.forRoot(),
TranslateModule.forRoot({
SharedModule, RouterTestingModule, HttpClientModule, HttpClientTestingModule, NgbModule.forRoot(), TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
useFactory: (
createTranslateLoader
),
deps: [HttpClient],
},
compiler: {
......@@ -48,15 +47,22 @@ describe('FooterBarComponent', () => {
}),
],
providers: [
FooterBarService,
SharedService,
{ provide: CurrentQuizService, useClass: CurrentQuizMockService },
SettingsService,
{ provide: ConnectionService, useClass: ConnectionMockService },
{ provide: WebsocketService, useClass: WebsocketMockService },
{ provide: TrackingService, useClass: TrackingMockService },
FileUploadService,
{ provide: ActiveQuestionGroupService, useClass: ActiveQuestionGroupMockService },
FooterBarService, SharedService, {
provide: CurrentQuizService,
useClass: CurrentQuizMockService,
}, SettingsService, {
provide: ConnectionService,
useClass: ConnectionMockService,
}, {
provide: WebsocketService,
useClass: WebsocketMockService,
}, {
provide: TrackingService,
useClass: TrackingMockService,
}, FileUploadService, {
provide: ActiveQuestionGroupService,
useClass: ActiveQuestionGroupMockService,
},
],
declarations: [
FooterBarComponent,
......@@ -78,30 +84,33 @@ describe('FooterBarComponent', () => {
expect(FooterBarComponent.TYPE).toEqual('FooterBarComponent');
}));
it('#getLinkTarget', (inject([FooterBarService],
(footerBarService: FooterBarService) => {
it('#getLinkTarget', (
inject([FooterBarService], (footerBarService: FooterBarService) => {
expect(component.getLinkTarget(footerBarService.footerElemAbout)).toEqual(jasmine.arrayContaining(['info', 'about']));
})));
})
));
it('#toggleSetting', (inject([FooterBarService, TrackingService],
(footerBarService: FooterBarService, trackingService: TrackingService) => {
it('#toggleSetting', (
inject([FooterBarService, TrackingService], (footerBarService: FooterBarService, trackingService: TrackingService) => {
const elem = footerBarService.footerElemAbout;
spyOn(elem, 'onClickCallback').and.callFake(() => {});
spyOn(trackingService, 'trackClickEvent').and.callFake(() => {});
component.toggleSetting(elem);
expect(elem.onClickCallback).toHaveBeenCalled();
expect(trackingService.trackClickEvent).toHaveBeenCalled();
})));
})
));
it('#fileChange', (inject([FileUploadService],
(fileUploadService: FileUploadService) => {
it('#fileChange', (
inject([FileUploadService], (fileUploadService: FileUploadService) => {
spyOn(fileUploadService, 'uploadFile').and.callFake(() => {});
component.fileChange({ target: { files: [{ name: 'testFile' }] } });
expect(fileUploadService.uploadFile).toHaveBeenCalled();
})));
})
));
it('#moveLeft', (inject([FooterBarService],
(footerBarService: FooterBarService) => {
it('#moveLeft', (
inject([FooterBarService], (footerBarService: FooterBarService) => {
component.footerElements = [
...Object.keys(footerBarService).map(t => footerBarService[t] instanceof FooterbarElement ? footerBarService[t] : false),
];
......@@ -110,10 +119,11 @@ describe('FooterBarComponent', () => {
expect(component.footerElemIndex).toEqual(1);
component.moveLeft();
expect(component.footerElemIndex).toEqual(1);
})));
})
));
it('#moveRight', (inject([FooterBarService],
(footerBarService: FooterBarService) => {
it('#moveRight', (
inject([FooterBarService], (footerBarService: FooterBarService) => {
component.footerElements = [
...Object.keys(footerBarService).map(t => footerBarService[t] instanceof FooterbarElement ? footerBarService[t] : false),
];
......@@ -124,5 +134,6 @@ describe('FooterBarComponent', () => {
component.moveRight();
}
expect(component.footerElemIndex).toEqual(component.footerElements.length - 1);
})));
})
));
});
......@@ -77,7 +77,7 @@
</div>
<div class="col-12 col-sm-6"
*ngIf="!!selectedKey">
<div *ngFor="let langKey of getKeys(languageLoaderService.languages)">
<div *ngFor="let langKey of getKeys(languageLoaderService.LANGUAGE)">
<p class="mb-0">{{langKey.toUpperCase()}}</p>
<textarea class="w-100 key-textarea"
(keyup)="updateKey($event, langKey, selectedKey)"
......
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbModalModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateCompiler, TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler';
import { createTranslateLoader } from '../../../lib/translation.factory';
import { PipesModule } from '../../pipes/pipes.module';
import { FooterBarService } from '../../service/footer-bar/footer-bar.service';
import { HeaderLabelService } from '../../service/header-label/header-label.service';
import { CasLoginService } from '../../service/login/cas-login.service';
import { ModalOrganizerService } from '../../service/modal-organizer/modal-organizer.service';
import { UserService } from '../../service/user/user.service';
import { SharedModule } from '../../shared/shared.module';
import { KeyOutputComponent } from '../key-output/key-output.component';
import { I18nManagerOverviewComponent } from './i18n-manager-overview.component';
......@@ -8,7 +22,25 @@ describe('I18nManagerOverviewComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [I18nManagerOverviewComponent],
imports: [
NgbModalModule.forRoot(), SharedModule, PipesModule, RouterTestingModule, HttpClientModule, TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (
createTranslateLoader
),
deps: [HttpClient],
},
compiler: {
provide: TranslateCompiler,
useClass: TranslateMessageFormatCompiler,
},
}),
],
providers: [
UserService, CasLoginService, FooterBarService, HeaderLabelService, ModalOrganizerService,
],
declarations: [KeyOutputComponent, I18nManagerOverviewComponent],
})
.compileComponents();
}));
......
import { Component, OnDestroy, OnInit } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { Component, Inject, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core';
import { Observable, of } from 'rxjs/index';
import { FooterBarService } from '../../service/footer-bar/footer-bar.service';
import { HeaderLabelService } from '../../service/header-label/header-label.service';
......@@ -18,7 +19,7 @@ export class I18nManagerOverviewComponent implements OnInit, OnDestroy {
public static readonly TYPE = 'I18nManagerOverviewComponent';
public readonly filters = FILTER;
private _langRef = ['en', 'de', 'fr', 'it', 'es'];
private _langRef = ['en', 'DE', 'FR', 'it', 'ES'];
get langRef(): Array<string> {
return this._langRef;
......@@ -95,6 +96,7 @@ export class I18nManagerOverviewComponent implements OnInit, OnDestroy {
}
constructor(
@Inject(PLATFORM_ID) private platformId: Object,
private footerBarService: FooterBarService,
private headerLabelService: HeaderLabelService,
public modalOrganizerService: ModalOrganizerService,
......@@ -109,13 +111,26 @@ export class I18nManagerOverviewComponent implements OnInit, OnDestroy {
public ngOnInit(): void {
this.setProject(PROJECT.FRONTEND);
document.getElementById('content-container').classList.remove('container');
document.getElementById('content-container').classList.add('container-fluid');
if (isPlatformBrowser(this.platformId)) {
const contentContainer = document.getElementById('content-container');
if (contentContainer) {
contentContainer.classList.remove('container');
contentContainer.classList.add('container-fluid');
}
}
}
public ngOnDestroy(): void {
document.getElementById('content-container').classList.add('container');
document.getElementById('content-container').classList.remove('container-fluid');
if (isPlatformBrowser(this.platformId)) {
const contentContainer = document.getElementById('content-container');
if (contentContainer) {
contentContainer.classList.add('container');
contentContainer.classList.remove('container-fluid');
}
}
}
public updateData(): void {
......
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { PipesModule } from '../../pipes/pipes.module';
import { SharedModule } from '../../shared/shared.module';
import { KeyOutputComponent } from './key-output.component';
......@@ -8,6 +10,7 @@ describe('KeyOutputComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [SharedModule, PipesModule],
declarations: [KeyOutputComponent],
})
.compileComponents();
......
......@@ -56,7 +56,7 @@ export class KeyOutputComponent {
}
public hasEmptyKeys(elem): boolean {
return this.getKeys(elem.value).length < this.getKeys(this.languageLoaderService.languages).length;
return this.getKeys(elem.value).length < this.getKeys(this.languageLoaderService.LANGUAGE).length;
}
public removeKey(target: any): void {
......
......@@ -16,7 +16,7 @@
(keyup)="key = $event.target.value"
placeholder="Enter the Key here"/>
<div *ngFor="let langKey of getKeys(languageLoaderService.languages)">
<div *ngFor="let langKey of getKeys(languageLoaderService.LANGUAGE)">
<p class="mb-0">{{langKey.toUpperCase()}}</p>
<textarea class="w-100 key-textarea"
(keyup)="updateKey($event, langKey)"></textarea>
......
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NgbActiveModal, NgbModalModule } from '@ng-bootstrap/ng-bootstrap';
import { SharedModule } from '../../shared/shared.module';
import { AddModeComponent } from './add-mode.component';
......@@ -8,6 +10,12 @@ describe('AddModeComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
SharedModule, NgbModalModule.forRoot(),
],
providers: [
NgbActiveModal,
],
declarations: [AddModeComponent],
})
.compileComponents();
......
......@@ -24,6 +24,7 @@ import { TrackingMockService } from '../../service/tracking/tracking.mock.servic
import { TrackingService } from '../../service/tracking/tracking.service';
import { WebsocketMockService } from '../../service/websocket/websocket.mock.service';
import { WebsocketService } from '../../service/websocket/websocket.service';
import { SharedModule } from '../../shared/shared.module';
import { AvailableQuizzesComponent } from './available-quizzes.component';
......@@ -34,14 +35,12 @@ describe('AvailableQuizzesComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
HttpClientModule,
HttpClientTestingModule,
NgbModule.forRoot(),
TranslateModule.forRoot({
SharedModule, RouterTestingModule, HttpClientModule, HttpClientTestingModule, NgbModule.forRoot(), TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
useFactory: (
createTranslateLoader
),
deps: [HttpClient],
},
compiler: {
......@@ -51,18 +50,25 @@ describe('AvailableQuizzesComponent', () => {
}),
],
providers: [
NgbActiveModal,
LobbyApiService,
QuizApiService,
{ provide: TrackingService, useClass: TrackingMockService },
{ provide: CurrentQuizService, useClass: CurrentQuizMockService },
FooterBarService,
SettingsService,
{ provide: ConnectionService, useClass: ConnectionMockService },
{ provide: WebsocketService, useClass: WebsocketMockService },
SharedService,
{ provide: ActiveQuestionGroupService, useClass: ActiveQuestionGroupMockService },
{ provide: FileUploadService, useClass: FileUploadMockService },
NgbActiveModal, LobbyApiService, QuizApiService, {
provide: TrackingService,
useClass: TrackingMockService,
}, {
provide: CurrentQuizService,
useClass: CurrentQuizMockService,
}, FooterBarService, SettingsService, {
provide: ConnectionService,
useClass: ConnectionMockService,
}, {
provide: WebsocketService,
useClass: WebsocketMockService,
}, SharedService, {
provide: ActiveQuestionGroupService,
useClass: ActiveQuestionGroupMockService,
}, {
provide: FileUploadService,
useClass: FileUploadMockService,
},
],
declarations: [AvailableQuizzesComponent],
}).compileComponents();
......@@ -112,10 +118,8 @@ describe('AvailableQuizzesComponent', () => {
expect(activeModal.close).toHaveBeenCalled();
})));
it('#startQuiz', (inject(
[CurrentQuizService, TrackingService],
(currentQuizService: CurrentQuizService, trackingService: TrackingService,
) => {
it('#startQuiz', (
inject([CurrentQuizService, TrackingService], (currentQuizService: CurrentQuizService, trackingService: TrackingService) => {
const quiz = currentQuizService.quiz;
spyOn(trackingService, 'trackClickEvent').and.callFake(() => {});
......@@ -123,11 +127,11 @@ describe('AvailableQuizzesComponent', () => {
component.startQuiz(quiz);
expect(trackingService.trackClickEvent).toHaveBeenCalled();
})));
})
));
it('#editQuiz', (inject(
[CurrentQuizService, TrackingService, ActiveQuestionGroupService, Router],
(
it('#editQuiz', (
inject([CurrentQuizService, TrackingService, ActiveQuestionGroupService, Router], (
currentQuizService: CurrentQuizService,
trackingService: TrackingService,
activeQuestionGroupService: ActiveQuestionGroupService,
......@@ -145,5 +149,6 @@ describe('AvailableQuizzesComponent', () => {
expect(activeQuestionGroupService.activeQuestionGroup).toEqual(quiz);
expect(router.navigate).toHaveBeenCalled();
expect(component.next).toHaveBeenCalled();
})));
})
));
});
......@@ -9,7 +9,9 @@ import { LobbyApiService } from '../../service/api/lobby/lobby-api.service';
import { QuizApiService } from '../../service/api/quiz/quiz-api.service';
import { CurrentQuizService } from '../../service/current-quiz/current-quiz.service';
import { FileUploadService } from '../../service/file-upload/file-upload.service';
import { StorageService } from '../../service/storage/storage.service';
import { TrackingService } from '../../service/tracking/tracking.service';
import { DB_TABLE, STORAGE_KEY } from '../../shared/enums';
@Component({
selector: 'app-available-quizzes',
......@@ -35,14 +37,9 @@ export class AvailableQuizzesComponent implements IModal {
private fileUploadService: FileUploadService,
private quizApiService: QuizApiService,
private lobbyApiService: LobbyApiService,
private storageService: StorageService,
) {
const sessions = JSON.parse(window.localStorage.getItem('config.owned_quizzes')) || [];
sessions.sort((a, b) => a > b);
const self = this;
sessions.forEach((elem) => {
elem = JSON.parse(window.localStorage.getItem(elem));
self.sessions.push(questionGroupReflection[elem.TYPE](elem));
});
this.loadData();
}
public dismiss(): void {
......@@ -59,7 +56,10 @@ export class AvailableQuizzesComponent implements IModal {
public async startQuiz(session: IQuestionGroup): Promise<any> {
return new Promise(async resolve => {
this.trackingService.trackClickEvent({ action: AvailableQuizzesComponent.TYPE, label: 'start-quiz' });
this.trackingService.trackClickEvent({
action: AvailableQuizzesComponent.TYPE,
label: 'start-quiz',
});
const quizStatusData = await this.quizApiService.getQuizStatus(session.hashtag).toPromise();
if (quizStatusData.status !== 'STATUS:SUCCESSFUL') {
......@@ -67,9 +67,9 @@ export class AvailableQuizzesComponent implements IModal {
return;
}
if (quizStatusData.step === 'QUIZ:UNDEFINED') {
const quizReservationOverrideResult = await this.quizApiService.postQuizReservationOverride({
await this.quizApiService.postQuizReservationOverride({
quizName: session.hashtag,
privateKey: window.localStorage.getItem('config.private_key'),
privateKey: await this.storageService.read(DB_TABLE.CONFIG, STORAGE_KEY.PRIVATE_KEY).toPromise(),
}).toPromise();
} else if (quizStatusData.step === 'QUIZ:AVAILABLE') {
......@@ -108,11 +108,25 @@ export class AvailableQuizzesComponent implements IModal {
}
public editQuiz(session: IQuestionGroup): void {
this.trackingService.trackClickEvent({ action: AvailableQuizzesComponent.TYPE, label: 'edit-quiz' });
this.trackingService.trackClickEvent({
action: AvailableQuizzesComponent.TYPE,
label: 'edit-quiz',
});
this.activeQuestionGroupService.activeQuestionGroup = session;
this.router.navigate(['/quiz', 'manager']);
this.next();
}
private async loadData(): Promise<void> {
const sessions = await this.storageService.getAllQuiznames();
sessions.sort((a: string, b: string) => 0 - (
a > b ? 1 : -1
));
sessions.forEach(async (elem) => {
const quizData = await this.storageService.read(DB_TABLE.QUIZ, elem).toPromise();
this.sessions.push(questionGroupReflection[quizData.TYPE](quizData));
});
}
}
......@@ -18,13 +18,13 @@ export class FilterKeysPipe implements PipeTransform {
case FILTER.INVALID_KEYS:
return value.filter(elem => this.hasEmptyKeys(elem));
case FILTER.INVALID_DE:
return value.filter(elem => this.hasEmptyKeysForLang(elem, 'de'));
return value.filter(elem => this.hasEmptyKeysForLang(elem, 'DE'));
case FILTER.INVALID_EN:
return value.filter(elem => this.hasEmptyKeysForLang(elem, 'en'));
case FILTER.INVALID_ES:
return value.filter(elem => this.hasEmptyKeysForLang(elem, 'es'));
return value.filter(elem => this.hasEmptyKeysForLang(elem, 'ES'));
case FILTER.INVALID_FR:
return value.filter(elem => this.hasEmptyKeysForLang(elem, 'fr'));
return value.filter(elem => this.hasEmptyKeysForLang(elem, 'FR'));
case FILTER.INVALID_IT:
return value.filter(elem => this.hasEmptyKeysForLang(elem, 'it'));
}
......@@ -38,7 +38,7 @@ export class FilterKeysPipe implements PipeTransform {
}
private hasEmptyKeys(elem): boolean {
return this.getKeys(elem.value).length < this.getKeys(this.languageLoaderService.languages).length;
return this.getKeys(elem.value).length < this.getKeys(this.languageLoaderService.LANGUAGE).length;
}
private hasEmptyKeysForLang(elem, lang): boolean {
......
......@@ -17,6 +17,7 @@ import { SettingsService } from '../../../service/settings/settings.service';
import { SharedService } from '../../../service/shared/shared.service';
import { WebsocketMockService } from '../../../service/websocket/websocket.mock.service';
import { WebsocketService } from '../../../service/websocket/websocket.service';
import { SharedModule } from '../../../shared/shared.module';
import { ConfidenceRateComponent } from './confidence-rate.component';
describe('QuizFlow: ConfidenceRateComponent', () => {
......@@ -26,12 +27,12 @@ describe('QuizFlow: ConfidenceRateComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
HttpClientModule,
TranslateModule.forRoot({
SharedModule, RouterTestingModule, HttpClientModule, TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
useFactory: (
createTranslateLoader
),
deps: [HttpClient],
},
compiler: {
......@@ -41,15 +42,19 @@ describe('QuizFlow: ConfidenceRateComponent', () => {
}),
],
providers: [
{ provide: ConnectionService, useClass: ConnectionMockService },
{ provide: AttendeeService, useClass: AttendeeMockService },
{ provide: CurrentQuizService, useClass: CurrentQuizMockService },
HeaderLabelService,
FooterBarService,
{ provide: WebsocketService, useClass: WebsocketMockService },
SharedService,
SettingsService,
MemberApiService,
{
provide: ConnectionService,
useClass: ConnectionMockService,
}, {
provide: AttendeeService,
useClass: AttendeeMockService,
}, {
provide: CurrentQuizService,
useClass: CurrentQuizMockService,
}, HeaderLabelService, FooterBarService, {
provide: WebsocketService,
useClass: WebsocketMockService,
}, SharedService, SettingsService, MemberApiService,
],
declarations: [ConfidenceRateComponent],
}).compileComponents();
......@@ -75,7 +80,9 @@ describe('QuizFlow: ConfidenceRateComponent', () => {
it('#updateConficence', async(() => {
const event = new Event('testEvent');
spyOnProperty(event, 'target').and.callFake(() => ({ value: '20' }));
spyOnProperty(event, 'target').and.callFake(() => (
{ value: '20' }
));
component.updateConficence(event);
......@@ -83,12 +90,11 @@ describe('QuizFlow: ConfidenceRateComponent', () => {
}));
it('#sendConfidence', async(() => {
spyOn(component, 'sendConfidence').and.callFake(() => {});
spyOn(component, 'sendConfidence').and.callFake(() => {});
component.sendConfidence();
component.sendConfidence();
expect(component.sendConfidence).not.toThrowError();
}),
);
expect(component.sendConfidence).not.toThrowError();
}));
});
......@@ -8,6 +8,8 @@ import { ConnectionService } from '../../../service/connection/connection.servic
import { CurrentQuizService } from '../../../service/current-quiz/current-quiz.service';
import { FooterBarService } from '../../../service/footer-bar/footer-bar.service';
import { HeaderLabelService } from '../../../service/header-label/header-label.service';
import { StorageService } from '../../../service/storage/storage.service';
import { DB_TABLE, STORAGE_KEY } from '../../../shared/enums';
@Component({
selector: 'app-confidence-rate',
......@@ -32,6 +34,7 @@ export class ConfidenceRateComponent implements OnInit {