From 0e4090c901067ea76b0508c7092b991ec9bc6306 Mon Sep 17 00:00:00 2001 From: FinnStutzenstein Date: Mon, 5 Aug 2019 15:00:21 +0200 Subject: [PATCH] Reverse relations --- .../core/core-services/app-load.service.ts | 4 +- .../core/core-services/data-store.service.ts | 16 +- .../app/core/core-services/http.service.ts | 2 +- .../core/core-services/operator.service.ts | 4 +- .../app/core/core-services/ping.service.ts | 4 +- .../relation-manager.service.spec.ts | 16 + .../core-services/relation-manager.service.ts | 275 +++++++++++++++ .../core/core-services/websocket.service.ts | 2 +- client/src/app/core/core.module.ts | 2 +- .../app/core/{ => definitions}/app-config.ts | 8 +- .../on-after-apps-loaded.ts} | 0 .../core/{ => definitions}/query-params.ts | 0 client/src/app/core/definitions/relations.ts | 190 +++++++++++ .../src/app/core/{ => promises}/deferred.ts | 0 .../core/{ => promises}/timeout-promise.ts | 0 .../agenda/item-repository.service.ts | 14 +- .../list-of-speakers-repository.service.ts | 25 +- .../assignment-repository.service.ts | 21 +- .../base-has-content-object-repository.ts | 114 +------ ...t-of-speakers-content-object-repository.ts | 34 +- ...s-agenda-item-content-object-repository.ts | 8 +- ...t-of-speakers-content-object-repository.ts | 8 +- .../app/core/repositories/base-repository.ts | 317 ++++++------------ .../config/config-repository.service.ts | 4 +- .../mediafile-repository.service.ts | 17 +- .../motions/category-repository.service.ts | 44 ++- ...hange-recommendation-repository.service.ts | 12 +- .../motion-block-repository.service.ts | 49 ++- ...tion-comment-section-repository.service.ts | 6 +- .../motions/motion-repository.service.ts | 20 +- .../motions/state-repository.service.ts | 11 +- .../statute-paragraph-repository.service.ts | 6 +- .../motions/workflow-repository.service.ts | 20 +- .../projector/countdown-repository.service.ts | 4 +- .../projection-default-repository.service.ts | 6 +- .../projector-message-repository.service.ts | 6 +- .../projector/projector-repository.service.ts | 18 +- .../tags/tag-repository.service.ts | 6 +- .../topics/topic-repository.service.ts | 8 +- .../users/group-repository.service.ts | 4 +- .../users/personal-note-repository.service.ts | 6 +- .../users/user-repository.service.ts | 7 +- .../{ => translate}/marked-translations.ts | 0 .../base/base-model-with-content-object.ts | 4 + client/src/app/site/agenda/agenda.config.ts | 2 +- .../src/app/site/agenda/models/view-item.ts | 5 +- .../agenda/models/view-list-of-speakers.ts | 6 +- .../app/site/agenda/models/view-speaker.ts | 6 +- .../site/assignments/assignments.config.ts | 2 +- .../models/view-assignment-poll-option.ts | 6 +- .../models/view-assignment-poll.ts | 6 +- .../models/view-assignment-related-user.ts | 5 +- .../assignments/models/view-assignment.ts | 5 +- ...l-with-agenda-item-and-list-of-speakers.ts | 4 - .../base/base-view-model-with-agenda-item.ts | 4 +- .../base-view-model-with-content-object.ts | 8 - .../base-view-model-with-list-of-speakers.ts | 4 +- client/src/app/site/base/base-view-model.ts | 7 +- client/src/app/site/common/common.config.ts | 2 +- client/src/app/site/config/config.config.ts | 2 +- .../src/app/site/config/models/view-config.ts | 5 +- client/src/app/site/history/history.config.ts | 2 +- .../app/site/mediafiles/mediafile.config.ts | 2 +- .../site/mediafiles/models/view-mediafile.ts | 5 +- .../app/site/motions/models/view-category.ts | 16 +- .../site/motions/models/view-motion-block.ts | 11 +- .../view-motion-change-recommendation.ts | 5 +- .../models/view-motion-comment-section.ts | 5 +- .../app/site/motions/models/view-motion.ts | 5 +- .../src/app/site/motions/models/view-state.ts | 5 +- .../motions/models/view-statute-paragraph.ts | 5 +- .../app/site/motions/models/view-submitter.ts | 6 +- .../app/site/motions/models/view-workflow.ts | 5 +- .../category-detail.component.ts | 22 +- .../category-list.component.html | 2 +- .../category-list/category-list.component.ts | 10 - .../motion-block-detail.component.ts | 2 +- .../motion-block-list.component.html | 10 +- .../motion-block-list.component.ts | 11 - client/src/app/site/motions/motions.config.ts | 2 +- .../services/motion-sort-list.service.ts | 2 +- .../site/projector/models/view-countdown.ts | 5 +- .../models/view-projection-default.ts | 5 +- .../models/view-projector-message.ts | 5 +- .../site/projector/models/view-projector.ts | 5 +- .../app/site/projector/projector.config.ts | 2 +- client/src/app/site/tags/models/view-tag.ts | 5 +- client/src/app/site/tags/tag.config.ts | 2 +- .../src/app/site/topics/models/view-topic.ts | 5 +- client/src/app/site/topics/topics.config.ts | 2 +- .../src/app/site/users/models/view-group.ts | 5 +- .../site/users/models/view-personal-note.ts | 5 +- client/src/app/site/users/models/view-user.ts | 5 +- client/src/app/site/users/users.config.ts | 2 +- 94 files changed, 923 insertions(+), 664 deletions(-) create mode 100644 client/src/app/core/core-services/relation-manager.service.spec.ts create mode 100644 client/src/app/core/core-services/relation-manager.service.ts rename client/src/app/core/{ => definitions}/app-config.ts (76%) rename client/src/app/core/{onAfterAppsLoaded.ts => definitions/on-after-apps-loaded.ts} (100%) rename client/src/app/core/{ => definitions}/query-params.ts (100%) create mode 100644 client/src/app/core/definitions/relations.ts rename client/src/app/core/{ => promises}/deferred.ts (100%) rename client/src/app/core/{ => promises}/timeout-promise.ts (100%) rename client/src/app/core/{ => translate}/marked-translations.ts (100%) diff --git a/client/src/app/core/core-services/app-load.service.ts b/client/src/app/core/core-services/app-load.service.ts index a71cb41f3..9688e7731 100644 --- a/client/src/app/core/core-services/app-load.service.ts +++ b/client/src/app/core/core-services/app-load.service.ts @@ -1,7 +1,7 @@ import { Injectable, Injector } from '@angular/core'; import { AgendaAppConfig } from '../../site/agenda/agenda.config'; -import { AppConfig, ModelEntry, SearchableModelEntry } from '../app-config'; +import { AppConfig, ModelEntry, SearchableModelEntry } from '../definitions/app-config'; import { BaseRepository } from 'app/core/repositories/base-repository'; import { HistoryAppConfig } from 'app/site/history/history.config'; import { ProjectorAppConfig } from 'app/site/projector/projector.config'; @@ -14,7 +14,7 @@ import { ServicesToLoadOnAppsLoaded } from '../core.module'; import { MainMenuService } from './main-menu.service'; import { MediafileAppConfig } from '../../site/mediafiles/mediafile.config'; import { MotionsAppConfig } from '../../site/motions/motions.config'; -import { OnAfterAppsLoaded } from '../onAfterAppsLoaded'; +import { OnAfterAppsLoaded } from '../definitions/on-after-apps-loaded'; import { plugins } from '../../../plugins'; import { SearchService } from '../ui-services/search.service'; import { isSearchable } from '../../site/base/searchable'; diff --git a/client/src/app/core/core-services/data-store.service.ts b/client/src/app/core/core-services/data-store.service.ts index bc40264ec..5b37c71d2 100644 --- a/client/src/app/core/core-services/data-store.service.ts +++ b/client/src/app/core/core-services/data-store.service.ts @@ -5,7 +5,7 @@ import { Observable, Subject } from 'rxjs'; import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model'; import { BaseRepository } from '../repositories/base-repository'; import { CollectionStringMapperService } from './collection-string-mapper.service'; -import { Deferred } from '../deferred'; +import { Deferred } from '../promises/deferred'; import { StorageService } from './storage.service'; /** @@ -102,6 +102,13 @@ export class UpdateSlot { return this.deletedModels[collection] || []; } + /** + * @returns the mapping of all deleted models + */ + public getDeletedModels(): CollectionIds { + return this.deletedModels; + } + /** * Compares this object to another update slot. */ @@ -221,9 +228,12 @@ export class DataStoreUpdateManagerService { } }); - // Phase 2: updating dependencies + // Phase 2: updating dependencies (deleting ad changing in this order) repositories.forEach(repo => { - if (repo.updateDependencies(slot.getChangedModels())) { + if (repo.updateDependenciesForDeletedModels(slot.getDeletedModels())) { + affectedRepos[repo.collectionString] = repo; + } + if (repo.updateDependenciesForChangedModels(slot.getChangedModels())) { affectedRepos[repo.collectionString] = repo; } }); diff --git a/client/src/app/core/core-services/http.service.ts b/client/src/app/core/core-services/http.service.ts index a6aeccab7..8b31e59fe 100644 --- a/client/src/app/core/core-services/http.service.ts +++ b/client/src/app/core/core-services/http.service.ts @@ -4,7 +4,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { OpenSlidesStatusService } from './openslides-status.service'; -import { formatQueryParams, QueryParams } from '../query-params'; +import { formatQueryParams, QueryParams } from '../definitions/query-params'; /** * Enum for different HTTPMethods diff --git a/client/src/app/core/core-services/operator.service.ts b/client/src/app/core/core-services/operator.service.ts index bcef700cf..ef91f90a2 100644 --- a/client/src/app/core/core-services/operator.service.ts +++ b/client/src/app/core/core-services/operator.service.ts @@ -8,10 +8,10 @@ import { Group } from 'app/shared/models/users/group'; import { ViewUser } from 'app/site/users/models/view-user'; import { CollectionStringMapperService } from './collection-string-mapper.service'; import { DataStoreService } from './data-store.service'; -import { Deferred } from '../deferred'; +import { Deferred } from '../promises/deferred'; import { HttpService } from './http.service'; import { OfflineService } from './offline.service'; -import { OnAfterAppsLoaded } from '../onAfterAppsLoaded'; +import { OnAfterAppsLoaded } from '../definitions/on-after-apps-loaded'; import { OpenSlidesStatusService } from './openslides-status.service'; import { StorageService } from './storage.service'; import { User } from '../../shared/models/users/user'; diff --git a/client/src/app/core/core-services/ping.service.ts b/client/src/app/core/core-services/ping.service.ts index fd770edb9..290da4bca 100644 --- a/client/src/app/core/core-services/ping.service.ts +++ b/client/src/app/core/core-services/ping.service.ts @@ -3,8 +3,8 @@ import { ApplicationRef, Injectable } from '@angular/core'; import { first, take } from 'rxjs/operators'; import { ConstantsService } from './constants.service'; -import { Deferred } from '../deferred'; -import { TimeoutPromise } from '../timeout-promise'; +import { Deferred } from '../promises/deferred'; +import { TimeoutPromise } from '../promises/timeout-promise'; import { WebsocketService } from './websocket.service'; interface OpenSlidesSettings { diff --git a/client/src/app/core/core-services/relation-manager.service.spec.ts b/client/src/app/core/core-services/relation-manager.service.spec.ts new file mode 100644 index 000000000..a91a00d51 --- /dev/null +++ b/client/src/app/core/core-services/relation-manager.service.spec.ts @@ -0,0 +1,16 @@ +import { inject, TestBed } from '@angular/core/testing'; + +import { E2EImportsModule } from '../../../e2e-imports.module'; +import { RelationManagerService } from './relation-manager.service'; + +describe('RelationManagerService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [E2EImportsModule], + providers: [RelationManagerService] + }); + }); + it('should be created', inject([RelationManagerService], (service: RelationManagerService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/client/src/app/core/core-services/relation-manager.service.ts b/client/src/app/core/core-services/relation-manager.service.ts new file mode 100644 index 000000000..7b9f4d55d --- /dev/null +++ b/client/src/app/core/core-services/relation-manager.service.ts @@ -0,0 +1,275 @@ +import { Injectable } from '@angular/core'; + +import { BaseModel } from 'app/shared/models/base/base-model'; +import { BaseViewModel, ViewModelConstructor } from 'app/site/base/base-view-model'; +import { + BaseOrderedRelation, + isCustomRelationDefinition, + isGenericRelationDefinition, + isNestedRelationDefinition, + isNormalRelationDefinition, + isReverseRelationDefinition, + RelationDefinition, + ReverseRelationDefinition +} from '../definitions/relations'; +import { ViewModelStoreService } from './view-model-store.service'; + +/** + * Manages relations between view models. This service is and should only used by the + * base repository to offload maanging relations between view models. + */ +@Injectable({ + providedIn: 'root' +}) +export class RelationManagerService { + public constructor(private viewModelStoreService: ViewModelStoreService) {} + + /** + * Sorts the array of foreign view models in the given view models for the given relation. + */ + public sortByRelation( + relation: BaseOrderedRelation, + viewModel: V + ): void { + const order = relation.order; + viewModel['_' + relation.ownKey].sort((a: BaseViewModel, b: BaseViewModel) => { + if (!order || a[order] === b[order]) { + return a.id - b.id; + } else { + return a[order] - b[order]; + } + }); + } + + /** + * Creates a view model from the given model and model ctor. All dependencies will be + * set accorting to relations. + */ + public createViewModel( + model: M, + modelCtor: ViewModelConstructor, + relations: RelationDefinition[] + ): V { + const viewModel = new modelCtor(model) as V; + + relations.forEach(relation => { + this.setRelationsInViewModel(model, viewModel, relation); + }); + + return viewModel; + } + + /** + * Sets one foreign view model in the view model according to the relation and the information + * from the model. + */ + protected setRelationsInViewModel( + model: M, + viewModel: V, + relation: RelationDefinition + ): void { + // no reverse setting needed. This is done in the second phase of the ds-upgrade-manager + if (isReverseRelationDefinition(relation)) { + return; + } + + if ( + (relation.type === 'M2M' || relation.type === 'O2M') && + model[relation.ownIdKey] && + model[relation.ownIdKey].constructor === Array + ) { + const foreignViewModels = this.viewModelStoreService.getMany( + relation.foreignModel, + model[relation.ownIdKey] + ); + viewModel['_' + relation.ownKey] = foreignViewModels; + this.sortByRelation(relation, viewModel); + } else if (relation.type === 'M2O') { + const foreignViewModel = this.viewModelStoreService.get(relation.foreignModel, model[relation.ownIdKey]); + viewModel['_' + relation.ownKey] = foreignViewModel; + } else if (isNestedRelationDefinition(relation)) { + const foreignViewModels: BaseViewModel[] = model[relation.ownKey].map(foreignModel => + this.createViewModel(foreignModel, relation.foreignModel, relation.relationDefinition || []) + ); + viewModel['_' + relation.ownKey] = foreignViewModels; + this.sortByRelation(relation, viewModel); + } else if (isGenericRelationDefinition(relation)) { + const contentObject = this.viewModelStoreService.get( + model[relation.ownContentObjectDataKey].collection, + model[relation.ownContentObjectDataKey].id + ); + if (contentObject && relation.isVForeign(contentObject)) { + viewModel['_' + relation.ownKey] = contentObject; + } + } else if (isCustomRelationDefinition(relation)) { + relation.setRelations(model, viewModel); + } + } + + /** + * Updates an own view model with an deleted model implicit given by the deletedId and + * the collection via the relation. + * + * @return true, if something was updated. + */ + public updateSingleDependencyForDeletedModel( + ownViewModel: BaseViewModel, + relation: ReverseRelationDefinition, + deletedId: number + ): boolean { + // In both relations, the ownViewModel holds an array of foreignViewModels. Try to find the deleted + // foreignViewModel in this array and remove it. + if (relation.type === 'O2M' || relation.type === 'M2M') { + const ownModelArray = ownViewModel['_' + relation.ownKey]; + if (!ownModelArray) { + return false; + } + // We have the array of foreign view models for our own view model. Put the foreignViewModel + // into it (replace or push). + const index = ownModelArray.findIndex(foreignViewModel => foreignViewModel.id === deletedId); + if (index > -1) { + ownModelArray.splice(index, 1); + return true; + } + } + + // The ownViewModel holds one foreignViewModel. Check, if it is the deleted one. + else if (relation.type === 'M2O') { + if (ownViewModel['_' + relation.ownKey] && ownViewModel['_' + relation.ownKey].id === deletedId) { + ownViewModel['_' + relation.ownKey] = null; + return true; + } + } + + return false; + } + + /** + * Updates an own view model with an implicit given model by the collection and changedId. + * + * @return true, if something was updated. + */ + public updateSingleDependencyForChangedModel( + ownViewModel: BaseViewModel, + relation: RelationDefinition, + collection: string, + changedId: number + ): boolean { + if (isNormalRelationDefinition(relation)) { + if (relation.type === 'M2M' || relation.type === 'O2M') { + // For the side of the ownViewModel these relations are the same: + // the ownViewModel does have may foreign models and we do have a normal relation (not a + // reverse one), we just set the many-part of the relation in the ownViewModel. + if ( + ownViewModel[relation.ownIdKey] && + ownViewModel[relation.ownIdKey].constructor === Array && + ownViewModel[relation.ownIdKey].includes(changedId) // The foreign view model belongs to us. + ) { + const foreignViewModel = this.viewModelStoreService.get(collection, changedId); + this.setForeingViewModelInOwnViewModelArray(foreignViewModel, ownViewModel, relation.ownKey); + return true; + } + } else if (relation.type === 'M2O') { + if (ownViewModel[relation.ownIdKey] === changedId) { + // Check, if this is the matching foreign view model. + ownViewModel['_' + relation.ownKey] = this.viewModelStoreService.get(collection, changedId); + return true; + } + } + } else if (isReverseRelationDefinition(relation)) { + const foreignViewModel = this.viewModelStoreService.get(collection, changedId); + + // The foreign model has one id. Check, if the ownViewModel is the matching view model. + // If so, add the foreignViewModel to the array from the ownViewModel (with many foreignViewModels) + if (relation.type === 'O2M') { + if (foreignViewModel[relation.foreignIdKey] === ownViewModel.id) { + this.setForeingViewModelInOwnViewModelArray(foreignViewModel, ownViewModel, relation.ownKey); + return true; + } + } + + // The foreign model should hold an array of ids. If the ownViewModel is in it, the foreignViewModel must + // be included into the array from the ownViewModel (with many foreignViewModels) + else if (relation.type === 'M2M') { + if ( + foreignViewModel[relation.foreignIdKey] && + foreignViewModel[relation.foreignIdKey].constructor === Array && + foreignViewModel[relation.foreignIdKey].includes(ownViewModel.id) + ) { + this.setForeingViewModelInOwnViewModelArray(foreignViewModel, ownViewModel, relation.ownKey); + return true; + } + } + + // The foreign model should hold an array of ids. If the ownViewModel is in it, the foreignViewModel is the + // one and only matching model for the ownViewModel + else if (relation.type === 'M2O') { + if ( + foreignViewModel[relation.foreignIdKey] && + foreignViewModel[relation.foreignIdKey].constructor === Array && + foreignViewModel[relation.foreignIdKey].includes(ownViewModel.id) + ) { + ownViewModel['_' + relation.ownKey] = foreignViewModel; + return true; + } + } + } else if (isNestedRelationDefinition(relation)) { + let updated = false; + (relation.relationDefinition || []).forEach(nestedRelation => { + const nestedViewModels = ownViewModel[relation.ownKey] as BaseViewModel[]; + nestedViewModels.forEach(nestedViewModel => { + if ( + this.updateSingleDependencyForChangedModel( + nestedViewModel, + nestedRelation, + collection, + changedId + ) + ) { + updated = true; + } + }); + }); + return updated; + } else if (isCustomRelationDefinition(relation)) { + const foreignViewModel = this.viewModelStoreService.get(collection, changedId); + return relation.updateDependency(ownViewModel, foreignViewModel); + } else if (isGenericRelationDefinition(relation)) { + const foreignModel = this.viewModelStoreService.get(collection, changedId); + if ( + foreignModel && + foreignModel.collectionString === ownViewModel[relation.ownContentObjectDataKey].collection && + foreignModel.id === ownViewModel[relation.ownContentObjectDataKey].id + ) { + if (relation.isVForeign(foreignModel)) { + ownViewModel['_' + relation.ownKey] = foreignModel; + return true; + } else { + console.warn(`The object is not an ${relation.VForeignVerbose}:` + foreignModel); + } + } + } + + return false; + } + + private setForeingViewModelInOwnViewModelArray( + foreignViewModel: BaseViewModel, + ownViewModel: BaseViewModel, + ownKey: string + ): void { + let ownViewModelArray = ownViewModel['_' + ownKey]; + if (!ownViewModelArray) { + ownViewModel['_' + ownKey] = []; + ownViewModelArray = ownViewModel['_' + ownKey]; // get the new reference + } + // We have the array of foreign view models for our own view model. Put the foreignViewModel + // into it (replace or push). + const index = ownViewModelArray.findIndex(_foreignViewModel => _foreignViewModel.id === foreignViewModel.id); + if (index < 0) { + ownViewModelArray.push(foreignViewModel); + } else { + ownViewModelArray[index] = foreignViewModel; + } + } +} diff --git a/client/src/app/core/core-services/websocket.service.ts b/client/src/app/core/core-services/websocket.service.ts index af8352d87..eb147901a 100644 --- a/client/src/app/core/core-services/websocket.service.ts +++ b/client/src/app/core/core-services/websocket.service.ts @@ -9,7 +9,7 @@ import { take } from 'rxjs/operators'; import { TextDecoder, TextEncoder } from 'text-encoding'; import { OpenSlidesStatusService } from './openslides-status.service'; -import { formatQueryParams, QueryParams } from '../query-params'; +import { formatQueryParams, QueryParams } from '../definitions/query-params'; /** * The generic message format in which messages are send and recieved by the server. diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index acbfdd456..8721fb1ce 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts @@ -4,7 +4,7 @@ import { Title } from '@angular/platform-browser'; import { ProjectionDialogComponent } from 'app/shared/components/projection-dialog/projection-dialog.component'; import { ChoiceDialogComponent } from '../shared/components/choice-dialog/choice-dialog.component'; -import { OnAfterAppsLoaded } from './onAfterAppsLoaded'; +import { OnAfterAppsLoaded } from './definitions/on-after-apps-loaded'; import { OperatorService } from './core-services/operator.service'; import { PromptDialogComponent } from '../shared/components/prompt-dialog/prompt-dialog.component'; diff --git a/client/src/app/core/app-config.ts b/client/src/app/core/definitions/app-config.ts similarity index 76% rename from client/src/app/core/app-config.ts rename to client/src/app/core/definitions/app-config.ts index 3f2f84aa7..412671363 100644 --- a/client/src/app/core/app-config.ts +++ b/client/src/app/core/definitions/app-config.ts @@ -1,10 +1,10 @@ import { Type } from '@angular/core'; import { BaseViewModel, ViewModelConstructor } from 'app/site/base/base-view-model'; -import { BaseModel, ModelConstructor } from '../shared/models/base/base-model'; -import { BaseRepository } from './repositories/base-repository'; -import { MainMenuEntry } from './core-services/main-menu.service'; -import { Searchable } from '../site/base/searchable'; +import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model'; +import { BaseRepository } from '../repositories/base-repository'; +import { MainMenuEntry } from '../core-services/main-menu.service'; +import { Searchable } from '../../site/base/searchable'; interface BaseModelEntry { collectionString: string; diff --git a/client/src/app/core/onAfterAppsLoaded.ts b/client/src/app/core/definitions/on-after-apps-loaded.ts similarity index 100% rename from client/src/app/core/onAfterAppsLoaded.ts rename to client/src/app/core/definitions/on-after-apps-loaded.ts diff --git a/client/src/app/core/query-params.ts b/client/src/app/core/definitions/query-params.ts similarity index 100% rename from client/src/app/core/query-params.ts rename to client/src/app/core/definitions/query-params.ts diff --git a/client/src/app/core/definitions/relations.ts b/client/src/app/core/definitions/relations.ts new file mode 100644 index 000000000..0f462b542 --- /dev/null +++ b/client/src/app/core/definitions/relations.ts @@ -0,0 +1,190 @@ +import { BaseModel } from 'app/shared/models/base/base-model'; +import { BaseViewModel, ViewModelConstructor } from 'app/site/base/base-view-model'; + +// All "standard" relations. +export type RelationDefinition = + | NormalRelationDefinition + | ReverseRelationDefinition + | NestedRelationDefinition + | CustomRelationDefinition + | GenericRelationDefinition; + +interface BaseRelationDefinition { + /** + * The name of the property, where the foreign view model should be accessable. + * Note, that this must be a getter to a private variable `_; +} + +export interface BaseOrderedRelation extends BaseRelationDefinition { + /** + * Provide an extra key (holding a number) to order by. + * If the value is equal or no order key is given, the models + * will be sorted by id. + */ + order?: string; +} + +interface BaseNormalRelationDefinition extends BaseRelationDefinition { + /** + * This is the key in the own model where the id(s) are given. Must be present in + * the model and view model. E.g. `category_id` in a motion. + */ + ownIdKey: string; +} + +/** + * These relations has to be read as in an ER-model. The right side is always the + * model where the relation is defined. + * - M2O: From this model to another one, where this model is the right (many). + * E.g. motions<->categories: One motions has One category; One category has + * Many motions. + * - O2M: Reverse relation to M2O. E.g. defined for categories: One category has + * Many motions and One motion has One category. + * - M2M: M2M relation from this to another model. + */ + +interface NormalM2MRelationDefinition + extends BaseNormalRelationDefinition, + BaseOrderedRelation { + type: 'M2M'; +} + +interface NormalO2MRelationDefinition + extends BaseNormalRelationDefinition, + BaseOrderedRelation { + type: 'O2M'; +} + +interface NormalM2ORelationDefinition extends BaseNormalRelationDefinition { + type: 'M2O'; +} + +export type NormalRelationDefinition = + | NormalM2MRelationDefinition + | NormalO2MRelationDefinition + | NormalM2ORelationDefinition; + +export function isNormalRelationDefinition(obj: RelationDefinition): obj is NormalRelationDefinition { + const relation = obj as NormalRelationDefinition; + return (relation.type === 'M2O' || relation.type === 'O2M' || relation.type === 'M2M') && !!relation.ownIdKey; +} + +interface BaseReverseRelationDefinition { + /** + * The key with the id(s) is given in the foreign model. Must be present in + * the model and view model. E.g. `category_id` from a motion but the relation is + * defined for a category. + */ + foreignIdKey: string; + + /** + * The name of the property, where the foreign view model should be accessable. + * Note, that this must be a getter to a private variable `_; +} + +interface ReverseM2MRelationDefinition + extends BaseReverseRelationDefinition, + BaseOrderedRelation { + type: 'M2M'; +} + +interface ReverseO2MRelationDefinition + extends BaseReverseRelationDefinition, + BaseOrderedRelation { + type: 'O2M'; +} + +interface ReverseM2ORelationDefinition extends BaseReverseRelationDefinition { + type: 'M2O'; +} + +export type ReverseRelationDefinition = + | ReverseM2MRelationDefinition + | ReverseO2MRelationDefinition + | ReverseM2ORelationDefinition; + +export function isReverseRelationDefinition(obj: RelationDefinition): obj is ReverseRelationDefinition { + const relation = obj as ReverseRelationDefinition; + return (relation.type === 'M2O' || relation.type === 'O2M' || relation.type === 'M2M') && !!relation.foreignIdKey; +} + +/** + * Nested relations in the REST-API. For the most values see + * `NormalRelationDefinition`. + */ +interface NestedRelationDefinition extends BaseOrderedRelation { + type: 'nested'; + ownKey: string; + + /** + * The nested relations. + */ + relationDefinition?: RelationDefinition[]; +} + +export function isNestedRelationDefinition(obj: RelationDefinition): obj is NestedRelationDefinition { + return obj.type === 'nested'; +} + +interface GenericRelationDefinition { + type: 'generic'; + + /** + * The key where the model and view model holds the ContentObject (object with collection and id). + * Similar to ownIdKey. + */ + ownContentObjectDataKey: string; + + /** + * The key where to but the content object. + */ + ownKey: string; + + possibleModels: ViewModelConstructor[]; + isVForeign: (obj: any) => obj is VForeign; + VForeignVerbose: string; +} + +export function isGenericRelationDefinition(obj: RelationDefinition): obj is GenericRelationDefinition { + return obj.type === 'generic'; +} + +/** + * A custom relation with callbacks with things todo. + */ +interface CustomRelationDefinition { + type: 'custom'; + foreignModel: ViewModelConstructor; + + /** + * Called, when the view model is created from the model. + */ + setRelations: (model: BaseModel, viewModel: BaseViewModel) => void; + + /** + * Called, when the dependency was updated. + */ + updateDependency: (ownViewModel: BaseViewModel, foreignViewModel: VForeign) => boolean; +} + +export function isCustomRelationDefinition(obj: RelationDefinition): obj is CustomRelationDefinition { + return obj.type === 'custom'; +} diff --git a/client/src/app/core/deferred.ts b/client/src/app/core/promises/deferred.ts similarity index 100% rename from client/src/app/core/deferred.ts rename to client/src/app/core/promises/deferred.ts diff --git a/client/src/app/core/timeout-promise.ts b/client/src/app/core/promises/timeout-promise.ts similarity index 100% rename from client/src/app/core/timeout-promise.ts rename to client/src/app/core/promises/timeout-promise.ts diff --git a/client/src/app/core/repositories/agenda/item-repository.service.ts b/client/src/app/core/repositories/agenda/item-repository.service.ts index 40d058bb5..5ca35f94e 100644 --- a/client/src/app/core/repositories/agenda/item-repository.service.ts +++ b/client/src/app/core/repositories/agenda/item-repository.service.ts @@ -4,7 +4,9 @@ import { TranslateService } from '@ngx-translate/core'; import { DataSendService } from 'app/core/core-services/data-send.service'; import { HttpService } from 'app/core/core-services/http.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; +import { RelationDefinition } from 'app/core/definitions/relations'; import { ConfigService } from 'app/core/ui-services/config.service'; import { TreeIdNode } from 'app/core/ui-services/tree.service'; import { Item } from 'app/shared/models/agenda/item'; @@ -19,18 +21,19 @@ import { import { ViewMotion } from 'app/site/motions/models/view-motion'; import { ViewMotionBlock } from 'app/site/motions/models/view-motion-block'; import { ViewTopic } from 'app/site/topics/models/view-topic'; -import { BaseHasContentObjectRepository, GenericRelationDefinition } from '../base-has-content-object-repository'; +import { BaseHasContentObjectRepository } from '../base-has-content-object-repository'; import { BaseIsAgendaItemContentObjectRepository } from '../base-is-agenda-item-content-object-repository'; -import { RelationDefinition } from '../base-repository'; import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service'; import { DataStoreService } from '../../core-services/data-store.service'; -const ItemRelations: (RelationDefinition | GenericRelationDefinition)[] = [ +const ItemRelations: RelationDefinition[] = [ { type: 'generic', possibleModels: [ViewMotion, ViewMotionBlock, ViewTopic, ViewAssignment], isVForeign: isBaseViewModelWithAgendaItem, - VForeignVerbose: 'BaseViewModelWithAgendaItem' + VForeignVerbose: 'BaseViewModelWithAgendaItem', + ownContentObjectDataKey: 'contentObjectData', + ownKey: 'contentObject' } ]; @@ -64,10 +67,11 @@ export class ItemRepositoryService extends BaseHasContentObjectRepository< mapperService: CollectionStringMapperService, viewModelStoreService: ViewModelStoreService, translate: TranslateService, + relationManager: RelationManagerService, private httpService: HttpService, private config: ConfigService ) { - super(DS, dataSend, mapperService, viewModelStoreService, translate, Item, ItemRelations); + super(DS, dataSend, mapperService, viewModelStoreService, translate, relationManager, Item, ItemRelations); this.setSortFunction((a, b) => a.weight - b.weight); } diff --git a/client/src/app/core/repositories/agenda/list-of-speakers-repository.service.ts b/client/src/app/core/repositories/agenda/list-of-speakers-repository.service.ts index 5454edc66..75c23ccbe 100644 --- a/client/src/app/core/repositories/agenda/list-of-speakers-repository.service.ts +++ b/client/src/app/core/repositories/agenda/list-of-speakers-repository.service.ts @@ -4,7 +4,9 @@ import { TranslateService } from '@ngx-translate/core'; import { DataSendService } from 'app/core/core-services/data-send.service'; import { HttpService } from 'app/core/core-services/http.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; +import { RelationDefinition } from 'app/core/definitions/relations'; import { ListOfSpeakers } from 'app/shared/models/agenda/list-of-speakers'; import { Identifiable } from 'app/shared/models/base/identifiable'; import { ListOfSpeakersTitleInformation, ViewListOfSpeakers } from 'app/site/agenda/models/view-list-of-speakers'; @@ -19,19 +21,20 @@ import { ViewMotion } from 'app/site/motions/models/view-motion'; import { ViewMotionBlock } from 'app/site/motions/models/view-motion-block'; import { ViewTopic } from 'app/site/topics/models/view-topic'; import { ViewUser } from 'app/site/users/models/view-user'; -import { BaseHasContentObjectRepository, GenericRelationDefinition } from '../base-has-content-object-repository'; +import { BaseHasContentObjectRepository } from '../base-has-content-object-repository'; import { BaseIsListOfSpeakersContentObjectRepository } from '../base-is-list-of-speakers-content-object-repository'; -import { RelationDefinition } from '../base-repository'; import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service'; import { DataStoreService } from '../../core-services/data-store.service'; import { ItemRepositoryService } from './item-repository.service'; -const ListOfSpeakersRelations: (RelationDefinition | GenericRelationDefinition)[] = [ +const ListOfSpeakersRelations: RelationDefinition[] = [ { type: 'generic', possibleModels: [ViewMotion, ViewMotionBlock, ViewTopic, ViewAssignment, ViewMediafile], isVForeign: isBaseViewModelWithListOfSpeakers, - VForeignVerbose: 'BaseViewModelWithListOfSpeakers' + VForeignVerbose: 'BaseViewModelWithListOfSpeakers', + ownContentObjectDataKey: 'contentObjectData', + ownKey: 'contentObject' }, { type: 'nested', @@ -40,7 +43,7 @@ const ListOfSpeakersRelations: (RelationDefinition | GenericRelationDefinition)[ order: 'weight', relationDefinition: [ { - type: 'O2M', + type: 'M2O', ownIdKey: 'user_id', ownKey: 'user', foreignModel: ViewUser @@ -79,10 +82,20 @@ export class ListOfSpeakersRepositoryService extends BaseHasContentObjectReposit mapperService: CollectionStringMapperService, viewModelStoreService: ViewModelStoreService, translate: TranslateService, + relationManager: RelationManagerService, private httpService: HttpService, private itemRepo: ItemRepositoryService ) { - super(DS, dataSend, mapperService, viewModelStoreService, translate, ListOfSpeakers, ListOfSpeakersRelations); + super( + DS, + dataSend, + mapperService, + viewModelStoreService, + translate, + relationManager, + ListOfSpeakers, + ListOfSpeakersRelations + ); } public getVerboseName = (plural: boolean = false) => { diff --git a/client/src/app/core/repositories/assignments/assignment-repository.service.ts b/client/src/app/core/repositories/assignments/assignment-repository.service.ts index fdde87fa9..527a84e58 100644 --- a/client/src/app/core/repositories/assignments/assignment-repository.service.ts +++ b/client/src/app/core/repositories/assignments/assignment-repository.service.ts @@ -4,7 +4,9 @@ import { TranslateService } from '@ngx-translate/core'; import { DataSendService } from 'app/core/core-services/data-send.service'; import { HttpService } from 'app/core/core-services/http.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; +import { RelationDefinition } from 'app/core/definitions/relations'; import { Assignment } from 'app/shared/models/assignments/assignment'; import { AssignmentPoll } from 'app/shared/models/assignments/assignment-poll'; import { AssignmentTitleInformation, ViewAssignment } from 'app/site/assignments/models/view-assignment'; @@ -15,7 +17,6 @@ import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile'; import { ViewTag } from 'app/site/tags/models/view-tag'; import { ViewUser } from 'app/site/users/models/view-user'; import { BaseIsAgendaItemAndListOfSpeakersContentObjectRepository } from '../base-is-agenda-item-and-list-of-speakers-content-object-repository'; -import { RelationDefinition } from '../base-repository'; import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service'; import { DataStoreService } from '../../core-services/data-store.service'; @@ -39,7 +40,7 @@ const AssignmentRelations: RelationDefinition[] = [ order: 'weight', relationDefinition: [ { - type: 'O2M', + type: 'M2O', ownIdKey: 'user_id', ownKey: 'user', foreignModel: ViewUser @@ -58,7 +59,7 @@ const AssignmentRelations: RelationDefinition[] = [ order: 'weight', relationDefinition: [ { - type: 'O2M', + type: 'M2O', ownIdKey: 'user_id', ownKey: 'user', foreignModel: ViewUser @@ -104,10 +105,20 @@ export class AssignmentRepositoryService extends BaseIsAgendaItemAndListOfSpeake dataSend: DataSendService, mapperService: CollectionStringMapperService, viewModelStoreService: ViewModelStoreService, - protected translate: TranslateService, + translate: TranslateService, + relationManager: RelationManagerService, private httpService: HttpService ) { - super(DS, dataSend, mapperService, viewModelStoreService, translate, Assignment, AssignmentRelations); + super( + DS, + dataSend, + mapperService, + viewModelStoreService, + translate, + relationManager, + Assignment, + AssignmentRelations + ); } public getTitle = (titleInformation: AssignmentTitleInformation) => { diff --git a/client/src/app/core/repositories/base-has-content-object-repository.ts b/client/src/app/core/repositories/base-has-content-object-repository.ts index e1b36e77e..283e9c1e4 100644 --- a/client/src/app/core/repositories/base-has-content-object-repository.ts +++ b/client/src/app/core/repositories/base-has-content-object-repository.ts @@ -1,25 +1,8 @@ -import { TranslateService } from '@ngx-translate/core'; - -import { ModelConstructor } from 'app/shared/models/base/base-model'; import { BaseModelWithContentObject } from 'app/shared/models/base/base-model-with-content-object'; import { ContentObject } from 'app/shared/models/base/content-object'; -import { BaseViewModel, TitleInformation, ViewModelConstructor } from 'app/site/base/base-view-model'; +import { BaseViewModel, TitleInformation } from 'app/site/base/base-view-model'; import { BaseViewModelWithContentObject } from 'app/site/base/base-view-model-with-content-object'; -import { BaseRepository, RelationDefinition } from './base-repository'; -import { CollectionStringMapperService } from '../core-services/collection-string-mapper.service'; -import { DataSendService } from '../core-services/data-send.service'; -import { DataStoreService } from '../core-services/data-store.service'; -import { ViewModelStoreService } from '../core-services/view-model-store.service'; - -/** - * A generic relation for models with a content_object - */ -export interface GenericRelationDefinition { - type: 'generic'; - possibleModels: ViewModelConstructor[]; - isVForeign: (obj: any) => obj is VForeign; - VForeignVerbose: string; -} +import { BaseRepository } from './base-repository'; /** * A base repository for objects that *have* content objects, e.g. items and lists of speakers. @@ -40,99 +23,6 @@ export abstract class BaseHasContentObjectRepository< }; } = {}; - public constructor( - DS: DataStoreService, - dataSend: DataSendService, - collectionStringMapperService: CollectionStringMapperService, - viewModelStoreService: ViewModelStoreService, - translate: TranslateService, - baseModelCtor: ModelConstructor, - relationDefinitions: (RelationDefinition | GenericRelationDefinition)[] = [] - ) { - super(DS, dataSend, collectionStringMapperService, viewModelStoreService, translate, baseModelCtor, < - RelationDefinition[] - >relationDefinitions); // This cast "hides" the new generic relation from the base repository. Typescript can't handle this... - } - - protected _groupRelationsByCollections( - relation: RelationDefinition | GenericRelationDefinition, - baseRelation: RelationDefinition - ): void { - if (relation.type === 'generic') { - relation.possibleModels.forEach(ctor => { - const collection = ctor.COLLECTIONSTRING; - if (!this.relationsByCollection[collection]) { - this.relationsByCollection[collection] = []; - } - // The cast to any is needed to convince Typescript, that a GenericRelationDefinition can also - // be used as a RelationDefinition - this.relationsByCollection[collection].push(baseRelation); - }); - } else { - super._groupRelationsByCollections(relation, baseRelation); - } - } - - /** - * Adds the generic relation. - */ - protected updateSingleDependency( - ownViewModel: V, - relation: RelationDefinition | GenericRelationDefinition, - collection: string, - changedId: number - ): boolean { - if (relation.type === 'generic') { - const foreignModel = this.viewModelStoreService.get(collection, changedId); - if ( - foreignModel && - foreignModel.collectionString === ownViewModel.contentObjectData.collection && - foreignModel.id === ownViewModel.contentObjectData.id - ) { - if (relation.isVForeign(foreignModel)) { - (ownViewModel)._contentObject = foreignModel; - return true; - } else { - console.warn(`The object is not an ${relation.VForeignVerbose}:` + foreignModel); - } - - // TODO: set reverse - } - return false; - } else { - return super.updateSingleDependency(ownViewModel, relation, collection, changedId); - } - } - - /** - * Adds the generic relation. - */ - protected setRelationsInViewModel( - model: M, - viewModel: K, - relation: RelationDefinition | GenericRelationDefinition - ): void { - if (relation.type === 'generic') { - (viewModel)._contentObject = this.getContentObject(model, relation); - } else { - super.setRelationsInViewModel(model, viewModel, relation); - } - } - - /** - * Tries to get the content object (as a view model) from the given model and relation. - */ - protected getContentObject(model: M, relation: GenericRelationDefinition): BaseViewModel { - const contentObject = this.viewModelStoreService.get( - model.content_object.collection, - model.content_object.id - ); - if (!contentObject || !relation.isVForeign(contentObject)) { - return null; - } - return contentObject; - } - /** * Returns the object with has the given content object as the content object. * diff --git a/client/src/app/core/repositories/base-is-agenda-item-and-list-of-speakers-content-object-repository.ts b/client/src/app/core/repositories/base-is-agenda-item-and-list-of-speakers-content-object-repository.ts index 056926745..77bdd1ca5 100644 --- a/client/src/app/core/repositories/base-is-agenda-item-and-list-of-speakers-content-object-repository.ts +++ b/client/src/app/core/repositories/base-is-agenda-item-and-list-of-speakers-content-object-repository.ts @@ -1,6 +1,4 @@ -import { TranslateService } from '@ngx-translate/core'; - -import { BaseModel, ModelConstructor } from 'app/shared/models/base/base-model'; +import { BaseModel } from 'app/shared/models/base/base-model'; import { ViewItem } from 'app/site/agenda/models/view-item'; import { ViewListOfSpeakers } from 'app/site/agenda/models/view-list-of-speakers'; import { BaseProjectableViewModel } from 'app/site/base/base-projectable-view-model'; @@ -17,11 +15,7 @@ import { IBaseIsListOfSpeakersContentObjectRepository, isBaseIsListOfSpeakersContentObjectRepository } from './base-is-list-of-speakers-content-object-repository'; -import { BaseRepository, RelationDefinition } from './base-repository'; -import { CollectionStringMapperService } from '../core-services/collection-string-mapper.service'; -import { DataSendService } from '../core-services/data-send.service'; -import { DataStoreService } from '../core-services/data-store.service'; -import { ViewModelStoreService } from '../core-services/view-model-store.service'; +import { BaseRepository } from './base-repository'; export function isBaseIsAgendaItemAndListOfSpeakersContentObjectRepository( obj: any @@ -43,35 +37,15 @@ export abstract class BaseIsAgendaItemAndListOfSpeakersContentObjectRepository< implements IBaseIsAgendaItemContentObjectRepository, IBaseIsListOfSpeakersContentObjectRepository { - public constructor( - DS: DataStoreService, - dataSend: DataSendService, - collectionStringMapperService: CollectionStringMapperService, - viewModelStoreService: ViewModelStoreService, - translate: TranslateService, - baseModelCtor: ModelConstructor, - relationDefinitions?: RelationDefinition[] - ) { - super( - DS, - dataSend, - collectionStringMapperService, - viewModelStoreService, - translate, - baseModelCtor, - relationDefinitions - ); - } - protected groupRelationsByCollections(): void { this.relationDefinitions.push({ - type: 'O2M', + type: 'M2O', ownIdKey: 'agenda_item_id', ownKey: 'item', foreignModel: ViewItem }); this.relationDefinitions.push({ - type: 'O2M', + type: 'M2O', ownIdKey: 'list_of_speakers_id', ownKey: 'list_of_speakers', foreignModel: ViewListOfSpeakers diff --git a/client/src/app/core/repositories/base-is-agenda-item-content-object-repository.ts b/client/src/app/core/repositories/base-is-agenda-item-content-object-repository.ts index af90b4cb6..eeaa8ad12 100644 --- a/client/src/app/core/repositories/base-is-agenda-item-content-object-repository.ts +++ b/client/src/app/core/repositories/base-is-agenda-item-content-object-repository.ts @@ -6,10 +6,12 @@ import { TitleInformationWithAgendaItem } from 'app/site/base/base-view-model-with-agenda-item'; import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model'; -import { BaseRepository, RelationDefinition } from './base-repository'; +import { BaseRepository } from './base-repository'; import { CollectionStringMapperService } from '../core-services/collection-string-mapper.service'; import { DataSendService } from '../core-services/data-send.service'; import { DataStoreService } from '../core-services/data-store.service'; +import { RelationManagerService } from '../core-services/relation-manager.service'; +import { RelationDefinition } from '../definitions/relations'; import { ViewModelStoreService } from '../core-services/view-model-store.service'; export function isBaseIsAgendaItemContentObjectRepository( @@ -45,6 +47,7 @@ export abstract class BaseIsAgendaItemContentObjectRepository< collectionStringMapperService: CollectionStringMapperService, viewModelStoreService: ViewModelStoreService, translate: TranslateService, + relationManager: RelationManagerService, baseModelCtor: ModelConstructor, relationDefinitions?: RelationDefinition[] ) { @@ -54,6 +57,7 @@ export abstract class BaseIsAgendaItemContentObjectRepository< collectionStringMapperService, viewModelStoreService, translate, + relationManager, baseModelCtor, relationDefinitions ); @@ -61,7 +65,7 @@ export abstract class BaseIsAgendaItemContentObjectRepository< protected groupRelationsByCollections(): void { this.relationDefinitions.push({ - type: 'O2M', + type: 'M2O', ownIdKey: 'agenda_item_id', ownKey: 'item', foreignModel: ViewItem diff --git a/client/src/app/core/repositories/base-is-list-of-speakers-content-object-repository.ts b/client/src/app/core/repositories/base-is-list-of-speakers-content-object-repository.ts index f552381db..8ae1ffefa 100644 --- a/client/src/app/core/repositories/base-is-list-of-speakers-content-object-repository.ts +++ b/client/src/app/core/repositories/base-is-list-of-speakers-content-object-repository.ts @@ -3,11 +3,13 @@ import { TranslateService } from '@ngx-translate/core'; import { ViewListOfSpeakers } from 'app/site/agenda/models/view-list-of-speakers'; import { BaseViewModelWithListOfSpeakers } from 'app/site/base/base-view-model-with-list-of-speakers'; import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model'; -import { BaseRepository, RelationDefinition } from './base-repository'; +import { BaseRepository } from './base-repository'; import { TitleInformation } from '../../site/base/base-view-model'; import { CollectionStringMapperService } from '../core-services/collection-string-mapper.service'; import { DataSendService } from '../core-services/data-send.service'; import { DataStoreService } from '../core-services/data-store.service'; +import { RelationManagerService } from '../core-services/relation-manager.service'; +import { RelationDefinition } from '../definitions/relations'; import { ViewModelStoreService } from '../core-services/view-model-store.service'; export function isBaseIsListOfSpeakersContentObjectRepository( @@ -43,6 +45,7 @@ export abstract class BaseIsListOfSpeakersContentObjectRepository< collectionStringMapperService: CollectionStringMapperService, viewModelStoreService: ViewModelStoreService, translate: TranslateService, + relationManager: RelationManagerService, baseModelCtor: ModelConstructor, relationDefinitions?: RelationDefinition[] ) { @@ -52,6 +55,7 @@ export abstract class BaseIsListOfSpeakersContentObjectRepository< collectionStringMapperService, viewModelStoreService, translate, + relationManager, baseModelCtor, relationDefinitions ); @@ -59,7 +63,7 @@ export abstract class BaseIsListOfSpeakersContentObjectRepository< protected groupRelationsByCollections(): void { this.relationDefinitions.push({ - type: 'O2M', + type: 'M2O', ownIdKey: 'list_of_speakers_id', ownKey: 'list_of_speakers', foreignModel: ViewListOfSpeakers diff --git a/client/src/app/core/repositories/base-repository.ts b/client/src/app/core/repositories/base-repository.ts index 3a2f577fb..4fb65da0e 100644 --- a/client/src/app/core/repositories/base-repository.ts +++ b/client/src/app/core/repositories/base-repository.ts @@ -9,92 +9,16 @@ import { CollectionStringMapperService } from '../core-services/collection-strin import { DataSendService } from '../core-services/data-send.service'; import { CollectionIds, DataStoreService } from '../core-services/data-store.service'; import { Identifiable } from '../../shared/models/base/identifiable'; -import { OnAfterAppsLoaded } from '../onAfterAppsLoaded'; +import { OnAfterAppsLoaded } from '../definitions/on-after-apps-loaded'; +import { RelationManagerService } from '../core-services/relation-manager.service'; +import { + isNormalRelationDefinition, + isReverseRelationDefinition, + RelationDefinition, + ReverseRelationDefinition +} from '../definitions/relations'; import { ViewModelStoreService } from '../core-services/view-model-store.service'; -// All "standard" relations. -export type RelationDefinition = - | NormalRelationDefinition - | NestedRelationDefinition - | CustomRelationDefinition; - -/** - * Normal relations. - */ -interface NormalRelationDefinition { - /** - * - O2M: From this model to another one, where this model is the One-side. - * E.g. motions<->categories: One motions has One category; One category has - * Many motions - * - M2M: M2M relation from this to another model. - */ - type: 'M2M' | 'O2M'; - - /** - * The key where the id(s) are given. Must be present in the model and view model. E.g. `category_id`. - */ - ownIdKey: string; - - /** - * The name of the property, where the foreign view model should be accessable. - * Note, that this must be a getter to a private variable `_; - - /** - * TODO: reverse relations. - */ - foreignKey?: keyof VForeign; -} - -/** - * Nested relations in the REST-API. For the most values see - * `NormalRelationDefinition`. - */ -interface NestedRelationDefinition { - type: 'nested'; - ownKey: string; - foreignModel: ViewModelConstructor; - foreignKey?: keyof VForeign; - - /** - * The nested relations. - */ - relationDefinition?: RelationDefinition[]; - - /** - * Provide an extra key (holding a number) to order by. - * If the value is equal or no order key is given, the models - * will be sorted by id. - */ - order?: string; -} - -/** - * A custom relation with callbacks with things todo. - */ -interface CustomRelationDefinition { - type: 'custom'; - foreignModel: ViewModelConstructor; - - /** - * Called, when the view model is created from the model. - */ - setRelations: (model: BaseModel, viewModel: BaseViewModel) => void; - - /** - * Called, when the dependency was updated. - */ - updateDependency: (ownViewModel: BaseViewModel, foreignViewModel: VForeign) => boolean; -} - export abstract class BaseRepository implements OnAfterAppsLoaded, Collection { /** @@ -163,6 +87,8 @@ export abstract class BaseRepository[] } = {}; + protected reverseRelationsByCollection: { [collection: string]: ReverseRelationDefinition[] } = {}; + /** * The view model ctor of the encapsulated view model. */ @@ -183,12 +109,14 @@ export abstract class BaseRepository, protected relationDefinitions: RelationDefinition[] = [] ) { this._collectionString = baseModelCtor.COLLECTIONSTRING; this.groupRelationsByCollections(); + this.buildReverseRelationsGrouping(); // All data is piped through an auditTime of 1ms. This is to prevent massive // updates, if e.g. an autoupdate with a lot motions come in. The result is just one @@ -219,15 +147,39 @@ export abstract class BaseRepository { this._groupRelationsByCollections(nestedRelation, baseRelation); }); - } else if (relation.type === 'O2M' || relation.type === 'M2M' || relation.type === 'custom') { + } else if ( + relation.type === 'M2O' || + relation.type === 'M2M' || + relation.type === 'O2M' || + relation.type === 'custom' + ) { const collection = relation.foreignModel.COLLECTIONSTRING; if (!this.relationsByCollection[collection]) { this.relationsByCollection[collection] = []; } this.relationsByCollection[collection].push(baseRelation); + } else if (relation.type === 'generic') { + relation.possibleModels.forEach(ctor => { + const collection = ctor.COLLECTIONSTRING; + if (!this.relationsByCollection[collection]) { + this.relationsByCollection[collection] = []; + } + this.relationsByCollection[collection].push(baseRelation); + }); } } + protected buildReverseRelationsGrouping(): void { + Object.keys(this.relationsByCollection).forEach(collection => { + const reverseRelations = this.relationsByCollection[collection].filter(relation => + isReverseRelationDefinition(relation) + ) as ReverseRelationDefinition[]; + if (reverseRelations.length) { + this.reverseRelationsByCollection[collection] = reverseRelations; + } + }); + } + public onAfterAppsLoaded(): void { this.baseViewModelCtor = this.collectionStringMapperService.getViewModelConstructor(this.collectionString); this.DS.clearObservable.subscribe(() => this.clear()); @@ -274,82 +226,27 @@ export abstract class BaseRepository this.getTitle(viewModel); viewModel.getListTitle = () => this.getListTitle(viewModel); viewModel.getVerboseName = this.getVerboseName; return viewModel; } - /** - * Creates a view model from the given model and model ctor. All dependencies will be - * set accorting to relations. - */ - protected createViewModel( - model: M, - modelCtor: ViewModelConstructor, - relations: RelationDefinition[] - ): K { - const viewModel = new modelCtor(model) as K; - - // no reverse setting needed - relations.forEach(relation => { - this.setRelationsInViewModel(model, viewModel, relation); - }); - - return viewModel; - } - - /** - * Sets one foreign view model in the view model according to the relation and the information - * from the model. - */ - protected setRelationsInViewModel( - model: M, - viewModel: K, - relation: RelationDefinition - ): void { - if (relation.type === 'M2M' && model[relation.ownIdKey] instanceof Array) { - const foreignViewModels = this.viewModelStoreService.getMany( - relation.foreignModel, - model[relation.ownIdKey] - ); - viewModel['_' + relation.ownKey] = foreignViewModels; - } else if (relation.type === 'O2M') { - const foreignViewModel = this.viewModelStoreService.get(relation.foreignModel, model[relation.ownIdKey]); - viewModel['_' + relation.ownKey] = foreignViewModel; - } else if (relation.type === 'nested') { - const foreignViewModels: BaseViewModel[] = model[relation.ownKey].map(foreignModel => - this.createViewModel(foreignModel, relation.foreignModel, relation.relationDefinition || []) - ); - foreignViewModels.sort((a: BaseViewModel, b: BaseViewModel) => { - const order = relation.order; - if (!relation.order || a[order] === b[order]) { - return a.id - b.id; - } else { - return a[order] - b[order]; - } - }); - viewModel['_' + relation.ownKey] = foreignViewModels; - } else if (relation.type === 'custom') { - relation.setRelations(model, viewModel); - } - } - /** * Updates all models in this repository with all changed models. * * @param changedModels A mapping of collections to ids of all changed models. * @returns if at least one model was affected. */ - public updateDependencies(changedModels: CollectionIds): boolean { + public updateDependenciesForChangedModels(changedModels: CollectionIds): boolean { if (!this.relationDefinitions.length) { - return; + return false; } // Get all viewModels from this repo once. - const viewModels = this.getViewModelList(); - let somethingUpdated = false; + const ownViewModels = this.getViewModelList(); + const updatedIds = []; Object.keys(changedModels).forEach(collection => { const dependencyChanged: boolean = Object.keys(this.relationsByCollection).includes(collection); if (!dependencyChanged) { @@ -357,85 +254,79 @@ export abstract class BaseRepository { - const relations = this.relationsByCollection[collection]; - if (!relations || !relations.length) { - return; - } + const relations = this.relationsByCollection[collection]; + ownViewModels.forEach(ownViewModel => { relations.forEach(relation => { changedModels[collection].forEach(id => { - if (this.updateSingleDependency(ownViewModel, relation, collection, id)) { - somethingUpdated = true; + if ( + this.relationManager.updateSingleDependencyForChangedModel( + ownViewModel, + relation, + collection, + id + ) + ) { + updatedIds.push(ownViewModel.id); } }); }); }); - }); - if (somethingUpdated) { - viewModels.forEach(ownViewModel => { - this.updateViewModelObservable(ownViewModel.id); - }); - } - return somethingUpdated; - } - - /** - * Updates an own view model with an implicit given model by the collection and changedId. - * - * @return true, if something was updated. - */ - protected updateSingleDependency( - ownViewModel: BaseViewModel, - relation: RelationDefinition, - collection: string, - changedId: number - ): boolean { - if (relation.type === 'M2M') { - if ( - ownViewModel[relation.ownIdKey] && - ownViewModel[relation.ownIdKey] instanceof Array && - ownViewModel[relation.ownIdKey].includes(changedId) - ) { - const foreignViewModel = this.viewModelStoreService.get(collection, changedId); - let ownModelArray = ownViewModel['_' + relation.ownKey]; - if (!ownModelArray) { - ownViewModel['_' + relation.ownKey] = []; - ownModelArray = ownViewModel['_' + relation.ownKey]; - } - const index = ownModelArray.findIndex(user => user.id === changedId); - if (index < 0) { - ownModelArray.push(foreignViewModel); - } else { - ownModelArray[index] = foreignViewModel; - } - // TODO: set reverse - - return true; - } - } else if (relation.type === 'O2M') { - if (ownViewModel[relation.ownIdKey] === changedId) { - ownViewModel['_' + relation.ownKey] = this.viewModelStoreService.get(collection, changedId); - // TODO: set reverse - - return true; - } - } else if (relation.type === 'nested') { - let updated = false; - (relation.relationDefinition || []).forEach(nestedRelation => { - const nestedViewModels = ownViewModel[relation.ownKey] as BaseViewModel[]; - nestedViewModels.forEach(nestedViewModel => { - if (this.updateSingleDependency(nestedViewModel, nestedRelation, collection, changedId)) { - updated = true; + // Order all relations, if neeed. + if (updatedIds.length) { + relations.forEach(relation => { + if ( + (isNormalRelationDefinition(relation) || isReverseRelationDefinition(relation)) && + (relation.type === 'M2M' || relation.type === 'O2M') && + relation.order + ) { + ownViewModels.forEach(ownViewModel => { + if (ownViewModel['_' + relation.ownKey]) { + this.relationManager.sortByRelation(relation, ownViewModel); + } + }); } }); + } + + // Inform about changes. (List updates is done in `commitUpdate` via `DataStoreUpdateManagerService`) + updatedIds.forEach(id => { + this.updateViewModelObservable(id); }); - return updated; - } else if (relation.type === 'custom') { - const foreignViewModel = this.viewModelStoreService.get(collection, changedId); - return relation.updateDependency(ownViewModel, foreignViewModel); + }); + return !!updatedIds.length; + } + + public updateDependenciesForDeletedModels(deletedModels: CollectionIds): boolean { + if (!Object.keys(this.reverseRelationsByCollection).length) { + return false; } - return false; + // Get all viewModels from this repo once. + const ownViewModels = this.getViewModelList(); + let somethingChanged = false; + Object.keys(deletedModels).forEach(collection => { + const dependencyChanged: boolean = Object.keys(this.reverseRelationsByCollection).includes(collection); + if (!dependencyChanged) { + return; + } + + // Ok, we are affected by this collection. Update all viewModels from this repo. + const relations = this.reverseRelationsByCollection[collection]; + ownViewModels.forEach(ownViewModel => { + relations.forEach(relation => { + deletedModels[collection].forEach(id => { + if (this.relationManager.updateSingleDependencyForDeletedModel(ownViewModel, relation, id)) { + // Inform about changes. (List updates is done in `commitUpdate` via `DataStoreUpdateManagerService`) + this.updateViewModelObservable(id); + somethingChanged = true; + } + }); + }); + }); + // Ordering all relations is not needed, because just deleting things out of arrays + // will not unorder them. + }); + return somethingChanged; } /** diff --git a/client/src/app/core/repositories/config/config-repository.service.ts b/client/src/app/core/repositories/config/config-repository.service.ts index 99ac54c85..0c6fe3140 100644 --- a/client/src/app/core/repositories/config/config-repository.service.ts +++ b/client/src/app/core/repositories/config/config-repository.service.ts @@ -8,6 +8,7 @@ import { ConstantsService } from 'app/core/core-services/constants.service'; import { DataSendService } from 'app/core/core-services/data-send.service'; import { DataStoreService } from 'app/core/core-services/data-store.service'; import { HttpService } from 'app/core/core-services/http.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; import { BaseRepository } from 'app/core/repositories/base-repository'; import { Identifiable } from 'app/shared/models/base/identifiable'; @@ -112,10 +113,11 @@ export class ConfigRepositoryService extends BaseRepository { this.createConfigStructure(constant); diff --git a/client/src/app/core/repositories/mediafiles/mediafile-repository.service.ts b/client/src/app/core/repositories/mediafiles/mediafile-repository.service.ts index 184856e05..81f4b72a9 100644 --- a/client/src/app/core/repositories/mediafiles/mediafile-repository.service.ts +++ b/client/src/app/core/repositories/mediafiles/mediafile-repository.service.ts @@ -7,19 +7,20 @@ import { first, map } from 'rxjs/operators'; import { DataSendService } from 'app/core/core-services/data-send.service'; import { HttpService } from 'app/core/core-services/http.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; +import { RelationDefinition } from 'app/core/definitions/relations'; import { Identifiable } from 'app/shared/models/base/identifiable'; import { Mediafile } from 'app/shared/models/mediafiles/mediafile'; import { MediafileTitleInformation, ViewMediafile } from 'app/site/mediafiles/models/view-mediafile'; import { ViewGroup } from 'app/site/users/models/view-group'; import { BaseIsListOfSpeakersContentObjectRepository } from '../base-is-list-of-speakers-content-object-repository'; -import { RelationDefinition } from '../base-repository'; import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service'; import { DataStoreService } from '../../core-services/data-store.service'; const MediafileRelations: RelationDefinition[] = [ { - type: 'O2M', + type: 'M2O', ownIdKey: 'parent_id', ownKey: 'parent', foreignModel: ViewMediafile @@ -64,9 +65,19 @@ export class MediafileRepositoryService extends BaseIsListOfSpeakersContentObjec viewModelStoreService: ViewModelStoreService, translate: TranslateService, dataSend: DataSendService, + relationManager: RelationManagerService, private httpService: HttpService ) { - super(DS, dataSend, mapperService, viewModelStoreService, translate, Mediafile, MediafileRelations); + super( + DS, + dataSend, + mapperService, + viewModelStoreService, + translate, + relationManager, + Mediafile, + MediafileRelations + ); this.directoryBehaviorSubject = new BehaviorSubject([]); this.getViewModelListObservable().subscribe(mediafiles => { if (mediafiles) { diff --git a/client/src/app/core/repositories/motions/category-repository.service.ts b/client/src/app/core/repositories/motions/category-repository.service.ts index 7cdf5f515..e42e415f5 100644 --- a/client/src/app/core/repositories/motions/category-repository.service.ts +++ b/client/src/app/core/repositories/motions/category-repository.service.ts @@ -2,12 +2,14 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; +import { RelationDefinition } from 'app/core/definitions/relations'; import { TreeIdNode } from 'app/core/ui-services/tree.service'; import { Category } from 'app/shared/models/motions/category'; -import { Motion } from 'app/shared/models/motions/motion'; import { CategoryTitleInformation, ViewCategory } from 'app/site/motions/models/view-category'; -import { BaseRepository, RelationDefinition } from '../base-repository'; +import { ViewMotion } from 'app/site/motions/models/view-motion'; +import { BaseRepository } from '../base-repository'; import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service'; import { DataSendService } from '../../core-services/data-send.service'; import { DataStoreService } from '../../core-services/data-store.service'; @@ -15,10 +17,24 @@ import { HttpService } from '../../core-services/http.service'; const CategoryRelations: RelationDefinition[] = [ { - type: 'O2M', + type: 'M2O', ownIdKey: 'parent_id', ownKey: 'parent', foreignModel: ViewCategory + }, + { + type: 'O2M', + foreignIdKey: 'category_id', + ownKey: 'motions', + foreignModel: ViewMotion, + order: 'category_weight' + }, + { + type: 'O2M', + foreignIdKey: 'parent_id', + ownKey: 'children', + foreignModel: ViewCategory, + order: 'weight' } ]; @@ -54,9 +70,19 @@ export class CategoryRepositoryService extends BaseRepository a.weight - b.weight); } @@ -98,14 +124,4 @@ export class CategoryRepositoryService extends BaseRepository { await this.httpService.post('/rest/motions/category/sort_categories/', data); } - - /** - * Filter the DataStore by Motions and returns the amount of motions in the given category - * - * @param category the category - * @returns the number of motions inside the category - */ - public getMotionAmountByCategory(category: ViewCategory): number { - return this.DS.filter(Motion, motion => motion.category_id === category.id).length; - } } diff --git a/client/src/app/core/repositories/motions/change-recommendation-repository.service.ts b/client/src/app/core/repositories/motions/change-recommendation-repository.service.ts index edce8bee0..0149ad894 100644 --- a/client/src/app/core/repositories/motions/change-recommendation-repository.service.ts +++ b/client/src/app/core/repositories/motions/change-recommendation-repository.service.ts @@ -7,6 +7,7 @@ import { map } from 'rxjs/operators'; import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service'; import { DataSendService } from 'app/core/core-services/data-send.service'; import { DataStoreService } from 'app/core/core-services/data-store.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; import { Identifiable } from 'app/shared/models/base/identifiable'; import { MotionChangeRecommendation } from 'app/shared/models/motions/motion-change-reco'; @@ -56,9 +57,18 @@ export class ChangeRecommendationRepositoryService extends BaseRepository< mapperService: CollectionStringMapperService, viewModelStoreService: ViewModelStoreService, translate: TranslateService, + relationManager: RelationManagerService, private diffService: DiffService ) { - super(DS, dataSend, mapperService, viewModelStoreService, translate, MotionChangeRecommendation); + super( + DS, + dataSend, + mapperService, + viewModelStoreService, + translate, + relationManager, + MotionChangeRecommendation + ); } public getTitle = (titleInformation: MotionChangeRecommendationTitleInformation) => { diff --git a/client/src/app/core/repositories/motions/motion-block-repository.service.ts b/client/src/app/core/repositories/motions/motion-block-repository.service.ts index 1436dc92c..b6411a514 100644 --- a/client/src/app/core/repositories/motions/motion-block-repository.service.ts +++ b/client/src/app/core/repositories/motions/motion-block-repository.service.ts @@ -1,21 +1,29 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service'; import { DataSendService } from 'app/core/core-services/data-send.service'; import { DataStoreService } from 'app/core/core-services/data-store.service'; import { HttpService } from 'app/core/core-services/http.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; -import { Motion } from 'app/shared/models/motions/motion'; +import { RelationDefinition } from 'app/core/definitions/relations'; import { MotionBlock } from 'app/shared/models/motions/motion-block'; import { ViewMotion } from 'app/site/motions/models/view-motion'; import { MotionBlockTitleInformation, ViewMotionBlock } from 'app/site/motions/models/view-motion-block'; import { BaseIsAgendaItemAndListOfSpeakersContentObjectRepository } from '../base-is-agenda-item-and-list-of-speakers-content-object-repository'; import { MotionRepositoryService } from './motion-repository.service'; +const MotionBlockRelations: RelationDefinition[] = [ + { + type: 'O2M', + foreignIdKey: 'motion_block_id', + ownKey: 'motions', + foreignModel: ViewMotion + } +]; + /** * Repository service for motion blocks */ @@ -42,10 +50,20 @@ export class MotionBlockRepositoryService extends BaseIsAgendaItemAndListOfSpeak mapperService: CollectionStringMapperService, viewModelStoreService: ViewModelStoreService, translate: TranslateService, + relationManager: RelationManagerService, private motionRepo: MotionRepositoryService, private httpService: HttpService ) { - super(DS, dataSend, mapperService, viewModelStoreService, translate, MotionBlock); + super( + DS, + dataSend, + mapperService, + viewModelStoreService, + translate, + relationManager, + MotionBlock, + MotionBlockRelations + ); this.initSorting(); } @@ -68,29 +86,6 @@ export class MotionBlockRepositoryService extends BaseIsAgendaItemAndListOfSpeak this.motionRepo.update(updateMotion, viewMotion); } - /** - * Filter the DataStore by Motions and returns the - * - * @param block the motion block - * @returns the number of motions inside a motion block - */ - public getMotionAmountByBlock(block: MotionBlock): number { - return this.DS.filter(Motion, motion => motion.motion_block_id === block.id).length; - } - - /** - * Observe the motion repository and return the motions belonging to the given - * block as observable - * - * @param block a motion block - * @returns an observable to view motions - */ - public getViewMotionsByBlock(block: MotionBlock): Observable { - return this.motionRepo - .getViewModelListObservable() - .pipe(map(viewMotions => viewMotions.filter(viewMotion => viewMotion.motion_block_id === block.id))); - } - /** * Retrieves motion blocks by name * diff --git a/client/src/app/core/repositories/motions/motion-comment-section-repository.service.ts b/client/src/app/core/repositories/motions/motion-comment-section-repository.service.ts index 5c3aec650..ef64e7aa9 100644 --- a/client/src/app/core/repositories/motions/motion-comment-section-repository.service.ts +++ b/client/src/app/core/repositories/motions/motion-comment-section-repository.service.ts @@ -3,7 +3,9 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { HttpService } from 'app/core/core-services/http.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; +import { RelationDefinition } from 'app/core/definitions/relations'; import { MotionCommentSection } from 'app/shared/models/motions/motion-comment-section'; import { ViewMotion } from 'app/site/motions/models/view-motion'; import { @@ -11,7 +13,7 @@ import { ViewMotionCommentSection } from 'app/site/motions/models/view-motion-comment-section'; import { ViewGroup } from 'app/site/users/models/view-group'; -import { BaseRepository, RelationDefinition } from '../base-repository'; +import { BaseRepository } from '../base-repository'; import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service'; import { DataSendService } from '../../core-services/data-send.service'; import { DataStoreService } from '../../core-services/data-store.service'; @@ -65,6 +67,7 @@ export class MotionCommentSectionRepositoryService extends BaseRepository< mapperService: CollectionStringMapperService, viewModelStoreService: ViewModelStoreService, translate: TranslateService, + relationManager: RelationManagerService, private http: HttpService ) { super( @@ -73,6 +76,7 @@ export class MotionCommentSectionRepositoryService extends BaseRepository< mapperService, viewModelStoreService, translate, + relationManager, MotionCommentSection, MotionCommentSectionRelations ); diff --git a/client/src/app/core/repositories/motions/motion-repository.service.ts b/client/src/app/core/repositories/motions/motion-repository.service.ts index 74b0b4b6f..d55bf1e38 100644 --- a/client/src/app/core/repositories/motions/motion-repository.service.ts +++ b/client/src/app/core/repositories/motions/motion-repository.service.ts @@ -8,7 +8,9 @@ import { map } from 'rxjs/operators'; import { DataStoreService } from 'app/core/core-services/data-store.service'; import { HttpService } from 'app/core/core-services/http.service'; import { OperatorService } from 'app/core/core-services/operator.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; +import { RelationDefinition } from 'app/core/definitions/relations'; import { ConfigService } from 'app/core/ui-services/config.service'; import { DiffLinesInParagraph, DiffService } from 'app/core/ui-services/diff.service'; import { TreeIdNode } from 'app/core/ui-services/tree.service'; @@ -30,7 +32,6 @@ import { ViewTag } from 'app/site/tags/models/view-tag'; import { ViewPersonalNote } from 'app/site/users/models/view-personal-note'; import { ViewUser } from 'app/site/users/models/view-user'; import { BaseIsAgendaItemAndListOfSpeakersContentObjectRepository } from '../base-is-agenda-item-and-list-of-speakers-content-object-repository'; -import { RelationDefinition } from '../base-repository'; import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service'; import { DataSendService } from '../../core-services/data-send.service'; import { LinenumberingService, LineNumberRange } from '../../ui-services/linenumbering.service'; @@ -69,31 +70,31 @@ export interface ParagraphToChoose { const MotionRelations: RelationDefinition[] = [ { - type: 'O2M', + type: 'M2O', ownIdKey: 'state_id', ownKey: 'state', foreignModel: ViewState }, { - type: 'O2M', + type: 'M2O', ownIdKey: 'recommendation_id', ownKey: 'recommendation', foreignModel: ViewState }, { - type: 'O2M', + type: 'M2O', ownIdKey: 'workflow_id', ownKey: 'workflow', foreignModel: ViewWorkflow }, { - type: 'O2M', + type: 'M2O', ownIdKey: 'category_id', ownKey: 'category', foreignModel: ViewCategory }, { - type: 'O2M', + type: 'M2O', ownIdKey: 'motion_block_id', ownKey: 'motion_block', foreignModel: ViewMotionBlock @@ -105,7 +106,7 @@ const MotionRelations: RelationDefinition[] = [ order: 'weight', relationDefinition: [ { - type: 'O2M', + type: 'M2O', ownIdKey: 'user_id', ownKey: 'user', foreignModel: ViewUser @@ -131,7 +132,7 @@ const MotionRelations: RelationDefinition[] = [ foreignModel: ViewTag }, { - type: 'O2M', + type: 'M2O', ownIdKey: 'parent_id', ownKey: 'parent', foreignModel: ViewMotion @@ -190,6 +191,7 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo mapperService: CollectionStringMapperService, viewModelStoreService: ViewModelStoreService, translate: TranslateService, + relationManager: RelationManagerService, config: ConfigService, private httpService: HttpService, private readonly sanitizer: DomSanitizer, @@ -197,7 +199,7 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo private readonly diff: DiffService, private operator: OperatorService ) { - super(DS, dataSend, mapperService, viewModelStoreService, translate, Motion, MotionRelations); + super(DS, dataSend, mapperService, viewModelStoreService, translate, relationManager, Motion, MotionRelations); config.get('motions_motions_sorting').subscribe(conf => { this.sortProperty = conf; this.setConfigSortFn(); diff --git a/client/src/app/core/repositories/motions/state-repository.service.ts b/client/src/app/core/repositories/motions/state-repository.service.ts index 550d18c23..e931e9d4a 100644 --- a/client/src/app/core/repositories/motions/state-repository.service.ts +++ b/client/src/app/core/repositories/motions/state-repository.service.ts @@ -2,18 +2,20 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; +import { RelationDefinition } from 'app/core/definitions/relations'; import { State } from 'app/shared/models/motions/state'; import { StateTitleInformation, ViewState } from 'app/site/motions/models/view-state'; import { ViewWorkflow, WorkflowTitleInformation } from 'app/site/motions/models/view-workflow'; -import { BaseRepository, RelationDefinition } from '../base-repository'; +import { BaseRepository } from '../base-repository'; import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service'; import { DataSendService } from '../../core-services/data-send.service'; import { DataStoreService } from '../../core-services/data-store.service'; const StateRelations: RelationDefinition[] = [ { - type: 'O2M', + type: 'M2O', ownIdKey: 'workflow_id', ownKey: 'workflow', foreignModel: ViewWorkflow @@ -54,9 +56,10 @@ export class StateRepositoryService extends BaseRepository { diff --git a/client/src/app/core/repositories/motions/statute-paragraph-repository.service.ts b/client/src/app/core/repositories/motions/statute-paragraph-repository.service.ts index ee10005e1..0b37f0b69 100644 --- a/client/src/app/core/repositories/motions/statute-paragraph-repository.service.ts +++ b/client/src/app/core/repositories/motions/statute-paragraph-repository.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; import { StatuteParagraph } from 'app/shared/models/motions/statute-paragraph'; import { StatuteParagraphTitleInformation, ViewStatuteParagraph } from 'app/site/motions/models/view-statute-paragraph'; @@ -39,9 +40,10 @@ export class StatuteParagraphRepositoryService extends BaseRepository< dataSend: DataSendService, mapperService: CollectionStringMapperService, viewModelStoreService: ViewModelStoreService, - translate: TranslateService + translate: TranslateService, + relationManager: RelationManagerService ) { - super(DS, dataSend, mapperService, viewModelStoreService, translate, StatuteParagraph); + super(DS, dataSend, mapperService, viewModelStoreService, translate, relationManager, StatuteParagraph); } public getTitle = (titleInformation: StatuteParagraphTitleInformation) => { diff --git a/client/src/app/core/repositories/motions/workflow-repository.service.ts b/client/src/app/core/repositories/motions/workflow-repository.service.ts index fa840a3b1..47707bc55 100644 --- a/client/src/app/core/repositories/motions/workflow-repository.service.ts +++ b/client/src/app/core/repositories/motions/workflow-repository.service.ts @@ -2,12 +2,14 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; +import { RelationDefinition } from 'app/core/definitions/relations'; import { Workflow } from 'app/shared/models/motions/workflow'; import { ViewMotion } from 'app/site/motions/models/view-motion'; import { ViewState } from 'app/site/motions/models/view-state'; import { ViewWorkflow, WorkflowTitleInformation } from 'app/site/motions/models/view-workflow'; -import { BaseRepository, RelationDefinition } from '../base-repository'; +import { BaseRepository } from '../base-repository'; import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service'; import { DataSendService } from '../../core-services/data-send.service'; import { DataStoreService } from '../../core-services/data-store.service'; @@ -20,7 +22,7 @@ const WorkflowRelations: RelationDefinition[] = [ foreignModel: ViewState }, { - type: 'O2M', + type: 'M2O', ownIdKey: 'first_state_id', ownKey: 'first_state', foreignModel: ViewState @@ -55,9 +57,19 @@ export class WorkflowRepositoryService extends BaseRepository { diff --git a/client/src/app/core/repositories/projector/countdown-repository.service.ts b/client/src/app/core/repositories/projector/countdown-repository.service.ts index 5f1fc78dc..f8d9e4a3d 100644 --- a/client/src/app/core/repositories/projector/countdown-repository.service.ts +++ b/client/src/app/core/repositories/projector/countdown-repository.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ServertimeService } from 'app/core/core-services/servertime.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; import { Countdown } from 'app/shared/models/core/countdown'; @@ -21,9 +22,10 @@ export class CountdownRepositoryService extends BaseRepository { diff --git a/client/src/app/core/repositories/projector/projection-default-repository.service.ts b/client/src/app/core/repositories/projector/projection-default-repository.service.ts index f85649248..928ba7f5b 100644 --- a/client/src/app/core/repositories/projector/projection-default-repository.service.ts +++ b/client/src/app/core/repositories/projector/projection-default-repository.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; import { Identifiable } from 'app/shared/models/base/identifiable'; import { ProjectionDefault } from 'app/shared/models/core/projection-default'; @@ -39,9 +40,10 @@ export class ProjectionDefaultRepositoryService extends BaseRepository< dataSend: DataSendService, mapperService: CollectionStringMapperService, viewModelStoreService: ViewModelStoreService, - translate: TranslateService + translate: TranslateService, + relationManager: RelationManagerService ) { - super(DS, dataSend, mapperService, viewModelStoreService, translate, ProjectionDefault); + super(DS, dataSend, mapperService, viewModelStoreService, translate, relationManager, ProjectionDefault); } public getVerboseName = (plural: boolean = false) => { diff --git a/client/src/app/core/repositories/projector/projector-message-repository.service.ts b/client/src/app/core/repositories/projector/projector-message-repository.service.ts index 18a886b0d..11d092f14 100644 --- a/client/src/app/core/repositories/projector/projector-message-repository.service.ts +++ b/client/src/app/core/repositories/projector/projector-message-repository.service.ts @@ -3,6 +3,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { DataSendService } from 'app/core/core-services/data-send.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; import { ProjectorMessage } from 'app/shared/models/core/projector-message'; import { @@ -26,9 +27,10 @@ export class ProjectorMessageRepositoryService extends BaseRepository< dataSend: DataSendService, mapperService: CollectionStringMapperService, viewModelStoreService: ViewModelStoreService, - translate: TranslateService + translate: TranslateService, + relationManager: RelationManagerService ) { - super(DS, dataSend, mapperService, viewModelStoreService, translate, ProjectorMessage); + super(DS, dataSend, mapperService, viewModelStoreService, translate, relationManager, ProjectorMessage); } public getTitle = (titleInformation: ProjectorMessageTitleInformation) => { diff --git a/client/src/app/core/repositories/projector/projector-repository.service.ts b/client/src/app/core/repositories/projector/projector-repository.service.ts index 65090bf0c..32fe13801 100644 --- a/client/src/app/core/repositories/projector/projector-repository.service.ts +++ b/client/src/app/core/repositories/projector/projector-repository.service.ts @@ -3,11 +3,13 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { HttpService } from 'app/core/core-services/http.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; +import { RelationDefinition } from 'app/core/definitions/relations'; import { Identifiable } from 'app/shared/models/base/identifiable'; import { Projector } from 'app/shared/models/core/projector'; import { ProjectorTitleInformation, ViewProjector } from 'app/site/projector/models/view-projector'; -import { BaseRepository, RelationDefinition } from '../base-repository'; +import { BaseRepository } from '../base-repository'; import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service'; import { DataSendService } from '../../core-services/data-send.service'; import { DataStoreService } from '../../core-services/data-store.service'; @@ -23,7 +25,7 @@ export enum ScrollScaleDirection { const ProjectorRelations: RelationDefinition[] = [ { - type: 'O2M', + type: 'M2O', ownIdKey: 'reference_projector_id', ownKey: 'referenceProjector', foreignModel: ViewProjector @@ -51,9 +53,19 @@ export class ProjectorRepositoryService extends BaseRepository { diff --git a/client/src/app/core/repositories/tags/tag-repository.service.ts b/client/src/app/core/repositories/tags/tag-repository.service.ts index 85cd63f65..d47c48589 100644 --- a/client/src/app/core/repositories/tags/tag-repository.service.ts +++ b/client/src/app/core/repositories/tags/tag-repository.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; import { Tag } from 'app/shared/models/core/tag'; import { TagTitleInformation, ViewTag } from 'app/site/tags/models/view-tag'; @@ -38,9 +39,10 @@ export class TagRepositoryService extends BaseRepository { diff --git a/client/src/app/core/repositories/users/group-repository.service.ts b/client/src/app/core/repositories/users/group-repository.service.ts index fb0d920f0..7263e5829 100644 --- a/client/src/app/core/repositories/users/group-repository.service.ts +++ b/client/src/app/core/repositories/users/group-repository.service.ts @@ -3,6 +3,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { HttpService } from 'app/core/core-services/http.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; import { Group } from 'app/shared/models/users/group'; import { GroupTitleInformation, ViewGroup } from 'app/site/users/models/view-group'; @@ -55,10 +56,11 @@ export class GroupRepositoryService extends BaseRepository { diff --git a/client/src/app/core/repositories/users/user-repository.service.ts b/client/src/app/core/repositories/users/user-repository.service.ts index af6a2c45e..8f6581f92 100644 --- a/client/src/app/core/repositories/users/user-repository.service.ts +++ b/client/src/app/core/repositories/users/user-repository.service.ts @@ -3,13 +3,15 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { HttpService } from 'app/core/core-services/http.service'; +import { RelationManagerService } from 'app/core/core-services/relation-manager.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; +import { RelationDefinition } from 'app/core/definitions/relations'; import { NewEntry } from 'app/core/ui-services/base-import.service'; import { ConfigService } from 'app/core/ui-services/config.service'; import { User } from 'app/shared/models/users/user'; import { ViewGroup } from 'app/site/users/models/view-group'; import { UserTitleInformation, ViewUser } from 'app/site/users/models/view-user'; -import { BaseRepository, RelationDefinition } from '../base-repository'; +import { BaseRepository } from '../base-repository'; import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service'; import { DataSendService } from '../../core-services/data-send.service'; import { DataStoreService } from '../../core-services/data-store.service'; @@ -61,11 +63,12 @@ export class UserRepositoryService extends BaseRepository('users_sort_by').subscribe(conf => { this.sortProperty = conf; diff --git a/client/src/app/core/marked-translations.ts b/client/src/app/core/translate/marked-translations.ts similarity index 100% rename from client/src/app/core/marked-translations.ts rename to client/src/app/core/translate/marked-translations.ts diff --git a/client/src/app/shared/models/base/base-model-with-content-object.ts b/client/src/app/shared/models/base/base-model-with-content-object.ts index 1228e5115..b0958ff23 100644 --- a/client/src/app/shared/models/base/base-model-with-content-object.ts +++ b/client/src/app/shared/models/base/base-model-with-content-object.ts @@ -6,4 +6,8 @@ import { ContentObject } from './content-object'; */ export abstract class BaseModelWithContentObject extends BaseModel { public abstract content_object: ContentObject; + + public get contentObjectData(): ContentObject { + return this.content_object; + } } diff --git a/client/src/app/site/agenda/agenda.config.ts b/client/src/app/site/agenda/agenda.config.ts index 63f81809b..757dacae3 100644 --- a/client/src/app/site/agenda/agenda.config.ts +++ b/client/src/app/site/agenda/agenda.config.ts @@ -1,4 +1,4 @@ -import { AppConfig } from '../../core/app-config'; +import { AppConfig } from '../../core/definitions/app-config'; import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service'; import { ListOfSpeakersRepositoryService } from 'app/core/repositories/agenda/list-of-speakers-repository.service'; import { ListOfSpeakers } from 'app/shared/models/agenda/list-of-speakers'; diff --git a/client/src/app/site/agenda/models/view-item.ts b/client/src/app/site/agenda/models/view-item.ts index 4ef6fd8de..be888e9f7 100644 --- a/client/src/app/site/agenda/models/view-item.ts +++ b/client/src/app/site/agenda/models/view-item.ts @@ -12,6 +12,7 @@ export interface ItemTitleInformation { export class ViewItem extends BaseViewModelWithContentObject implements ItemTitleInformation { public static COLLECTIONSTRING = Item.COLLECTIONSTRING; + protected _collectionString = Item.COLLECTIONSTRING; public get item(): Item { return this._model; @@ -83,8 +84,4 @@ export class ViewItem extends BaseViewModelWithContentObject implements ListOfSpeakersTitleInformation, Projectable { public static COLLECTIONSTRING = ListOfSpeakers.COLLECTIONSTRING; + protected _collectionString = ListOfSpeakers.COLLECTIONSTRING; private _speakers?: ViewSpeaker[]; @@ -48,10 +48,6 @@ export class ViewListOfSpeakers extends BaseViewModelWithContentObject { public static COLLECTIONSTRING = Speaker.COLLECTIONSTRING; + protected _collectionString = Speaker.COLLECTIONSTRING; + private _user?: ViewUser; public get speaker(): Speaker { @@ -80,10 +82,6 @@ export class ViewSpeaker extends BaseViewModel { return this.user ? this.user.gender : ''; } - public constructor(speaker: Speaker) { - super(Speaker.COLLECTIONSTRING, speaker); - } - public getTitle = () => { return this.name; }; diff --git a/client/src/app/site/assignments/assignments.config.ts b/client/src/app/site/assignments/assignments.config.ts index d504e457d..6826f666a 100644 --- a/client/src/app/site/assignments/assignments.config.ts +++ b/client/src/app/site/assignments/assignments.config.ts @@ -1,4 +1,4 @@ -import { AppConfig } from '../../core/app-config'; +import { AppConfig } from '../../core/definitions/app-config'; import { AssignmentRepositoryService } from 'app/core/repositories/assignments/assignment-repository.service'; import { Assignment } from '../../shared/models/assignments/assignment'; import { ViewAssignment } from './models/view-assignment'; diff --git a/client/src/app/site/assignments/models/view-assignment-poll-option.ts b/client/src/app/site/assignments/models/view-assignment-poll-option.ts index 9a7c606ca..508f23c15 100644 --- a/client/src/app/site/assignments/models/view-assignment-poll-option.ts +++ b/client/src/app/site/assignments/models/view-assignment-poll-option.ts @@ -10,6 +10,8 @@ const votesOrder: PollVoteValue[] = ['Votes', 'Yes', 'No', 'Abstain']; export class ViewAssignmentPollOption extends BaseViewModel { public static COLLECTIONSTRING = AssignmentPollOption.COLLECTIONSTRING; + protected _collectionString = AssignmentPollOption.COLLECTIONSTRING; + private _user?: ViewUser; // This is the "candidate". We'll stay consistent wich user here... public get option(): AssignmentPollOption { @@ -49,8 +51,4 @@ export class ViewAssignmentPollOption extends BaseViewModel { public static COLLECTIONSTRING = AssignmentPoll.COLLECTIONSTRING; + protected _collectionString = AssignmentPoll.COLLECTIONSTRING; + private _options: ViewAssignmentPollOption[]; public get poll(): AssignmentPoll { @@ -76,10 +78,6 @@ export class ViewAssignmentPoll extends BaseProjectableViewModel return this.poll.assignment_id; } - public constructor(assignmentPoll: AssignmentPoll) { - super(AssignmentPoll.COLLECTIONSTRING, assignmentPoll); - } - public getTitle = () => { return 'Poll'; }; diff --git a/client/src/app/site/assignments/models/view-assignment-related-user.ts b/client/src/app/site/assignments/models/view-assignment-related-user.ts index bba9a4ceb..16db71261 100644 --- a/client/src/app/site/assignments/models/view-assignment-related-user.ts +++ b/client/src/app/site/assignments/models/view-assignment-related-user.ts @@ -4,6 +4,7 @@ import { ViewUser } from 'app/site/users/models/view-user'; export class ViewAssignmentRelatedUser extends BaseViewModel { public static COLLECTIONSTRING = AssignmentRelatedUser.COLLECTIONSTRING; + protected _collectionString = AssignmentRelatedUser.COLLECTIONSTRING; private _user?: ViewUser; @@ -37,10 +38,6 @@ export class ViewAssignmentRelatedUser extends BaseViewModel string = this.getTitle; - public constructor(assignmentRelatedUser: AssignmentRelatedUser) { - super(AssignmentRelatedUser.COLLECTIONSTRING, assignmentRelatedUser); - } - public getTitle: () => string = () => { return this.user ? this.user.getFullName() : ''; }; diff --git a/client/src/app/site/assignments/models/view-assignment.ts b/client/src/app/site/assignments/models/view-assignment.ts index 2b1a29027..28a4de0b4 100644 --- a/client/src/app/site/assignments/models/view-assignment.ts +++ b/client/src/app/site/assignments/models/view-assignment.ts @@ -39,6 +39,7 @@ export const AssignmentPhases: { name: string; value: number; display_name: stri export class ViewAssignment extends BaseViewModelWithAgendaItemAndListOfSpeakers implements AssignmentTitleInformation { public static COLLECTIONSTRING = Assignment.COLLECTIONSTRING; + protected _collectionString = Assignment.COLLECTIONSTRING; private _assignment_related_users?: ViewAssignmentRelatedUser[]; private _polls?: ViewAssignmentPoll[]; @@ -125,10 +126,6 @@ export class ViewAssignment extends BaseViewModelWithAgendaItemAndListOfSpeakers return this._assignment_related_users ? this._assignment_related_users.length : 0; } - public constructor(assignment: Assignment) { - super(Assignment.COLLECTIONSTRING, assignment); - } - public formatForSearch(): SearchRepresentation { return [this.title]; } diff --git a/client/src/app/site/base/base-view-model-with-agenda-item-and-list-of-speakers.ts b/client/src/app/site/base/base-view-model-with-agenda-item-and-list-of-speakers.ts index 1eb2bd469..6b7c62aa2 100644 --- a/client/src/app/site/base/base-view-model-with-agenda-item-and-list-of-speakers.ts +++ b/client/src/app/site/base/base-view-model-with-agenda-item-and-list-of-speakers.ts @@ -49,10 +49,6 @@ export abstract class BaseViewModelWithAgendaItemAndListOfSpeakers< public getListOfSpeakersTitle: () => string; public getListOfSpeakersSlideTitle: () => string; - public constructor(collectionString: string, model: M) { - super(collectionString, model); - } - /** * @returns the (optional) descriptive text to be exported in the CSV. * May be overridden by inheriting classes diff --git a/client/src/app/site/base/base-view-model-with-agenda-item.ts b/client/src/app/site/base/base-view-model-with-agenda-item.ts index e8ff90b9c..31e796cfd 100644 --- a/client/src/app/site/base/base-view-model-with-agenda-item.ts +++ b/client/src/app/site/base/base-view-model-with-agenda-item.ts @@ -85,8 +85,8 @@ export abstract class BaseViewModelWithAgendaItem string; - public constructor(collecitonString: string, model: M, item?: any) { - super(collecitonString, model); + public constructor(model: M, item?: any) { + super(model); this._item = item || null; // Explicit set to null instead of undefined, if not given } diff --git a/client/src/app/site/base/base-view-model-with-content-object.ts b/client/src/app/site/base/base-view-model-with-content-object.ts index 51cc22e8b..a56677eeb 100644 --- a/client/src/app/site/base/base-view-model-with-content-object.ts +++ b/client/src/app/site/base/base-view-model-with-content-object.ts @@ -22,12 +22,4 @@ export abstract class BaseViewModelWithContentObject< public get contentObject(): C | null { return this._contentObject; } - - /** - * @param collectionString The collection string of this model - * @param model the model this view model captures - */ - public constructor(collectionString: string, model: M) { - super(collectionString, model); - } } diff --git a/client/src/app/site/base/base-view-model-with-list-of-speakers.ts b/client/src/app/site/base/base-view-model-with-list-of-speakers.ts index 26f439702..2d005f10b 100644 --- a/client/src/app/site/base/base-view-model-with-list-of-speakers.ts +++ b/client/src/app/site/base/base-view-model-with-list-of-speakers.ts @@ -49,8 +49,8 @@ export abstract class BaseViewModelWithListOfSpeakers string; public getListOfSpeakersSlideTitle: () => string; - public constructor(collectionString: string, model: M, listOfSpeakers?: any) { - super(collectionString, model); + public constructor(model: M, listOfSpeakers?: any) { + super(model); this._list_of_speakers = listOfSpeakers || null; // Explicit set to null instead of undefined, if not given } diff --git a/client/src/app/site/base/base-view-model.ts b/client/src/app/site/base/base-view-model.ts index 3d545772c..53ddf92de 100644 --- a/client/src/app/site/base/base-view-model.ts +++ b/client/src/app/site/base/base-view-model.ts @@ -14,8 +14,6 @@ export interface ViewModelConstructor { * Base class for view models. alls view models should have titles. */ export abstract class BaseViewModel implements Displayable, Identifiable, Collection { - protected _model: M; - public get id(): number { return this._model.id; } @@ -58,10 +56,7 @@ export abstract class BaseViewModel implements Displa * @param collectionString * @param model */ - public constructor(collectionString: string, model: M) { - this._collectionString = collectionString; - this._model = model; - } + public constructor(protected _model: M) {} /** * @returns the main underlying model of the view model diff --git a/client/src/app/site/common/common.config.ts b/client/src/app/site/common/common.config.ts index 65ac0c907..554777767 100644 --- a/client/src/app/site/common/common.config.ts +++ b/client/src/app/site/common/common.config.ts @@ -1,4 +1,4 @@ -import { AppConfig } from '../../core/app-config'; +import { AppConfig } from '../../core/definitions/app-config'; export const CommonAppConfig: AppConfig = { name: 'common', diff --git a/client/src/app/site/config/config.config.ts b/client/src/app/site/config/config.config.ts index f31a79e08..6208dad30 100644 --- a/client/src/app/site/config/config.config.ts +++ b/client/src/app/site/config/config.config.ts @@ -1,4 +1,4 @@ -import { AppConfig } from '../../core/app-config'; +import { AppConfig } from '../../core/definitions/app-config'; import { Config } from '../../shared/models/core/config'; import { ConfigRepositoryService } from '../../core/repositories/config/config-repository.service'; import { ViewConfig } from './models/view-config'; diff --git a/client/src/app/site/config/models/view-config.ts b/client/src/app/site/config/models/view-config.ts index 7addb905c..5c206725d 100644 --- a/client/src/app/site/config/models/view-config.ts +++ b/client/src/app/site/config/models/view-config.ts @@ -41,6 +41,7 @@ export interface ConfigTitleInformation { */ export class ViewConfig extends BaseViewModel implements ConfigTitleInformation { public static COLLECTIONSTRING = Config.COLLECTIONSTRING; + protected _collectionString = Config.COLLECTIONSTRING; /* This private members are set by setConstantsInfo. */ private _helpText: string; @@ -90,10 +91,6 @@ export class ViewConfig extends BaseViewModel implements ConfigTitleInfo return this._defaultValue; } - public constructor(config: Config) { - super(Config.COLLECTIONSTRING, config); - } - /** * Returns the time this config field needs to debounce before sending a request to the server. * A little debounce time for all inputs is given here and is usefull, if inputs sends multiple onChange-events, diff --git a/client/src/app/site/history/history.config.ts b/client/src/app/site/history/history.config.ts index 27450eea1..01f77edd4 100644 --- a/client/src/app/site/history/history.config.ts +++ b/client/src/app/site/history/history.config.ts @@ -1,4 +1,4 @@ -import { AppConfig } from '../../core/app-config'; +import { AppConfig } from '../../core/definitions/app-config'; /** * Config object for history. diff --git a/client/src/app/site/mediafiles/mediafile.config.ts b/client/src/app/site/mediafiles/mediafile.config.ts index 5c408ac97..0df6a7fa0 100644 --- a/client/src/app/site/mediafiles/mediafile.config.ts +++ b/client/src/app/site/mediafiles/mediafile.config.ts @@ -1,4 +1,4 @@ -import { AppConfig } from '../../core/app-config'; +import { AppConfig } from '../../core/definitions/app-config'; import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service'; import { Mediafile } from '../../shared/models/mediafiles/mediafile'; import { ViewMediafile } from './models/view-mediafile'; diff --git a/client/src/app/site/mediafiles/models/view-mediafile.ts b/client/src/app/site/mediafiles/models/view-mediafile.ts index a2766b77b..e2d9dca68 100644 --- a/client/src/app/site/mediafiles/models/view-mediafile.ts +++ b/client/src/app/site/mediafiles/models/view-mediafile.ts @@ -16,6 +16,7 @@ export interface MediafileTitleInformation { export class ViewMediafile extends BaseViewModelWithListOfSpeakers implements MediafileTitleInformation, Searchable { public static COLLECTIONSTRING = Mediafile.COLLECTIONSTRING; + protected _collectionString = Mediafile.COLLECTIONSTRING; private _parent?: ViewMediafile; private _access_groups?: ViewGroup[]; @@ -101,10 +102,6 @@ export class ViewMediafile extends BaseViewModelWithListOfSpeakers return this.mediafile.create_timestamp ? this.mediafile.create_timestamp : null; } - public constructor(mediafile: Mediafile) { - super(Mediafile.COLLECTIONSTRING, mediafile); - } - public formatForSearch(): SearchRepresentation { return [this.title, this.path]; } diff --git a/client/src/app/site/motions/models/view-category.ts b/client/src/app/site/motions/models/view-category.ts index 17064a79a..7854a2b08 100644 --- a/client/src/app/site/motions/models/view-category.ts +++ b/client/src/app/site/motions/models/view-category.ts @@ -2,6 +2,7 @@ import { SearchRepresentation } from 'app/core/ui-services/search.service'; import { Category } from 'app/shared/models/motions/category'; import { Searchable } from 'app/site/base/searchable'; import { BaseViewModel } from '../../base/base-view-model'; +import { ViewMotion } from './view-motion'; export interface CategoryTitleInformation { prefix: string; @@ -17,8 +18,11 @@ export interface CategoryTitleInformation { */ export class ViewCategory extends BaseViewModel implements CategoryTitleInformation, Searchable { public static COLLECTIONSTRING = Category.COLLECTIONSTRING; + protected _collectionString = Category.COLLECTIONSTRING; private _parent?: ViewCategory; + private _children?: ViewCategory[]; + private _motions?: ViewMotion[]; public get category(): Category { return this._model; @@ -28,6 +32,14 @@ export class ViewCategory extends BaseViewModel implements CategoryTit return this._parent; } + public get children(): ViewCategory[] { + return this._children || []; + } + + public get motions(): ViewMotion[] { + return this._motions || []; + } + public get name(): string { return this.category.name; } @@ -75,10 +87,6 @@ export class ViewCategory extends BaseViewModel implements CategoryTit } } - public constructor(category: Category) { - super(Category.COLLECTIONSTRING, category); - } - public formatForSearch(): SearchRepresentation { return [this.name, this.prefix]; } diff --git a/client/src/app/site/motions/models/view-motion-block.ts b/client/src/app/site/motions/models/view-motion-block.ts index ff1bb8d6a..86cab032b 100644 --- a/client/src/app/site/motions/models/view-motion-block.ts +++ b/client/src/app/site/motions/models/view-motion-block.ts @@ -4,6 +4,7 @@ import { TitleInformationWithAgendaItem } from 'app/site/base/base-view-model-wi import { BaseViewModelWithAgendaItemAndListOfSpeakers } from 'app/site/base/base-view-model-with-agenda-item-and-list-of-speakers'; import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable'; import { Searchable } from 'app/site/base/searchable'; +import { ViewMotion } from './view-motion'; export interface MotionBlockTitleInformation extends TitleInformationWithAgendaItem { title: string; @@ -16,10 +17,16 @@ export interface MotionBlockTitleInformation extends TitleInformationWithAgendaI export class ViewMotionBlock extends BaseViewModelWithAgendaItemAndListOfSpeakers implements MotionBlockTitleInformation, Searchable { public static COLLECTIONSTRING = MotionBlock.COLLECTIONSTRING; + protected _collectionString = MotionBlock.COLLECTIONSTRING; + + private _motions?: ViewMotion[]; public get motionBlock(): MotionBlock { return this._model; } + public get motions(): ViewMotion[] { + return this._motions || []; + } public get title(): string { return this.motionBlock.title; @@ -29,10 +36,6 @@ export class ViewMotionBlock extends BaseViewModelWithAgendaItemAndListOfSpeaker return this.motionBlock.internal; } - public constructor(motionBlock: MotionBlock) { - super(MotionBlock.COLLECTIONSTRING, motionBlock); - } - /** * Formats the category for search * diff --git a/client/src/app/site/motions/models/view-motion-change-recommendation.ts b/client/src/app/site/motions/models/view-motion-change-recommendation.ts index 590d2c2d5..f3a4c0009 100644 --- a/client/src/app/site/motions/models/view-motion-change-recommendation.ts +++ b/client/src/app/site/motions/models/view-motion-change-recommendation.ts @@ -15,15 +15,12 @@ export type MotionChangeRecommendationTitleInformation = object; export class ViewMotionChangeRecommendation extends BaseViewModel implements MotionChangeRecommendationTitleInformation, ViewUnifiedChange { public static COLLECTIONSTRING = MotionChangeRecommendation.COLLECTIONSTRING; + protected _collectionString = MotionChangeRecommendation.COLLECTIONSTRING; public get changeRecommendation(): MotionChangeRecommendation { return this._model; } - public constructor(motionChangeRecommendation: MotionChangeRecommendation) { - super(MotionChangeRecommendation.COLLECTIONSTRING, motionChangeRecommendation); - } - public updateChangeReco(type: number, text: string, internal: boolean): void { // @TODO HTML sanitazion this.changeRecommendation.type = type; diff --git a/client/src/app/site/motions/models/view-motion-comment-section.ts b/client/src/app/site/motions/models/view-motion-comment-section.ts index f5894c520..dfde766b5 100644 --- a/client/src/app/site/motions/models/view-motion-comment-section.ts +++ b/client/src/app/site/motions/models/view-motion-comment-section.ts @@ -16,6 +16,7 @@ export interface MotionCommentSectionTitleInformation { export class ViewMotionCommentSection extends BaseViewModel implements MotionCommentSectionTitleInformation { public static COLLECTIONSTRING = MotionCommentSection.COLLECTIONSTRING; + protected _collectionString = MotionCommentSection.COLLECTIONSTRING; private _read_groups: ViewGroup[]; private _write_groups: ViewGroup[]; @@ -59,10 +60,6 @@ export class ViewMotionCommentSection extends BaseViewModel implements MotionTitleInformation, Searchable { public static COLLECTIONSTRING = Motion.COLLECTIONSTRING; + protected _collectionString = Motion.COLLECTIONSTRING; protected _category?: ViewCategory; protected _submitters?: ViewSubmitter[]; @@ -340,10 +341,6 @@ export class ViewMotion extends BaseViewModelWithAgendaItemAndListOfSpeakers string; - public constructor(motion: Motion) { - super(Motion.COLLECTIONSTRING, motion); - } - /** * Formats the category for search * diff --git a/client/src/app/site/motions/models/view-state.ts b/client/src/app/site/motions/models/view-state.ts index 84316e81a..20f574380 100644 --- a/client/src/app/site/motions/models/view-state.ts +++ b/client/src/app/site/motions/models/view-state.ts @@ -12,6 +12,7 @@ export interface StateTitleInformation { */ export class ViewState extends BaseViewModel implements StateTitleInformation { public static COLLECTIONSTRING = State.COLLECTIONSTRING; + protected _collectionString = State.COLLECTIONSTRING; private _next_states?: ViewState[]; public _workflow?: ViewWorkflow; @@ -92,8 +93,4 @@ export class ViewState extends BaseViewModel implements StateTitleInforma return state.next_states_id.includes(this.id); }); } - - public constructor(state: State) { - super(State.COLLECTIONSTRING, state); - } } diff --git a/client/src/app/site/motions/models/view-statute-paragraph.ts b/client/src/app/site/motions/models/view-statute-paragraph.ts index 701a6ae56..1634f9ae0 100644 --- a/client/src/app/site/motions/models/view-statute-paragraph.ts +++ b/client/src/app/site/motions/models/view-statute-paragraph.ts @@ -17,6 +17,7 @@ export interface StatuteParagraphTitleInformation { export class ViewStatuteParagraph extends BaseViewModel implements StatuteParagraphTitleInformation, Searchable { public static COLLECTIONSTRING = StatuteParagraph.COLLECTIONSTRING; + protected _collectionString = StatuteParagraph.COLLECTIONSTRING; public get statuteParagraph(): StatuteParagraph { return this._model; @@ -34,10 +35,6 @@ export class ViewStatuteParagraph extends BaseViewModel return this.statuteParagraph.weight; } - public constructor(statuteParagraph: StatuteParagraph) { - super(StatuteParagraph.COLLECTIONSTRING, statuteParagraph); - } - public formatForSearch(): SearchRepresentation { return [this.title]; } diff --git a/client/src/app/site/motions/models/view-submitter.ts b/client/src/app/site/motions/models/view-submitter.ts index 7c6e1e5eb..b2b121355 100644 --- a/client/src/app/site/motions/models/view-submitter.ts +++ b/client/src/app/site/motions/models/view-submitter.ts @@ -4,6 +4,8 @@ import { ViewUser } from 'app/site/users/models/view-user'; export class ViewSubmitter extends BaseViewModel { public static COLLECTIONSTRING = Submitter.COLLECTIONSTRING; + protected _collectionString = Submitter.COLLECTIONSTRING; + private _user?: ViewUser; public get submitter(): Submitter { @@ -30,10 +32,6 @@ export class ViewSubmitter extends BaseViewModel { return this.submitter.weight; } - public constructor(submitter: Submitter) { - super(Submitter.COLLECTIONSTRING, submitter); - } - public getTitle = () => { return this.user ? this.user.getTitle() : ''; }; diff --git a/client/src/app/site/motions/models/view-workflow.ts b/client/src/app/site/motions/models/view-workflow.ts index ba2b4af1c..930d4269d 100644 --- a/client/src/app/site/motions/models/view-workflow.ts +++ b/client/src/app/site/motions/models/view-workflow.ts @@ -12,6 +12,7 @@ export interface WorkflowTitleInformation { */ export class ViewWorkflow extends BaseViewModel implements WorkflowTitleInformation { public static COLLECTIONSTRING = Workflow.COLLECTIONSTRING; + protected _collectionString = Workflow.COLLECTIONSTRING; private _states?: ViewState[]; private _first_state?: ViewState; @@ -39,8 +40,4 @@ export class ViewWorkflow extends BaseViewModel implements WorkflowTit public get first_state(): ViewState | null { return this._first_state; } - - public constructor(workflow: Workflow) { - super(Workflow.COLLECTIONSTRING, workflow); - } } diff --git a/client/src/app/site/motions/modules/category/components/category-detail/category-detail.component.ts b/client/src/app/site/motions/modules/category/components/category-detail/category-detail.component.ts index 288aee6bf..40113d076 100644 --- a/client/src/app/site/motions/modules/category/components/category-detail/category-detail.component.ts +++ b/client/src/app/site/motions/modules/category/components/category-detail/category-detail.component.ts @@ -107,7 +107,7 @@ export class CategoryDetailComponent extends BaseViewComponent implements OnInit return; } - // Find index of last child. THis can be easily done by searching, becuase this + // Find index of last child. This can be easily done by searching, because this // is the flat sorted tree this.selectedCategory = categories[selectedCategoryIndex]; super.setTitle(this.selectedCategory.prefixedName); @@ -122,24 +122,10 @@ export class CategoryDetailComponent extends BaseViewComponent implements OnInit this.categories = categories.slice(selectedCategoryIndex, lastChildIndex); // setup datasources: - const allMotions = this.motionRepo - .getViewModelList() - .sort((a, b) => a.category_weight - b.category_weight); this.categories.forEach(category => { - if (!this.dataSources[category.id]) { - const dataSource = new MatTableDataSource(); - dataSource.data = allMotions.filter(motion => motion.category_id === category.id); - this.dataSources[category.id] = dataSource; - } - }); - }), - this.motionRepo.getViewModelListObservable().subscribe(motions => { - motions = motions - .filter(motion => !!motion.category_id) - .sort((a, b) => a.category_weight - b.category_weight); - Object.keys(this.dataSources).forEach(_id => { - const id = +_id; - this.dataSources[id].data = motions.filter(motion => motion.category_id === id); + const dataSource = new MatTableDataSource(); + dataSource.data = category.motions; + this.dataSources[category.id] = dataSource; }); }) ); diff --git a/client/src/app/site/motions/modules/category/components/category-list/category-list.component.html b/client/src/app/site/motions/modules/category/components/category-list/category-list.component.html index 0971e8c70..1d327c7ca 100644 --- a/client/src/app/site/motions/modules/category/components/category-list/category-list.component.html +++ b/client/src/app/site/motions/modules/category/components/category-list/category-list.component.html @@ -66,7 +66,7 @@ Motions - {{ getMotionAmount(category) }} + {{ category.motions.length }} diff --git a/client/src/app/site/motions/modules/category/components/category-list/category-list.component.ts b/client/src/app/site/motions/modules/category/components/category-list/category-list.component.ts index 18f8afa46..19f2ddfa9 100644 --- a/client/src/app/site/motions/modules/category/components/category-list/category-list.component.ts +++ b/client/src/app/site/motions/modules/category/components/category-list/category-list.component.ts @@ -95,16 +95,6 @@ export class CategoryListComponent extends BaseViewComponent implements OnInit { return ['title', 'amount', 'anchor']; } - /** - * return the amount of motions in a category - * - * @param category the category to determine the amount of motions for - * @returns a number that indicates how many motions are in the given category - */ - public getMotionAmount(category: ViewCategory): number { - return this.repo.getMotionAmountByCategory(category); - } - /** * Click handler for the plus button */ diff --git a/client/src/app/site/motions/modules/motion-block/components/motion-block-detail/motion-block-detail.component.ts b/client/src/app/site/motions/modules/motion-block/components/motion-block-detail/motion-block-detail.component.ts index d0bab4a48..df675e646 100644 --- a/client/src/app/site/motions/modules/motion-block/components/motion-block-detail/motion-block-detail.component.ts +++ b/client/src/app/site/motions/modules/motion-block/components/motion-block-detail/motion-block-detail.component.ts @@ -132,7 +132,7 @@ export class MotionBlockDetailComponent extends BaseViewComponent implements OnI this.dataSource = createDS() .onTrigger(() => { - return this.repo.getViewMotionsByBlock(this.block.motionBlock); + return this.block.motions; }) .create(); } diff --git a/client/src/app/site/motions/modules/motion-block/components/motion-block-list/motion-block-list.component.html b/client/src/app/site/motions/modules/motion-block/components/motion-block-list/motion-block-list.component.html index 1b9dddd0c..2d04cf7f2 100644 --- a/client/src/app/site/motions/modules/motion-block/components/motion-block-list/motion-block-list.component.html +++ b/client/src/app/site/motions/modules/motion-block/components/motion-block-list/motion-block-list.component.html @@ -15,22 +15,22 @@ (dataSourceChange)="onDataSourceChange($event)" > -
+
- lock + lock {{ title }}
-
- {{ getMotionAmount(block.motionBlock) }} +
+ {{ motionBlock.motions.length }}
diff --git a/client/src/app/site/motions/modules/motion-block/components/motion-block-list/motion-block-list.component.ts b/client/src/app/site/motions/modules/motion-block/components/motion-block-list/motion-block-list.component.ts index f8a6d48e7..c5a651952 100644 --- a/client/src/app/site/motions/modules/motion-block/components/motion-block-list/motion-block-list.component.ts +++ b/client/src/app/site/motions/modules/motion-block/components/motion-block-list/motion-block-list.component.ts @@ -12,7 +12,6 @@ import { OperatorService } from 'app/core/core-services/operator.service'; import { StorageService } from 'app/core/core-services/storage.service'; import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service'; import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service'; -import { MotionBlock } from 'app/shared/models/motions/motion-block'; import { infoDialogSettings } from 'app/shared/utils/dialog-settings'; import { ViewItem } from 'app/site/agenda/models/view-item'; import { BaseListViewComponent } from 'app/site/base/base-list-view'; @@ -117,16 +116,6 @@ export class MotionBlockListComponent extends BaseListViewComponent implements CountdownTitleInformation { public static COLLECTIONSTRING = Countdown.COLLECTIONSTRING; + protected _collectionString = Countdown.COLLECTIONSTRING; public get countdown(): Countdown { return this._model; @@ -34,10 +35,6 @@ export class ViewCountdown extends BaseProjectableViewModel implement return this.countdown.title; } - public constructor(countdown: Countdown) { - super(Countdown.COLLECTIONSTRING, countdown); - } - public getSlide(): ProjectorElementBuildDeskriptor { return { getBasicProjectorElement: options => ({ diff --git a/client/src/app/site/projector/models/view-projection-default.ts b/client/src/app/site/projector/models/view-projection-default.ts index 1b70835c9..92a5b2b74 100644 --- a/client/src/app/site/projector/models/view-projection-default.ts +++ b/client/src/app/site/projector/models/view-projection-default.ts @@ -8,6 +8,7 @@ export interface ProjectionDefaultTitleInformation { export class ViewProjectionDefault extends BaseViewModel implements ProjectionDefaultTitleInformation { public static COLLECTIONSTRING = ProjectionDefault.COLLECTIONSTRING; + protected _collectionString = ProjectionDefault.COLLECTIONSTRING; public get projectionDefault(): ProjectionDefault { return this._model; @@ -24,8 +25,4 @@ export class ViewProjectionDefault extends BaseViewModel public get display_name(): string { return this.projectionDefault.display_name; } - - public constructor(projectionDefault: ProjectionDefault) { - super(ProjectionDefault.COLLECTIONSTRING, projectionDefault); - } } diff --git a/client/src/app/site/projector/models/view-projector-message.ts b/client/src/app/site/projector/models/view-projector-message.ts index 0433946b5..18d50d765 100644 --- a/client/src/app/site/projector/models/view-projector-message.ts +++ b/client/src/app/site/projector/models/view-projector-message.ts @@ -8,6 +8,7 @@ export type ProjectorMessageTitleInformation = object; export class ViewProjectorMessage extends BaseProjectableViewModel implements ProjectorMessageTitleInformation { public static COLLECTIONSTRING = ProjectorMessage.COLLECTIONSTRING; + protected _collectionString = ProjectorMessage.COLLECTIONSTRING; public get projectormessage(): ProjectorMessage { return this._model; @@ -17,10 +18,6 @@ export class ViewProjectorMessage extends BaseProjectableViewModel ({ diff --git a/client/src/app/site/projector/models/view-projector.ts b/client/src/app/site/projector/models/view-projector.ts index 63b0835b3..26f071b94 100644 --- a/client/src/app/site/projector/models/view-projector.ts +++ b/client/src/app/site/projector/models/view-projector.ts @@ -7,6 +7,7 @@ export interface ProjectorTitleInformation { export class ViewProjector extends BaseViewModel { public static COLLECTIONSTRING = Projector.COLLECTIONSTRING; + protected _collectionString = Projector.COLLECTIONSTRING; private _referenceProjector: ViewProjector; @@ -105,8 +106,4 @@ export class ViewProjector extends BaseViewModel { public get show_logo(): boolean { return this.projector.show_logo; } - - public constructor(projector: Projector) { - super(Projector.COLLECTIONSTRING, projector); - } } diff --git a/client/src/app/site/projector/projector.config.ts b/client/src/app/site/projector/projector.config.ts index d8ce60ac0..c0b8012cd 100644 --- a/client/src/app/site/projector/projector.config.ts +++ b/client/src/app/site/projector/projector.config.ts @@ -1,4 +1,4 @@ -import { AppConfig } from '../../core/app-config'; +import { AppConfig } from '../../core/definitions/app-config'; import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service'; import { ProjectionDefaultRepositoryService } from 'app/core/repositories/projector/projection-default-repository.service'; import { ProjectorMessageRepositoryService } from 'app/core/repositories/projector/projector-message-repository.service'; diff --git a/client/src/app/site/tags/models/view-tag.ts b/client/src/app/site/tags/models/view-tag.ts index 4264b188a..ce58726e8 100644 --- a/client/src/app/site/tags/models/view-tag.ts +++ b/client/src/app/site/tags/models/view-tag.ts @@ -16,6 +16,7 @@ export interface TagTitleInformation { */ export class ViewTag extends BaseViewModel implements TagTitleInformation, Searchable { public static COLLECTIONSTRING = Tag.COLLECTIONSTRING; + protected _collectionString = Tag.COLLECTIONSTRING; public get tag(): Tag { return this._model; @@ -25,10 +26,6 @@ export class ViewTag extends BaseViewModel implements TagTitleInformation, return this.tag.name; } - public constructor(tag: Tag) { - super(Tag.COLLECTIONSTRING, tag); - } - public formatForSearch(): SearchRepresentation { return [this.name]; } diff --git a/client/src/app/site/tags/tag.config.ts b/client/src/app/site/tags/tag.config.ts index 18ac98b0d..99377fccc 100644 --- a/client/src/app/site/tags/tag.config.ts +++ b/client/src/app/site/tags/tag.config.ts @@ -1,4 +1,4 @@ -import { AppConfig } from '../../core/app-config'; +import { AppConfig } from '../../core/definitions/app-config'; import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository.service'; import { Tag } from '../../shared/models/core/tag'; import { ViewTag } from './models/view-tag'; diff --git a/client/src/app/site/topics/models/view-topic.ts b/client/src/app/site/topics/models/view-topic.ts index fdb640deb..0361f9e84 100644 --- a/client/src/app/site/topics/models/view-topic.ts +++ b/client/src/app/site/topics/models/view-topic.ts @@ -16,6 +16,7 @@ export interface TopicTitleInformation extends TitleInformationWithAgendaItem { */ export class ViewTopic extends BaseViewModelWithAgendaItemAndListOfSpeakers implements TopicTitleInformation { public static COLLECTIONSTRING = Topic.COLLECTIONSTRING; + protected _collectionString = Topic.COLLECTIONSTRING; private _attachments?: ViewMediafile[]; @@ -39,10 +40,6 @@ export class ViewTopic extends BaseViewModelWithAgendaItemAndListOfSpeakers impl return this.topic.text; } - public constructor(topic: Topic) { - super(Topic.COLLECTIONSTRING, topic); - } - /** * Formats the category for search * diff --git a/client/src/app/site/topics/topics.config.ts b/client/src/app/site/topics/topics.config.ts index 9ba115fd7..957bf0d13 100644 --- a/client/src/app/site/topics/topics.config.ts +++ b/client/src/app/site/topics/topics.config.ts @@ -1,4 +1,4 @@ -import { AppConfig } from '../../core/app-config'; +import { AppConfig } from '../../core/definitions/app-config'; import { TopicRepositoryService } from 'app/core/repositories/topics/topic-repository.service'; import { Topic } from '../../shared/models/topics/topic'; import { ViewTopic } from './models/view-topic'; diff --git a/client/src/app/site/users/models/view-group.ts b/client/src/app/site/users/models/view-group.ts index 8d783e6e3..aba0f2778 100644 --- a/client/src/app/site/users/models/view-group.ts +++ b/client/src/app/site/users/models/view-group.ts @@ -7,6 +7,7 @@ export interface GroupTitleInformation { export class ViewGroup extends BaseViewModel implements GroupTitleInformation { public static COLLECTIONSTRING = Group.COLLECTIONSTRING; + protected _collectionString = Group.COLLECTIONSTRING; public get group(): Group { return this._model; @@ -29,10 +30,6 @@ export class ViewGroup extends BaseViewModel implements GroupTitleInforma return this.group.permissions; } - public constructor(group?: Group) { - super(Group.COLLECTIONSTRING, group); - } - public hasPermission(perm: string): boolean { return this.permissions.includes(perm); } diff --git a/client/src/app/site/users/models/view-personal-note.ts b/client/src/app/site/users/models/view-personal-note.ts index ad54f2599..8584a9b15 100644 --- a/client/src/app/site/users/models/view-personal-note.ts +++ b/client/src/app/site/users/models/view-personal-note.ts @@ -5,6 +5,7 @@ export type PersonalNoteTitleInformation = object; export class ViewPersonalNote extends BaseViewModel implements PersonalNoteTitleInformation { public static COLLECTIONSTRING = PersonalNote.COLLECTIONSTRING; + protected _collectionString = PersonalNote.COLLECTIONSTRING; public get personalNote(): PersonalNote { return this._model; @@ -18,10 +19,6 @@ export class ViewPersonalNote extends BaseViewModel implements Per return this.personalNote.notes; } - public constructor(personalNote: PersonalNote) { - super(PersonalNote.COLLECTIONSTRING, personalNote); - } - public getNoteContent(collection: string, id: number): PersonalNoteContent | null { if (this.notes[collection]) { return this.notes[collection][id]; diff --git a/client/src/app/site/users/models/view-user.ts b/client/src/app/site/users/models/view-user.ts index bbea56037..77ff6e49e 100644 --- a/client/src/app/site/users/models/view-user.ts +++ b/client/src/app/site/users/models/view-user.ts @@ -16,6 +16,7 @@ export interface UserTitleInformation { export class ViewUser extends BaseProjectableViewModel implements UserTitleInformation, Searchable { public static COLLECTIONSTRING = User.COLLECTIONSTRING; + protected _collectionString = User.COLLECTIONSTRING; private _groups: ViewGroup[]; @@ -120,10 +121,6 @@ export class ViewUser extends BaseProjectableViewModel implements UserTitl public getFullName: () => string; public getShortName: () => string; - public constructor(user: User) { - super(User.COLLECTIONSTRING, user); - } - /** * Formats the category for search * diff --git a/client/src/app/site/users/users.config.ts b/client/src/app/site/users/users.config.ts index 74ddde762..c3b24868d 100644 --- a/client/src/app/site/users/users.config.ts +++ b/client/src/app/site/users/users.config.ts @@ -1,4 +1,4 @@ -import { AppConfig } from '../../core/app-config'; +import { AppConfig } from '../../core/definitions/app-config'; import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service'; import { PersonalNoteRepositoryService } from 'app/core/repositories/users/personal-note-repository.service'; import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';