Merge pull request #3870 from FinnStutzenstein/DS

Don't static-inject the DataStore
This commit is contained in:
Sean 2018-09-13 17:17:26 +02:00 committed by GitHub
commit 68b39ee8f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 43 additions and 174 deletions

View File

@ -1,10 +1,6 @@
import { Component, NgModuleRef } from '@angular/core'; import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { OperatorService } from './core/services/operator.service'; import { OperatorService } from './core/services/operator.service';
import { Subject } from 'rxjs';
import { AppModule } from './app.module';
import { OpenSlidesComponent } from './openslides.component';
import { OpenSlidesService } from './core/services/openslides.service';
import { LoginDataService } from './core/services/login-data.service'; import { LoginDataService } from './core/services/login-data.service';
import { ConfigService } from './core/services/config.service'; import { ConfigService } from './core/services/config.service';
@ -17,20 +13,6 @@ import { ConfigService } from './core/services/config.service';
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss']
}) })
export class AppComponent { export class AppComponent {
/**
* This subject gets called, when the bootstrapping of the hole application is done.
*/
private static bootstrapDoneSubject: Subject<NgModuleRef<AppModule>> = new Subject<NgModuleRef<AppModule>>();
/**
* This function should only be called, when the bootstrapping is done with a reference to
* the bootstrapped module.
* @param moduleRef Reference to the bootstrapped AppModule
*/
public static bootstrapDone(moduleRef: NgModuleRef<AppModule>): void {
AppComponent.bootstrapDoneSubject.next(moduleRef);
}
/** /**
* Initialises the translation unit. * Initialises the translation unit.
* @param autoupdateService * @param autoupdateService
@ -39,10 +21,9 @@ export class AppComponent {
*/ */
public constructor( public constructor(
translate: TranslateService, translate: TranslateService,
private operator: OperatorService, operator: OperatorService,
private OpenSlides: OpenSlidesService, configService: ConfigService,
private configService: ConfigService, loginDataService: LoginDataService
private loginDataService: LoginDataService
) { ) {
// manually add the supported languages // manually add the supported languages
translate.addLangs(['en', 'de', 'fr']); translate.addLangs(['en', 'de', 'fr']);
@ -52,22 +33,5 @@ export class AppComponent {
const browserLang = translate.getBrowserLang(); const browserLang = translate.getBrowserLang();
// try to use the browser language if it is available. If not, uses english. // try to use the browser language if it is available. If not, uses english.
translate.use(translate.getLangs().includes(browserLang) ? browserLang : 'en'); translate.use(translate.getLangs().includes(browserLang) ? browserLang : 'en');
AppComponent.bootstrapDoneSubject.asObservable().subscribe(this.setup.bind(this));
}
/**
* Gets called, when bootstrapping is done. Gets the root injector, sets up the operator and starts OpenSlides.
* @param moduleRef
*/
private setup(moduleRef: NgModuleRef<AppModule>): void {
OpenSlidesComponent.injector = moduleRef.injector;
// Setup the operator after the root injector is known.
this.operator.setupSubscription();
this.configService.setupSubscription();
this.loginDataService.setupSubscription();
this.OpenSlides.bootup(); // Yeah!
} }
} }

View File

@ -4,6 +4,7 @@ import { OpenSlidesComponent } from 'app/openslides.component';
import { WebsocketService } from './websocket.service'; import { WebsocketService } from './websocket.service';
import { CollectionStringModelMapperService } from './collectionStringModelMapper.service'; import { CollectionStringModelMapperService } from './collectionStringModelMapper.service';
import { DataStoreService } from './data-store.service';
/** /**
* Handles the initial update and automatic updates using the {@link WebsocketService} * Handles the initial update and automatic updates using the {@link WebsocketService}
@ -20,7 +21,7 @@ export class AutoupdateService extends OpenSlidesComponent {
* Constructor to create the AutoupdateService. Calls the constructor of the parent class. * Constructor to create the AutoupdateService. Calls the constructor of the parent class.
* @param websocketService * @param websocketService
*/ */
public constructor(websocketService: WebsocketService) { public constructor(websocketService: WebsocketService, private DS: DataStoreService) {
super(); super();
websocketService.getOberservable<any>('autoupdate').subscribe(response => { websocketService.getOberservable<any>('autoupdate').subscribe(response => {
this.storeResponse(response); this.storeResponse(response);

View File

@ -3,6 +3,7 @@ import { Injectable } from '@angular/core';
import { OpenSlidesComponent } from 'app/openslides.component'; import { OpenSlidesComponent } from 'app/openslides.component';
import { Observable, BehaviorSubject } from 'rxjs'; import { Observable, BehaviorSubject } from 'rxjs';
import { Config } from '../../shared/models/core/config'; import { Config } from '../../shared/models/core/config';
import { DataStoreService } from './data-store.service';
/** /**
* Handler for config variables. * Handler for config variables.
@ -31,11 +32,9 @@ export class ConfigService extends OpenSlidesComponent {
/** /**
* Listen for changes of config variables. * Listen for changes of config variables.
*/ */
public constructor() { public constructor(private DS: DataStoreService) {
super(); super();
}
public setupSubscription(): void {
this.DS.changeObservable.subscribe(data => { this.DS.changeObservable.subscribe(data => {
// on changes notify the observers for specific keys. // on changes notify the observers for specific keys.
if (data instanceof Config && this.configSubjects[data.key]) { if (data instanceof Config && this.configSubjects[data.key]) {

View File

@ -43,13 +43,7 @@ export class LoginDataService extends OpenSlidesComponent {
*/ */
public constructor(private configService: ConfigService) { public constructor(private configService: ConfigService) {
super(); super();
}
/**
* Should be called, when the data store is set up. Updates the values when the
* corresponding config variables change.
*/
public setupSubscription(): void {
this.configService.get('general_event_privacy_policy').subscribe(value => { this.configService.get('general_event_privacy_policy').subscribe(value => {
this.setPrivacyPolicy(value); this.setPrivacyPolicy(value);
}); });

View File

@ -6,6 +6,7 @@ import { WebsocketService } from './websocket.service';
import { OperatorService } from './operator.service'; import { OperatorService } from './operator.service';
import { CacheService } from './cache.service'; import { CacheService } from './cache.service';
import { AutoupdateService } from './autoupdate.service'; import { AutoupdateService } from './autoupdate.service';
import { DataStoreService } from './data-store.service';
/** /**
* Handles the bootup/showdown of this application. * Handles the bootup/showdown of this application.
@ -32,7 +33,8 @@ export class OpenSlidesService extends OpenSlidesComponent {
private operator: OperatorService, private operator: OperatorService,
private websocketService: WebsocketService, private websocketService: WebsocketService,
private router: Router, private router: Router,
private autoupdateService: AutoupdateService private autoupdateService: AutoupdateService,
private DS: DataStoreService
) { ) {
super(); super();
@ -41,6 +43,8 @@ export class OpenSlidesService extends OpenSlidesComponent {
websocketService.reconnectEvent.subscribe(() => { websocketService.reconnectEvent.subscribe(() => {
this.checkOperator(); this.checkOperator();
}); });
this.bootup();
} }
/** /**

View File

@ -6,6 +6,7 @@ import { OpenSlidesComponent } from 'app/openslides.component';
import { Group } from 'app/shared/models/users/group'; import { Group } from 'app/shared/models/users/group';
import { User } from '../../shared/models/users/user'; import { User } from '../../shared/models/users/user';
import { environment } from 'environments/environment'; import { environment } from 'environments/environment';
import { DataStoreService } from './data-store.service';
/** /**
* Permissions on the client are just strings. This makes clear, that * Permissions on the client are just strings. This makes clear, that
@ -74,15 +75,9 @@ export class OperatorService extends OpenSlidesComponent {
/** /**
* @param http HttpClient * @param http HttpClient
*/ */
public constructor(private http: HttpClient) { public constructor(private http: HttpClient, private DS: DataStoreService) {
super(); super();
}
/**
* Setup the subscription of the DataStore.Update the user and it's
* permissions if the user or groups changes.
*/
public setupSubscription(): void {
this.DS.changeObservable.subscribe(newModel => { this.DS.changeObservable.subscribe(newModel => {
if (this._user) { if (this._user) {
if (newModel instanceof Group) { if (newModel instanceof Group) {
@ -146,7 +141,7 @@ export class OperatorService extends OpenSlidesComponent {
} }
} else { } else {
const permissionSet = new Set(); const permissionSet = new Set();
this.user.groups.forEach(group => { this.DS.getMany(Group, this.user.groups_id).forEach(group => {
group.permissions.forEach(permission => { group.permissions.forEach(permission => {
permissionSet.add(permission); permissionSet.add(permission);
}); });

View File

@ -1,21 +1,10 @@
import { Injector } from '@angular/core';
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { DataStoreService } from './core/services/data-store.service';
import { CacheService } from './core/services/cache.service';
/** /**
* injects the {@link DataStoreService} to all its children and provides a generic function to catch errors * injects the {@link DataStoreService} to all its children and provides a generic function to catch errors
* should be abstract and a mere parent to all {@link DataStoreService} accessors * should be abstract and a mere parent to all {@link DataStoreService} accessors
*/ */
export abstract class OpenSlidesComponent { export abstract class OpenSlidesComponent {
/**
* The dataStore Service
*/
private static _DS: DataStoreService;
public static injector: Injector;
/** /**
* Empty constructor * Empty constructor
* *
@ -24,31 +13,6 @@ export abstract class OpenSlidesComponent {
*/ */
public constructor() {} public constructor() {}
/**
* getter to access the {@link DataStoreService}
* @example this.DS.get(User)
* @return access to dataStoreService
*/
public get DS(): DataStoreService {
if (!OpenSlidesComponent.injector) {
throw new Error('OpenSlides is not bootstrapping right. This component should have the Injector.');
}
if (OpenSlidesComponent._DS == null) {
const injector = Injector.create({
providers: [
{
provide: DataStoreService,
useClass: DataStoreService,
deps: [CacheService]
}
],
parent: OpenSlidesComponent.injector
});
OpenSlidesComponent._DS = injector.get(DataStoreService);
}
return OpenSlidesComponent._DS;
}
/** /**
* Generic error handling for everything that makes HTTP Calls * Generic error handling for everything that makes HTTP Calls
* TODO: could have more features * TODO: could have more features

View File

@ -1,6 +1,5 @@
import { BaseModel } from '../base.model'; import { BaseModel } from '../base.model';
import { Speaker } from './speaker'; import { Speaker } from './speaker';
import { User } from '../users/user';
interface ContentObject { interface ContentObject {
id: number; id: number;
@ -23,7 +22,7 @@ export class Item extends BaseModel {
public duration: number; public duration: number;
public speakers: Speaker[]; public speakers: Speaker[];
public speaker_list_closed: boolean; public speaker_list_closed: boolean;
private content_object: ContentObject; public content_object: ContentObject;
public weight: number; public weight: number;
public parent_id: number; public parent_id: number;
@ -31,19 +30,6 @@ export class Item extends BaseModel {
super('agenda/item', input); super('agenda/item', input);
} }
public getSpeakers(): User[] {
const speakerIds: number[] = this.speakers
.sort((a: Speaker, b: Speaker) => {
return a.weight - b.weight;
})
.map((speaker: Speaker) => speaker.user_id);
return this.DS.getMany<User>('users/user', speakerIds);
}
public get contentObject(): BaseModel {
return this.DS.get<BaseModel>(this.content_object.collection, this.content_object.id);
}
public deserialize(input: any): void { public deserialize(input: any): void {
Object.assign(this, input); Object.assign(this, input);

View File

@ -1,8 +1,6 @@
import { BaseModel } from '../base.model'; import { BaseModel } from '../base.model';
import { AssignmentUser } from './assignment-user'; import { AssignmentUser } from './assignment-user';
import { Poll } from './poll'; import { Poll } from './poll';
import { Tag } from '../core/tag';
import { User } from '../users/user';
/** /**
* Representation of an assignment. * Representation of an assignment.
@ -24,16 +22,12 @@ export class Assignment extends BaseModel {
super('assignments/assignment', input); super('assignments/assignment', input);
} }
public getAssignmentReleatedUsers(): BaseModel | BaseModel[] { public get candidateIds(): number[] {
const userIds = []; return this.assignment_related_users
this.assignment_related_users.forEach(user => { .sort((a: AssignmentUser, b: AssignmentUser) => {
userIds.push(user.user_id); return a.weight - b.weight;
}); })
return this.DS.getMany<User>('users/user', userIds); .map((candidate: AssignmentUser) => candidate.user_id);
}
public getTags(): BaseModel | BaseModel[] {
return this.DS.getMany<Tag>('core/tag', this.tags_id);
} }
public deserialize(input: any): void { public deserialize(input: any): void {

View File

@ -1,5 +1,4 @@
import { BaseModel } from '../base.model'; import { BaseModel } from '../base.model';
import { User } from '../users/user';
/** /**
* Representation of chat messages. * Representation of chat messages.
@ -15,10 +14,6 @@ export class ChatMessage extends BaseModel {
super('core/chat-message', input); super('core/chat-message', input);
} }
public getUser(): User {
return this.DS.get<User>('users/user', this.user_id);
}
public toString(): string { public toString(): string {
return this.message; return this.message;
} }

View File

@ -1,6 +1,5 @@
import { BaseModel } from '../base.model'; import { BaseModel } from '../base.model';
import { File } from './file'; import { File } from './file';
import { User } from '../users/user';
/** /**
* Representation of MediaFile. Has the nested property "File" * Representation of MediaFile. Has the nested property "File"
@ -25,10 +24,6 @@ export class Mediafile extends BaseModel {
this.mediafile = new File(input.mediafile); this.mediafile = new File(input.mediafile);
} }
public getUploader(): User {
return this.DS.get<User>('users/user', this.uploader_id);
}
public toString(): string { public toString(): string {
return this.title; return this.title;
} }

View File

@ -14,10 +14,6 @@ export class MotionBlock extends BaseModel {
super('motions/motion-block', input); super('motions/motion-block', input);
} }
public getAgenda(): BaseModel | BaseModel[] {
return this.DS.get<Item>('agenda/item', this.agenda_item_id);
}
public toString(): string { public toString(): string {
return this.title; return this.title;
} }

View File

@ -1,6 +1,4 @@
import { BaseModel } from '../base.model'; import { BaseModel } from '../base.model';
import { Mediafile } from '../mediafiles/mediafile';
import { Item } from '../agenda/item';
/** /**
* Representation of a topic. * Representation of a topic.
@ -17,14 +15,6 @@ export class Topic extends BaseModel {
super('topics/topic', input); super('topics/topic', input);
} }
public getAttachments(): Mediafile[] {
return this.DS.getMany<Mediafile>('mediafiles/mediafile', this.attachments_id);
}
public getAgenda(): Item {
return this.DS.get<Item>('agenda/item', this.agenda_item_id);
}
public toString(): string { public toString(): string {
return this.title; return this.title;
} }

View File

@ -1,5 +1,4 @@
import { BaseModel } from '../base.model'; import { BaseModel } from '../base.model';
import { User } from './user';
/** /**
* Representation of user group. * Representation of user group.
@ -14,13 +13,6 @@ export class Group extends BaseModel {
super('users/group', input); super('users/group', input);
} }
public get users(): User[] {
// We have to use the string version to avoid circular dependencies.
return this.DS.filter<User>('users/user', user => {
return user.groups_id.includes(this.id);
});
}
public toString(): string { public toString(): string {
return this.name; return this.name;
} }

View File

@ -14,10 +14,6 @@ export class PersonalNote extends BaseModel {
super('users/personal-note', input); super('users/personal-note', input);
} }
public getUser(): User {
return this.DS.get<User>('users/user', this.user_id);
}
public toString(): string { public toString(): string {
return this.notes.toString(); return this.notes.toString();
} }

View File

@ -1,5 +1,4 @@
import { BaseModel } from '../base.model'; import { BaseModel } from '../base.model';
import { Group } from './group';
/** /**
* Representation of a user in contrast to the operator. * Representation of a user in contrast to the operator.
@ -27,10 +26,6 @@ export class User extends BaseModel {
super('users/user', input); super('users/user', input);
} }
public get groups(): Group[] {
return this.DS.getMany(Group, this.groups_id);
}
public get full_name(): string { public get full_name(): string {
let name = this.short_name; let name = this.short_name;
const addition: string[] = []; const addition: string[] = [];

View File

@ -3,6 +3,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
import { BaseViewModel } from './base-view-model'; import { BaseViewModel } from './base-view-model';
import { BaseModel, ModelConstructor } from '../shared/models/base.model'; import { BaseModel, ModelConstructor } from '../shared/models/base.model';
import { CollectionStringModelMapperService } from '../core/services/collectionStringModelMapper.service'; import { CollectionStringModelMapperService } from '../core/services/collectionStringModelMapper.service';
import { DataStoreService } from '../core/services/data-store.service';
export abstract class BaseRepository<V extends BaseViewModel, M extends BaseModel> extends OpenSlidesComponent { export abstract class BaseRepository<V extends BaseViewModel, M extends BaseModel> extends OpenSlidesComponent {
/** /**
@ -27,6 +28,7 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
* If one of those changes, the view models will be updated. * If one of those changes, the view models will be updated.
*/ */
public constructor( public constructor(
protected DS: DataStoreService,
protected baseModelCtor: ModelConstructor<M>, protected baseModelCtor: ModelConstructor<M>,
protected depsModelCtors: ModelConstructor<BaseModel>[] protected depsModelCtors: ModelConstructor<BaseModel>[]
) { ) {

View File

@ -6,6 +6,7 @@ import { TranslateService } from '@ngx-translate/core';
import { BaseComponent } from '../../../../base.component'; import { BaseComponent } from '../../../../base.component';
import { Category } from '../../../../shared/models/motions/category'; import { Category } from '../../../../shared/models/motions/category';
import { DataStoreService } from '../../../../core/services/data-store.service';
/** /**
* List view for the categories. * List view for the categories.
@ -31,19 +32,25 @@ export class CategoryListComponent extends BaseComponent implements OnInit {
/** /**
* The table itself. * The table itself.
*/ */
@ViewChild(MatTable) public table: MatTable<Category>; @ViewChild(MatTable)
public table: MatTable<Category>;
/** /**
* Sort the Table * Sort the Table
*/ */
@ViewChild(MatSort) public sort: MatSort; @ViewChild(MatSort)
public sort: MatSort;
/** /**
* The usual component constructor * The usual component constructor
* @param titleService * @param titleService
* @param translate * @param translate
*/ */
public constructor(protected titleService: Title, protected translate: TranslateService) { public constructor(
protected titleService: Title,
protected translate: TranslateService,
protected DS: DataStoreService
) {
super(titleService, translate); super(titleService, translate);
} }

View File

@ -9,6 +9,7 @@ import { ViewportService } from '../../../../core/services/viewport.service';
import { MotionRepositoryService } from '../../services/motion-repository.service'; import { MotionRepositoryService } from '../../services/motion-repository.service';
import { ViewMotion } from '../../models/view-motion'; import { ViewMotion } from '../../models/view-motion';
import { User } from '../../../../shared/models/users/user'; import { User } from '../../../../shared/models/users/user';
import { DataStoreService } from '../../../../core/services/data-store.service';
/** /**
* Component for the motion detail view * Component for the motion detail view
@ -77,7 +78,8 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
private router: Router, private router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private repo: MotionRepositoryService private repo: MotionRepositoryService,
private DS: DataStoreService
) { ) {
super(); super();
this.createForm(); this.createForm();

View File

@ -9,6 +9,7 @@ import { WorkflowState } from '../../../shared/models/motions/workflow-state';
import { ViewMotion } from '../models/view-motion'; import { ViewMotion } from '../models/view-motion';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { BaseRepository } from '../../base-repository'; import { BaseRepository } from '../../base-repository';
import { DataStoreService } from '../../../core/services/data-store.service';
/** /**
* Repository Services for motions (and potentially categories) * Repository Services for motions (and potentially categories)
@ -31,8 +32,8 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
* Handles CRUD using an observer to the DataStore * Handles CRUD using an observer to the DataStore
* @param DataSend * @param DataSend
*/ */
public constructor(private dataSend: DataSendService) { public constructor(DS: DataStoreService, private dataSend: DataSendService) {
super(Motion, [Category, User, Workflow]); super(DS, Motion, [Category, User, Workflow]);
} }
/** /**

View File

@ -9,6 +9,7 @@ import { User } from 'app/shared/models/users/user';
import { Config } from '../../shared/models/core/config'; import { Config } from '../../shared/models/core/config';
import { Motion } from '../../shared/models/motions/motion'; import { Motion } from '../../shared/models/motions/motion';
import { MotionSubmitter } from '../../shared/models/motions/motion-submitter'; import { MotionSubmitter } from '../../shared/models/motions/motion-submitter';
import { DataStoreService } from '../../core/services/data-store.service';
@Component({ @Component({
selector: 'os-start', selector: 'os-start',
@ -25,7 +26,7 @@ export class StartComponent extends BaseComponent implements OnInit {
* @param titleService the title serve * @param titleService the title serve
* @param translate to translation module * @param translate to translation module
*/ */
public constructor(titleService: Title, protected translate: TranslateService) { public constructor(titleService: Title, protected translate: TranslateService, private DS: DataStoreService) {
super(titleService, translate); super(titleService, translate);
} }

View File

@ -3,7 +3,6 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module'; import { AppModule } from './app/app.module';
import { environment } from './environments/environment'; import { environment } from './environments/environment';
import { AppComponent } from 'app/app.component';
if (environment.production) { if (environment.production) {
enableProdMode(); enableProdMode();
@ -11,7 +10,4 @@ if (environment.production) {
platformBrowserDynamic() platformBrowserDynamic()
.bootstrapModule(AppModule) .bootstrapModule(AppModule)
.then((moduleRef: NgModuleRef<AppModule>) => {
AppComponent.bootstrapDone(moduleRef);
})
.catch(err => console.log(err)); .catch(err => console.log(err));