Removed root injector

This commit is contained in:
FinnStutzenstein 2018-09-13 14:40:04 +02:00
parent 2269ddef91
commit 1b691f5eb6
22 changed files with 46 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 { 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 { ConfigService } from './core/services/config.service';
@ -17,20 +13,6 @@ import { ConfigService } from './core/services/config.service';
styleUrls: ['./app.component.scss']
})
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.
* @param autoupdateService
@ -39,11 +21,11 @@ export class AppComponent {
*/
public constructor(
translate: TranslateService,
private operator: OperatorService,
private OpenSlides: OpenSlidesService,
private configService: ConfigService,
private loginDataService: LoginDataService
operator: OperatorService,
configService: ConfigService,
loginDataService: LoginDataService
) {
console.log('app ctor');
// manually add the supported languages
translate.addLangs(['en', 'de', 'fr']);
// this language will be used as a fallback when a translation isn't found in the current language
@ -52,22 +34,5 @@ export class AppComponent {
const browserLang = translate.getBrowserLang();
// try to use the browser language if it is available. If not, uses english.
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 { CollectionStringModelMapperService } from './collectionStringModelMapper.service';
import { DataStoreService } from './data-store.service';
/**
* 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.
* @param websocketService
*/
public constructor(websocketService: WebsocketService) {
public constructor(websocketService: WebsocketService, private DS: DataStoreService) {
super();
websocketService.getOberservable<any>('autoupdate').subscribe(response => {
this.storeResponse(response);

View File

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

View File

@ -43,13 +43,7 @@ export class LoginDataService extends OpenSlidesComponent {
*/
public constructor(private configService: ConfigService) {
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.setPrivacyPolicy(value);
});

View File

@ -6,6 +6,7 @@ import { WebsocketService } from './websocket.service';
import { OperatorService } from './operator.service';
import { CacheService } from './cache.service';
import { AutoupdateService } from './autoupdate.service';
import { DataStoreService } from './data-store.service';
/**
* Handles the bootup/showdown of this application.
@ -32,15 +33,20 @@ export class OpenSlidesService extends OpenSlidesComponent {
private operator: OperatorService,
private websocketService: WebsocketService,
private router: Router,
private autoupdateService: AutoupdateService
private autoupdateService: AutoupdateService,
private DS: DataStoreService
) {
super();
console.log('OS ctor');
// Handler that gets called, if the websocket connection reconnects after a disconnection.
// There might have changed something on the server, so we check the operator, if he changed.
websocketService.reconnectEvent.subscribe(() => {
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 { User } from '../../shared/models/users/user';
import { environment } from 'environments/environment';
import { DataStoreService } from './data-store.service';
/**
* Permissions on the client are just strings. This makes clear, that
@ -74,15 +75,9 @@ export class OperatorService extends OpenSlidesComponent {
/**
* @param http HttpClient
*/
public constructor(private http: HttpClient) {
public constructor(private http: HttpClient, private DS: DataStoreService) {
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 => {
if (this._user) {
if (newModel instanceof Group) {
@ -146,7 +141,7 @@ export class OperatorService extends OpenSlidesComponent {
}
} else {
const permissionSet = new Set();
this.user.groups.forEach(group => {
this.DS.getMany(Group, this.user.groups_id).forEach(group => {
group.permissions.forEach(permission => {
permissionSet.add(permission);
});

View File

@ -1,21 +1,10 @@
import { Injector } from '@angular/core';
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
* should be abstract and a mere parent to all {@link DataStoreService} accessors
*/
export abstract class OpenSlidesComponent {
/**
* The dataStore Service
*/
private static _DS: DataStoreService;
public static injector: Injector;
/**
* Empty constructor
*
@ -24,31 +13,6 @@ export abstract class OpenSlidesComponent {
*/
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
* TODO: could have more features

View File

@ -1,6 +1,5 @@
import { BaseModel } from '../base.model';
import { Speaker } from './speaker';
import { User } from '../users/user';
interface ContentObject {
id: number;
@ -23,7 +22,7 @@ export class Item extends BaseModel {
public duration: number;
public speakers: Speaker[];
public speaker_list_closed: boolean;
private content_object: ContentObject;
public content_object: ContentObject;
public weight: number;
public parent_id: number;
@ -31,19 +30,6 @@ export class Item extends BaseModel {
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 {
Object.assign(this, input);

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,4 @@
import { BaseModel } from '../base.model';
import { Mediafile } from '../mediafiles/mediafile';
import { Item } from '../agenda/item';
/**
* Representation of a topic.
@ -17,14 +15,6 @@ export class Topic extends BaseModel {
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 {
return this.title;
}

View File

@ -1,5 +1,4 @@
import { BaseModel } from '../base.model';
import { User } from './user';
/**
* Representation of user group.
@ -14,13 +13,6 @@ export class Group extends BaseModel {
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 {
return this.name;
}

View File

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

View File

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

View File

@ -3,6 +3,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
import { BaseViewModel } from './base-view-model';
import { BaseModel, ModelConstructor } from '../shared/models/base.model';
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 {
/**
@ -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.
*/
public constructor(
protected DS: DataStoreService,
protected baseModelCtor: ModelConstructor<M>,
protected depsModelCtors: ModelConstructor<BaseModel>[]
) {

View File

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

View File

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

View File

@ -9,6 +9,7 @@ import { WorkflowState } from '../../../shared/models/motions/workflow-state';
import { ViewMotion } from '../models/view-motion';
import { Observable } from 'rxjs';
import { BaseRepository } from '../../base-repository';
import { DataStoreService } from '../../../core/services/data-store.service';
/**
* 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
* @param DataSend
*/
public constructor(private dataSend: DataSendService) {
super(Motion, [Category, User, Workflow]);
public constructor(DS: DataStoreService, private dataSend: DataSendService) {
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 { Motion } from '../../shared/models/motions/motion';
import { MotionSubmitter } from '../../shared/models/motions/motion-submitter';
import { DataStoreService } from '../../core/services/data-store.service';
@Component({
selector: 'os-start',
@ -25,7 +26,7 @@ export class StartComponent extends BaseComponent implements OnInit {
* @param titleService the title serve
* @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);
}

View File

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